1
2
3
4
5
6
7 package pkix
8
9 import (
10 "encoding/hex"
11 "fmt"
12 "math/big"
13 "time"
14
15 "github.com/google/certificate-transparency-go/asn1"
16 )
17
18
19
20 type AlgorithmIdentifier struct {
21 Algorithm asn1.ObjectIdentifier
22 Parameters asn1.RawValue `asn1:"optional"`
23 }
24
25 type RDNSequence []RelativeDistinguishedNameSET
26
27 var 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
40
41 func (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
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
96 type RelativeDistinguishedNameSET []AttributeTypeAndValue
97
98
99
100 type AttributeTypeAndValue struct {
101 Type asn1.ObjectIdentifier
102 Value interface{}
103 }
104
105
106
107 type AttributeTypeAndValueSET struct {
108 Type asn1.ObjectIdentifier
109 Value [][]AttributeTypeAndValue `asn1:"set"`
110 }
111
112
113
114 type Extension struct {
115 Id asn1.ObjectIdentifier
116 Critical bool `asn1:"optional"`
117 Value []byte
118 }
119
120
121
122
123
124 type 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
134 func (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
174 var (
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
197
198
199
200 func (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
214 func (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
236
237 func (n Name) String() string {
238 return n.ToRDNSequence().String()
239 }
240
241
242
243 func 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
253
254
255 type CertificateList struct {
256 TBSCertList TBSCertificateList
257 SignatureAlgorithm AlgorithmIdentifier
258 SignatureValue asn1.BitString
259 }
260
261
262 func (certList *CertificateList) HasExpired(now time.Time) bool {
263 return !now.Before(certList.TBSCertList.NextUpdate)
264 }
265
266
267
268 type 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
280
281
282 type RevokedCertificate struct {
283 SerialNumber *big.Int
284 RevocationTime time.Time
285 Extensions []Extension `asn1:"optional"`
286 }
287
View as plain text