diff --git a/ca/crl.go b/ca/crl.go index aa4118f64..070153120 100644 --- a/ca/crl.go +++ b/ca/crl.go @@ -127,6 +127,12 @@ func (ci *crlImpl) GenerateCRL(stream capb.CRLGenerator_GenerateCRLServer) error } template.RevokedCertificates = rcs + + err := issuer.Linter.CheckCRL(template) + if err != nil { + return err + } + crlBytes, err := crl_x509.CreateRevocationList( rand.Reader, template, diff --git a/crl/crl_x509/crl.go b/crl/crl_x509/crl.go index 719035f59..ba53b8130 100644 --- a/crl/crl_x509/crl.go +++ b/crl/crl_x509/crl.go @@ -30,6 +30,10 @@ var ( // a CRL. // NOTE: This type does not exist in upstream. type RevokedCertificate struct { + // Raw contains the raw bytes of the revokedCertificates entry. It is set when + // parsing a CRL; it is ignored when generating a CRL. + Raw []byte + // SerialNumber represents the serial number of a revoked certificate. It is // both used when creating a CRL and populated when parsing a CRL. It MUST NOT // be nil. @@ -45,11 +49,15 @@ type RevokedCertificate struct { // value of 0 represents a reasonCode extension containing enum value 0 (this // SHOULD NOT happen, but can and does). ReasonCode *int - // When creating a CRL, ExtraExtensions should contain all extra extensions to - // add to the CRL entry. If ExtraExtensions contains a reasonCode extension, - // it will be ignored in favor of the ReasonCode field above. When parsing a - // CRL, ExtraExtensions contains all raw extensions parsed from the CRL entry, - // except for reasonCode which is represented by the ReasonCode field above. + + // Extensions contains raw X.509 extensions. When creating a CRL, the + // Extensions field is ignored, see ExtraExtensions. + Extensions []pkix.Extension + // ExtraExtensions contains any additional extensions to add directly to the + // revokedCertificate entry. It is up to the caller to ensure that this field + // does not contain any extensions which duplicate extensions created by this + // package (currently, the reasonCode extension). The ExtraExtensions field is + // not populated when parsing a CRL, see Extensions. ExtraExtensions []pkix.Extension } @@ -102,13 +110,14 @@ type RevocationList struct { // the issuer information instead. AuthorityKeyId []byte - // Extensions contains raw X.509 extensions. When creating a CRL, - // the Extensions field is ignored, see ExtraExtensions. + // Extensions contains raw X.509 extensions. When creating a CRL, the + // Extensions field is ignored, see ExtraExtensions. Extensions []pkix.Extension - // ExtraExtensions contains any additional extensions to add directly to the - // CRL. The ExtraExtensions field is not populated when parsing a CRL, see - // Extensions. + // CRL. It is up to the caller to ensure that this field does not contain any + // extensions which duplicate extensions created by this package (currently, + // the number and authorityKeyIdentifier extensions). The ExtraExtensions + // field is not populated when parsing a CRL, see Extensions. ExtraExtensions []pkix.Extension } @@ -122,22 +131,22 @@ func ParseRevocationList(der []byte) (*RevocationList, error) { // we can populate RevocationList.Raw, before unwrapping the // SEQUENCE so it can be operated on if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed certificate") + return nil, errors.New("x509: malformed crl") } rl.Raw = input if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed certificate") + return nil, errors.New("x509: malformed crl") } var tbs cryptobyte.String // do the same trick again as above to extract the raw // bytes for Certificate.RawTBSCertificate if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed tbs certificate") + return nil, errors.New("x509: malformed tbs crl") } rl.RawTBSRevocationList = tbs if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed tbs certificate") + return nil, errors.New("x509: malformed tbs crl") } var version int @@ -200,16 +209,20 @@ func ParseRevocationList(der []byte) (*RevocationList, error) { } if tbs.PeekASN1Tag(cryptobyte_asn1.SEQUENCE) { + rcs := make([]RevokedCertificate, 0) var revokedSeq cryptobyte.String if !tbs.ReadASN1(&revokedSeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed crl") } for !revokedSeq.Empty() { var certSeq cryptobyte.String - if !revokedSeq.ReadASN1(&certSeq, cryptobyte_asn1.SEQUENCE) { + if !revokedSeq.ReadASN1Element(&certSeq, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: malformed crl") + } + rc := RevokedCertificate{Raw: certSeq} + if !certSeq.ReadASN1(&certSeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed crl") } - rc := RevokedCertificate{} rc.SerialNumber = new(big.Int) if !certSeq.ReadASN1Integer(rc.SerialNumber) { return nil, errors.New("x509: malformed serial number") @@ -240,14 +253,14 @@ func ParseRevocationList(der []byte) (*RevocationList, error) { if !val.ReadASN1Enum(rc.ReasonCode) { return nil, fmt.Errorf("x509: malformed reasonCode extension") } - continue } - rc.ExtraExtensions = append(rc.ExtraExtensions, ext) + rc.Extensions = append(rc.Extensions, ext) } } - rl.RevokedCertificates = append(rl.RevokedCertificates, rc) + rcs = append(rcs, rc) } + rl.RevokedCertificates = rcs } var extensions cryptobyte.String @@ -272,12 +285,11 @@ func ParseRevocationList(der []byte) (*RevocationList, error) { if ext.Id.Equal(oidExtensionAuthorityKeyId) { rl.AuthorityKeyId = ext.Value } else if ext.Id.Equal(oidExtensionCRLNumber) { - number := new(big.Int) value := cryptobyte.String(ext.Value) - if !value.ReadASN1Integer(number) { + rl.Number = new(big.Int) + if !value.ReadASN1Integer(rl.Number) { return nil, errors.New("x509: malformed crl number") } - rl.Number = number } rl.Extensions = append(rl.Extensions, ext) } @@ -357,7 +369,9 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *x509 }) } - prc.Extensions = exts + if len(exts) > 0 { + prc.Extensions = exts + } revokedCerts[i] = prc } diff --git a/crl/crl_x509/crl_test.go b/crl/crl_x509/crl_test.go index efad2bc28..459917b95 100644 --- a/crl/crl_x509/crl_test.go +++ b/crl/crl_x509/crl_test.go @@ -352,9 +352,41 @@ func TestCreateRevocationList(t *testing.T) { tc.template.SignatureAlgorithm) } - if !reflect.DeepEqual(parsedCRL.RevokedCertificates, tc.template.RevokedCertificates) { - t.Fatalf("RevokedCertificates mismatch: got %v; want %v.", - parsedCRL.RevokedCertificates, tc.template.RevokedCertificates) + if len(parsedCRL.RevokedCertificates) != len(tc.template.RevokedCertificates) { + t.Fatalf("RevokedCertificates length mismatch: got %d; want %d.", + len(parsedCRL.RevokedCertificates), len(tc.template.RevokedCertificates)) + } + for i, rc := range parsedCRL.RevokedCertificates { + erc := tc.template.RevokedCertificates[i] + if rc.SerialNumber.Cmp(erc.SerialNumber) != 0 { + t.Errorf("RevokedCertificates entry %d serial mismatch: got %s; want %s.", + i, rc.SerialNumber.String(), erc.SerialNumber.String()) + } + if rc.RevocationTime != erc.RevocationTime { + t.Errorf("RevokedCertificates entry %d date mismatch: got %v; want %v.", + i, rc.RevocationTime, erc.RevocationTime) + } + numExtra := 0 + if erc.ReasonCode != nil { + if rc.ReasonCode == nil { + t.Errorf("RevokedCertificates entry %d reason mismatch: got nil; want %v.", + i, *erc.ReasonCode) + } + if *rc.ReasonCode != *erc.ReasonCode { + t.Errorf("RevokedCertificates entry %d reason mismatch: got %v; want %v.", + i, *rc.ReasonCode, *erc.ReasonCode) + } + numExtra = 1 + } else { + if rc.ReasonCode != nil { + t.Errorf("RevokedCertificates entry %d reason mismatch: got %v; want nil.", + i, *rc.ReasonCode) + } + } + if len(rc.Extensions) != numExtra+len(erc.ExtraExtensions) { + t.Errorf("RevokedCertificates entry %d has wrong number of extensions: got %d; want %d", + i, len(rc.Extensions), numExtra+len(erc.ExtraExtensions)) + } } if len(parsedCRL.Extensions) != 2+len(tc.template.ExtraExtensions) { diff --git a/linter/linter.go b/linter/linter.go index 59066e3f8..c6c1fda38 100644 --- a/linter/linter.go +++ b/linter/linter.go @@ -13,6 +13,9 @@ import ( "github.com/zmap/zlint/v3" "github.com/zmap/zlint/v3/lint" + "github.com/letsencrypt/boulder/crl/crl_x509" + crllints "github.com/letsencrypt/boulder/linter/lints/crl" + _ "github.com/letsencrypt/boulder/linter/lints/all" _ "github.com/letsencrypt/boulder/linter/lints/intermediate" _ "github.com/letsencrypt/boulder/linter/lints/root" @@ -72,7 +75,20 @@ func (l Linter) Check(tbs *x509.Certificate, subjectPubKey crypto.PublicKey) err if err != nil { return err } - return check(cert, l.registry) + lintRes := zlint.LintCertificateEx(cert, l.registry) + return processResultSet(lintRes) +} + +// CheckCRL signs the given RevocationList template using the Linter's fake +// issuer cert and private key, then runs the resulting CRL through our suite +// of CRL checks. It returns an error if any check fails. +func (l Linter) CheckCRL(tbs *crl_x509.RevocationList) error { + crl, err := makeLintCRL(tbs, l.issuer, l.signer) + if err != nil { + return err + } + lintRes := crllints.LintCRL(crl) + return processResultSet(lintRes) } func makeSigner(realSigner crypto.Signer) (crypto.Signer, error) { @@ -174,8 +190,7 @@ func makeLintCert(tbs *x509.Certificate, subjectPubKey crypto.PublicKey, issuer return lintCert, nil } -func check(lintCert *zlintx509.Certificate, lints lint.Registry) error { - lintRes := zlint.LintCertificateEx(lintCert, lints) +func processResultSet(lintRes *zlint.ResultSet) error { if lintRes.NoticesPresent || lintRes.WarningsPresent || lintRes.ErrorsPresent || lintRes.FatalsPresent { var failedLints []string for lintName, result := range lintRes.Results { @@ -187,3 +202,15 @@ func check(lintCert *zlintx509.Certificate, lints lint.Registry) error { } return nil } + +func makeLintCRL(tbs *crl_x509.RevocationList, issuer *x509.Certificate, signer crypto.Signer) (*crl_x509.RevocationList, error) { + lintCRLBytes, err := crl_x509.CreateRevocationList(rand.Reader, tbs, issuer, signer) + if err != nil { + return nil, err + } + lintCRL, err := crl_x509.ParseRevocationList(lintCRLBytes) + if err != nil { + return nil, err + } + return lintCRL, nil +} diff --git a/linter/lints/crl/lints.go b/linter/lints/crl/lints.go new file mode 100644 index 000000000..7529884f6 --- /dev/null +++ b/linter/lints/crl/lints.go @@ -0,0 +1,371 @@ +package crl + +import ( + "crypto/x509/pkix" + "encoding/asn1" + "time" + + "github.com/zmap/zlint/v3" + "github.com/zmap/zlint/v3/lint" + "golang.org/x/crypto/cryptobyte" + cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" + + "github.com/letsencrypt/boulder/crl/crl_x509" +) + +type crlLint func(*crl_x509.RevocationList) *lint.LintResult + +// registry is the collection of all known CRL lints. It is populated by this +// file's init(), and should not be touched by anything else on pain of races. +var registry map[string]crlLint + +func init() { + // NOTE TO DEVS: you MUST add your new lint function to this list or it + // WILL NOT be run. + registry = map[string]crlLint{ + "hasIssuerName": hasIssuerName, + "hasNextUpdate": hasNextUpdate, + "noEmptyRevokedCertificatesList": noEmptyRevokedCertificatesList, + "hasAKI": hasAKI, + "hasNumber": hasNumber, + "isNotDelta": isNotDelta, + "hasNoIDP": hasNoIDP, + "hasNoFreshest": hasNoFreshest, + "hasNoAIA": hasNoAIA, + "noZeroReasonCodes": noZeroReasonCodes, + "hasNoCertIssuers": hasNoCertIssuers, + "hasAcceptableValidity": hasAcceptableValidity, + "noCriticalReasons": noCriticalReasons, + "noCertificateHolds": noCertificateHolds, + "hasMozReasonCodes": hasMozReasonCodes, + } +} + +// getExtWithOID is a helper for several lints in this file. It returns the +// extension with the given OID if it exists, or nil otherwise. +func getExtWithOID(exts []pkix.Extension, oid asn1.ObjectIdentifier) *pkix.Extension { + for _, ext := range exts { + if ext.Id.Equal(oid) { + return &ext + } + } + return nil +} + +// LintCRL examines the given lint CRL, runs it through all of our checks, and +// returns a list of all failures +func LintCRL(lintCRL *crl_x509.RevocationList) *zlint.ResultSet { + rset := zlint.ResultSet{ + Version: 0, + Timestamp: time.Now().UnixNano(), + Results: make(map[string]*lint.LintResult), + } + + type namedResult struct { + Name string + Result *lint.LintResult + } + resChan := make(chan namedResult, len(registry)) + + for name, callable := range registry { + go func(name string, callable crlLint) { + resChan <- namedResult{name, callable(lintCRL)} + }(name, callable) + } + + for i := 0; i < len(registry); i++ { + res := <-resChan + switch res.Result.Status { + case lint.Notice: + rset.NoticesPresent = true + case lint.Warn: + rset.WarningsPresent = true + case lint.Error: + rset.ErrorsPresent = true + case lint.Fatal: + rset.FatalsPresent = true + } + rset.Results[res.Name] = res.Result + } + + return &rset +} + +// hasIssuerName checks RFC 5280, Section 5.1.2.3: +// The issuer field MUST contain a non-empty X.500 distinguished name (DN). +// This lint does not enforce that the issuer field complies with the rest of +// the encoding rules of a certificate issuer name, because it (perhaps wrongly) +// assumes that those were checked when the issuer was itself issued, and on all +// certificates issued by this CRL issuer. Also because there are just a lot of +// things to check there, and zlint doesn't expose a public helper for it. +func hasIssuerName(crl *crl_x509.RevocationList) *lint.LintResult { + if len(crl.Issuer.Names) == 0 { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRLs MUST have a non-empty issuer field", + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// TODO(#6222): Write a lint which checks RFC 5280, Section 5.1.2.4 and 5.1.2.5: +// CRL issuers conforming to this profile MUST encode thisUpdate and nextUpdate +// as UTCTime for dates through the year 2049. UTCTime and GeneralizedTime +// values MUST be expressed in Greenwich Mean Time (Zulu) and MUST include +// seconds, even where the number of seconds is zero. + +// hasNextUpdate checks RFC 5280, Section 5.1.2.5: +// Conforming CRL issuers MUST include the nextUpdate field in all CRLs. +func hasNextUpdate(crl *crl_x509.RevocationList) *lint.LintResult { + if crl.NextUpdate.IsZero() { + return &lint.LintResult{ + Status: lint.Error, + Details: "Conforming CRL issuers MUST include the nextUpdate field in all CRLs", + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// noEmptyRevokedCertificatesList checks RFC 5280, Section 5.1.2.6: +// When there are no revoked certificates, the revoked certificates list MUST be +// absent. +func noEmptyRevokedCertificatesList(crl *crl_x509.RevocationList) *lint.LintResult { + if crl.RevokedCertificates != nil && len(crl.RevokedCertificates) == 0 { + return &lint.LintResult{ + Status: lint.Error, + Details: "If the revokedCertificates list is empty, it must not be present", + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// hasAKI checks RFC 5280, Section 5.2.1: +// Conforming CRL issuers MUST use the key identifier method, and MUST include +// this extension in all CRLs issued. +func hasAKI(crl *crl_x509.RevocationList) *lint.LintResult { + if len(crl.AuthorityKeyId) == 0 { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRLs MUST include the authority key identifier extension", + } + } + aki := cryptobyte.String(crl.AuthorityKeyId) + var akiBody cryptobyte.String + if !aki.ReadASN1(&akiBody, cryptobyte_asn1.SEQUENCE) { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRL has a malformed authority key identifier extension", + } + } + if !akiBody.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRLs MUST use the key identifier method in the authority key identifier extension", + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// hasNumber checks RFC 5280, Section 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 hasNumber(crl *crl_x509.RevocationList) *lint.LintResult { + if crl.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 := getExtWithOID(crl.Extensions, crlNumberOID) + if ext != nil && ext.Critical { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRL Number MUST NOT be marked critical", + } + } + + numBytes := crl.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} +} + +// isNotDelta checks that the CRL is not a Delta CRL. (RFC 5280, Section 5.2.4). +// There's no requirement against this, but Delta CRLs come with extra +// requirements we don't want to deal with. +func isNotDelta(crl *crl_x509.RevocationList) *lint.LintResult { + deltaCRLIndicatorOID := asn1.ObjectIdentifier{2, 5, 29, 27} // id-ce-deltaCRLIndicator + if getExtWithOID(crl.Extensions, deltaCRLIndicatorOID) != nil { + return &lint.LintResult{ + Status: lint.Notice, + Details: "CRL is a Delta CRL", + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// hasNoIDP checks that the CRL does not have an Issuing Distribution Point +// extension (RFC 5280, Section 5.2.5). There's no requirement against this, but +// IDPs come with extra requirements we don't want to deal with. +func hasNoIDP(crl *crl_x509.RevocationList) *lint.LintResult { + idpOID := asn1.ObjectIdentifier{2, 5, 29, 28} // id-ce-issuingDistributionPoint + if getExtWithOID(crl.Extensions, idpOID) != nil { + return &lint.LintResult{ + Status: lint.Notice, + Details: "CRL has an Issuing Distribution Point url", + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// hasNoFreshest checks that the CRL is does not have a Freshest CRL extension +// (RFC 5280, Section 5.2.6). There's no requirement against this, but Freshest +// CRL extensions (and the Delta CRLs they imply) come with extra requirements +// we don't want to deal with. +func hasNoFreshest(crl *crl_x509.RevocationList) *lint.LintResult { + freshestOID := asn1.ObjectIdentifier{2, 5, 29, 46} // id-ce-freshestCRL + if getExtWithOID(crl.Extensions, freshestOID) != nil { + return &lint.LintResult{ + Status: lint.Notice, + Details: "CRL has a Freshest CRL url", + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// hasNoAIA checks that the CRL is does not have an Authority Information Access +// extension (RFC 5280, Section 5.2.7). There's no requirement against this, but +// AIAs come with extra requirements we don't want to deal with. +func hasNoAIA(crl *crl_x509.RevocationList) *lint.LintResult { + aiaOID := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 1} // id-pe-authorityInfoAccess + if getExtWithOID(crl.Extensions, aiaOID) != nil { + return &lint.LintResult{ + Status: lint.Notice, + Details: "CRL has an Authority Information Access url", + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// hasNoCertIssuers checks that the CRL does not have any entries with the +// Certificate Issuer extension (RFC 5280, Section 5.3.3). There is no +// requirement against this, but the presence of this extension would mean that +// the CRL includes certificates issued by an issuer other than the one signing +// the CRL itself, which we don't want to do. +func hasNoCertIssuers(crl *crl_x509.RevocationList) *lint.LintResult { + certIssuerOID := asn1.ObjectIdentifier{2, 5, 29, 29} // id-ce-certificateIssuer + for _, entry := range crl.RevokedCertificates { + if getExtWithOID(entry.Extensions, certIssuerOID) != nil { + return &lint.LintResult{ + Status: lint.Notice, + Details: "CRL has an entry with a Certificate Issuer extension", + } + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// hasAcceptableValidity checks Baseline Requirements, Section 4.9.7: +// The value of the nextUpdate field MUST NOT be more than ten days beyond the +// value of the thisUpdate field. +func hasAcceptableValidity(crl *crl_x509.RevocationList) *lint.LintResult { + validity := crl.NextUpdate.Sub(crl.ThisUpdate) + if validity <= 0 { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRL has NextUpdate at or before ThisUpdate", + } + } else if validity > 10*24*time.Hour { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRL has validity period greater than ten days", + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// noZeroReasonCodes checks Baseline Requirements, Section 7.2.2.1: +// The CRLReason indicated MUST NOT be unspecified (0). If the reason for +// revocation is unspecified, CAs MUST omit reasonCode entry extension, if +// allowed by the previous requirements. +// By extension, it therefore also checks RFC 5280, Section 5.3.1: +// The reason code CRL entry extension SHOULD be absent instead of using the +// unspecified (0) reasonCode value. +func noZeroReasonCodes(crl *crl_x509.RevocationList) *lint.LintResult { + for _, entry := range crl.RevokedCertificates { + if entry.ReasonCode != nil && *entry.ReasonCode == 0 { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRL entries MUST NOT contain the unspecified (0) reason code", + } + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// noCrticialReasons checks Baseline Requirements, Section 7.2.2.1: +// If present, [the reasonCode] extension MUST NOT be marked critical. +func noCriticalReasons(crl *crl_x509.RevocationList) *lint.LintResult { + reasonCodeOID := asn1.ObjectIdentifier{2, 5, 29, 21} // id-ce-reasonCode + for _, rc := range crl.RevokedCertificates { + for _, ext := range rc.Extensions { + if ext.Id.Equal(reasonCodeOID) && ext.Critical { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRL entry reasonCodes MUST NOT be critical", + } + } + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// noCertificateHolds checks Baseline Requirements, Section 7.2.2.1: +// The CRLReason MUST NOT be certificateHold (6). +func noCertificateHolds(crl *crl_x509.RevocationList) *lint.LintResult { + for _, entry := range crl.RevokedCertificates { + if entry.ReasonCode != nil && *entry.ReasonCode == 6 { + return &lint.LintResult{ + Status: lint.Error, + Details: "CRL entries MUST NOT use the certificateHold (6) reason code", + } + } + } + return &lint.LintResult{Status: lint.Pass} +} + +// hasMozReasonCodes checks MRSP v2.8 Section 6.1.1: +// When the CRLReason code is not one of the following, then the reasonCode extension MUST NOT be provided: +// - keyCompromise (RFC 5280 CRLReason #1); +// - privilegeWithdrawn (RFC 5280 CRLReason #9); +// - cessationOfOperation (RFC 5280 CRLReason #5); +// - affiliationChanged (RFC 5280 CRLReason #3); or +// - superseded (RFC 5280 CRLReason #4). +func hasMozReasonCodes(crl *crl_x509.RevocationList) *lint.LintResult { + for _, rc := range crl.RevokedCertificates { + if rc.ReasonCode == nil { + continue + } + switch *rc.ReasonCode { + case 1: // keyCompromise + case 3: // affiliationChanged + case 4: // superseded + case 5: // cessationOfOperation + case 9: // privilegeWithdrawn + continue + default: + return &lint.LintResult{ + Status: lint.Error, + Details: "CRLs MUST NOT include reasonCodes other than 1, 3, 4, 5, and 9", + } + } + } + return &lint.LintResult{Status: lint.Pass} +} diff --git a/linter/lints/crl/lints_test.go b/linter/lints/crl/lints_test.go new file mode 100644 index 000000000..5814df316 --- /dev/null +++ b/linter/lints/crl/lints_test.go @@ -0,0 +1,253 @@ +package crl + +import ( + "encoding/pem" + "os" + "testing" + + "github.com/letsencrypt/boulder/crl/crl_x509" + "github.com/letsencrypt/boulder/test" + "github.com/zmap/zlint/v3/lint" +) + +func loadPEMCRL(t *testing.T, filename string) *crl_x509.RevocationList { + t.Helper() + file, err := os.ReadFile(filename) + test.AssertNotError(t, err, "reading CRL file") + block, rest := pem.Decode(file) + test.AssertEquals(t, block.Type, "X509 CRL") + test.AssertEquals(t, len(rest), 0) + crl, err := crl_x509.ParseRevocationList(block.Bytes) + test.AssertNotError(t, err, "parsing CRL bytes") + return crl +} + +func TestHasIssuerName(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasIssuerName(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/no_issuer_name.pem") + res = hasIssuerName(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST have a non-empty issuer") +} + +func TestHasNextUpdate(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasNextUpdate(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/no_next_update.pem") + res = hasNextUpdate(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST include the nextUpdate") +} + +func TestNoEmptyRevokedCertificatesList(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := noEmptyRevokedCertificatesList(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/none_revoked.pem") + res = noEmptyRevokedCertificatesList(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/empty_revoked.pem") + res = noEmptyRevokedCertificatesList(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "must not be present") +} + +func TestHasAKI(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasAKI(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/no_aki.pem") + res = hasAKI(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST include the authority key identifier") + + crl = loadPEMCRL(t, "testdata/aki_name_and_serial.pem") + res = hasAKI(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST use the key identifier method") +} + +func TestHashNumber(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasNumber(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/no_number.pem") + res = hasNumber(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST include the CRL number") + + crl = loadPEMCRL(t, "testdata/critical_number.pem") + res = hasNumber(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST NOT be marked critical") + + crl = loadPEMCRL(t, "testdata/long_number.pem") + res = hasNumber(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST NOT be longer than 20 octets") +} + +func TestIsNotDelta(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := isNotDelta(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/delta.pem") + res = isNotDelta(crl) + test.AssertEquals(t, res.Status, lint.Notice) + test.AssertContains(t, res.Details, "Delta") +} + +func TestHasNoIDP(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasNoIDP(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/idp.pem") + res = hasNoIDP(crl) + test.AssertEquals(t, res.Status, lint.Notice) + test.AssertContains(t, res.Details, "Issuing Distribution Point") +} + +func TestHasNoFreshest(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasNoFreshest(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/freshest.pem") + res = hasNoFreshest(crl) + test.AssertEquals(t, res.Status, lint.Notice) + test.AssertContains(t, res.Details, "Freshest") +} + +func TestHasNoAIA(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasNoAIA(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/aia.pem") + res = hasNoAIA(crl) + test.AssertEquals(t, res.Status, lint.Notice) + test.AssertContains(t, res.Details, "Authority Information Access") +} + +func TestHasNoCertIssuers(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasNoCertIssuers(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/cert_issuer.pem") + res = hasNoCertIssuers(crl) + test.AssertEquals(t, res.Status, lint.Notice) + test.AssertContains(t, res.Details, "Certificate Issuer") +} + +func TestHasAcceptableValidity(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasAcceptableValidity(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/negative_validity.pem") + res = hasAcceptableValidity(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "at or before") + + crl = loadPEMCRL(t, "testdata/long_validity.pem") + res = hasAcceptableValidity(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "greater than ten days") +} + +func TestNoZeroReasonCodes(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := noZeroReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/reason_0.pem") + res = noZeroReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST NOT contain the unspecified") +} + +func TestNoCriticalReasons(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := noCriticalReasons(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/critical_reason.pem") + res = noCriticalReasons(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "reasonCodes MUST NOT be critical") +} + +func TestNoCertificateHolds(t *testing.T) { + crl := loadPEMCRL(t, "testdata/good.pem") + res := noCertificateHolds(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/reason_6.pem") + res = noCertificateHolds(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST NOT use the certificateHold") +} + +func TestHasMozReasonCodes(t *testing.T) { + // good.pem contains a revocation entry with no reason code extension. + crl := loadPEMCRL(t, "testdata/good.pem") + res := hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/reason_0.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST NOT include reasonCodes other than") + + crl = loadPEMCRL(t, "testdata/reason_1.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/reason_2.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST NOT include reasonCodes other than") + + crl = loadPEMCRL(t, "testdata/reason_3.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/reason_4.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/reason_5.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/reason_6.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST NOT include reasonCodes other than") + + crl = loadPEMCRL(t, "testdata/reason_8.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST NOT include reasonCodes other than") + + crl = loadPEMCRL(t, "testdata/reason_9.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Pass) + + crl = loadPEMCRL(t, "testdata/reason_10.pem") + res = hasMozReasonCodes(crl) + test.AssertEquals(t, res.Status, lint.Error) + test.AssertContains(t, res.Details, "MUST NOT include reasonCodes other than") +} diff --git a/linter/lints/crl/testdata/README.md b/linter/lints/crl/testdata/README.md new file mode 100644 index 000000000..8f8601ee4 --- /dev/null +++ b/linter/lints/crl/testdata/README.md @@ -0,0 +1,35 @@ +# Test Lint CRLs + +The contents of this directory are a variety of PEM-encoded CRLs uses to test +the CRL linting functions in the parent directory. + +To create a new test CRL to exercise a new lint: + +1. Install the `der2text` and `text2der` tools: + + ```sh + $ go install github.com/syncsynchalt/der2text/cmds/text2der@latest + $ go install github.com/syncsynchalt/der2text/cmds/der2text@latest + ``` + +2. Use `der2text` to create an editable version of CRL you want to start with, usually `good.pem`: + + ```sh + $ der2text good.pem > my_new_crl.txt + ``` + +3. Edit the text file. See [the der2text readme](https://github.com/syncsynchalt/der2text) for details about the file format. + +4. Write the new PEM file and run the tests to see if it works! Repeat steps 3 and 4 as necessary until you get the correct result. + + ```sh + $ text2der my_new_crl.txt >| my_new_crl.pem + $ go test .. + ``` + +5. Remove the text file and commit your new CRL. + + ```sh + $ rm my_new_crl.txt + $ git add . + ``` diff --git a/linter/lints/crl/testdata/aia.pem b/linter/lints/crl/testdata/aia.pem new file mode 100644 index 000000000..406305d85 --- /dev/null +++ b/linter/lints/crl/testdata/aia.pem @@ -0,0 +1,11 @@ +-----BEGIN X509 CRL----- +MIIBgDCCAQcCAQEwCgYIKoZIzj0EAwMwSTELMAkGA1UEBhMCWFgxFTATBgNVBAoT +DEJvdWxkZXIgVGVzdDEjMCEGA1UEAxMaKFRFU1QpIEVsZWdhbnQgRWxlcGhhbnQg +RTEXDTIyMDcwNjE2NDMzOFoXDTIyMDcxNTE2NDMzOFowKTAnAggDrlHbURVaPBcN +MjIwNzA2MTU0MzM4WjAMMAoGA1UdFQQDCgEBoGIwYDAfBgNVHSMEGDAWgBQB2rt6 +yyUgjl551vmWQi8CQSkHvjARBgNVHRQECgIIFv9LJt+yGA8wKgYIKwYBBQUHAQEE +HjAcMBoGCCsGAQUFBzABgg5lMS5vLmxlbmNyLm9yZzAKBggqhkjOPQQDAwNnADBk +AjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQsHqk +qEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E4c5Z +HFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/aki_name_and_serial.pem b/linter/lints/crl/testdata/aki_name_and_serial.pem new file mode 100644 index 000000000..f223479e2 --- /dev/null +++ b/linter/lints/crl/testdata/aki_name_and_serial.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBazCB8wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgTjBMMDcGA1UdIwQwMC6BFzAVghNp +bnQtZTEuYm91bGRlci50ZXN0ghMCEQChCjEx4ZnD1S6gsNFjWXmlMBEGA1UdFAQK +AggW/0sm37IYDzAKBggqhkjOPQQDAwNnADBkAjBWshNFi60aMWl82G3TwIuwBBK+ +dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQsHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4 +hMicW23oENHmLNZQx9ddruZeFJDqKD2E4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/cert_issuer.pem b/linter/lints/crl/testdata/cert_issuer.pem new file mode 100644 index 000000000..3ff128cfa --- /dev/null +++ b/linter/lints/crl/testdata/cert_issuer.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBczCB+wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjBJMEcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMCwwCgYDVR0VBAMKAQEwHgYDVR0dBBcwFYITaW50LWUxLmJv +dWxkZXIudGVzdKA2MDQwHwYDVR0jBBgwFoAUAdq7esslII5eedb5lkIvAkEpB74w +EQYDVR0UBAoCCBb/SybfshgPMAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRoxaXzY +bdPAi7AEEr53OIulDND4vPlN0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6Ke7wn +xjuxc+jdK7iEyJxbbegQ0eYs1lDH112u5l4UkOooPYThzlkcUdNC +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/critical_number.pem b/linter/lints/crl/testdata/critical_number.pem new file mode 100644 index 000000000..1fdccc98d --- /dev/null +++ b/linter/lints/crl/testdata/critical_number.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBVjCB3gIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgOTA3MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBQGA1UdFAEB/wQKAggW/0sm37IYDzAKBggqhkjOPQQD +AwNnADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD +6rFQsHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDq +KD2E4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/critical_reason.pem b/linter/lints/crl/testdata/critical_reason.pem new file mode 100644 index 000000000..91f0732e0 --- /dev/null +++ b/linter/lints/crl/testdata/critical_reason.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBVjCB3gIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjAsMCoCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMA8wDQYDVR0VAQH/BAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHa +u3rLJSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQD +AwNnADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD +6rFQsHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDq +KD2E4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/delta.pem b/linter/lints/crl/testdata/delta.pem new file mode 100644 index 000000000..3019facec --- /dev/null +++ b/linter/lints/crl/testdata/delta.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBZjCB7gIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgSTBHMB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzARBgNVHRsECgIIFv9L +Jt+yGA4wCgYIKoZIzj0EAwMDZwAwZAIwVrITRYutGjFpfNht08CLsAQSvnc4i6UM +0Pi8+U3T8DRHImIiuB9cQ+qxULB6pKhBAjBbuGCwTop7vCfGO7Fz6N0ruITInFtt +6BDR5izWUMfXXa7mXhSQ6ig9hOHOWRxR00I= +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/empty_revoked.pem b/linter/lints/crl/testdata/empty_revoked.pem new file mode 100644 index 000000000..874518ce7 --- /dev/null +++ b/linter/lints/crl/testdata/empty_revoked.pem @@ -0,0 +1,9 @@ +-----BEGIN X509 CRL----- +MIIBKjCBsgIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjAAoDYwNDAfBgNVHSMEGDAW +gBQB2rt6yyUgjl551vmWQi8CQSkHvjARBgNVHRQECgIIFv9LJt+yGA8wCgYIKoZI +zj0EAwMDZwAwZAIwVrITRYutGjFpfNht08CLsAQSvnc4i6UM0Pi8+U3T8DRHImIi +uB9cQ+qxULB6pKhBAjBbuGCwTop7vCfGO7Fz6N0ruITInFtt6BDR5izWUMfXXa7m +XhSQ6ig9hOHOWRxR00I= +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/freshest.pem b/linter/lints/crl/testdata/freshest.pem new file mode 100644 index 000000000..196871fa1 --- /dev/null +++ b/linter/lints/crl/testdata/freshest.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBdjCB/gIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgWTBXMB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAhBgNVHS4EGjAYMBaA +FIASMBCCDmUxLmMubGVuY3Iub3JnMAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRox +aXzYbdPAi7AEEr53OIulDND4vPlN0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6K +e7wnxjuxc+jdK7iEyJxbbegQ0eYs1lDH112u5l4UkOooPYThzlkcUdNC +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/good.pem b/linter/lints/crl/testdata/good.pem new file mode 100644 index 000000000..aad762e75 --- /dev/null +++ b/linter/lints/crl/testdata/good.pem @@ -0,0 +1,9 @@ +-----BEGIN X509 CRL----- +MIIBRTCBzQIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjAbMBkCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaoDYwNDAfBgNVHSMEGDAWgBQB2rt6yyUgjl551vmWQi8CQSkH +vjARBgNVHRQECgIIFv9LJt+yGA8wCgYIKoZIzj0EAwMDZwAwZAIwVrITRYutGjFp +fNht08CLsAQSvnc4i6UM0Pi8+U3T8DRHImIiuB9cQ+qxULB6pKhBAjBbuGCwTop7 +vCfGO7Fz6N0ruITInFtt6BDR5izWUMfXXa7mXhSQ6ig9hOHOWRxR00I= +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/good_old.pem b/linter/lints/crl/testdata/good_old.pem new file mode 100644 index 000000000..0331fa9a8 --- /dev/null +++ b/linter/lints/crl/testdata/good_old.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/idp.pem b/linter/lints/crl/testdata/idp.pem new file mode 100644 index 000000000..185e1faac --- /dev/null +++ b/linter/lints/crl/testdata/idp.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBYTCB6QIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgRDBCMB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAMBgNVHRwEBTADgQH/ +MAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRoxaXzYbdPAi7AEEr53OIulDND4vPlN +0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6Ke7wnxjuxc+jdK7iEyJxbbegQ0eYs +1lDH112u5l4UkOooPYThzlkcUdNC +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/long_number.pem b/linter/lints/crl/testdata/long_number.pem new file mode 100644 index 000000000..e8b855dbe --- /dev/null +++ b/linter/lints/crl/testdata/long_number.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBYDCB6AIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgQzBBMB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MB4GA1UdFAQXAhUW/0sm37IYDxb/SybfshgPFv9LJt8w +CgYIKoZIzj0EAwMDZwAwZAIwVrITRYutGjFpfNht08CLsAQSvnc4i6UM0Pi8+U3T +8DRHImIiuB9cQ+qxULB6pKhBAjBbuGCwTop7vCfGO7Fz6N0ruITInFtt6BDR5izW +UMfXXa7mXhSQ6ig9hOHOWRxR00I= +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/long_validity.pem b/linter/lints/crl/testdata/long_validity.pem new file mode 100644 index 000000000..cb745bfa7 --- /dev/null +++ b/linter/lints/crl/testdata/long_validity.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE2MTY0MzM5WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/negative_validity.pem b/linter/lints/crl/testdata/negative_validity.pem new file mode 100644 index 000000000..fc16812d6 --- /dev/null +++ b/linter/lints/crl/testdata/negative_validity.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzA2MTY0MzM3WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/no_aki.pem b/linter/lints/crl/testdata/no_aki.pem new file mode 100644 index 000000000..a1fdf6e43 --- /dev/null +++ b/linter/lints/crl/testdata/no_aki.pem @@ -0,0 +1,9 @@ +-----BEGIN X509 CRL----- +MIIBMjCBugIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgFTATMBEGA1UdFAQKAggW/0sm37IY +DzAKBggqhkjOPQQDAwNnADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5 +TdPwNEciYiK4H1xD6rFQsHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHm +LNZQx9ddruZeFJDqKD2E4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/no_issuer_name.pem b/linter/lints/crl/testdata/no_issuer_name.pem new file mode 100644 index 000000000..c45c428c0 --- /dev/null +++ b/linter/lints/crl/testdata/no_issuer_name.pem @@ -0,0 +1,8 @@ +-----BEGIN X509 CRL----- +MIIBCjCBkgIBATAKBggqhkjOPQQDAzAAFw0yMjA3MDYxNjQzMzhaFw0yMjA3MTUx +NjQzMzhaMCkwJwIIA65R21EVWjwXDTIyMDcwNjE1NDMzOFowDDAKBgNVHRUEAwoB +AaA2MDQwHwYDVR0jBBgwFoAUAdq7esslII5eedb5lkIvAkEpB74wEQYDVR0UBAoC +CBb/SybfshgPMAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRoxaXzYbdPAi7AEEr53 +OIulDND4vPlN0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6Ke7wnxjuxc+jdK7iE +yJxbbegQ0eYs1lDH112u5l4UkOooPYThzlkcUdNC +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/no_next_update.pem b/linter/lints/crl/testdata/no_next_update.pem new file mode 100644 index 000000000..83d86bd18 --- /dev/null +++ b/linter/lints/crl/testdata/no_next_update.pem @@ -0,0 +1,9 @@ +-----BEGIN X509 CRL----- +MIIBRDCBzAIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0yMjA3MDYxNTQzMzhaMAww +CgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rLJSCOXnnW+ZZCLwJBKQe+ +MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNnADBkAjBWshNFi60aMWl8 +2G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQsHqkqEECMFu4YLBOinu8 +J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/no_number.pem b/linter/lints/crl/testdata/no_number.pem new file mode 100644 index 000000000..65578de8b --- /dev/null +++ b/linter/lints/crl/testdata/no_number.pem @@ -0,0 +1,9 @@ +-----BEGIN X509 CRL----- +MIIBQDCByAIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgIzAhMB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRoxaXzYbdPA +i7AEEr53OIulDND4vPlN0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6Ke7wnxjux +c+jdK7iEyJxbbegQ0eYs1lDH112u5l4UkOooPYThzlkcUdNC +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/none_revoked.pem b/linter/lints/crl/testdata/none_revoked.pem new file mode 100644 index 000000000..b73885ddb --- /dev/null +++ b/linter/lints/crl/testdata/none_revoked.pem @@ -0,0 +1,9 @@ +-----BEGIN X509 CRL----- +MIIBKDCBsAIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WqA2MDQwHwYDVR0jBBgwFoAU +Adq7esslII5eedb5lkIvAkEpB74wEQYDVR0UBAoCCBb/SybfshgPMAoGCCqGSM49 +BAMDA2cAMGQCMFayE0WLrRoxaXzYbdPAi7AEEr53OIulDND4vPlN0/A0RyJiIrgf +XEPqsVCweqSoQQIwW7hgsE6Ke7wnxjuxc+jdK7iEyJxbbegQ0eYs1lDH112u5l4U +kOooPYThzlkcUdNC +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_0.pem b/linter/lints/crl/testdata/reason_0.pem new file mode 100644 index 000000000..308fd94d9 --- /dev/null +++ b/linter/lints/crl/testdata/reason_0.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQCgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_1.pem b/linter/lints/crl/testdata/reason_1.pem new file mode 100644 index 000000000..0331fa9a8 --- /dev/null +++ b/linter/lints/crl/testdata/reason_1.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_10.pem b/linter/lints/crl/testdata/reason_10.pem new file mode 100644 index 000000000..86c791916 --- /dev/null +++ b/linter/lints/crl/testdata/reason_10.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQqgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_2.pem b/linter/lints/crl/testdata/reason_2.pem new file mode 100644 index 000000000..bbeaaee00 --- /dev/null +++ b/linter/lints/crl/testdata/reason_2.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQKgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_3.pem b/linter/lints/crl/testdata/reason_3.pem new file mode 100644 index 000000000..66d2fae7d --- /dev/null +++ b/linter/lints/crl/testdata/reason_3.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQOgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_4.pem b/linter/lints/crl/testdata/reason_4.pem new file mode 100644 index 000000000..62e2d1456 --- /dev/null +++ b/linter/lints/crl/testdata/reason_4.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQSgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_5.pem b/linter/lints/crl/testdata/reason_5.pem new file mode 100644 index 000000000..879783e1b --- /dev/null +++ b/linter/lints/crl/testdata/reason_5.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQWgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_6.pem b/linter/lints/crl/testdata/reason_6.pem new file mode 100644 index 000000000..cc91f53f3 --- /dev/null +++ b/linter/lints/crl/testdata/reason_6.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQagNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_8.pem b/linter/lints/crl/testdata/reason_8.pem new file mode 100644 index 000000000..4d1ff3e8d --- /dev/null +++ b/linter/lints/crl/testdata/reason_8.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQigNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/linter/lints/crl/testdata/reason_9.pem b/linter/lints/crl/testdata/reason_9.pem new file mode 100644 index 000000000..ae24a3d5f --- /dev/null +++ b/linter/lints/crl/testdata/reason_9.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQmgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL----- diff --git a/test/hierarchy/int-e1.crl.pem b/test/hierarchy/int-e1.crl.pem new file mode 100644 index 000000000..0331fa9a8 --- /dev/null +++ b/test/hierarchy/int-e1.crl.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM +Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF +MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y +MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL +JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn +ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ +sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E +4c5ZHFHTQg== +-----END X509 CRL-----