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