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. 7package pkix 8 9import ( 10 "encoding/hex" 11 "fmt" 12 "math/big" 13 "time" 14 15 "github.com/google/certificate-transparency-go/asn1" 16) 17 18// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC 19// 5280, section 4.1.1.2. 20type AlgorithmIdentifier struct { 21 Algorithm asn1.ObjectIdentifier 22 Parameters asn1.RawValue `asn1:"optional"` 23} 24 25type RDNSequence []RelativeDistinguishedNameSET 26 27var attributeTypeNames = map[string]string{ 28 "2.5.4.6": "C", 29 "2.5.4.10": "O", 30 "2.5.4.11": "OU", 31 "2.5.4.3": "CN", 32 "2.5.4.5": "SERIALNUMBER", 33 "2.5.4.7": "L", 34 "2.5.4.8": "ST", 35 "2.5.4.9": "STREET", 36 "2.5.4.17": "POSTALCODE", 37} 38 39// String returns a string representation of the sequence r, 40// roughly following the RFC 2253 Distinguished Names syntax. 41func (r RDNSequence) String() string { 42 s := "" 43 for i := 0; i < len(r); i++ { 44 rdn := r[len(r)-1-i] 45 if i > 0 { 46 s += "," 47 } 48 for j, tv := range rdn { 49 if j > 0 { 50 s += "+" 51 } 52 53 oidString := tv.Type.String() 54 typeName, ok := attributeTypeNames[oidString] 55 if !ok { 56 derBytes, err := asn1.Marshal(tv.Value) 57 if err == nil { 58 s += oidString + "=#" + hex.EncodeToString(derBytes) 59 continue // No value escaping necessary. 60 } 61 62 typeName = oidString 63 } 64 65 valueString := fmt.Sprint(tv.Value) 66 escaped := make([]rune, 0, len(valueString)) 67 68 for k, c := range valueString { 69 escape := false 70 71 switch c { 72 case ',', '+', '"', '\\', '<', '>', ';': 73 escape = true 74 75 case ' ': 76 escape = k == 0 || k == len(valueString)-1 77 78 case '#': 79 escape = k == 0 80 } 81 82 if escape { 83 escaped = append(escaped, '\\', c) 84 } else { 85 escaped = append(escaped, c) 86 } 87 } 88 89 s += typeName + "=" + string(escaped) 90 } 91 } 92 93 return s 94} 95 96type RelativeDistinguishedNameSET []AttributeTypeAndValue 97 98// AttributeTypeAndValue mirrors the ASN.1 structure of the same name in 99// RFC 5280, Section 4.1.2.4. 100type AttributeTypeAndValue struct { 101 Type asn1.ObjectIdentifier 102 Value interface{} 103} 104 105// AttributeTypeAndValueSET represents a set of ASN.1 sequences of 106// AttributeTypeAndValue sequences from RFC 2986 (PKCS #10). 107type AttributeTypeAndValueSET struct { 108 Type asn1.ObjectIdentifier 109 Value [][]AttributeTypeAndValue `asn1:"set"` 110} 111 112// Extension represents the ASN.1 structure of the same name. See RFC 113// 5280, section 4.2. 114type Extension struct { 115 Id asn1.ObjectIdentifier 116 Critical bool `asn1:"optional"` 117 Value []byte 118} 119 120// Name represents an X.509 distinguished name. This only includes the common 121// elements of a DN. When parsing, all elements are stored in Names and 122// non-standard elements can be extracted from there. When marshaling, elements 123// in ExtraNames are appended and override other values with the same OID. 124type Name struct { 125 Country, Organization, OrganizationalUnit []string 126 Locality, Province []string 127 StreetAddress, PostalCode []string 128 SerialNumber, CommonName string 129 130 Names []AttributeTypeAndValue 131 ExtraNames []AttributeTypeAndValue 132} 133 134func (n *Name) FillFromRDNSequence(rdns *RDNSequence) { 135 for _, rdn := range *rdns { 136 if len(rdn) == 0 { 137 continue 138 } 139 140 for _, atv := range rdn { 141 n.Names = append(n.Names, atv) 142 value, ok := atv.Value.(string) 143 if !ok { 144 continue 145 } 146 147 t := atv.Type 148 if len(t) == 4 && t[0] == OIDAttribute[0] && t[1] == OIDAttribute[1] && t[2] == OIDAttribute[2] { 149 switch t[3] { 150 case OIDCommonName[3]: 151 n.CommonName = value 152 case OIDSerialNumber[3]: 153 n.SerialNumber = value 154 case OIDCountry[3]: 155 n.Country = append(n.Country, value) 156 case OIDLocality[3]: 157 n.Locality = append(n.Locality, value) 158 case OIDProvince[3]: 159 n.Province = append(n.Province, value) 160 case OIDStreetAddress[3]: 161 n.StreetAddress = append(n.StreetAddress, value) 162 case OIDOrganization[3]: 163 n.Organization = append(n.Organization, value) 164 case OIDOrganizationalUnit[3]: 165 n.OrganizationalUnit = append(n.OrganizationalUnit, value) 166 case OIDPostalCode[3]: 167 n.PostalCode = append(n.PostalCode, value) 168 } 169 } 170 } 171 } 172} 173 174var ( 175 OIDAttribute = asn1.ObjectIdentifier{2, 5, 4} 176 OIDCountry = asn1.ObjectIdentifier{2, 5, 4, 6} 177 OIDOrganization = asn1.ObjectIdentifier{2, 5, 4, 10} 178 OIDOrganizationalUnit = asn1.ObjectIdentifier{2, 5, 4, 11} 179 OIDCommonName = asn1.ObjectIdentifier{2, 5, 4, 3} 180 OIDSerialNumber = asn1.ObjectIdentifier{2, 5, 4, 5} 181 OIDLocality = asn1.ObjectIdentifier{2, 5, 4, 7} 182 OIDProvince = asn1.ObjectIdentifier{2, 5, 4, 8} 183 OIDStreetAddress = asn1.ObjectIdentifier{2, 5, 4, 9} 184 OIDPostalCode = asn1.ObjectIdentifier{2, 5, 4, 17} 185 186 OIDPseudonym = asn1.ObjectIdentifier{2, 5, 4, 65} 187 OIDTitle = asn1.ObjectIdentifier{2, 5, 4, 12} 188 OIDDnQualifier = asn1.ObjectIdentifier{2, 5, 4, 46} 189 OIDName = asn1.ObjectIdentifier{2, 5, 4, 41} 190 OIDSurname = asn1.ObjectIdentifier{2, 5, 4, 4} 191 OIDGivenName = asn1.ObjectIdentifier{2, 5, 4, 42} 192 OIDInitials = asn1.ObjectIdentifier{2, 5, 4, 43} 193 OIDGenerationQualifier = asn1.ObjectIdentifier{2, 5, 4, 44} 194) 195 196// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence 197// and returns the new value. The relativeDistinguishedNameSET contains an 198// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and 199// search for AttributeTypeAndValue. 200func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence { 201 if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) { 202 return in 203 } 204 205 s := make([]AttributeTypeAndValue, len(values)) 206 for i, value := range values { 207 s[i].Type = oid 208 s[i].Value = value 209 } 210 211 return append(in, s) 212} 213 214func (n Name) ToRDNSequence() (ret RDNSequence) { 215 ret = n.appendRDNs(ret, n.Country, OIDCountry) 216 ret = n.appendRDNs(ret, n.Province, OIDProvince) 217 ret = n.appendRDNs(ret, n.Locality, OIDLocality) 218 ret = n.appendRDNs(ret, n.StreetAddress, OIDStreetAddress) 219 ret = n.appendRDNs(ret, n.PostalCode, OIDPostalCode) 220 ret = n.appendRDNs(ret, n.Organization, OIDOrganization) 221 ret = n.appendRDNs(ret, n.OrganizationalUnit, OIDOrganizationalUnit) 222 if len(n.CommonName) > 0 { 223 ret = n.appendRDNs(ret, []string{n.CommonName}, OIDCommonName) 224 } 225 if len(n.SerialNumber) > 0 { 226 ret = n.appendRDNs(ret, []string{n.SerialNumber}, OIDSerialNumber) 227 } 228 for _, atv := range n.ExtraNames { 229 ret = append(ret, []AttributeTypeAndValue{atv}) 230 } 231 232 return ret 233} 234 235// String returns the string form of n, roughly following 236// the RFC 2253 Distinguished Names syntax. 237func (n Name) String() string { 238 return n.ToRDNSequence().String() 239} 240 241// oidInAttributeTypeAndValue reports whether a type with the given OID exists 242// in atv. 243func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool { 244 for _, a := range atv { 245 if a.Type.Equal(oid) { 246 return true 247 } 248 } 249 return false 250} 251 252// CertificateList represents the ASN.1 structure of the same name. See RFC 253// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the 254// signature. 255type CertificateList struct { 256 TBSCertList TBSCertificateList 257 SignatureAlgorithm AlgorithmIdentifier 258 SignatureValue asn1.BitString 259} 260 261// HasExpired reports whether certList should have been updated by now. 262func (certList *CertificateList) HasExpired(now time.Time) bool { 263 return !now.Before(certList.TBSCertList.NextUpdate) 264} 265 266// TBSCertificateList represents the ASN.1 structure TBSCertList. See RFC 267// 5280, section 5.1. 268type TBSCertificateList struct { 269 Raw asn1.RawContent 270 Version int `asn1:"optional,default:0"` 271 Signature AlgorithmIdentifier 272 Issuer RDNSequence 273 ThisUpdate time.Time 274 NextUpdate time.Time `asn1:"optional"` 275 RevokedCertificates []RevokedCertificate `asn1:"optional"` 276 Extensions []Extension `asn1:"tag:0,optional,explicit"` 277} 278 279// RevokedCertificate represents the unnamed ASN.1 structure that makes up the 280// revokedCertificates member of the TBSCertList structure. See RFC 281// 5280, section 5.1. 282type RevokedCertificate struct { 283 SerialNumber *big.Int 284 RevocationTime time.Time 285 Extensions []Extension `asn1:"optional"` 286} 287