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