{"record":{"id":"c1ad59e448ac4dfb","repo":"grpc/grpc-go","slug":"authority-key-identifier-extension-missing","errorCode":null,"errorMessage":"authority key identifier extension missing","messagePattern":"authority key identifier extension missing","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"security/advancedtls/crl.go","lineNumber":360,"sourceCode":"\t\t\t}\n\n\t\t\tif dp.OnlyContainsUserCerts || dp.OnlyContainsCACerts || dp.OnlyContainsAttributeCerts {\n\t\t\t\treturn nil, errors.New(\"CRL only contains some certificate types\")\n\t\t\t}\n\t\t\tif dp.IndirectCRL {\n\t\t\t\treturn nil, errors.New(\"indirect CRLs unsupported\")\n\t\t\t}\n\t\t\tif dp.OnlySomeReasons.BitLength != 0 {\n\t\t\t\treturn nil, errors.New(\"onlySomeReasons unsupported\")\n\t\t\t}\n\n\t\tcase ext.Critical:\n\t\t\treturn nil, fmt.Errorf(\"unsupported critical extension: %v\", ext.Id)\n\t\t}\n\t}\n\n\tif len(certList.authorityKeyID) == 0 {\n\t\treturn nil, errors.New(\"authority key identifier extension missing\")\n\t}\n\treturn certList, nil\n}\n\nfunc verifyCRL(crl *CRL, chain []*x509.Certificate) error {\n\t// RFC5280, 6.3.3 (f) Obtain and validate the certification path for the issuer of the complete CRL\n\t// We intentionally limit our CRLs to be signed with the same certificate path as the certificate\n\t// so we can use the chain from the connection.\n\n\tfor _, c := range chain {\n\t\t// Use the key where the subject and KIDs match.\n\t\t// This departs from RFC4158, 3.5.12 which states that KIDs\n\t\t// cannot eliminate certificates, but RFC5280, 5.2.1 states that\n\t\t// \"Conforming CRL issuers MUST use the key identifier method, and MUST\n\t\t// include this extension in all CRLs issued.\"\n\t\t// So, this is much simpler than RFC4158 and should be compatible.\n\t\tif bytes.Equal(c.SubjectKeyId, crl.authorityKeyID) && bytes.Equal(c.RawSubject, crl.rawIssuer) {\n\t\t\t// RFC5280, 6.3.3 (f) Key usage and cRLSign bit.","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/security/advancedtls/crl.go#L342-L378","documentation":"Returned by parseCRLExtensions (crl.go:359) after iterating all CRL extensions if no Authority Key Identifier (AKID) was found. RFC 5280 section 5.2.1 mandates that conforming CRL issuers include the AKID extension in every CRL, and gRPC relies on it to match the CRL issuer to a certificate in the peer chain (see verifyCRL at crl.go:377). Without it, the validator cannot safely bind the CRL to an issuer and refuses it.","triggerScenarios":"Loading a CRL that lacks the Authority Key Identifier extension (oid 2.5.29.35) into advancedtls revocation checking. The loop never hits the oidAuthorityKeyIdentifier case, so certList.authorityKeyID stays empty and the post-loop check fails.","commonSituations":"Legacy or non-conformant CA that omits the AKID extension; a manually crafted/edited CRL; a CA whose newer CRLs dropped the field due to a misconfiguration; some Windows-based or older OpenSSL CAs historically produced AKID-less CRLs.","solutions":["Re-fetch the CRL from the CA's distribution point; if the issue persists, regenerate the CRL with OpenSSL `ca -gencrl` from a CA cert that itself has a Subject Key Identifier.","Ensure the issuing CA certificate has a Subject Key Identifier (SKID), since most CAs copy AKID from the issuer's SKID.","Validate the CRL with `openssl crl -in crl.pem -noout -text` and confirm an 'Authority Key Identifier' section is present before loading it."],"exampleFix":"// before: CRL has no AKID extension -> rejected\n// after: regenerate CRL from a CA cert that has Subject Key Identifier\n//   openssl ca -gencrl -out crl.pem\n// Verify AKID present:\n//   openssl crl -in crl.pem -noout -text | grep -A2 'Authority Key'","handlingStrategy":"validation","validationCode":"import \"crypto/x509\"\n\nfunc crlHasAKID(c *x509.RevocationList) bool {\n    if c == nil { return false }\n    // Authority Key Identifier oid 2.5.29.35\n    oidAKI := []int{2, 5, 29, 35}\n    for _, ext := range c.Extensions {\n        if len(ext.Id) == len(oidAKI) {\n            match := true\n            for i := range oidAKI {\n                if ext.Id[i] != oidAKI[i] { match = false; break }\n            }\n            if match { return true }\n        }\n    }\n    return false\n}","typeGuard":"func isConformantCRL(c *x509.RevocationList) bool {\n    return c != nil && crlHasAKID(c)\n}","tryCatchPattern":null,"preventionTips":["Confirm 'Authority Key Identifier' appears in `openssl crl -text` output.","Ensure issuing CA certs carry a Subject Key Identifier so CAs copy it into the CRL AKID.","Unit-test your CRL loader against a deliberately AKID-less CRL to confirm clean rejection."],"tags":["crl","advancedtls","security","x509","pki","revocation"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}