1
2
3
4
5
6 package x509
7
8 import (
9 "bytes"
10 "encoding/pem"
11 "time"
12
13 "github.com/google/certificate-transparency-go/asn1"
14 "github.com/google/certificate-transparency-go/x509/pkix"
15 )
16
17
18 var (
19 OIDExtensionCRLNumber = asn1.ObjectIdentifier{2, 5, 29, 20}
20 OIDExtensionDeltaCRLIndicator = asn1.ObjectIdentifier{2, 5, 29, 27}
21 OIDExtensionIssuingDistributionPoint = asn1.ObjectIdentifier{2, 5, 29, 28}
22 )
23
24
25 var (
26 OIDExtensionCRLReasons = asn1.ObjectIdentifier{2, 5, 29, 21}
27 OIDExtensionInvalidityDate = asn1.ObjectIdentifier{2, 5, 29, 24}
28 OIDExtensionCertificateIssuer = asn1.ObjectIdentifier{2, 5, 29, 29}
29 )
30
31
32 type RevocationReasonCode asn1.Enumerated
33
34
35 var (
36 Unspecified = RevocationReasonCode(0)
37 KeyCompromise = RevocationReasonCode(1)
38 CACompromise = RevocationReasonCode(2)
39 AffiliationChanged = RevocationReasonCode(3)
40 Superseded = RevocationReasonCode(4)
41 CessationOfOperation = RevocationReasonCode(5)
42 CertificateHold = RevocationReasonCode(6)
43 RemoveFromCRL = RevocationReasonCode(8)
44 PrivilegeWithdrawn = RevocationReasonCode(9)
45 AACompromise = RevocationReasonCode(10)
46 )
47
48
49 type ReasonFlag int
50
51
52 const (
53 UnusedFlag ReasonFlag = 1 << iota
54 KeyCompromiseFlag
55 CACompromiseFlag
56 AffiliationChangedFlag
57 SupersededFlag
58 CessationOfOperationFlag
59 CertificateHoldFlag
60 PrivilegeWithdrawnFlag
61 AACompromiseFlag
62 )
63
64
65
66
67 type CertificateList struct {
68 Raw asn1.RawContent
69 TBSCertList TBSCertList
70 SignatureAlgorithm pkix.AlgorithmIdentifier
71 SignatureValue asn1.BitString
72 }
73
74
75 func (certList *CertificateList) ExpiredAt(now time.Time) bool {
76 return now.After(certList.TBSCertList.NextUpdate)
77 }
78
79
80
81 var listExtCritical = map[string]bool{
82
83 OIDExtensionAuthorityKeyId.String(): false,
84 OIDExtensionIssuerAltName.String(): false,
85 OIDExtensionCRLNumber.String(): false,
86 OIDExtensionDeltaCRLIndicator.String(): true,
87 OIDExtensionIssuingDistributionPoint.String(): true,
88 OIDExtensionFreshestCRL.String(): false,
89 OIDExtensionAuthorityInfoAccess.String(): false,
90 }
91
92 var certExtCritical = map[string]bool{
93
94 OIDExtensionCRLReasons.String(): false,
95 OIDExtensionInvalidityDate.String(): false,
96 OIDExtensionCertificateIssuer.String(): true,
97 }
98
99
100
101 type IssuingDistributionPoint struct {
102 DistributionPoint distributionPointName `asn1:"optional,tag:0"`
103 OnlyContainsUserCerts bool `asn1:"optional,tag:1"`
104 OnlyContainsCACerts bool `asn1:"optional,tag:2"`
105 OnlySomeReasons asn1.BitString `asn1:"optional,tag:3"`
106 IndirectCRL bool `asn1:"optional,tag:4"`
107 OnlyContainsAttributeCerts bool `asn1:"optional,tag:5"`
108 }
109
110
111
112
113 type TBSCertList struct {
114 Raw asn1.RawContent
115 Version int
116 Signature pkix.AlgorithmIdentifier
117 Issuer pkix.RDNSequence
118 ThisUpdate time.Time
119 NextUpdate time.Time
120 RevokedCertificates []*RevokedCertificate
121 Extensions []pkix.Extension
122
123 AuthorityKeyID []byte
124 IssuerAltNames GeneralNames
125 CRLNumber int
126 BaseCRLNumber int
127 IssuingDistributionPoint IssuingDistributionPoint
128 IssuingDPFullNames GeneralNames
129 FreshestCRLDistributionPoint []string
130 OCSPServer []string
131 IssuingCertificateURL []string
132 }
133
134
135
136
137
138 func ParseCertificateList(clBytes []byte) (*CertificateList, error) {
139 if bytes.HasPrefix(clBytes, pemCRLPrefix) {
140 block, _ := pem.Decode(clBytes)
141 if block != nil && block.Type == pemType {
142 clBytes = block.Bytes
143 }
144 }
145 return ParseCertificateListDER(clBytes)
146 }
147
148
149
150
151 func ParseCertificateListDER(derBytes []byte) (*CertificateList, error) {
152 var errs Errors
153
154 pkixList := new(pkix.CertificateList)
155 if rest, err := asn1.Unmarshal(derBytes, pkixList); err != nil {
156 errs.AddID(ErrInvalidCertList, err)
157 return nil, &errs
158 } else if len(rest) != 0 {
159 errs.AddID(ErrTrailingCertList)
160 return nil, &errs
161 }
162
163
164 revokedCerts := make([]*RevokedCertificate, len(pkixList.TBSCertList.RevokedCertificates))
165 for i, pkixRevoked := range pkixList.TBSCertList.RevokedCertificates {
166 revokedCerts[i] = parseRevokedCertificate(pkixRevoked, &errs)
167 if revokedCerts[i] == nil {
168 return nil, &errs
169 }
170 }
171
172 certList := CertificateList{
173 Raw: derBytes,
174 TBSCertList: TBSCertList{
175 Raw: pkixList.TBSCertList.Raw,
176 Version: pkixList.TBSCertList.Version,
177 Signature: pkixList.TBSCertList.Signature,
178 Issuer: pkixList.TBSCertList.Issuer,
179 ThisUpdate: pkixList.TBSCertList.ThisUpdate,
180 NextUpdate: pkixList.TBSCertList.NextUpdate,
181 RevokedCertificates: revokedCerts,
182 Extensions: pkixList.TBSCertList.Extensions,
183 CRLNumber: -1,
184 BaseCRLNumber: -1,
185 },
186 SignatureAlgorithm: pkixList.SignatureAlgorithm,
187 SignatureValue: pkixList.SignatureValue,
188 }
189
190
191 for _, e := range certList.TBSCertList.Extensions {
192 if expectCritical, present := listExtCritical[e.Id.String()]; present {
193 if e.Critical && !expectCritical {
194 errs.AddID(ErrUnexpectedlyCriticalCertListExtension, e.Id)
195 } else if !e.Critical && expectCritical {
196 errs.AddID(ErrUnexpectedlyNonCriticalCertListExtension, e.Id)
197 }
198 }
199 switch {
200 case e.Id.Equal(OIDExtensionAuthorityKeyId):
201
202 var a authKeyId
203 if rest, err := asn1.Unmarshal(e.Value, &a); err != nil {
204 errs.AddID(ErrInvalidCertListAuthKeyID, err)
205 } else if len(rest) != 0 {
206 errs.AddID(ErrTrailingCertListAuthKeyID)
207 }
208 certList.TBSCertList.AuthorityKeyID = a.Id
209 case e.Id.Equal(OIDExtensionIssuerAltName):
210
211 if err := parseGeneralNames(e.Value, &certList.TBSCertList.IssuerAltNames); err != nil {
212 errs.AddID(ErrInvalidCertListIssuerAltName, err)
213 }
214 case e.Id.Equal(OIDExtensionCRLNumber):
215
216 if rest, err := asn1.Unmarshal(e.Value, &certList.TBSCertList.CRLNumber); err != nil {
217 errs.AddID(ErrInvalidCertListCRLNumber, err)
218 } else if len(rest) != 0 {
219 errs.AddID(ErrTrailingCertListCRLNumber)
220 }
221 if certList.TBSCertList.CRLNumber < 0 {
222 errs.AddID(ErrNegativeCertListCRLNumber, certList.TBSCertList.CRLNumber)
223 }
224 case e.Id.Equal(OIDExtensionDeltaCRLIndicator):
225
226 if rest, err := asn1.Unmarshal(e.Value, &certList.TBSCertList.BaseCRLNumber); err != nil {
227 errs.AddID(ErrInvalidCertListDeltaCRL, err)
228 } else if len(rest) != 0 {
229 errs.AddID(ErrTrailingCertListDeltaCRL)
230 }
231 if certList.TBSCertList.BaseCRLNumber < 0 {
232 errs.AddID(ErrNegativeCertListDeltaCRL, certList.TBSCertList.BaseCRLNumber)
233 }
234 case e.Id.Equal(OIDExtensionIssuingDistributionPoint):
235 parseIssuingDistributionPoint(e.Value, &certList.TBSCertList.IssuingDistributionPoint, &certList.TBSCertList.IssuingDPFullNames, &errs)
236 case e.Id.Equal(OIDExtensionFreshestCRL):
237
238 if err := parseDistributionPoints(e.Value, &certList.TBSCertList.FreshestCRLDistributionPoint); err != nil {
239 errs.AddID(ErrInvalidCertListFreshestCRL, err)
240 return nil, err
241 }
242 case e.Id.Equal(OIDExtensionAuthorityInfoAccess):
243
244 var aia []accessDescription
245 if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil {
246 errs.AddID(ErrInvalidCertListAuthInfoAccess, err)
247 } else if len(rest) != 0 {
248 errs.AddID(ErrTrailingCertListAuthInfoAccess)
249 }
250
251 for _, v := range aia {
252
253 if v.Location.Tag != tagURI {
254 continue
255 }
256 switch {
257 case v.Method.Equal(OIDAuthorityInfoAccessOCSP):
258 certList.TBSCertList.OCSPServer = append(certList.TBSCertList.OCSPServer, string(v.Location.Bytes))
259 case v.Method.Equal(OIDAuthorityInfoAccessIssuers):
260 certList.TBSCertList.IssuingCertificateURL = append(certList.TBSCertList.IssuingCertificateURL, string(v.Location.Bytes))
261 }
262
263 }
264 default:
265 if e.Critical {
266 errs.AddID(ErrUnhandledCriticalCertListExtension, e.Id)
267 }
268 }
269 }
270
271 if errs.Fatal() {
272 return nil, &errs
273 }
274 if errs.Empty() {
275 return &certList, nil
276 }
277 return &certList, &errs
278 }
279
280 func parseIssuingDistributionPoint(data []byte, idp *IssuingDistributionPoint, name *GeneralNames, errs *Errors) {
281
282 if rest, err := asn1.Unmarshal(data, idp); err != nil {
283 errs.AddID(ErrInvalidCertListIssuingDP, err)
284 } else if len(rest) != 0 {
285 errs.AddID(ErrTrailingCertListIssuingDP)
286 }
287
288 typeCount := 0
289 if idp.OnlyContainsUserCerts {
290 typeCount++
291 }
292 if idp.OnlyContainsCACerts {
293 typeCount++
294 }
295 if idp.OnlyContainsAttributeCerts {
296 typeCount++
297 }
298 if typeCount > 1 {
299 errs.AddID(ErrCertListIssuingDPMultipleTypes, idp.OnlyContainsUserCerts, idp.OnlyContainsCACerts, idp.OnlyContainsAttributeCerts)
300 }
301 for _, fn := range idp.DistributionPoint.FullName {
302 if _, err := parseGeneralName(fn.FullBytes, name, false); err != nil {
303 errs.AddID(ErrCertListIssuingDPInvalidFullName, err)
304 }
305 }
306 }
307
308
309
310
311
312 type RevokedCertificate struct {
313 pkix.RevokedCertificate
314
315 RevocationReason RevocationReasonCode
316 InvalidityDate time.Time
317 Issuer GeneralNames
318 }
319
320 func parseRevokedCertificate(pkixRevoked pkix.RevokedCertificate, errs *Errors) *RevokedCertificate {
321 result := RevokedCertificate{RevokedCertificate: pkixRevoked}
322 for _, e := range pkixRevoked.Extensions {
323 if expectCritical, present := certExtCritical[e.Id.String()]; present {
324 if e.Critical && !expectCritical {
325 errs.AddID(ErrUnexpectedlyCriticalRevokedCertExtension, e.Id)
326 } else if !e.Critical && expectCritical {
327 errs.AddID(ErrUnexpectedlyNonCriticalRevokedCertExtension, e.Id)
328 }
329 }
330 switch {
331 case e.Id.Equal(OIDExtensionCRLReasons):
332
333 var reason asn1.Enumerated
334 if rest, err := asn1.Unmarshal(e.Value, &reason); err != nil {
335 errs.AddID(ErrInvalidRevocationReason, err)
336 } else if len(rest) != 0 {
337 errs.AddID(ErrTrailingRevocationReason)
338 }
339 result.RevocationReason = RevocationReasonCode(reason)
340 case e.Id.Equal(OIDExtensionInvalidityDate):
341
342 if rest, err := asn1.Unmarshal(e.Value, &result.InvalidityDate); err != nil {
343 errs.AddID(ErrInvalidRevocationInvalidityDate, err)
344 } else if len(rest) != 0 {
345 errs.AddID(ErrTrailingRevocationInvalidityDate)
346 }
347 case e.Id.Equal(OIDExtensionCertificateIssuer):
348
349 if err := parseGeneralNames(e.Value, &result.Issuer); err != nil {
350 errs.AddID(ErrInvalidRevocationIssuer, err)
351 }
352 default:
353 if e.Critical {
354 errs.AddID(ErrUnhandledCriticalRevokedCertExtension, e.Id)
355 }
356 }
357 }
358 return &result
359 }
360
361
362 func (c *Certificate) CheckCertificateListSignature(crl *CertificateList) error {
363 algo := SignatureAlgorithmFromAI(crl.SignatureAlgorithm)
364 return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
365 }
366
View as plain text