golang/go · error

crypto/rsa: missing public modulus

Error message

crypto/rsa: missing public modulus

What it means

Returned by checkPublicKeySize when k.N is nil. checkPublicKeySize runs at the entry of every public operation that uses a PublicKey (EncryptPKCS1v15, EncryptOAEP, VerifyPKCS1v15, VerifyPSS, SignJSON callers via the encrypt/verify wrappers). A nil N means the key was never populated — there is no modulus to operate on, so the operation cannot proceed.

Source

Thrown at src/crypto/rsa/rsa.go:303

// rsa1024min is a GODEBUG that re-enables weak RSA keys if set to "0".
// See https://go.dev/issue/68762.
var rsa1024min = godebug.New("rsa1024min")

func checkKeySize(size int) error {
	if size >= 1024 {
		return nil
	}
	if rsa1024min.Value() == "0" {
		rsa1024min.IncNonDefault()
		return nil
	}
	return fmt.Errorf("crypto/rsa: %d-bit keys are insecure (see https://go.dev/pkg/crypto/rsa#hdr-Minimum_key_size)", size)
}

func checkPublicKeySize(k *PublicKey) error {
	if k.N == nil {
		return errors.New("crypto/rsa: missing public modulus")
	}
	return checkKeySize(k.N.BitLen())
}

// GenerateKey generates a random RSA private key of the given bit size.
//
// If bits is less than 1024, [GenerateKey] returns an error. See the "[Minimum
// key size]" section for further details.
//
// Since Go 1.26, a secure source of random bytes is always used, and the Reader is
// ignored unless GODEBUG=cryptocustomrand=1 is set. This setting will be removed
// in a future Go release. Instead, use [testing/cryptotest.SetGlobalRandom].
//
// [Minimum key size]: https://pkg.go.dev/crypto/rsa#hdr-Minimum_key_size
func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
	if err := checkKeySize(bits); err != nil {
		return nil, err
	}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure the *rsa.PublicKey was produced by x509.ParsePKIXPublicKey / ParsePKCS1PublicKey and that the input was actually RSA.
  2. Add a nil check: if pub == nil || pub.N == nil { return ErrInvalidKey }.
  3. Construct public-key variables only via parsing helpers or rsa.PrivateKey.PublicKey, never by hand.

Example fix

// before
var pub rsa.PublicKey // zero value, N == nil
ct, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, &pub, msg, nil)

// after
pubAny, err := x509.ParsePKIXPublicKey(der)
if err != nil { return err }
pub, ok := pubAny.(*rsa.PublicKey)
if !ok || pub.N == nil { return errors.New("not an RSA public key") }
ct, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, pub, msg, nil)
Defensive patterns

Strategy: validation

Validate before calling

if pub == nil || pub.N == nil {
    return errors.New("RSA public key is missing modulus")
}
return nil // then call EncryptOAEP/Verify*

Type guard

func isUsableRSAPublicKey(pub *rsa.PublicKey) bool {
    return pub != nil && pub.N != nil && pub.N.Sign() > 0 && pub.E > 0
}

Prevention

When it happens

Trigger: Use a zero-value rsa.PublicKey{}; call rsa.EncryptOAEP on a *rsa.PublicKey whose N was not assigned; parse a key with x509.ParsePKIXPublicKey but type-asserted to *rsa.PublicKey when the underlying algorithm was ECDSA (N stays nil).

Common situations: Default struct initialization in tests; wrong type assertion after parsing (e.g. *rsa.PublicKey vs *ecdsa.PublicKey); copying only E but not N from a parsed key.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/f87588b1f9f555ee. Report an issue: GitHub.