{"record":{"id":"c86db1d9db11d04e","repo":"golang/go","slug":"crypto-rsa-invalid-prime","errorCode":null,"errorMessage":"crypto/rsa: invalid prime","messagePattern":"crypto/rsa: invalid prime","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/internal/fips140/rsa/rsa.go","lineNumber":219,"sourceCode":"\tif priv.dP == nil {\n\t\t// Legacy and deprecated multi-prime keys.\n\t\tpriv.fipsApproved = false\n\t\treturn nil\n\t}\n\n\tN := priv.pub.N\n\tp := priv.p\n\tq := priv.q\n\n\t// FIPS 186-5, Section 5.1 requires \"that p and q be of the same bit length.\"\n\tif p.BitLen() != q.BitLen() {\n\t\tpriv.fipsApproved = false\n\t}\n\n\t// Check that pq ≡ 1 mod N (and that p < N and q < N).\n\tpN := bigmod.NewNat().ExpandFor(N)\n\tif _, err := pN.SetBytes(p.Nat().Bytes(p), N); err != nil {\n\t\treturn errors.New(\"crypto/rsa: invalid prime\")\n\t}\n\tqN := bigmod.NewNat().ExpandFor(N)\n\tif _, err := qN.SetBytes(q.Nat().Bytes(q), N); err != nil {\n\t\treturn errors.New(\"crypto/rsa: invalid prime\")\n\t}\n\tif pN.Mul(qN, N).IsZero() != 1 {\n\t\treturn errors.New(\"crypto/rsa: p * q != n\")\n\t}\n\n\t// Check that de ≡ 1 mod p-1, and de ≡ 1 mod q-1.\n\t//\n\t// This implies that e is coprime to each p-1 as e has a multiplicative\n\t// inverse. Therefore e is coprime to lcm(p-1,q-1) = λ(N).\n\t// It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 mod p. Thus a^de ≡ a\n\t// mod n for all a coprime to n, as required.\n\t//\n\t// This checks dP, dQ, and e.\n\tpMinus1, err := bigmod.NewModulus(p.Nat().SubOne(p).Bytes(p))","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/rsa/rsa.go#L201-L237","documentation":"Thrown by the private-key consistency check when p's byte representation cannot be set into a bigmod Nat sized for modulus N (pN.SetBytes fails). SetBytes rejects values >= the modulus, so this fires when p >= N. For a valid RSA key N = p*q with p,q > 1, p is always strictly less than N, so failure means the key's p and N are inconsistent.","triggerScenarios":"The key-validation routine runs (e.g. during rsa.GenerateKey sanity pass or explicit validation) and p.Nat().Bytes(p) is too large to fit modulus N. Indicates p >= N in the supplied key material.","commonSituations":"Swapped fields during key import (p loaded where N belongs). A copy/paste or endianness error in serialized key parsing. Tampered or randomly corrupted key bytes.","solutions":["Re-serialize and re-import the key using the standard crypto/x509 or encoding/asn1 parsers instead of manual field assignment.","Verify N == p*q with math/big before invoking the fips RSA path.","Compare against a known-good export of the same key to locate the field swap."],"exampleFix":"// before\n// manual field assignment from parsed ASN.1, p and N possibly swapped\n\n// after\n// use standard parser which assigns fields in defined order\nkey, err := x509.ParsePKCS1PrivateKey(pkcs1DER)","handlingStrategy":"validation","validationCode":"if p.Cmp(n) >= 0 {\n    return errors.New(\"p must be less than N\")\n}","typeGuard":"func primeFitsModulus(p, n *big.Int) bool { return p.Cmp(n) < 0 }","tryCatchPattern":"err := validateKey(priv)\nif err != nil && strings.Contains(err.Error(), \"invalid prime\") {\n    // re-import or regenerate; do not use the key\n    return err\n}","preventionTips":["Parse keys with x509.ParsePKCS1PrivateKey / ParsePKCS8PrivateKey instead of manual field assignment.","Cross-check p < N and q < N with math/big on import.","Keep the source-of-truth key in a keystore/HSM to avoid field-swap corruption."],"tags":["crypto","rsa","key-validation","go"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}