grpc/grpc-go · error

onlySomeReasons unsupported

Error message

onlySomeReasons unsupported

What it means

Returned by parseCRLExtensions when the IssuingDistributionPoint extension carries a non-empty onlySomeReasons bit string. onlySomeReasons narrows a CRL to revocations for specific reason codes (e.g. keyCompromise only); grpc-go does not implement reason-scoped revocation matching, so such CRLs are rejected to avoid false 'unrevoked' answers.

Solutions

  1. Provide a full CRL whose IDP does not set onlySomeReasons.
  2. If reason partitioning is mandatory, fall back to OCSP for revocation status.
  3. Confirm with the CA that a base (unpartitioned) CRL is available at a different distribution point.
Defensive patterns

Strategy: validation

Validate before calling

// Reject reason-scoped CRLs up front.
func isUnscopedCRL(crlDER []byte) (bool, error) {
    l, err := x509.ParseRevocationList(crlDER)
    if err != nil { return false, err }
    for _, ext := range l.Extensions {
        if ext.Id.Equal(oidIssuingDistributionPoint) {
            var dp issuingDistributionPoint
            if _, err := asn1.Unmarshal(ext.Value, &dp); err != nil { return false, err }
            if dp.OnlySomeReasons.BitLength != 0 { return false, nil }
        }
    }
    return true, nil
}

Try / catch

Treat the parse error as 'CRL not usable'; keep the previous unscoped CRL active. Alert PKI/ops so a base CRL is published.

Prevention

When it happens

Trigger: The CRL's IDP extension has OnlySomeReasons with a non-zero BitLength. Encountered while parsing the CRL in the advancedtls CRL verifier.

Common situations: A CA publishes reason-partitioned CRLs (one for keyCompromise, one for caCompromise, etc.). Operator pointed the CRL provider at one of these partitions. Specialized enterprise PKI that splits revocation by reason.

Related errors


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

Appendix: source

Thrown at security/advancedtls/crl.go:351

			}
			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 {
				return nil, errors.New("onlySomeReasons unsupported")
			}

		case ext.Critical:
			return nil, fmt.Errorf("unsupported critical extension: %v", ext.Id)
		}
	}

	if len(certList.authorityKeyID) == 0 {
		return nil, errors.New("authority key identifier extension missing")
	}
	return certList, nil
}

func verifyCRL(crl *CRL, chain []*x509.Certificate) error {
	// RFC5280, 6.3.3 (f) Obtain and validate the certification path for the issuer of the complete CRL
	// We intentionally limit our CRLs to be signed with the same certificate path as the certificate
	// so we can use the chain from the connection.

View on GitHub (pinned to 0c51461d27)