github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/ct/x509/pkix/pkix.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package pkix contains shared, low level structures used for ASN.1 parsing 6 // and serialization of X.509 certificates, CRL and OCSP. 7 package pkix 8 9 import ( 10 // START CT CHANGES 11 "github.com/zmap/zcrypto/ct/asn1" 12 "strings" 13 // END CT CHANGES 14 "math/big" 15 "time" 16 ) 17 18 // AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC 19 // 5280, section 4.1.1.2. 20 type AlgorithmIdentifier struct { 21 Algorithm asn1.ObjectIdentifier 22 Parameters asn1.RawValue `asn1:"optional"` 23 } 24 25 type RDNSequence []RelativeDistinguishedNameSET 26 27 type RelativeDistinguishedNameSET []AttributeTypeAndValue 28 29 // AttributeTypeAndValue mirrors the ASN.1 structure of the same name in 30 // http://tools.ietf.org/html/rfc5280#section-4.1.2.4 31 type AttributeTypeAndValue struct { 32 Type asn1.ObjectIdentifier 33 Value interface{} 34 } 35 36 // Extension represents the ASN.1 structure of the same name. See RFC 37 // 5280, section 4.2. 38 type Extension struct { 39 Id asn1.ObjectIdentifier 40 Critical bool `asn1:"optional"` 41 Value []byte 42 } 43 44 // Name represents an X.509 distinguished name. This only includes the common 45 // elements of a DN. Additional elements in the name are ignored. 46 type Name struct { 47 Country, Organization, OrganizationalUnit []string 48 Locality, Province []string 49 StreetAddress, PostalCode []string 50 SerialNumber, CommonName string 51 52 Names []AttributeTypeAndValue 53 } 54 55 func (n *Name) FillFromRDNSequence(rdns *RDNSequence) { 56 for _, rdn := range *rdns { 57 if len(rdn) == 0 { 58 continue 59 } 60 atv := rdn[0] 61 n.Names = append(n.Names, atv) 62 value, ok := atv.Value.(string) 63 if !ok { 64 continue 65 } 66 67 t := atv.Type 68 if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 { 69 switch t[3] { 70 case 3: 71 n.CommonName = value 72 case 5: 73 n.SerialNumber = value 74 case 6: 75 n.Country = append(n.Country, value) 76 case 7: 77 n.Locality = append(n.Locality, value) 78 case 8: 79 n.Province = append(n.Province, value) 80 case 9: 81 n.StreetAddress = append(n.StreetAddress, value) 82 case 10: 83 n.Organization = append(n.Organization, value) 84 case 11: 85 n.OrganizationalUnit = append(n.OrganizationalUnit, value) 86 case 17: 87 n.PostalCode = append(n.PostalCode, value) 88 } 89 } 90 } 91 } 92 93 var ( 94 oidCountry = []int{2, 5, 4, 6} 95 oidOrganization = []int{2, 5, 4, 10} 96 oidOrganizationalUnit = []int{2, 5, 4, 11} 97 oidCommonName = []int{2, 5, 4, 3} 98 oidSerialNumber = []int{2, 5, 4, 5} 99 oidLocality = []int{2, 5, 4, 7} 100 oidProvince = []int{2, 5, 4, 8} 101 oidStreetAddress = []int{2, 5, 4, 9} 102 oidPostalCode = []int{2, 5, 4, 17} 103 ) 104 105 // appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence 106 // and returns the new value. The relativeDistinguishedNameSET contains an 107 // attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and 108 // search for AttributeTypeAndValue. 109 func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence { 110 if len(values) == 0 { 111 return in 112 } 113 114 s := make([]AttributeTypeAndValue, len(values)) 115 for i, value := range values { 116 s[i].Type = oid 117 s[i].Value = value 118 } 119 120 return append(in, s) 121 } 122 123 func (n Name) ToRDNSequence() (ret RDNSequence) { 124 if len(n.CommonName) > 0 { 125 ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName) 126 } 127 ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit) 128 ret = appendRDNs(ret, n.Organization, oidOrganization) 129 ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress) 130 ret = appendRDNs(ret, n.Locality, oidLocality) 131 ret = appendRDNs(ret, n.Province, oidProvince) 132 ret = appendRDNs(ret, n.PostalCode, oidPostalCode) 133 ret = appendRDNs(ret, n.Country, oidCountry) 134 if len(n.SerialNumber) > 0 { 135 ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber) 136 } 137 138 return ret 139 } 140 141 func (n *Name) String() string { 142 parts := make([]string, 0, 8) 143 for _, name := range n.Names { 144 oidString := name.Type.String() 145 attrParts := make([]string, 0, 2) 146 oidName, ok := oidDotNotationToNames[oidString] 147 if ok { 148 attrParts = append(attrParts, oidName.ShortName) 149 } else { 150 attrParts = append(attrParts, oidString) 151 } 152 switch value := name.Value.(type) { 153 case string: 154 attrParts = append(attrParts, value) 155 case []byte: 156 attrParts = append(attrParts, string(value)) 157 default: 158 continue 159 } 160 attrString := strings.Join(attrParts, "=") 161 parts = append(parts, attrString) 162 } 163 joined := strings.Join(parts, ", ") 164 return joined 165 } 166 167 // CertificateList represents the ASN.1 structure of the same name. See RFC 168 // 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the 169 // signature. 170 type CertificateList struct { 171 TBSCertList TBSCertificateList 172 SignatureAlgorithm AlgorithmIdentifier 173 SignatureValue asn1.BitString 174 } 175 176 // HasExpired reports whether now is past the expiry time of certList. 177 func (certList *CertificateList) HasExpired(now time.Time) bool { 178 return now.After(certList.TBSCertList.NextUpdate) 179 } 180 181 // TBSCertificateList represents the ASN.1 structure of the same name. See RFC 182 // 5280, section 5.1. 183 type TBSCertificateList struct { 184 Raw asn1.RawContent 185 Version int `asn1:"optional,default:2"` 186 Signature AlgorithmIdentifier 187 Issuer RDNSequence 188 ThisUpdate time.Time 189 NextUpdate time.Time 190 RevokedCertificates []RevokedCertificate `asn1:"optional"` 191 Extensions []Extension `asn1:"tag:0,optional,explicit"` 192 } 193 194 // RevokedCertificate represents the ASN.1 structure of the same name. See RFC 195 // 5280, section 5.1. 196 type RevokedCertificate struct { 197 SerialNumber *big.Int 198 RevocationTime time.Time 199 Extensions []Extension `asn1:"optional"` 200 }