github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/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 "encoding/hex" 11 "fmt" 12 "math/big" 13 "time" 14 15 "github.com/zmap/zcrypto/encoding/asn1" 16 ) 17 18 // LegacyNameString allows to specify legacy ZCrypto behaviour 19 // for X509Name.String() in reverse order 20 var LegacyNameString = false 21 22 // AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC 23 // 5280, section 4.1.1.2. 24 type AlgorithmIdentifier struct { 25 Algorithm asn1.ObjectIdentifier 26 Parameters asn1.RawValue `asn1:"optional"` 27 } 28 29 type RDNSequence []RelativeDistinguishedNameSET 30 31 type RelativeDistinguishedNameSET []AttributeTypeAndValue 32 33 // AttributeTypeAndValue mirrors the ASN.1 structure of the same name in 34 // RFC 5280, Section 4.1.2.4. 35 type AttributeTypeAndValue struct { 36 Type asn1.ObjectIdentifier `json:"type"` 37 Value interface{} `json:"value"` 38 } 39 40 // AttributeTypeAndValueSET represents a set of ASN.1 sequences of 41 // AttributeTypeAndValue sequences from RFC 2986 (PKCS #10). 42 type AttributeTypeAndValueSET struct { 43 Type asn1.ObjectIdentifier 44 Value [][]AttributeTypeAndValue `asn1:"set"` 45 } 46 47 // Extension represents the ASN.1 structure of the same name. See RFC 48 // 5280, section 4.2. 49 type Extension struct { 50 Id asn1.ObjectIdentifier 51 Critical bool `asn1:"optional"` 52 Value []byte 53 } 54 55 // Name represents an X.509 distinguished name. This only includes the common 56 // elements of a DN. Note that Name is only an approximation of the X.509 57 // structure. If an accurate representation is needed, asn1.Unmarshal the raw 58 // subject or issuer as an RDNSequence. 59 type Name struct { 60 Country, Organization, OrganizationalUnit []string 61 Locality, Province []string 62 StreetAddress, PostalCode, DomainComponent []string 63 EmailAddress []string 64 SerialNumber, CommonName string 65 SerialNumbers, CommonNames []string 66 GivenName, Surname []string 67 OrganizationIDs []string 68 // EV Components 69 JurisdictionLocality, JurisdictionProvince, JurisdictionCountry []string 70 71 // Names contains all parsed attributes. When parsing distinguished names, 72 // this can be used to extract non-standard attributes that are not parsed 73 // by this package. When marshaling to RDNSequences, the Names field is 74 // ignored, see ExtraNames. 75 Names []AttributeTypeAndValue 76 77 // ExtraNames contains attributes to be copied, raw, into any marshaled 78 // distinguished names. Values override any attributes with the same OID. 79 // The ExtraNames field is not populated when parsing, see Names. 80 ExtraNames []AttributeTypeAndValue 81 // OriginalRDNS is saved if the name is populated using FillFromRDNSequence. 82 // Additionally, if OriginalRDNS is non-nil, the String and ToRDNSequence 83 // methods will simply use this. 84 OriginalRDNS RDNSequence 85 } 86 87 // FillFromRDNSequence populates n from the provided RDNSequence. 88 // Multi-entry RDNs are flattened, all entries are added to the 89 // relevant n fields, and the grouping is not preserved. 90 func (n *Name) FillFromRDNSequence(rdns *RDNSequence) { 91 n.OriginalRDNS = *rdns 92 for _, rdn := range *rdns { 93 if len(rdn) == 0 { 94 continue 95 } 96 97 for _, atv := range rdn { 98 n.Names = append(n.Names, atv) 99 value, ok := atv.Value.(string) 100 if !ok { 101 continue 102 } 103 104 t := atv.Type 105 if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 { 106 switch t[3] { 107 case 3: 108 n.CommonName = value 109 n.CommonNames = append(n.CommonNames, value) 110 case 4: 111 n.Surname = append(n.Surname, value) 112 case 5: 113 n.SerialNumber = value 114 n.SerialNumbers = append(n.SerialNumbers, value) 115 case 6: 116 n.Country = append(n.Country, value) 117 case 7: 118 n.Locality = append(n.Locality, value) 119 case 8: 120 n.Province = append(n.Province, value) 121 case 9: 122 n.StreetAddress = append(n.StreetAddress, value) 123 case 10: 124 n.Organization = append(n.Organization, value) 125 case 11: 126 n.OrganizationalUnit = append(n.OrganizationalUnit, value) 127 case 17: 128 n.PostalCode = append(n.PostalCode, value) 129 case 42: 130 n.GivenName = append(n.GivenName, value) 131 case 97: 132 n.OrganizationIDs = append(n.OrganizationIDs, value) 133 } 134 } else if t.Equal(oidDomainComponent) { 135 n.DomainComponent = append(n.DomainComponent, value) 136 } else if t.Equal(oidDNEmailAddress) { 137 // Deprecated, see RFC 5280 Section 4.1.2.6 138 n.EmailAddress = append(n.EmailAddress, value) 139 } else if t.Equal(oidJurisdictionLocality) { 140 n.JurisdictionLocality = append(n.JurisdictionLocality, value) 141 } else if t.Equal(oidJurisdictionProvince) { 142 n.JurisdictionProvince = append(n.JurisdictionProvince, value) 143 } else if t.Equal(oidJurisdictionCountry) { 144 n.JurisdictionCountry = append(n.JurisdictionCountry, value) 145 } 146 } 147 } 148 } 149 150 var ( 151 oidCountry = []int{2, 5, 4, 6} 152 oidOrganization = []int{2, 5, 4, 10} 153 oidOrganizationalUnit = []int{2, 5, 4, 11} 154 oidCommonName = []int{2, 5, 4, 3} 155 oidSurname = []int{2, 5, 4, 4} 156 oidSerialNumber = []int{2, 5, 4, 5} 157 oidLocality = []int{2, 5, 4, 7} 158 oidProvince = []int{2, 5, 4, 8} 159 oidStreetAddress = []int{2, 5, 4, 9} 160 oidPostalCode = []int{2, 5, 4, 17} 161 oidGivenName = []int{2, 5, 4, 42} 162 oidDomainComponent = []int{0, 9, 2342, 19200300, 100, 1, 25} 163 oidDNEmailAddress = []int{1, 2, 840, 113549, 1, 9, 1} 164 // EV 165 oidJurisdictionLocality = []int{1, 3, 6, 1, 4, 1, 311, 60, 2, 1, 1} 166 oidJurisdictionProvince = []int{1, 3, 6, 1, 4, 1, 311, 60, 2, 1, 2} 167 oidJurisdictionCountry = []int{1, 3, 6, 1, 4, 1, 311, 60, 2, 1, 3} 168 // QWACS 169 oidOrganizationID = []int{2, 5, 4, 97} 170 ) 171 172 // appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence 173 // and returns the new value. The relativeDistinguishedNameSET contains an 174 // attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and 175 // search for AttributeTypeAndValue. 176 func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence { 177 // NOTE: stdlib prevents adding if the oid is already present in n.ExtraNames 178 //if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) { 179 if len(values) == 0 { 180 return in 181 } 182 183 s := make([]AttributeTypeAndValue, len(values)) 184 for i, value := range values { 185 s[i].Type = oid 186 s[i].Value = value 187 } 188 189 return append(in, s) 190 } 191 192 // String returns a string representation of the sequence r, 193 // roughly following the RFC 2253 Distinguished Names syntax. 194 func (r RDNSequence) String() string { 195 s := "" 196 for i := 0; i < len(r); i++ { 197 idx := len(r) - 1 - i 198 if LegacyNameString { 199 idx = i 200 } 201 rdn := r[idx] 202 if i > 0 { 203 s += ", " 204 } 205 for j, tv := range rdn { 206 if j > 0 { 207 s += ", " 208 } 209 210 oidString := tv.Type.String() 211 var typeName string 212 if oidName, ok := oidDotNotationToNames[oidString]; ok { 213 typeName = oidName.ShortName 214 } 215 if typeName == "" { 216 derBytes, err := asn1.Marshal(tv.Value) 217 if err == nil { 218 s += oidString + "=#" + hex.EncodeToString(derBytes) 219 continue // No value escaping necessary. 220 } 221 222 typeName = oidString 223 } 224 225 valueString := fmt.Sprint(tv.Value) 226 escaped := make([]rune, 0, len(valueString)) 227 228 for k, c := range valueString { 229 escape := false 230 231 switch c { 232 case ',', '+', '"', '\\', '<', '>', ';': 233 escape = true 234 235 case ' ': 236 escape = k == 0 || k == len(valueString)-1 237 238 case '#': 239 escape = k == 0 240 } 241 242 if escape { 243 escaped = append(escaped, '\\', c) 244 } else { 245 escaped = append(escaped, c) 246 } 247 } 248 249 s += typeName + "=" + string(escaped) 250 } 251 } 252 253 return s 254 } 255 256 // ToRDNSequence converts n into a single RDNSequence. The following 257 // attributes are encoded as multi-value RDNs: 258 // 259 // - Country 260 // - Organization 261 // - OrganizationalUnit 262 // - Locality 263 // - Province 264 // - StreetAddress 265 // - PostalCode 266 // 267 // Each ExtraNames entry is encoded as an individual RDN. 268 func (n Name) ToRDNSequence() (ret RDNSequence) { 269 if n.OriginalRDNS != nil { 270 return n.OriginalRDNS 271 } 272 if len(n.CommonName) > 0 { 273 ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName) 274 } 275 ret = n.appendRDNs(ret, n.EmailAddress, oidDNEmailAddress) 276 ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit) 277 ret = n.appendRDNs(ret, n.Organization, oidOrganization) 278 ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress) 279 ret = n.appendRDNs(ret, n.Locality, oidLocality) 280 ret = n.appendRDNs(ret, n.Province, oidProvince) 281 ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode) 282 ret = n.appendRDNs(ret, n.Country, oidCountry) 283 ret = n.appendRDNs(ret, n.DomainComponent, oidDomainComponent) 284 // EV Components 285 ret = n.appendRDNs(ret, n.JurisdictionLocality, oidJurisdictionLocality) 286 ret = n.appendRDNs(ret, n.JurisdictionProvince, oidJurisdictionProvince) 287 ret = n.appendRDNs(ret, n.JurisdictionCountry, oidJurisdictionCountry) 288 // QWACS 289 ret = n.appendRDNs(ret, n.OrganizationIDs, oidOrganizationID) 290 if len(n.SerialNumber) > 0 { 291 ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber) 292 } 293 for _, atv := range n.ExtraNames { 294 ret = append(ret, []AttributeTypeAndValue{atv}) 295 } 296 297 return ret 298 } 299 300 // CertificateList represents the ASN.1 structure of the same name. See RFC 301 // 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the 302 // signature. 303 type CertificateList struct { 304 TBSCertList TBSCertificateList 305 SignatureAlgorithm AlgorithmIdentifier 306 SignatureValue asn1.BitString 307 } 308 309 // HasExpired reports whether certList should have been updated by now. 310 func (certList *CertificateList) HasExpired(now time.Time) bool { 311 return !now.Before(certList.TBSCertList.NextUpdate) 312 } 313 314 // String returns the string form of n, roughly following 315 // the RFC 2253 Distinguished Names syntax. 316 func (n Name) String() string { 317 var rdns RDNSequence 318 // If there are no ExtraNames, surface the parsed value (all entries in 319 // Names) instead. 320 if n.ExtraNames == nil { 321 for _, atv := range n.Names { 322 t := atv.Type 323 if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 { 324 switch t[3] { 325 case 3, 5, 6, 7, 8, 9, 10, 11, 17: 326 // These attributes were already parsed into named fields. 327 continue 328 } 329 } 330 // Place non-standard parsed values at the beginning of the sequence 331 // so they will be at the end of the string. See Issue 39924. 332 rdns = append(rdns, []AttributeTypeAndValue{atv}) 333 } 334 } 335 rdns = append(rdns, n.ToRDNSequence()...) 336 return rdns.String() 337 } 338 339 // OtherName represents the ASN.1 structure of the same name. See RFC 340 // 5280, section 4.2.1.6. 341 type OtherName struct { 342 TypeID asn1.ObjectIdentifier 343 Value asn1.RawValue `asn1:"explicit"` 344 } 345 346 // EDIPartyName represents the ASN.1 structure of the same name. See RFC 347 // 5280, section 4.2.1.6. 348 type EDIPartyName struct { 349 NameAssigner string `asn1:"tag:0,optional,explicit" json:"name_assigner,omitempty"` 350 PartyName string `asn1:"tag:1,explicit" json:"party_name"` 351 } 352 353 // TBSCertificateList represents the ASN.1 structure of the same name. See RFC 354 // 5280, section 5.1. 355 type TBSCertificateList struct { 356 Raw asn1.RawContent 357 Version int `asn1:"optional,default:0"` 358 Signature AlgorithmIdentifier 359 Issuer RDNSequence 360 ThisUpdate time.Time 361 NextUpdate time.Time `asn1:"optional"` 362 RevokedCertificates []RevokedCertificate `asn1:"optional"` 363 Extensions []Extension `asn1:"tag:0,optional,explicit"` 364 } 365 366 // RevokedCertificate represents the ASN.1 structure of the same name. See RFC 367 // 5280, section 5.1. 368 type RevokedCertificate struct { 369 SerialNumber *big.Int 370 RevocationTime time.Time 371 Extensions []Extension `asn1:"optional"` 372 }