github.com/letsencrypt/boulder@v0.20251208.0/linter/lints/rfc/lint_crl_has_number.go (about) 1 package rfc 2 3 import ( 4 "github.com/zmap/zcrypto/encoding/asn1" 5 "github.com/zmap/zcrypto/x509" 6 "github.com/zmap/zlint/v3/lint" 7 "github.com/zmap/zlint/v3/util" 8 9 "github.com/letsencrypt/boulder/linter/lints" 10 ) 11 12 type crlHasNumber struct{} 13 14 /************************************************ 15 RFC 5280: 5.2.3 16 CRL issuers conforming to this profile MUST include this extension in all CRLs 17 and MUST mark this extension as non-critical. Conforming CRL issuers MUST NOT 18 use CRLNumber values longer than 20 octets. 19 ************************************************/ 20 21 func init() { 22 lint.RegisterRevocationListLint(&lint.RevocationListLint{ 23 LintMetadata: lint.LintMetadata{ 24 Name: "e_crl_has_number", 25 Description: "CRLs must have a well-formed CRL Number extension", 26 Citation: "RFC 5280: 5.2.3", 27 Source: lint.RFC5280, 28 EffectiveDate: util.RFC5280Date, 29 }, 30 Lint: NewCrlHasNumber, 31 }) 32 } 33 34 func NewCrlHasNumber() lint.RevocationListLintInterface { 35 return &crlHasNumber{} 36 } 37 38 func (l *crlHasNumber) CheckApplies(c *x509.RevocationList) bool { 39 return true 40 } 41 42 func (l *crlHasNumber) Execute(c *x509.RevocationList) *lint.LintResult { 43 if c.Number == nil { 44 return &lint.LintResult{ 45 Status: lint.Error, 46 Details: "CRLs MUST include the CRL number extension", 47 } 48 } 49 50 crlNumberOID := asn1.ObjectIdentifier{2, 5, 29, 20} // id-ce-cRLNumber 51 ext := lints.GetExtWithOID(c.Extensions, crlNumberOID) 52 if ext != nil && ext.Critical { 53 return &lint.LintResult{ 54 Status: lint.Error, 55 Details: "CRL Number MUST NOT be marked critical", 56 } 57 } 58 59 numBytes := c.Number.Bytes() 60 if len(numBytes) > 20 || (len(numBytes) == 20 && numBytes[0]&0x80 != 0) { 61 return &lint.LintResult{ 62 Status: lint.Error, 63 Details: "CRL Number MUST NOT be longer than 20 octets", 64 } 65 } 66 return &lint.LintResult{Status: lint.Pass} 67 }