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