Source file
src/crypto/x509/parser_test.go
1
2
3
4
5 package x509
6
7 import (
8 "crypto/ecdsa"
9 "crypto/elliptic"
10 "crypto/rand"
11 "encoding/asn1"
12 "encoding/pem"
13 "os"
14 "strings"
15 "testing"
16
17 cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
18 )
19
20 func TestParseASN1String(t *testing.T) {
21 tests := []struct {
22 name string
23 tag cryptobyte_asn1.Tag
24 value []byte
25 expected string
26 expectedErr string
27 }{
28 {
29 name: "T61String",
30 tag: cryptobyte_asn1.T61String,
31 value: []byte{0xbf, 0x61, 0x3f},
32 expected: string("¿a?"),
33 },
34 {
35 name: "PrintableString",
36 tag: cryptobyte_asn1.PrintableString,
37 value: []byte{80, 81, 82},
38 expected: string("PQR"),
39 },
40 {
41 name: "PrintableString (invalid)",
42 tag: cryptobyte_asn1.PrintableString,
43 value: []byte{1, 2, 3},
44 expectedErr: "invalid PrintableString",
45 },
46 {
47 name: "UTF8String",
48 tag: cryptobyte_asn1.UTF8String,
49 value: []byte{80, 81, 82},
50 expected: string("PQR"),
51 },
52 {
53 name: "UTF8String (invalid)",
54 tag: cryptobyte_asn1.UTF8String,
55 value: []byte{255},
56 expectedErr: "invalid UTF-8 string",
57 },
58 {
59 name: "BMPString",
60 tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
61 value: []byte{80, 81},
62 expected: string("偑"),
63 },
64 {
65 name: "BMPString (invalid length)",
66 tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
67 value: []byte{255},
68 expectedErr: "invalid BMPString",
69 },
70 {
71 name: "BMPString (invalid surrogate)",
72 tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
73 value: []byte{80, 81, 216, 1},
74 expectedErr: "invalid BMPString",
75 },
76 {
77 name: "BMPString (invalid noncharacter 0xfdd1)",
78 tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
79 value: []byte{80, 81, 253, 209},
80 expectedErr: "invalid BMPString",
81 },
82 {
83 name: "BMPString (invalid noncharacter 0xffff)",
84 tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
85 value: []byte{80, 81, 255, 255},
86 expectedErr: "invalid BMPString",
87 },
88 {
89 name: "BMPString (invalid noncharacter 0xfffe)",
90 tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
91 value: []byte{80, 81, 255, 254},
92 expectedErr: "invalid BMPString",
93 },
94 {
95 name: "IA5String",
96 tag: cryptobyte_asn1.IA5String,
97 value: []byte{80, 81},
98 expected: string("PQ"),
99 },
100 {
101 name: "IA5String (invalid)",
102 tag: cryptobyte_asn1.IA5String,
103 value: []byte{255},
104 expectedErr: "invalid IA5String",
105 },
106 {
107 name: "NumericString",
108 tag: cryptobyte_asn1.Tag(asn1.TagNumericString),
109 value: []byte{49, 50},
110 expected: string("12"),
111 },
112 {
113 name: "NumericString (invalid)",
114 tag: cryptobyte_asn1.Tag(asn1.TagNumericString),
115 value: []byte{80},
116 expectedErr: "invalid NumericString",
117 },
118 }
119
120 for _, tc := range tests {
121 t.Run(tc.name, func(t *testing.T) {
122 out, err := parseASN1String(tc.tag, tc.value)
123 if err != nil && err.Error() != tc.expectedErr {
124 t.Fatalf("parseASN1String returned unexpected error: got %q, want %q", err, tc.expectedErr)
125 } else if err == nil && tc.expectedErr != "" {
126 t.Fatalf("parseASN1String didn't fail, expected: %s", tc.expectedErr)
127 }
128 if out != tc.expected {
129 t.Fatalf("parseASN1String returned unexpected value: got %q, want %q", out, tc.expected)
130 }
131 })
132 }
133 }
134
135 const policyPEM = `-----BEGIN CERTIFICATE-----
136 MIIGeDCCBWCgAwIBAgIUED9KQBi0ScBDoufB2mgAJ63G5uIwDQYJKoZIhvcNAQEL
137 BQAwVTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsG
138 A1UECxMERlBLSTEdMBsGA1UEAxMURmVkZXJhbCBCcmlkZ2UgQ0EgRzQwHhcNMjAx
139 MDIyMTcwNDE5WhcNMjMxMDIyMTcwNDE5WjCBgTELMAkGA1UEBhMCVVMxHTAbBgNV
140 BAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1hbnRlYyBUcnVz
141 dCBOZXR3b3JrMTIwMAYDVQQDEylTeW1hbnRlYyBDbGFzcyAzIFNTUCBJbnRlcm1l
142 ZGlhdGUgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2p
143 75cMpx86sS2aH4r+0o8r+m/KTrPrknWP0RA9Kp6sewAzkNa7BVwg0jOhyamiv1iP
144 Cns10usoH93nxYbXLWF54vOLRdYU/53KEPNmgkj2ipMaTLuaReBghNibikWSnAmy
145 S8RItaDMs8tdF2goKPI4xWiamNwqe92VC+pic2tq0Nva3Y4kvMDJjtyje3uduTtL
146 oyoaaHkrX7i7gE67psnMKj1THUtre1JV1ohl9+oOuyot4p3eSxVlrMWiiwb11bnk
147 CakecOz/mP2DHMGg6pZ/BeJ+ThaLUylAXECARIqHc9UwRPKC9BfLaCX4edIoeYiB
148 loRs4KdqLdg/I9eTwKkCAwEAAaOCAxEwggMNMB0GA1UdDgQWBBQ1Jn1QleGhwb0F
149 1cOdd0LHDBOWjDAfBgNVHSMEGDAWgBR58ABJ6393wl1BAmU0ipAjmx4HbzAOBgNV
150 HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCBiAYDVR0gBIGAMH4wDAYKYIZI
151 AWUDAgEDAzAMBgpghkgBZQMCAQMMMAwGCmCGSAFlAwIBAw4wDAYKYIZIAWUDAgED
152 DzAMBgpghkgBZQMCAQMSMAwGCmCGSAFlAwIBAxMwDAYKYIZIAWUDAgEDFDAMBgpg
153 hkgBZQMCAQMlMAwGCmCGSAFlAwIBAyYwggESBgNVHSEEggEJMIIBBTAbBgpghkgB
154 ZQMCAQMDBg1ghkgBhvhFAQcXAwEGMBsGCmCGSAFlAwIBAwwGDWCGSAGG+EUBBxcD
155 AQcwGwYKYIZIAWUDAgEDDgYNYIZIAYb4RQEHFwMBDjAbBgpghkgBZQMCAQMPBg1g
156 hkgBhvhFAQcXAwEPMBsGCmCGSAFlAwIBAxIGDWCGSAGG+EUBBxcDARIwGwYKYIZI
157 AWUDAgEDEwYNYIZIAYb4RQEHFwMBETAbBgpghkgBZQMCAQMUBg1ghkgBhvhFAQcX
158 AwEUMBsGCmCGSAFlAwIBAyUGDWCGSAGG+EUBBxcDAQgwGwYKYIZIAWUDAgEDJgYN
159 YIZIAYb4RQEHFwMBJDBgBggrBgEFBQcBCwRUMFIwUAYIKwYBBQUHMAWGRGh0dHA6
160 Ly9zc3Atc2lhLnN5bWF1dGguY29tL1NUTlNTUC9DZXJ0c19Jc3N1ZWRfYnlfQ2xh
161 c3MzU1NQQ0EtRzMucDdjMA8GA1UdJAQIMAaAAQCBAQAwCgYDVR02BAMCAQAwUQYI
162 KwYBBQUHAQEERTBDMEEGCCsGAQUFBzAChjVodHRwOi8vcmVwby5mcGtpLmdvdi9i
163 cmlkZ2UvY2FDZXJ0c0lzc3VlZFRvZmJjYWc0LnA3YzA3BgNVHR8EMDAuMCygKqAo
164 hiZodHRwOi8vcmVwby5mcGtpLmdvdi9icmlkZ2UvZmJjYWc0LmNybDANBgkqhkiG
165 9w0BAQsFAAOCAQEAA751TycC1f/WTkHmedF9ZWxP58Jstmwvkyo8bKueJ0eF7LTG
166 BgQlzE2B9vke4sFhd4V+BdgOPGE1dsGzllYKCWg0BhkCBs5kIJ7F6Ay6G1TBuGU1
167 Ie8247GL+P9pcC5TVvXHC/62R2w3DuD/vAPLbYEbSQjobXlsqt8Kmtd6yK/jVuDV
168 BTZMdZmvoNtjemqmgcBXHsf0ctVm0m6tH5uYqyVxu8tfyUis6Cf303PHj+spWP1k
169 gc5PYnVF0ot7qAmNFENIpbKg3BdusBkF9rGxLaDSUBvSc7+s9iQz9d/iRuAebrYu
170 +eqUlJ2lsjS1U8qyPmlH+spfPNbAEQEsuP32Aw==
171 -----END CERTIFICATE-----
172 `
173
174 func TestPolicyParse(t *testing.T) {
175 b, _ := pem.Decode([]byte(policyPEM))
176 c, err := ParseCertificate(b.Bytes)
177 if err != nil {
178 t.Fatal(err)
179 }
180 if len(c.Policies) != 9 {
181 t.Errorf("unexpected number of policies: got %d, want %d", len(c.Policies), 9)
182 }
183 if len(c.PolicyMappings) != 9 {
184 t.Errorf("unexpected number of policy mappings: got %d, want %d", len(c.PolicyMappings), 9)
185 }
186 if !c.RequireExplicitPolicyZero {
187 t.Error("expected RequireExplicitPolicyZero to be set")
188 }
189 if !c.InhibitPolicyMappingZero {
190 t.Error("expected InhibitPolicyMappingZero to be set")
191 }
192 if !c.InhibitAnyPolicyZero {
193 t.Error("expected InhibitAnyPolicyZero to be set")
194 }
195 }
196
197 func TestParsePolicies(t *testing.T) {
198 for _, tc := range []string{
199 "testdata/policy_leaf_duplicate.pem",
200 "testdata/policy_leaf_invalid.pem",
201 } {
202 t.Run(tc, func(t *testing.T) {
203 b, err := os.ReadFile(tc)
204 if err != nil {
205 t.Fatal(err)
206 }
207 p, _ := pem.Decode(b)
208 _, err = ParseCertificate(p.Bytes)
209 if err == nil {
210 t.Error("parsing should've failed")
211 }
212 })
213 }
214 }
215
216 func TestParseCertificateNegativeMaxPathLength(t *testing.T) {
217 certs := []string{
218
219 `
220 -----BEGIN CERTIFICATE-----
221 MIIByTCCATKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDEwRURVNU
222 MB4XDTcwMDEwMTAwMTY0MFoXDTcwMDEwMjAzNDY0MFowDzENMAsGA1UEAxMEVEVT
223 VDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsaHglFuSicTT8TKfipgsSi3N
224 Wb/TcvuAhanFF1VGB+vS95kO7yFqyfRgX3GgOwT0KlJVsVjPjghEGR9RGTSLqkTD
225 UFbiBgm8+VEPMOrUtIHIHXhl+ye44AkOEStxfz7gjN/EAS2h8ffPKhvDTHOlShKw
226 Y3LQlxR0LdeJXq3eSqUCAwEAAaM1MDMwEgYDVR0TAQH/BAgwBgEB/wIB/zAdBgNV
227 HQ4EFgQUrbrk0tqQAEsce8uYifP0BIVhuFAwDQYJKoZIhvcNAQELBQADgYEAIkhV
228 ZBj1ThT+eyh50XsoU570NUysTg3Nj/3lbkEolzdcE+wu0CPXvgxLRM6Y62u1ey82
229 8d5VQHstzF4dXgc3W+O9UySa+CKdcHx/q7o7seOGXdysT0IJtAY3w66mFkuF7PIn
230 y9b7M5t6pmWjb7N0QqGuWeNqi4ZvS8gLKmVEgGY=
231 -----END CERTIFICATE-----
232 `,
233
234 `
235 -----BEGIN CERTIFICATE-----
236 MIIByTCCATKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDEwRURVNU
237 MB4XDTcwMDEwMTAwMTY0MFoXDTcwMDEwMjAzNDY0MFowDzENMAsGA1UEAxMEVEVT
238 VDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsaHglFuSicTT8TKfipgsSi3N
239 Wb/TcvuAhanFF1VGB+vS95kO7yFqyfRgX3GgOwT0KlJVsVjPjghEGR9RGTSLqkTD
240 UFbiBgm8+VEPMOrUtIHIHXhl+ye44AkOEStxfz7gjN/EAS2h8ffPKhvDTHOlShKw
241 Y3LQlxR0LdeJXq3eSqUCAwEAAaM1MDMwEgYDVR0TAQH/BAgwBgEB/wIB/jAdBgNV
242 HQ4EFgQUrbrk0tqQAEsce8uYifP0BIVhuFAwDQYJKoZIhvcNAQELBQADgYEAGjIr
243 YGQc7Ods+BuKck7p+vpAMONM8SLEuUtKorCP3ecsO51MoA4/niLbgMHaOGNHwzMp
244 ajg0zLbY0Dj6Ml0VZ+lS3rjgTEhYXc626eZkoQqgUzL1jhe3S0ZbSxxmHMBKjJFl
245 d5l1tRhScKu2NBgm74nYmJxJYgvuTA38wGhRrGU=
246 -----END CERTIFICATE-----
247 `,
248 }
249
250 for _, cert := range certs {
251 b, _ := pem.Decode([]byte(cert))
252 _, err := ParseCertificate(b.Bytes)
253 if err == nil || err.Error() != "x509: invalid basic constraints" {
254 t.Errorf(`ParseCertificate() = %v; want = "x509: invalid basic constraints"`, err)
255 }
256 }
257 }
258
259 func TestDomainNameValid(t *testing.T) {
260 for _, tc := range []struct {
261 name string
262 dnsName string
263 constraint bool
264 valid bool
265 }{
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 {"254 char label, name", strings.Repeat("a.a", 84) + "aaa", false, true},
282 {"254 char label, constraint", strings.Repeat("a.a", 84) + "aaa", true, true},
283 {"253 char label, name", strings.Repeat("a.a", 84) + "aa", false, true},
284 {"253 char label, constraint", strings.Repeat("a.a", 84) + "aa", true, true},
285 {"64 char single label, name", strings.Repeat("a", 64), false, true},
286 {"64 char single label, constraint", strings.Repeat("a", 64), true, true},
287 {"64 char label, name", "a." + strings.Repeat("a", 64), false, true},
288 {"64 char label, constraint", "a." + strings.Repeat("a", 64), true, true},
289
290
291 {"empty name, constraint", "", true, true},
292 {"empty label, name", "a..a", false, false},
293 {"empty label, constraint", "a..a", true, false},
294 {"period, name", ".", false, false},
295 {"period, constraint", ".", true, false},
296 {"valid, name", "a.b.c", false, true},
297 {"valid, constraint", "a.b.c", true, true},
298 {"leading period, name", ".a.b.c", false, false},
299 {"leading period, constraint", ".a.b.c", true, true},
300 {"trailing period, name", "a.", false, false},
301 {"trailing period, constraint", "a.", true, false},
302 {"bare label, name", "a", false, true},
303 {"bare label, constraint", "a", true, true},
304 {"63 char single label, name", strings.Repeat("a", 63), false, true},
305 {"63 char single label, constraint", strings.Repeat("a", 63), true, true},
306 {"63 char label, name", "a." + strings.Repeat("a", 63), false, true},
307 {"63 char label, constraint", "a." + strings.Repeat("a", 63), true, true},
308 } {
309 t.Run(tc.name, func(t *testing.T) {
310 valid := domainNameValid(tc.dnsName, tc.constraint)
311 if tc.valid != valid {
312 t.Errorf("domainNameValid(%q, %t) = %v; want %v", tc.dnsName, tc.constraint, !tc.valid, tc.valid)
313 }
314
315 trimmedName := tc.dnsName
316 if tc.constraint && len(trimmedName) > 1 && trimmedName[0] == '.' {
317 trimmedName = trimmedName[1:]
318 }
319 _, revValid := domainToReverseLabels(trimmedName)
320 if valid != revValid {
321 t.Errorf("domainNameValid(%q, %t) = %t != domainToReverseLabels(%q) = %t", tc.dnsName, tc.constraint, valid, trimmedName, revValid)
322 }
323 })
324 }
325 }
326
327 func TestRoundtripWeirdSANs(t *testing.T) {
328
329
330
331 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
332 if err != nil {
333 t.Fatal(err)
334 }
335 badNames := []string{
336 "baredomain",
337 "baredomain.",
338 strings.Repeat("a", 255),
339 strings.Repeat("a", 65) + ".com",
340 }
341 tmpl := &Certificate{
342 EmailAddresses: badNames,
343 DNSNames: badNames,
344 }
345 b, err := CreateCertificate(rand.Reader, tmpl, tmpl, &k.PublicKey, k)
346 if err != nil {
347 t.Fatal(err)
348 }
349 _, err = ParseCertificate(b)
350 if err != nil {
351 t.Fatalf("Couldn't roundtrip certificate: %v", err)
352 }
353 }
354
355 func FuzzDomainNameValid(f *testing.F) {
356 f.Fuzz(func(t *testing.T, data string) {
357 domainNameValid(data, false)
358 domainNameValid(data, true)
359 })
360 }
361
View as plain text