1
2
3
4
5
6
7 package pkix
8
9 import (
10 "encoding/asn1"
11 "encoding/hex"
12 "fmt"
13 "math/big"
14 "strings"
15 "time"
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 var buf strings.Builder
43 for i := 0; i < len(r); i++ {
44 rdn := r[len(r)-1-i]
45 if i > 0 {
46 buf.WriteByte(',')
47 }
48 for j, tv := range rdn {
49 if j > 0 {
50 buf.WriteByte('+')
51 }
52
53 oidString := tv.Type.String()
54 typeName, ok := attributeTypeNames[oidString]
55 if !ok {
56
57
58
59 if _, ok := tv.Value.(string); !ok {
60 derBytes, err := asn1.Marshal(tv.Value)
61 if err == nil {
62 buf.WriteString(oidString)
63 buf.WriteString("=#")
64 buf.WriteString(hex.EncodeToString(derBytes))
65 continue
66 }
67 }
68
69 typeName = oidString
70 }
71
72 valueString := fmt.Sprint(tv.Value)
73 escaped := make([]rune, 0, len(valueString))
74
75 for k, c := range valueString {
76 escape := false
77
78 switch c {
79 case ',', '+', '"', '\\', '<', '>', ';':
80 escape = true
81
82 case ' ':
83 escape = k == 0 || k == len(valueString)-1
84
85 case '#':
86 escape = k == 0
87 }
88
89 if escape {
90 escaped = append(escaped, '\\', c)
91 } else {
92 escaped = append(escaped, c)
93 }
94 }
95
96 buf.WriteString(typeName)
97 buf.WriteByte('=')
98 buf.WriteString(string(escaped))
99 }
100 }
101
102 return buf.String()
103 }
104
105 type RelativeDistinguishedNameSET []AttributeTypeAndValue
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 type AttributeTypeAndValue struct {
124 Type asn1.ObjectIdentifier
125 Value any
126 }
127
128
129
130 type AttributeTypeAndValueSET struct {
131 Type asn1.ObjectIdentifier
132 Value [][]AttributeTypeAndValue `asn1:"set"`
133 }
134
135
136
137 type Extension struct {
138 Id asn1.ObjectIdentifier
139 Critical bool `asn1:"optional"`
140 Value []byte
141 }
142
143
144
145
146
147 type Name struct {
148 Country, Organization, OrganizationalUnit []string
149 Locality, Province []string
150 StreetAddress, PostalCode []string
151 SerialNumber, CommonName string
152
153
154
155
156
157 Names []AttributeTypeAndValue
158
159
160
161
162 ExtraNames []AttributeTypeAndValue
163 }
164
165
166
167
168 func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
169 for _, rdn := range *rdns {
170 if len(rdn) == 0 {
171 continue
172 }
173
174 for _, atv := range rdn {
175 n.Names = append(n.Names, atv)
176 value, ok := atv.Value.(string)
177 if !ok {
178 continue
179 }
180
181 t := atv.Type
182 if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
183 switch t[3] {
184 case 3:
185 n.CommonName = value
186 case 5:
187 n.SerialNumber = value
188 case 6:
189 n.Country = append(n.Country, value)
190 case 7:
191 n.Locality = append(n.Locality, value)
192 case 8:
193 n.Province = append(n.Province, value)
194 case 9:
195 n.StreetAddress = append(n.StreetAddress, value)
196 case 10:
197 n.Organization = append(n.Organization, value)
198 case 11:
199 n.OrganizationalUnit = append(n.OrganizationalUnit, value)
200 case 17:
201 n.PostalCode = append(n.PostalCode, value)
202 }
203 }
204 }
205 }
206 }
207
208 var (
209 oidCountry = []int{2, 5, 4, 6}
210 oidOrganization = []int{2, 5, 4, 10}
211 oidOrganizationalUnit = []int{2, 5, 4, 11}
212 oidCommonName = []int{2, 5, 4, 3}
213 oidSerialNumber = []int{2, 5, 4, 5}
214 oidLocality = []int{2, 5, 4, 7}
215 oidProvince = []int{2, 5, 4, 8}
216 oidStreetAddress = []int{2, 5, 4, 9}
217 oidPostalCode = []int{2, 5, 4, 17}
218 )
219
220
221
222
223
224 func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
225 if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) {
226 return in
227 }
228
229 s := make([]AttributeTypeAndValue, len(values))
230 for i, value := range values {
231 s[i].Type = oid
232 s[i].Value = value
233 }
234
235 return append(in, s)
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249
250 func (n Name) ToRDNSequence() (ret RDNSequence) {
251 ret = n.appendRDNs(ret, n.Country, oidCountry)
252 ret = n.appendRDNs(ret, n.Province, oidProvince)
253 ret = n.appendRDNs(ret, n.Locality, oidLocality)
254 ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress)
255 ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode)
256 ret = n.appendRDNs(ret, n.Organization, oidOrganization)
257 ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
258 if len(n.CommonName) > 0 {
259 ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName)
260 }
261 if len(n.SerialNumber) > 0 {
262 ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
263 }
264 for _, atv := range n.ExtraNames {
265 ret = append(ret, []AttributeTypeAndValue{atv})
266 }
267
268 return ret
269 }
270
271
272
273 func (n Name) String() string {
274 var rdns RDNSequence
275
276
277 if n.ExtraNames == nil {
278 for _, atv := range n.Names {
279 t := atv.Type
280 if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
281 switch t[3] {
282 case 3, 5, 6, 7, 8, 9, 10, 11, 17:
283
284 continue
285 }
286 }
287
288
289 rdns = append(rdns, []AttributeTypeAndValue{atv})
290 }
291 }
292 rdns = append(rdns, n.ToRDNSequence()...)
293 return rdns.String()
294 }
295
296
297
298 func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool {
299 for _, a := range atv {
300 if a.Type.Equal(oid) {
301 return true
302 }
303 }
304 return false
305 }
306
307
308
309
310
311
312 type CertificateList struct {
313 TBSCertList TBSCertificateList
314 SignatureAlgorithm AlgorithmIdentifier
315 SignatureValue asn1.BitString
316 }
317
318
319 func (certList *CertificateList) HasExpired(now time.Time) bool {
320 return !now.Before(certList.TBSCertList.NextUpdate)
321 }
322
323
324
325
326
327 type TBSCertificateList struct {
328 Raw asn1.RawContent
329 Version int `asn1:"optional,default:0"`
330 Signature AlgorithmIdentifier
331 Issuer RDNSequence
332 ThisUpdate time.Time
333 NextUpdate time.Time `asn1:"optional"`
334 RevokedCertificates []RevokedCertificate `asn1:"optional"`
335 Extensions []Extension `asn1:"tag:0,optional,explicit"`
336 }
337
338
339
340 type RevokedCertificate struct {
341 SerialNumber *big.Int
342 RevocationTime time.Time
343 Extensions []Extension `asn1:"optional"`
344 }
345
View as plain text