Add CRL linting framework and first few lints (#6205)
Add a collection of lints (structured similarly, but not identically, to zlint's certificate lints) which check a variety of requirements based on RFC 5280, the Baseline Requirements, and the Mozilla Root Store Policy. Add a method to lint CRLs to the existing linter package which uses its fake issuer to sign the CRL, calls all of the above lints, and returns all of their findings. Call this new method from within the CA's new GenerateCRL method immediately before signing the real CRL using the real issuer. Fixes #6188
This commit is contained in:
parent
436061fb35
commit
c7014dfd29
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -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 .
|
||||
```
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBgDCCAQcCAQEwCgYIKoZIzj0EAwMwSTELMAkGA1UEBhMCWFgxFTATBgNVBAoT
|
||||
DEJvdWxkZXIgVGVzdDEjMCEGA1UEAxMaKFRFU1QpIEVsZWdhbnQgRWxlcGhhbnQg
|
||||
RTEXDTIyMDcwNjE2NDMzOFoXDTIyMDcxNTE2NDMzOFowKTAnAggDrlHbURVaPBcN
|
||||
MjIwNzA2MTU0MzM4WjAMMAoGA1UdFQQDCgEBoGIwYDAfBgNVHSMEGDAWgBQB2rt6
|
||||
yyUgjl551vmWQi8CQSkHvjARBgNVHRQECgIIFv9LJt+yGA8wKgYIKwYBBQUHAQEE
|
||||
HjAcMBoGCCsGAQUFBzABgg5lMS5vLmxlbmNyLm9yZzAKBggqhkjOPQQDAwNnADBk
|
||||
AjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQsHqk
|
||||
qEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E4c5Z
|
||||
HFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBazCB8wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgTjBMMDcGA1UdIwQwMC6BFzAVghNp
|
||||
bnQtZTEuYm91bGRlci50ZXN0ghMCEQChCjEx4ZnD1S6gsNFjWXmlMBEGA1UdFAQK
|
||||
AggW/0sm37IYDzAKBggqhkjOPQQDAwNnADBkAjBWshNFi60aMWl82G3TwIuwBBK+
|
||||
dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQsHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4
|
||||
hMicW23oENHmLNZQx9ddruZeFJDqKD2E4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBczCB+wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjBJMEcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMCwwCgYDVR0VBAMKAQEwHgYDVR0dBBcwFYITaW50LWUxLmJv
|
||||
dWxkZXIudGVzdKA2MDQwHwYDVR0jBBgwFoAUAdq7esslII5eedb5lkIvAkEpB74w
|
||||
EQYDVR0UBAoCCBb/SybfshgPMAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRoxaXzY
|
||||
bdPAi7AEEr53OIulDND4vPlN0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6Ke7wn
|
||||
xjuxc+jdK7iEyJxbbegQ0eYs1lDH112u5l4UkOooPYThzlkcUdNC
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBVjCB3gIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgOTA3MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBQGA1UdFAEB/wQKAggW/0sm37IYDzAKBggqhkjOPQQD
|
||||
AwNnADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD
|
||||
6rFQsHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDq
|
||||
KD2E4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBVjCB3gIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjAsMCoCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMA8wDQYDVR0VAQH/BAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHa
|
||||
u3rLJSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQD
|
||||
AwNnADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD
|
||||
6rFQsHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDq
|
||||
KD2E4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBZjCB7gIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgSTBHMB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzARBgNVHRsECgIIFv9L
|
||||
Jt+yGA4wCgYIKoZIzj0EAwMDZwAwZAIwVrITRYutGjFpfNht08CLsAQSvnc4i6UM
|
||||
0Pi8+U3T8DRHImIiuB9cQ+qxULB6pKhBAjBbuGCwTop7vCfGO7Fz6N0ruITInFtt
|
||||
6BDR5izWUMfXXa7mXhSQ6ig9hOHOWRxR00I=
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBKjCBsgIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjAAoDYwNDAfBgNVHSMEGDAW
|
||||
gBQB2rt6yyUgjl551vmWQi8CQSkHvjARBgNVHRQECgIIFv9LJt+yGA8wCgYIKoZI
|
||||
zj0EAwMDZwAwZAIwVrITRYutGjFpfNht08CLsAQSvnc4i6UM0Pi8+U3T8DRHImIi
|
||||
uB9cQ+qxULB6pKhBAjBbuGCwTop7vCfGO7Fz6N0ruITInFtt6BDR5izWUMfXXa7m
|
||||
XhSQ6ig9hOHOWRxR00I=
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBdjCB/gIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgWTBXMB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAhBgNVHS4EGjAYMBaA
|
||||
FIASMBCCDmUxLmMubGVuY3Iub3JnMAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRox
|
||||
aXzYbdPAi7AEEr53OIulDND4vPlN0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6K
|
||||
e7wnxjuxc+jdK7iEyJxbbegQ0eYs1lDH112u5l4UkOooPYThzlkcUdNC
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBRTCBzQIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjAbMBkCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaoDYwNDAfBgNVHSMEGDAWgBQB2rt6yyUgjl551vmWQi8CQSkH
|
||||
vjARBgNVHRQECgIIFv9LJt+yGA8wCgYIKoZIzj0EAwMDZwAwZAIwVrITRYutGjFp
|
||||
fNht08CLsAQSvnc4i6UM0Pi8+U3T8DRHImIiuB9cQ+qxULB6pKhBAjBbuGCwTop7
|
||||
vCfGO7Fz6N0ruITInFtt6BDR5izWUMfXXa7mXhSQ6ig9hOHOWRxR00I=
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBYTCB6QIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgRDBCMB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAMBgNVHRwEBTADgQH/
|
||||
MAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRoxaXzYbdPAi7AEEr53OIulDND4vPlN
|
||||
0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6Ke7wnxjuxc+jdK7iEyJxbbegQ0eYs
|
||||
1lDH112u5l4UkOooPYThzlkcUdNC
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBYDCB6AIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgQzBBMB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MB4GA1UdFAQXAhUW/0sm37IYDxb/SybfshgPFv9LJt8w
|
||||
CgYIKoZIzj0EAwMDZwAwZAIwVrITRYutGjFpfNht08CLsAQSvnc4i6UM0Pi8+U3T
|
||||
8DRHImIiuB9cQ+qxULB6pKhBAjBbuGCwTop7vCfGO7Fz6N0ruITInFtt6BDR5izW
|
||||
UMfXXa7mXhSQ6ig9hOHOWRxR00I=
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE2MTY0MzM5WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzA2MTY0MzM3WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBMjCBugIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgFTATMBEGA1UdFAQKAggW/0sm37IY
|
||||
DzAKBggqhkjOPQQDAwNnADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5
|
||||
TdPwNEciYiK4H1xD6rFQsHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHm
|
||||
LNZQx9ddruZeFJDqKD2E4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBCjCBkgIBATAKBggqhkjOPQQDAzAAFw0yMjA3MDYxNjQzMzhaFw0yMjA3MTUx
|
||||
NjQzMzhaMCkwJwIIA65R21EVWjwXDTIyMDcwNjE1NDMzOFowDDAKBgNVHRUEAwoB
|
||||
AaA2MDQwHwYDVR0jBBgwFoAUAdq7esslII5eedb5lkIvAkEpB74wEQYDVR0UBAoC
|
||||
CBb/SybfshgPMAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRoxaXzYbdPAi7AEEr53
|
||||
OIulDND4vPlN0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6Ke7wnxjuxc+jdK7iE
|
||||
yJxbbegQ0eYs1lDH112u5l4UkOooPYThzlkcUdNC
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBRDCBzAIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0yMjA3MDYxNTQzMzhaMAww
|
||||
CgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rLJSCOXnnW+ZZCLwJBKQe+
|
||||
MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNnADBkAjBWshNFi60aMWl8
|
||||
2G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQsHqkqEECMFu4YLBOinu8
|
||||
J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBQDCByAIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgIzAhMB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MAoGCCqGSM49BAMDA2cAMGQCMFayE0WLrRoxaXzYbdPA
|
||||
i7AEEr53OIulDND4vPlN0/A0RyJiIrgfXEPqsVCweqSoQQIwW7hgsE6Ke7wnxjux
|
||||
c+jdK7iEyJxbbegQ0eYs1lDH112u5l4UkOooPYThzlkcUdNC
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBKDCBsAIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WqA2MDQwHwYDVR0jBBgwFoAU
|
||||
Adq7esslII5eedb5lkIvAkEpB74wEQYDVR0UBAoCCBb/SybfshgPMAoGCCqGSM49
|
||||
BAMDA2cAMGQCMFayE0WLrRoxaXzYbdPAi7AEEr53OIulDND4vPlN0/A0RyJiIrgf
|
||||
XEPqsVCweqSoQQIwW7hgsE6Ke7wnxjuxc+jdK7iEyJxbbegQ0eYs1lDH112u5l4U
|
||||
kOooPYThzlkcUdNC
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQCgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQqgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQKgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQOgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQSgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQWgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQagNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQigNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQmgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIBUzCB2wIBATAKBggqhkjOPQQDAzBJMQswCQYDVQQGEwJYWDEVMBMGA1UEChMM
|
||||
Qm91bGRlciBUZXN0MSMwIQYDVQQDExooVEVTVCkgRWxlZ2FudCBFbGVwaGFudCBF
|
||||
MRcNMjIwNzA2MTY0MzM4WhcNMjIwNzE1MTY0MzM4WjApMCcCCAOuUdtRFVo8Fw0y
|
||||
MjA3MDYxNTQzMzhaMAwwCgYDVR0VBAMKAQGgNjA0MB8GA1UdIwQYMBaAFAHau3rL
|
||||
JSCOXnnW+ZZCLwJBKQe+MBEGA1UdFAQKAggW/0sm37IYDzAKBggqhkjOPQQDAwNn
|
||||
ADBkAjBWshNFi60aMWl82G3TwIuwBBK+dziLpQzQ+Lz5TdPwNEciYiK4H1xD6rFQ
|
||||
sHqkqEECMFu4YLBOinu8J8Y7sXPo3Su4hMicW23oENHmLNZQx9ddruZeFJDqKD2E
|
||||
4c5ZHFHTQg==
|
||||
-----END X509 CRL-----
|
||||
Loading…
Reference in New Issue