1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package x509util
18
19 import (
20 "bytes"
21 "crypto/dsa"
22 "crypto/ecdsa"
23 "crypto/elliptic"
24 "crypto/rsa"
25 "encoding/base64"
26 "encoding/hex"
27 "encoding/pem"
28 "errors"
29 "fmt"
30 "net"
31 "strconv"
32
33 ct "github.com/google/certificate-transparency-go"
34 "github.com/google/certificate-transparency-go/asn1"
35 "github.com/google/certificate-transparency-go/gossip/minimal/x509ext"
36 "github.com/google/certificate-transparency-go/tls"
37 "github.com/google/certificate-transparency-go/x509"
38 "github.com/google/certificate-transparency-go/x509/pkix"
39 )
40
41
42
43 func OIDForStandardExtension(oid asn1.ObjectIdentifier) bool {
44 if oid.Equal(x509.OIDExtensionSubjectKeyId) ||
45 oid.Equal(x509.OIDExtensionKeyUsage) ||
46 oid.Equal(x509.OIDExtensionExtendedKeyUsage) ||
47 oid.Equal(x509.OIDExtensionAuthorityKeyId) ||
48 oid.Equal(x509.OIDExtensionBasicConstraints) ||
49 oid.Equal(x509.OIDExtensionSubjectAltName) ||
50 oid.Equal(x509.OIDExtensionCertificatePolicies) ||
51 oid.Equal(x509.OIDExtensionNameConstraints) ||
52 oid.Equal(x509.OIDExtensionCRLDistributionPoints) ||
53 oid.Equal(x509.OIDExtensionIssuerAltName) ||
54 oid.Equal(x509.OIDExtensionSubjectDirectoryAttributes) ||
55 oid.Equal(x509.OIDExtensionInhibitAnyPolicy) ||
56 oid.Equal(x509.OIDExtensionPolicyConstraints) ||
57 oid.Equal(x509.OIDExtensionPolicyMappings) ||
58 oid.Equal(x509.OIDExtensionFreshestCRL) ||
59 oid.Equal(x509.OIDExtensionSubjectInfoAccess) ||
60 oid.Equal(x509.OIDExtensionAuthorityInfoAccess) ||
61 oid.Equal(x509.OIDExtensionIPPrefixList) ||
62 oid.Equal(x509.OIDExtensionASList) ||
63 oid.Equal(x509.OIDExtensionCTPoison) ||
64 oid.Equal(x509.OIDExtensionCTSCT) {
65 return true
66 }
67 return false
68 }
69
70
71
72
73 func OIDInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) (int, bool) {
74 count := 0
75 critical := false
76 for _, ext := range extensions {
77 if ext.Id.Equal(oid) {
78 count++
79 if ext.Critical {
80 critical = true
81 }
82 }
83 }
84 return count, critical
85 }
86
87
88 func bitStringToString(b asn1.BitString) string {
89 result := hex.EncodeToString(b.Bytes)
90 bitsLeft := b.BitLength % 8
91 if bitsLeft != 0 {
92 result += " (" + strconv.Itoa(8-bitsLeft) + " unused bits)"
93 }
94 return result
95 }
96
97 func publicKeyAlgorithmToString(algo x509.PublicKeyAlgorithm) string {
98
99 switch algo {
100 case x509.RSA:
101 return "rsaEncryption"
102 case x509.DSA:
103 return "dsaEncryption"
104 case x509.ECDSA:
105 return "id-ecPublicKey"
106 default:
107 return strconv.Itoa(int(algo))
108 }
109 }
110
111
112
113
114 func appendHexData(buf *bytes.Buffer, data []byte, count int, prefix string) {
115 for ii, b := range data {
116 if ii%count == 0 {
117 if ii > 0 {
118 buf.WriteString("\n")
119 }
120 buf.WriteString(prefix)
121 }
122 buf.WriteString(fmt.Sprintf("%02x:", b))
123 }
124 }
125
126 func curveOIDToString(oid asn1.ObjectIdentifier) (t string, bitlen int) {
127 switch {
128 case oid.Equal(x509.OIDNamedCurveP224):
129 return "secp224r1", 224
130 case oid.Equal(x509.OIDNamedCurveP256):
131 return "prime256v1", 256
132 case oid.Equal(x509.OIDNamedCurveP384):
133 return "secp384r1", 384
134 case oid.Equal(x509.OIDNamedCurveP521):
135 return "secp521r1", 521
136 case oid.Equal(x509.OIDNamedCurveP192):
137 return "secp192r1", 192
138 }
139 return fmt.Sprintf("%v", oid), -1
140 }
141
142 func publicKeyToString(_ x509.PublicKeyAlgorithm, pub interface{}) string {
143 var buf bytes.Buffer
144 switch pub := pub.(type) {
145 case *rsa.PublicKey:
146 bitlen := pub.N.BitLen()
147 buf.WriteString(fmt.Sprintf(" Public Key: (%d bit)\n", bitlen))
148 buf.WriteString(" Modulus:\n")
149 data := pub.N.Bytes()
150 appendHexData(&buf, data, 15, " ")
151 buf.WriteString("\n")
152 buf.WriteString(fmt.Sprintf(" Exponent: %d (0x%x)", pub.E, pub.E))
153 case *dsa.PublicKey:
154 buf.WriteString(" pub:\n")
155 appendHexData(&buf, pub.Y.Bytes(), 15, " ")
156 buf.WriteString("\n")
157 buf.WriteString(" P:\n")
158 appendHexData(&buf, pub.P.Bytes(), 15, " ")
159 buf.WriteString("\n")
160 buf.WriteString(" Q:\n")
161 appendHexData(&buf, pub.Q.Bytes(), 15, " ")
162 buf.WriteString("\n")
163 buf.WriteString(" G:\n")
164 appendHexData(&buf, pub.G.Bytes(), 15, " ")
165 case *ecdsa.PublicKey:
166 data := elliptic.Marshal(pub.Curve, pub.X, pub.Y)
167 oid, ok := x509.OIDFromNamedCurve(pub.Curve)
168 if !ok {
169 return " <unsupported elliptic curve>"
170 }
171 oidname, bitlen := curveOIDToString(oid)
172 buf.WriteString(fmt.Sprintf(" Public Key: (%d bit)\n", bitlen))
173 buf.WriteString(" pub:\n")
174 appendHexData(&buf, data, 15, " ")
175 buf.WriteString("\n")
176 buf.WriteString(fmt.Sprintf(" ASN1 OID: %s", oidname))
177 default:
178 buf.WriteString(fmt.Sprintf("%v", pub))
179 }
180 return buf.String()
181 }
182
183 func commaAppend(buf *bytes.Buffer, s string) {
184 if buf.Len() > 0 {
185 buf.WriteString(", ")
186 }
187 buf.WriteString(s)
188 }
189
190 func keyUsageToString(k x509.KeyUsage) string {
191 var buf bytes.Buffer
192 if k&x509.KeyUsageDigitalSignature != 0 {
193 commaAppend(&buf, "Digital Signature")
194 }
195 if k&x509.KeyUsageContentCommitment != 0 {
196 commaAppend(&buf, "Content Commitment")
197 }
198 if k&x509.KeyUsageKeyEncipherment != 0 {
199 commaAppend(&buf, "Key Encipherment")
200 }
201 if k&x509.KeyUsageDataEncipherment != 0 {
202 commaAppend(&buf, "Data Encipherment")
203 }
204 if k&x509.KeyUsageKeyAgreement != 0 {
205 commaAppend(&buf, "Key Agreement")
206 }
207 if k&x509.KeyUsageCertSign != 0 {
208 commaAppend(&buf, "Certificate Signing")
209 }
210 if k&x509.KeyUsageCRLSign != 0 {
211 commaAppend(&buf, "CRL Signing")
212 }
213 if k&x509.KeyUsageEncipherOnly != 0 {
214 commaAppend(&buf, "Encipher Only")
215 }
216 if k&x509.KeyUsageDecipherOnly != 0 {
217 commaAppend(&buf, "Decipher Only")
218 }
219 return buf.String()
220 }
221
222 func extKeyUsageToString(u x509.ExtKeyUsage) string {
223 switch u {
224 case x509.ExtKeyUsageAny:
225 return "Any"
226 case x509.ExtKeyUsageServerAuth:
227 return "TLS Web server authentication"
228 case x509.ExtKeyUsageClientAuth:
229 return "TLS Web client authentication"
230 case x509.ExtKeyUsageCodeSigning:
231 return "Signing of executable code"
232 case x509.ExtKeyUsageEmailProtection:
233 return "Email protection"
234 case x509.ExtKeyUsageIPSECEndSystem:
235 return "IPSEC end system"
236 case x509.ExtKeyUsageIPSECTunnel:
237 return "IPSEC tunnel"
238 case x509.ExtKeyUsageIPSECUser:
239 return "IPSEC user"
240 case x509.ExtKeyUsageTimeStamping:
241 return "Time stamping"
242 case x509.ExtKeyUsageOCSPSigning:
243 return "OCSP signing"
244 case x509.ExtKeyUsageMicrosoftServerGatedCrypto:
245 return "Microsoft server gated cryptography"
246 case x509.ExtKeyUsageNetscapeServerGatedCrypto:
247 return "Netscape server gated cryptography"
248 case x509.ExtKeyUsageCertificateTransparency:
249 return "Certificate transparency"
250 default:
251 return "Unknown"
252 }
253 }
254
255 func attributeOIDToString(oid asn1.ObjectIdentifier) string {
256 switch {
257 case oid.Equal(pkix.OIDCountry):
258 return "Country"
259 case oid.Equal(pkix.OIDOrganization):
260 return "Organization"
261 case oid.Equal(pkix.OIDOrganizationalUnit):
262 return "OrganizationalUnit"
263 case oid.Equal(pkix.OIDCommonName):
264 return "CommonName"
265 case oid.Equal(pkix.OIDSerialNumber):
266 return "SerialNumber"
267 case oid.Equal(pkix.OIDLocality):
268 return "Locality"
269 case oid.Equal(pkix.OIDProvince):
270 return "Province"
271 case oid.Equal(pkix.OIDStreetAddress):
272 return "StreetAddress"
273 case oid.Equal(pkix.OIDPostalCode):
274 return "PostalCode"
275 case oid.Equal(pkix.OIDPseudonym):
276 return "Pseudonym"
277 case oid.Equal(pkix.OIDTitle):
278 return "Title"
279 case oid.Equal(pkix.OIDDnQualifier):
280 return "DnQualifier"
281 case oid.Equal(pkix.OIDName):
282 return "Name"
283 case oid.Equal(pkix.OIDSurname):
284 return "Surname"
285 case oid.Equal(pkix.OIDGivenName):
286 return "GivenName"
287 case oid.Equal(pkix.OIDInitials):
288 return "Initials"
289 case oid.Equal(pkix.OIDGenerationQualifier):
290 return "GenerationQualifier"
291 default:
292 return oid.String()
293 }
294 }
295
296
297 func NameToString(name pkix.Name) string {
298 var result bytes.Buffer
299 addSingle := func(prefix, item string) {
300 if len(item) == 0 {
301 return
302 }
303 commaAppend(&result, prefix)
304 result.WriteString(item)
305 }
306 addList := func(prefix string, items []string) {
307 for _, item := range items {
308 addSingle(prefix, item)
309 }
310 }
311 addList("C=", name.Country)
312 addList("O=", name.Organization)
313 addList("OU=", name.OrganizationalUnit)
314 addList("L=", name.Locality)
315 addList("ST=", name.Province)
316 addList("streetAddress=", name.StreetAddress)
317 addList("postalCode=", name.PostalCode)
318 addSingle("serialNumber=", name.SerialNumber)
319 addSingle("CN=", name.CommonName)
320 for _, atv := range name.Names {
321 value, ok := atv.Value.(string)
322 if !ok {
323 continue
324 }
325 t := atv.Type
326
327
328 if len(t) == 4 && t[0] == pkix.OIDAttribute[0] && t[1] == pkix.OIDAttribute[1] && t[2] == pkix.OIDAttribute[2] {
329
330 switch t[3] {
331 case pkix.OIDCommonName[3], pkix.OIDSerialNumber[3], pkix.OIDCountry[3], pkix.OIDLocality[3], pkix.OIDProvince[3],
332 pkix.OIDStreetAddress[3], pkix.OIDOrganization[3], pkix.OIDOrganizationalUnit[3], pkix.OIDPostalCode[3]:
333 continue
334 case pkix.OIDPseudonym[3]:
335 addSingle("pseudonym=", value)
336 continue
337 case pkix.OIDTitle[3]:
338 addSingle("title=", value)
339 continue
340 case pkix.OIDDnQualifier[3]:
341 addSingle("dnQualifier=", value)
342 continue
343 case pkix.OIDName[3]:
344 addSingle("name=", value)
345 continue
346 case pkix.OIDSurname[3]:
347 addSingle("surname=", value)
348 continue
349 case pkix.OIDGivenName[3]:
350 addSingle("givenName=", value)
351 continue
352 case pkix.OIDInitials[3]:
353 addSingle("initials=", value)
354 continue
355 case pkix.OIDGenerationQualifier[3]:
356 addSingle("generationQualifier=", value)
357 continue
358 }
359 }
360 addSingle(t.String()+"=", value)
361 }
362 return result.String()
363 }
364
365
366 func OtherNameToString(other x509.OtherName) string {
367 return fmt.Sprintf("%v=%v", other.TypeID, hex.EncodeToString(other.Value.Bytes))
368 }
369
370
371 func GeneralNamesToString(gname *x509.GeneralNames) string {
372 var buf bytes.Buffer
373 for _, name := range gname.DNSNames {
374 commaAppend(&buf, "DNS:"+name)
375 }
376 for _, email := range gname.EmailAddresses {
377 commaAppend(&buf, "email:"+email)
378 }
379 for _, name := range gname.DirectoryNames {
380 commaAppend(&buf, "DirName:"+NameToString(name))
381 }
382 for _, uri := range gname.URIs {
383 commaAppend(&buf, "URI:"+uri)
384 }
385 for _, ip := range gname.IPNets {
386 if ip.Mask == nil {
387 commaAppend(&buf, "IP Address:"+ip.IP.String())
388 } else {
389 commaAppend(&buf, "IP Address:"+ip.IP.String()+"/"+ip.Mask.String())
390 }
391 }
392 for _, id := range gname.RegisteredIDs {
393 commaAppend(&buf, "Registered ID:"+id.String())
394 }
395 for _, other := range gname.OtherNames {
396 commaAppend(&buf, "othername:"+OtherNameToString(other))
397 }
398 return buf.String()
399 }
400
401
402
403 func CertificateToString(cert *x509.Certificate) string {
404 var result bytes.Buffer
405 result.WriteString("Certificate:\n")
406 result.WriteString(" Data:\n")
407 result.WriteString(fmt.Sprintf(" Version: %d (%#x)\n", cert.Version, cert.Version-1))
408 result.WriteString(fmt.Sprintf(" Serial Number: %s (0x%s)\n", cert.SerialNumber.Text(10), cert.SerialNumber.Text(16)))
409 result.WriteString(fmt.Sprintf(" Signature Algorithm: %v\n", cert.SignatureAlgorithm))
410 result.WriteString(fmt.Sprintf(" Issuer: %v\n", NameToString(cert.Issuer)))
411 result.WriteString(" Validity:\n")
412 result.WriteString(fmt.Sprintf(" Not Before: %v\n", cert.NotBefore))
413 result.WriteString(fmt.Sprintf(" Not After : %v\n", cert.NotAfter))
414 result.WriteString(fmt.Sprintf(" Subject: %v\n", NameToString(cert.Subject)))
415 result.WriteString(" Subject Public Key Info:\n")
416 result.WriteString(fmt.Sprintf(" Public Key Algorithm: %v\n", publicKeyAlgorithmToString(cert.PublicKeyAlgorithm)))
417 result.WriteString(fmt.Sprintf("%v\n", publicKeyToString(cert.PublicKeyAlgorithm, cert.PublicKey)))
418
419 if len(cert.Extensions) > 0 {
420 result.WriteString(" X509v3 extensions:\n")
421 }
422
423 showAuthKeyID(&result, cert)
424 showSubjectKeyID(&result, cert)
425 showKeyUsage(&result, cert)
426 showExtendedKeyUsage(&result, cert)
427 showBasicConstraints(&result, cert)
428 showSubjectAltName(&result, cert)
429 showNameConstraints(&result, cert)
430 showCertPolicies(&result, cert)
431 showCRLDPs(&result, cert)
432 showAuthInfoAccess(&result, cert)
433 showSubjectInfoAccess(&result, cert)
434 showRPKIAddressRanges(&result, cert)
435 showRPKIASIdentifiers(&result, cert)
436 showCTPoison(&result, cert)
437 showCTSCT(&result, cert)
438 showCTLogSTHInfo(&result, cert)
439
440 showUnhandledExtensions(&result, cert)
441 showSignature(&result, cert)
442
443 return result.String()
444 }
445
446 func showCritical(result *bytes.Buffer, critical bool) {
447 if critical {
448 result.WriteString(" critical")
449 }
450 result.WriteString("\n")
451 }
452
453 func showAuthKeyID(result *bytes.Buffer, cert *x509.Certificate) {
454 count, critical := OIDInExtensions(x509.OIDExtensionAuthorityKeyId, cert.Extensions)
455 if count > 0 {
456 result.WriteString(" X509v3 Authority Key Identifier:")
457 showCritical(result, critical)
458 result.WriteString(fmt.Sprintf(" keyid:%v\n", hex.EncodeToString(cert.AuthorityKeyId)))
459 }
460 }
461
462 func showSubjectKeyID(result *bytes.Buffer, cert *x509.Certificate) {
463 count, critical := OIDInExtensions(x509.OIDExtensionSubjectKeyId, cert.Extensions)
464 if count > 0 {
465 result.WriteString(" X509v3 Subject Key Identifier:")
466 showCritical(result, critical)
467 result.WriteString(fmt.Sprintf(" keyid:%v\n", hex.EncodeToString(cert.SubjectKeyId)))
468 }
469 }
470
471 func showKeyUsage(result *bytes.Buffer, cert *x509.Certificate) {
472 count, critical := OIDInExtensions(x509.OIDExtensionKeyUsage, cert.Extensions)
473 if count > 0 {
474 result.WriteString(" X509v3 Key Usage:")
475 showCritical(result, critical)
476 result.WriteString(fmt.Sprintf(" %v\n", keyUsageToString(cert.KeyUsage)))
477 }
478 }
479
480 func showExtendedKeyUsage(result *bytes.Buffer, cert *x509.Certificate) {
481 count, critical := OIDInExtensions(x509.OIDExtensionExtendedKeyUsage, cert.Extensions)
482 if count > 0 {
483 result.WriteString(" X509v3 Extended Key Usage:")
484 showCritical(result, critical)
485 var usages bytes.Buffer
486 for _, usage := range cert.ExtKeyUsage {
487 commaAppend(&usages, extKeyUsageToString(usage))
488 }
489 for _, oid := range cert.UnknownExtKeyUsage {
490 commaAppend(&usages, oid.String())
491 }
492 result.WriteString(fmt.Sprintf(" %v\n", usages.String()))
493 }
494 }
495
496 func showBasicConstraints(result *bytes.Buffer, cert *x509.Certificate) {
497 count, critical := OIDInExtensions(x509.OIDExtensionBasicConstraints, cert.Extensions)
498 if count > 0 {
499 result.WriteString(" X509v3 Basic Constraints:")
500 showCritical(result, critical)
501 result.WriteString(fmt.Sprintf(" CA:%t", cert.IsCA))
502 if cert.MaxPathLen > 0 || cert.MaxPathLenZero {
503 result.WriteString(fmt.Sprintf(", pathlen:%d", cert.MaxPathLen))
504 }
505 result.WriteString("\n")
506 }
507 }
508
509 func showSubjectAltName(result *bytes.Buffer, cert *x509.Certificate) {
510 count, critical := OIDInExtensions(x509.OIDExtensionSubjectAltName, cert.Extensions)
511 if count > 0 {
512 result.WriteString(" X509v3 Subject Alternative Name:")
513 showCritical(result, critical)
514 var buf bytes.Buffer
515 for _, name := range cert.DNSNames {
516 commaAppend(&buf, "DNS:"+name)
517 }
518 for _, email := range cert.EmailAddresses {
519 commaAppend(&buf, "email:"+email)
520 }
521 for _, ip := range cert.IPAddresses {
522 commaAppend(&buf, "IP Address:"+ip.String())
523 }
524
525 result.WriteString(fmt.Sprintf(" %v\n", buf.String()))
526
527 }
528 }
529
530 func showNameConstraints(result *bytes.Buffer, cert *x509.Certificate) {
531 count, critical := OIDInExtensions(x509.OIDExtensionNameConstraints, cert.Extensions)
532 if count > 0 {
533 result.WriteString(" X509v3 Name Constraints:")
534 showCritical(result, critical)
535 if len(cert.PermittedDNSDomains) > 0 {
536 result.WriteString(" Permitted:\n")
537 var buf bytes.Buffer
538 for _, name := range cert.PermittedDNSDomains {
539 commaAppend(&buf, "DNS:"+name)
540 }
541 result.WriteString(fmt.Sprintf(" %v\n", buf.String()))
542 }
543
544 }
545
546 }
547
548 func showCertPolicies(result *bytes.Buffer, cert *x509.Certificate) {
549 count, critical := OIDInExtensions(x509.OIDExtensionCertificatePolicies, cert.Extensions)
550 if count > 0 {
551 result.WriteString(" X509v3 Certificate Policies:")
552 showCritical(result, critical)
553 for _, oid := range cert.PolicyIdentifiers {
554 result.WriteString(fmt.Sprintf(" Policy: %v\n", oid.String()))
555
556 }
557 }
558
559 }
560
561 func showCRLDPs(result *bytes.Buffer, cert *x509.Certificate) {
562 count, critical := OIDInExtensions(x509.OIDExtensionCRLDistributionPoints, cert.Extensions)
563 if count > 0 {
564 result.WriteString(" X509v3 CRL Distribution Points:")
565 showCritical(result, critical)
566 result.WriteString(" Full Name:\n")
567 var buf bytes.Buffer
568 for _, pt := range cert.CRLDistributionPoints {
569 commaAppend(&buf, "URI:"+pt)
570 }
571 result.WriteString(fmt.Sprintf(" %v\n", buf.String()))
572
573 }
574
575 }
576
577 func showAuthInfoAccess(result *bytes.Buffer, cert *x509.Certificate) {
578 count, critical := OIDInExtensions(x509.OIDExtensionAuthorityInfoAccess, cert.Extensions)
579 if count > 0 {
580 result.WriteString(" Authority Information Access:")
581 showCritical(result, critical)
582 var issuerBuf bytes.Buffer
583 for _, issuer := range cert.IssuingCertificateURL {
584 commaAppend(&issuerBuf, "URI:"+issuer)
585 }
586 if issuerBuf.Len() > 0 {
587 result.WriteString(fmt.Sprintf(" CA Issuers - %v\n", issuerBuf.String()))
588 }
589 var ocspBuf bytes.Buffer
590 for _, ocsp := range cert.OCSPServer {
591 commaAppend(&ocspBuf, "URI:"+ocsp)
592 }
593 if ocspBuf.Len() > 0 {
594 result.WriteString(fmt.Sprintf(" OCSP - %v\n", ocspBuf.String()))
595 }
596
597 }
598 }
599
600 func showSubjectInfoAccess(result *bytes.Buffer, cert *x509.Certificate) {
601 count, critical := OIDInExtensions(x509.OIDExtensionSubjectInfoAccess, cert.Extensions)
602 if count > 0 {
603 result.WriteString(" Subject Information Access:")
604 showCritical(result, critical)
605 var tsBuf bytes.Buffer
606 for _, ts := range cert.SubjectTimestamps {
607 commaAppend(&tsBuf, "URI:"+ts)
608 }
609 if tsBuf.Len() > 0 {
610 result.WriteString(fmt.Sprintf(" AD Time Stamping - %v\n", tsBuf.String()))
611 }
612 var repoBuf bytes.Buffer
613 for _, repo := range cert.SubjectCARepositories {
614 commaAppend(&repoBuf, "URI:"+repo)
615 }
616 if repoBuf.Len() > 0 {
617 result.WriteString(fmt.Sprintf(" CA repository - %v\n", repoBuf.String()))
618 }
619 }
620 }
621
622 func showAddressRange(prefix x509.IPAddressPrefix, afi uint16) string {
623 switch afi {
624 case x509.IPv4AddressFamilyIndicator, x509.IPv6AddressFamilyIndicator:
625 size := 4
626 if afi == x509.IPv6AddressFamilyIndicator {
627 size = 16
628 }
629 ip := make([]byte, size)
630 copy(ip, prefix.Bytes)
631 addr := net.IPNet{IP: ip, Mask: net.CIDRMask(prefix.BitLength, 8*size)}
632 return addr.String()
633 default:
634 return fmt.Sprintf("%x/%d", prefix.Bytes, prefix.BitLength)
635 }
636
637 }
638
639 func showRPKIAddressRanges(result *bytes.Buffer, cert *x509.Certificate) {
640 count, critical := OIDInExtensions(x509.OIDExtensionIPPrefixList, cert.Extensions)
641 if count > 0 {
642 result.WriteString(" sbgp-ipAddrBlock:")
643 showCritical(result, critical)
644 for _, blocks := range cert.RPKIAddressRanges {
645 afi := blocks.AFI
646 switch afi {
647 case x509.IPv4AddressFamilyIndicator:
648 result.WriteString(" IPv4")
649 case x509.IPv6AddressFamilyIndicator:
650 result.WriteString(" IPv6")
651 default:
652 result.WriteString(fmt.Sprintf(" %d", afi))
653 }
654 if blocks.SAFI != 0 {
655 result.WriteString(fmt.Sprintf(" SAFI=%d", blocks.SAFI))
656 }
657 result.WriteString(":")
658 if blocks.InheritFromIssuer {
659 result.WriteString(" inherit\n")
660 continue
661 }
662 result.WriteString("\n")
663 for _, prefix := range blocks.AddressPrefixes {
664 result.WriteString(fmt.Sprintf(" %s\n", showAddressRange(prefix, afi)))
665 }
666 for _, ipRange := range blocks.AddressRanges {
667 result.WriteString(fmt.Sprintf(" [%s, %s]\n", showAddressRange(ipRange.Min, afi), showAddressRange(ipRange.Max, afi)))
668 }
669 }
670 }
671 }
672
673 func showASIDs(result *bytes.Buffer, asids *x509.ASIdentifiers, label string) {
674 if asids == nil {
675 return
676 }
677 result.WriteString(fmt.Sprintf(" %s:\n", label))
678 if asids.InheritFromIssuer {
679 result.WriteString(" inherit\n")
680 return
681 }
682 for _, id := range asids.ASIDs {
683 result.WriteString(fmt.Sprintf(" %d\n", id))
684 }
685 for _, idRange := range asids.ASIDRanges {
686 result.WriteString(fmt.Sprintf(" %d-%d\n", idRange.Min, idRange.Max))
687 }
688 }
689
690 func showRPKIASIdentifiers(result *bytes.Buffer, cert *x509.Certificate) {
691 count, critical := OIDInExtensions(x509.OIDExtensionASList, cert.Extensions)
692 if count > 0 {
693 result.WriteString(" sbgp-autonomousSysNum:")
694 showCritical(result, critical)
695 showASIDs(result, cert.RPKIASNumbers, "Autonomous System Numbers")
696 showASIDs(result, cert.RPKIRoutingDomainIDs, "Routing Domain Identifiers")
697 }
698 }
699 func showCTPoison(result *bytes.Buffer, cert *x509.Certificate) {
700 count, critical := OIDInExtensions(x509.OIDExtensionCTPoison, cert.Extensions)
701 if count > 0 {
702 result.WriteString(" RFC6962 Pre-Certificate Poison:")
703 showCritical(result, critical)
704 result.WriteString(" .....\n")
705 }
706 }
707
708 func showCTSCT(result *bytes.Buffer, cert *x509.Certificate) {
709 count, critical := OIDInExtensions(x509.OIDExtensionCTSCT, cert.Extensions)
710 if count > 0 {
711 result.WriteString(" RFC6962 Certificate Transparency SCT:")
712 showCritical(result, critical)
713 for i, sctData := range cert.SCTList.SCTList {
714 result.WriteString(fmt.Sprintf(" SCT [%d]:\n", i))
715 var sct ct.SignedCertificateTimestamp
716 _, err := tls.Unmarshal(sctData.Val, &sct)
717 if err != nil {
718 appendHexData(result, sctData.Val, 16, " ")
719 result.WriteString("\n")
720 continue
721 }
722 result.WriteString(fmt.Sprintf(" Version: %d\n", sct.SCTVersion))
723 result.WriteString(fmt.Sprintf(" LogID: %s\n", base64.StdEncoding.EncodeToString(sct.LogID.KeyID[:])))
724 result.WriteString(fmt.Sprintf(" Timestamp: %d\n", sct.Timestamp))
725 result.WriteString(fmt.Sprintf(" Signature: %s\n", sct.Signature.Algorithm))
726 result.WriteString(" Signature:\n")
727 appendHexData(result, sct.Signature.Signature, 16, " ")
728 result.WriteString("\n")
729 }
730 }
731 }
732
733 func showCTLogSTHInfo(result *bytes.Buffer, cert *x509.Certificate) {
734 count, critical := OIDInExtensions(x509ext.OIDExtensionCTSTH, cert.Extensions)
735 if count > 0 {
736 result.WriteString(" Certificate Transparency STH:")
737 showCritical(result, critical)
738 sthInfo, err := x509ext.LogSTHInfoFromCert(cert)
739 if err != nil {
740 result.WriteString(" Failed to decode STH:\n")
741 return
742 }
743 result.WriteString(fmt.Sprintf(" LogURL: %s\n", string(sthInfo.LogURL)))
744 result.WriteString(fmt.Sprintf(" Version: %d\n", sthInfo.Version))
745 result.WriteString(fmt.Sprintf(" TreeSize: %d\n", sthInfo.TreeSize))
746 result.WriteString(fmt.Sprintf(" Timestamp: %d\n", sthInfo.Timestamp))
747 result.WriteString(" RootHash:\n")
748 appendHexData(result, sthInfo.SHA256RootHash[:], 16, " ")
749 result.WriteString("\n")
750 result.WriteString(fmt.Sprintf(" TreeHeadSignature: %s\n", sthInfo.TreeHeadSignature.Algorithm))
751 appendHexData(result, sthInfo.TreeHeadSignature.Signature, 16, " ")
752 result.WriteString("\n")
753 }
754 }
755
756 func showUnhandledExtensions(result *bytes.Buffer, cert *x509.Certificate) {
757 for _, ext := range cert.Extensions {
758
759 if oidAlreadyPrinted(ext.Id) {
760 continue
761 }
762 result.WriteString(fmt.Sprintf(" %v:", ext.Id))
763 showCritical(result, ext.Critical)
764 appendHexData(result, ext.Value, 16, " ")
765 result.WriteString("\n")
766 }
767 }
768
769 func showSignature(result *bytes.Buffer, cert *x509.Certificate) {
770 result.WriteString(fmt.Sprintf(" Signature Algorithm: %v\n", cert.SignatureAlgorithm))
771 appendHexData(result, cert.Signature, 18, " ")
772 result.WriteString("\n")
773 }
774
775
776 func oidAlreadyPrinted(oid asn1.ObjectIdentifier) bool {
777 if oid.Equal(x509.OIDExtensionSubjectKeyId) ||
778 oid.Equal(x509.OIDExtensionKeyUsage) ||
779 oid.Equal(x509.OIDExtensionExtendedKeyUsage) ||
780 oid.Equal(x509.OIDExtensionAuthorityKeyId) ||
781 oid.Equal(x509.OIDExtensionBasicConstraints) ||
782 oid.Equal(x509.OIDExtensionSubjectAltName) ||
783 oid.Equal(x509.OIDExtensionCertificatePolicies) ||
784 oid.Equal(x509.OIDExtensionNameConstraints) ||
785 oid.Equal(x509.OIDExtensionCRLDistributionPoints) ||
786 oid.Equal(x509.OIDExtensionAuthorityInfoAccess) ||
787 oid.Equal(x509.OIDExtensionSubjectInfoAccess) ||
788 oid.Equal(x509.OIDExtensionIPPrefixList) ||
789 oid.Equal(x509.OIDExtensionASList) ||
790 oid.Equal(x509.OIDExtensionCTPoison) ||
791 oid.Equal(x509.OIDExtensionCTSCT) ||
792 oid.Equal(x509ext.OIDExtensionCTSTH) {
793 return true
794 }
795 return false
796 }
797
798
799
800 func CertificateFromPEM(pemBytes []byte) (*x509.Certificate, error) {
801 block, rest := pem.Decode(pemBytes)
802 if len(rest) != 0 {
803 return nil, errors.New("trailing data found after PEM block")
804 }
805 if block == nil {
806 return nil, errors.New("PEM block is nil")
807 }
808 if block.Type != "CERTIFICATE" {
809 return nil, errors.New("PEM block is not a CERTIFICATE")
810 }
811 return x509.ParseCertificate(block.Bytes)
812 }
813
814
815
816
817
818 func CertificatesFromPEM(pemBytes []byte) ([]*x509.Certificate, error) {
819 var chain []*x509.Certificate
820 for {
821 var block *pem.Block
822 block, pemBytes = pem.Decode(pemBytes)
823 if block == nil {
824 return chain, nil
825 }
826 if block.Type != "CERTIFICATE" {
827 return nil, fmt.Errorf("PEM block is not a CERTIFICATE")
828 }
829 cert, err := x509.ParseCertificate(block.Bytes)
830 if err != nil {
831 return nil, errors.New("failed to parse certificate")
832 }
833 chain = append(chain, cert)
834 }
835 }
836
837
838 func ParseSCTsFromSCTList(sctList *x509.SignedCertificateTimestampList) ([]*ct.SignedCertificateTimestamp, error) {
839 var scts []*ct.SignedCertificateTimestamp
840 for i, data := range sctList.SCTList {
841 sct, err := ExtractSCT(&data)
842 if err != nil {
843 return nil, fmt.Errorf("error extracting SCT number %d: %s", i, err)
844 }
845 scts = append(scts, sct)
846 }
847 return scts, nil
848 }
849
850
851 func ExtractSCT(sctData *x509.SerializedSCT) (*ct.SignedCertificateTimestamp, error) {
852 if sctData == nil {
853 return nil, errors.New("SCT is nil")
854 }
855 var sct ct.SignedCertificateTimestamp
856 if rest, err := tls.Unmarshal(sctData.Val, &sct); err != nil {
857 return nil, fmt.Errorf("error parsing SCT: %s", err)
858 } else if len(rest) > 0 {
859 return nil, fmt.Errorf("extra data (%d bytes) after serialized SCT", len(rest))
860 }
861 return &sct, nil
862 }
863
864
865 func MarshalSCTsIntoSCTList(scts []*ct.SignedCertificateTimestamp) (*x509.SignedCertificateTimestampList, error) {
866 var sctList x509.SignedCertificateTimestampList
867 sctList.SCTList = []x509.SerializedSCT{}
868 for i, sct := range scts {
869 if sct == nil {
870 return nil, fmt.Errorf("SCT number %d is nil", i)
871 }
872 encd, err := tls.Marshal(*sct)
873 if err != nil {
874 return nil, fmt.Errorf("error serializing SCT number %d: %s", i, err)
875 }
876 sctData := x509.SerializedSCT{Val: encd}
877 sctList.SCTList = append(sctList.SCTList, sctData)
878 }
879 return &sctList, nil
880 }
881
882 var pemCertificatePrefix = []byte("-----BEGIN CERTIFICATE")
883
884
885
886
887
888 func ParseSCTsFromCertificate(certBytes []byte) ([]*ct.SignedCertificateTimestamp, error) {
889 var cert *x509.Certificate
890 var err error
891 if bytes.HasPrefix(certBytes, pemCertificatePrefix) {
892 cert, err = CertificateFromPEM(certBytes)
893 } else {
894 cert, err = x509.ParseCertificate(certBytes)
895 }
896 if err != nil {
897 return nil, fmt.Errorf("failed to parse certificate: %s", err)
898 }
899 return ParseSCTsFromSCTList(&cert.SCTList)
900 }
901
View as plain text