grpc/grpc-go · error

trailing data after AKID extension

Error message

trailing data after AKID extension

What it means

Returned by parseCRLExtensions when asn1.Unmarshal of the AuthorityKeyIdentifier extension consumed the value but left non-empty trailing bytes. RFC 5280 expects a single SEQUENCE encoding with no leftover; trailing bytes indicate the extension is malformed or has been tampered with, and grpc-go refuses to use the CRL.

Solutions

  1. Re-download the CRL from the CA's distribution point to rule out transfer corruption.
  2. Validate the CRL with openssl crl -inform DER -text -noout and confirm no ASN.1 errors are reported.
  3. If the CA's CRL is genuinely non-conformant, request a fixed CRL or disable CRL checking for that issuer (with documented risk).
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify a CRL's AKID extension parses cleanly before installing it.
func precheckAKID(crlDER []byte) error {
    l, err := x509.ParseRevocationList(crlDER)
    if err != nil { return err }
    for _, ext := range l.Extensions {
        if ext.Id.Equal(oidAuthorityKeyIdentifier) {
            var a authKeyID
            rest, err := asn1.Unmarshal(ext.Value, &a)
            if err != nil { return err }
            if len(rest) != 0 { return errors.New("AKID has trailing bytes") }
        }
    }
    return nil
}

Try / catch

When loading a CRL, wrap the parse in error handling: on malformed-extension errors, log the CRL URL and skip installing it (do not crash the server). Re-fetch after backoff.

Prevention

When it happens

Trigger: The CRL's AuthorityKeyIdentifier extension value decodes to a valid authKeyID struct but extra bytes remain (len(rest) != 0). Encountered when loading/parsing a CRL file via the advancedtls CRL provider.

Common situations: Corrupted or truncated CRL file. CRL produced by non-conformant CA software that appended extra fields to the AKID extension. Hand-edited/DER-patched CRL used for testing.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/8e3933183fbf8313. Report an issue: GitHub.

Appendix: source

Thrown at security/advancedtls/crl.go:332

// parseCRLExtensions parses the extensions for a CRL
// and checks that they're supported by the parser.
func parseCRLExtensions(c *x509.RevocationList) (*CRL, error) {
	if c == nil {
		return nil, errors.New("c is nil, expected any value")
	}
	certList := &CRL{certList: c}

	for _, ext := range c.Extensions {
		switch {
		case oidDeltaCRLIndicator.Equal(ext.Id):
			return nil, fmt.Errorf("delta CRLs unsupported")

		case oidAuthorityKeyIdentifier.Equal(ext.Id):
			var a authKeyID
			if rest, err := asn1.Unmarshal(ext.Value, &a); err != nil {
				return nil, fmt.Errorf("asn1.Unmarshal failed: %v", err)
			} else if len(rest) != 0 {
				return nil, errors.New("trailing data after AKID extension")
			}
			certList.authorityKeyID = a.ID

		case oidIssuingDistributionPoint.Equal(ext.Id):
			var dp issuingDistributionPoint
			if rest, err := asn1.Unmarshal(ext.Value, &dp); err != nil {
				return nil, fmt.Errorf("asn1.Unmarshal failed: %v", err)
			} else if len(rest) != 0 {
				return nil, errors.New("trailing data after IssuingDistributionPoint extension")
			}

			if dp.OnlyContainsUserCerts || dp.OnlyContainsCACerts || dp.OnlyContainsAttributeCerts {
				return nil, errors.New("CRL only contains some certificate types")
			}
			if dp.IndirectCRL {
				return nil, errors.New("indirect CRLs unsupported")
			}
			if dp.OnlySomeReasons.BitLength != 0 {

View on GitHub (pinned to 0c51461d27)