github.com/letsencrypt/boulder@v0.20251208.0/linter/lints/common.go (about) 1 package lints 2 3 import ( 4 "bytes" 5 "net/url" 6 "time" 7 8 "github.com/zmap/zcrypto/encoding/asn1" 9 "github.com/zmap/zcrypto/x509/pkix" 10 "github.com/zmap/zlint/v3/lint" 11 "golang.org/x/crypto/cryptobyte" 12 cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" 13 ) 14 15 const ( 16 // CABF Baseline Requirements 6.3.2 Certificate operational periods: 17 // For the purpose of calculations, a day is measured as 86,400 seconds. 18 // Any amount of time greater than this, including fractional seconds and/or 19 // leap seconds, shall represent an additional day. 20 BRDay time.Duration = 86400 * time.Second 21 22 // Declare our own Sources for use in zlint registry filtering. 23 LetsEncryptCPS lint.LintSource = "LECPS" 24 ChromeCTPolicy lint.LintSource = "ChromeCT" 25 ) 26 27 var ( 28 CPSV33Date = time.Date(2021, time.June, 8, 0, 0, 0, 0, time.UTC) 29 MozillaPolicy281Date = time.Date(2023, time.February, 15, 0, 0, 0, 0, time.UTC) 30 ) 31 32 // IssuingDistributionPoint stores the IA5STRING value(s) of the optional 33 // distributionPoint, and the (implied OPTIONAL) BOOLEAN values of 34 // onlyContainsUserCerts and onlyContainsCACerts. 35 // 36 // RFC 5280 37 // * Section 5.2.5 38 // IssuingDistributionPoint ::= SEQUENCE { 39 // distributionPoint [0] DistributionPointName OPTIONAL, 40 // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, 41 // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, 42 // ... 43 // } 44 // 45 // * Section 4.2.1.13 46 // DistributionPointName ::= CHOICE { 47 // fullName [0] GeneralNames, 48 // ... } 49 // 50 // * Appendix A.1, Page 128 51 // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 52 // GeneralName ::= CHOICE { 53 // ... 54 // uniformResourceIdentifier [6] IA5String, 55 // ... } 56 // 57 // Because this struct is used by cryptobyte (not by encoding/asn1), and because 58 // we only care about the uniformResourceIdentifier flavor of GeneralName, we 59 // are able to flatten the DistributionPointName down into a slice of URIs. 60 type IssuingDistributionPoint struct { 61 DistributionPointURIs []*url.URL 62 OnlyContainsUserCerts bool 63 OnlyContainsCACerts bool 64 } 65 66 // NewIssuingDistributionPoint is a constructor which returns an 67 // IssuingDistributionPoint with each field set to zero values. 68 func NewIssuingDistributionPoint() *IssuingDistributionPoint { 69 return &IssuingDistributionPoint{} 70 } 71 72 // GetExtWithOID is a helper for several of our custom lints. It returns the 73 // extension with the given OID if it exists, or nil otherwise. 74 func GetExtWithOID(exts []pkix.Extension, oid asn1.ObjectIdentifier) *pkix.Extension { 75 for _, ext := range exts { 76 if ext.Id.Equal(oid) { 77 return &ext 78 } 79 } 80 return nil 81 } 82 83 // ReadOptionalASN1BooleanWithTag attempts to read and advance incoming to 84 // search for an optional DER-encoded ASN.1 element tagged with the given tag. 85 // Unless out is nil, it stores whether an element with the tag was found in 86 // out, otherwise out will take the default value. It reports whether all reads 87 // were successful. 88 func ReadOptionalASN1BooleanWithTag(incoming *cryptobyte.String, out *bool, tag cryptobyte_asn1.Tag, defaultValue bool) bool { 89 // ReadOptionalASN1 performs a peek and will not advance if the tag is 90 // missing, meaning that incoming will retain bytes. 91 var valuePresent bool 92 var valueBytes cryptobyte.String 93 if !incoming.ReadOptionalASN1(&valueBytes, &valuePresent, tag) { 94 return false 95 } 96 val := defaultValue 97 if valuePresent { 98 /* 99 X.690 (07/2002) 100 https://www.itu.int/rec/T-REC-X.690-200207-S/en 101 102 Section 8.2.2: 103 If the boolean value is: 104 FALSE 105 the octet shall be zero. 106 If the boolean value is 107 TRUE 108 the octet shall have any non-zero value, as a sender's option. 109 110 Section 11.1 Boolean values: 111 If the encoding represents the boolean value TRUE, its single contents octet shall have all eight 112 bits set to one. (Contrast with 8.2.2.) 113 114 Succinctly, BER encoding states any nonzero value is TRUE. The DER 115 encoding restricts the value 0xFF as TRUE and any other: 0x01, 116 0x23, 0xFE, etc as invalid encoding. 117 */ 118 boolBytes := []byte(valueBytes) 119 if bytes.Equal(boolBytes, []byte{0xFF}) { 120 val = true 121 } else if bytes.Equal(boolBytes, []byte{0x00}) { 122 val = false 123 } else { 124 // Unrecognized DER encoding of boolean! 125 return false 126 } 127 } 128 if out != nil { 129 *out = val 130 } 131 132 // All reads were successful. 133 return true 134 }