boulder/linter/lints/rfc/lint_crl_has_number.go

68 lines
1.8 KiB
Go

package rfc
import (
"github.com/zmap/zcrypto/encoding/asn1"
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
"github.com/letsencrypt/boulder/linter/lints"
)
type crlHasNumber struct{}
/************************************************
RFC 5280: 5.2.3
CRL issuers conforming to this profile MUST include this extension in all CRLs
and MUST mark this extension as non-critical. Conforming CRL issuers MUST NOT
use CRLNumber values longer than 20 octets.
************************************************/
func init() {
lint.RegisterRevocationListLint(&lint.RevocationListLint{
LintMetadata: lint.LintMetadata{
Name: "e_crl_has_number",
Description: "CRLs must have a well-formed CRL Number extension",
Citation: "RFC 5280: 5.2.3",
Source: lint.RFC5280,
EffectiveDate: util.RFC5280Date,
},
Lint: NewCrlHasNumber,
})
}
func NewCrlHasNumber() lint.RevocationListLintInterface {
return &crlHasNumber{}
}
func (l *crlHasNumber) CheckApplies(c *x509.RevocationList) bool {
return true
}
func (l *crlHasNumber) Execute(c *x509.RevocationList) *lint.LintResult {
if c.Number == nil {
return &lint.LintResult{
Status: lint.Error,
Details: "CRLs MUST include the CRL number extension",
}
}
crlNumberOID := asn1.ObjectIdentifier{2, 5, 29, 20} // id-ce-cRLNumber
ext := lints.GetExtWithOID(c.Extensions, crlNumberOID)
if ext != nil && ext.Critical {
return &lint.LintResult{
Status: lint.Error,
Details: "CRL Number MUST NOT be marked critical",
}
}
numBytes := c.Number.Bytes()
if len(numBytes) > 20 || (len(numBytes) == 20 && numBytes[0]&0x80 != 0) {
return &lint.LintResult{
Status: lint.Error,
Details: "CRL Number MUST NOT be longer than 20 octets",
}
}
return &lint.LintResult{Status: lint.Pass}
}