...
1 package cabfbr
2
3 import (
4 "fmt"
5 "time"
6
7 "github.com/letsencrypt/boulder/linter/lints"
8 "github.com/zmap/zcrypto/encoding/asn1"
9 "github.com/zmap/zcrypto/x509"
10 "github.com/zmap/zlint/v3/lint"
11 "github.com/zmap/zlint/v3/util"
12 "golang.org/x/crypto/cryptobyte"
13
14 cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
15 )
16
17 type crlValidityPeriod struct{}
18
19
27
28 func init() {
29 lint.RegisterRevocationListLint(&lint.RevocationListLint{
30 LintMetadata: lint.LintMetadata{
31 Name: "e_crl_validity_period",
32 Description: "Let's Encrypt CRLs must have an acceptable validity period",
33 Citation: "BRs: 4.9.7",
34 Source: lint.CABFBaselineRequirements,
35 EffectiveDate: util.CABFBRs_1_2_1_Date,
36 },
37 Lint: NewCrlValidityPeriod,
38 })
39 }
40
41 func NewCrlValidityPeriod() lint.RevocationListLintInterface {
42 return &crlValidityPeriod{}
43 }
44
45 func (l *crlValidityPeriod) CheckApplies(c *x509.RevocationList) bool {
46 return true
47 }
48
49 func (l *crlValidityPeriod) Execute(c *x509.RevocationList) *lint.LintResult {
50
62
63
64
65
66 idpOID := asn1.ObjectIdentifier{2, 5, 29, 28}
67 idpe := lints.GetExtWithOID(c.Extensions, idpOID)
68 if idpe == nil {
69 return &lint.LintResult{
70 Status: lint.Warn,
71 Details: "CRL missing IssuingDistributionPoint",
72 }
73 }
74
75
76
77 idpv := cryptobyte.String(idpe.Value)
78 if !idpv.ReadASN1(&idpv, cryptobyte_asn1.SEQUENCE) {
79 return &lint.LintResult{
80 Status: lint.Warn,
81 Details: "Failed to read IssuingDistributionPoint distributionPoint",
82 }
83 }
84
85
86 distributionPointTag := cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()
87 _ = idpv.SkipOptionalASN1(distributionPointTag)
88
89
90
91 idp := lints.NewIssuingDistributionPoint()
92 onlyContainsUserCertsTag := cryptobyte_asn1.Tag(1).ContextSpecific()
93 if !lints.ReadOptionalASN1BooleanWithTag(&idpv, &idp.OnlyContainsUserCerts, onlyContainsUserCertsTag, false) {
94 return &lint.LintResult{
95 Status: lint.Warn,
96 Details: "Failed to read IssuingDistributionPoint onlyContainsUserCerts",
97 }
98 }
99
100 onlyContainsCACertsTag := cryptobyte_asn1.Tag(2).ContextSpecific()
101 if !lints.ReadOptionalASN1BooleanWithTag(&idpv, &idp.OnlyContainsCACerts, onlyContainsCACertsTag, false) {
102 return &lint.LintResult{
103 Status: lint.Warn,
104 Details: "Failed to read IssuingDistributionPoint onlyContainsCACerts",
105 }
106 }
107
108
109
110
111 if idp.OnlyContainsUserCerts && idp.OnlyContainsCACerts {
112 return &lint.LintResult{
113 Status: lint.Error,
114 Details: "IssuingDistributionPoint should not have both onlyContainsUserCerts: TRUE and onlyContainsCACerts: TRUE",
115 }
116 }
117
118
119 var BRValidity = 10 * 24 * time.Hour
120 var validityString = "10 days"
121 if idp.OnlyContainsCACerts {
122 BRValidity = 365 * lints.BRDay
123 validityString = "365 days"
124 }
125
126 parsedValidity := c.NextUpdate.Sub(c.ThisUpdate)
127 if parsedValidity <= 0 {
128 return &lint.LintResult{
129 Status: lint.Error,
130 Details: "CRL has NextUpdate at or before ThisUpdate",
131 }
132 }
133
134 if parsedValidity > BRValidity {
135 return &lint.LintResult{
136 Status: lint.Error,
137 Details: fmt.Sprintf("CRL has validity period greater than %s", validityString),
138 }
139 }
140 return &lint.LintResult{Status: lint.Pass}
141 }
142
View as plain text