OpenNHP/opennhp · error

invalid n

Error message

invalid n: %w

What it means

parseTeePubkey decodes the JWK-style RSA public key fields with base64.RawURLEncoding. This error is returned when the teePubKey.n field is not valid unpadded base64url, so the modulus cannot be decoded. The underlying decode error is wrapped in 'invalid n: %w'.

Solutions

  1. Fix the client to emit n as unpadded base64url (base64.RawURLEncoding on the producer side)
  2. Strip any '=' padding before decoding: base64.RawURLEncoding.DecodeString(strings.TrimRight(pubkey.N, "="))
  3. Try a tolerant decoder that attempts RawURLEncoding then RawStdEncoding
  4. Validate the n field on receipt and return a clear 400 to the client instead of an internal 500

Example fix

// before
nBytes, err := base64.RawURLEncoding.DecodeString(pubkey.N)
if err != nil {
	return nil, fmt.Errorf("invalid n: %w", err)
}
// after
nBytes, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(pubkey.N, "="))
if err != nil {
	return nil, fmt.Errorf("invalid n encoding (expect unpadded base64url): %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

var jwk struct{ Kty, N, E string }
if err := json.Unmarshal(body, &jwk); err != nil || jwk.Kty != "RSA" {
	return fmt.Errorf("expect RSA JWK")
}
if _, err := base64.RawURLEncoding.DecodeString(jwk.N); err != nil {
	return fmt.Errorf("n is not unpadded base64url")
}

Type guard

func isValidRawURLBase64(s string) bool {
	_, err := base64.RawURLEncoding.DecodeString(s)
	return err == nil && s != ""
}

Try / catch

pubkey, err := parseTeePubkey(body)
if err != nil {
	if strings.HasPrefix(err.Error(), "invalid n") || strings.HasPrefix(err.Error(), "invalid e") {
		http.Error(w, "malformed TEK public key", http.StatusBadRequest)
		return
	}
	return err
}

Prevention

When it happens

Trigger: Attest receives a TEK pubkey JSON whose n contains padded base64 ('=' chars), standard-base64 symbols ('+','/'), whitespace, or other invalid characters, and RawURLEncoding.DecodeString fails.

Common situations: Clients producing JWKs with padded base64url; a JSON value that got percent-encoded or newline-wrapped; hand-edited keys; mixing standard and URL-safe alphabets between signer and verifier.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/5af6083ab1a5a832. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/server/kbs/attest/attest.go:108

		"kbs-session-id",
		sessionID,
		3600,
		"/", "", true, true, // Secure: only send over HTTPS
	)

	c.JSON(http.StatusOK, gin.H{
		"token": token,
	})
}

func parseTeePubkey(pubkey TeePubkey) (*rsa.PublicKey, error) {
	if pubkey.Kty != "RSA" {
		return nil, errors.New("unsupported key type, expect RSA")
	}

	nBytes, err := base64.RawURLEncoding.DecodeString(pubkey.N)
	if err != nil {
		return nil, fmt.Errorf("invalid n: %w", err)
	}

	eBytes, err := base64.RawURLEncoding.DecodeString(pubkey.E)
	if err != nil {
		return nil, fmt.Errorf("invalid e: %w", err)
	}

	e := 0
	for _, b := range eBytes {
		e = e<<8 | int(b)
	}

	return &rsa.PublicKey{
		N: new(big.Int).SetBytes(nBytes),
		E: e,
	}, nil
}

View on GitHub (pinned to 6e04ca5ff0)