-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil_test.go
332 lines (312 loc) · 12.1 KB
/
util_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
package main
import (
"bytes"
"encoding/base64"
"encoding/pem"
"errors"
"net/http"
"net/http/httptest"
"testing"
)
func decodeBase64(b64 string) []byte {
bs, err := base64.StdEncoding.DecodeString(b64)
if err != nil {
panic("cannot decode DER encoded CRL: " + err.Error())
}
return bs
}
func unsafePEMToDER(pemCRL string) []byte {
block, _ := pem.Decode([]byte(pemCRL))
if block == nil || block.Type != "X509 CRL" {
panic("invalid test PEM CRL data")
}
return block.Bytes
}
var derCRL = decodeBase64(`MIIB6DCB0QIBATANBgkqhkiG9w0BAQsFADB4MQswCQYDVQQGEwJDSDEPMA0GA1UECBMGR2VuZXZhMRgwFgYDVQQHEw9QbGFuLWxlcy1PdWF0ZXMxHTAbBgNVBAoTFGUtWHBlcnQgU29sdXRpb25zIFNBMQswCQYDVQQLEwJJVDESMBAGA1UEAxMJbG9jYWxob3N0Fw0xNzA5MDQxMjA0MTBaFw0yMzAyMjUxMjA0MTBaMACgIzAhMB8GA1UdIwQYMBaAFLvZTBeieT0TR5i4fLXtXS3b0X3eMA0GCSqGSIb3DQEBCwUAA4IBAQAWOV/I6CbhIFL7JTeOqp1sl/uHWhKtLBQ2NShUh2/3spdKbM0wl2yG0DFuRoBpmOx5xqD58XWZh0FuP3IeTSRpXj7Kz79RKho17P5cFKVkhYO1EfO8eiS/DfSf2XKEEPCyRiGfIbwbi8QDXBZSKowqH91nBlUO+bGpk93Bd/PpdKz8lwA4NGN4dJG4ntMcQb8zshbI3Hg7YeVll1MKVKxuM6juH/i7MXIWjKUK3XzABIyjDjJzPBPbTvOjan9whYP3w4ggGuQa/c9dOad5LWhOGf8MucoF5tub7gCOv3GFr/IYfYAIuj9S9v8As1Om/MUPYyZ1hvcXBKIfbxsEW7jZ`)
var pemCRL = []byte(`-----BEGIN X509 CRL-----
MIIB6DCB0QIBATANBgkqhkiG9w0BAQsFADB4MQswCQYDVQQGEwJDSDEPMA0GA1UE
CBMGR2VuZXZhMRgwFgYDVQQHEw9QbGFuLWxlcy1PdWF0ZXMxHTAbBgNVBAoTFGUt
WHBlcnQgU29sdXRpb25zIFNBMQswCQYDVQQLEwJJVDESMBAGA1UEAxMJbG9jYWxo
b3N0Fw0xNzA5MDQxMjA0MTBaFw0yMzAyMjUxMjA0MTBaMACgIzAhMB8GA1UdIwQY
MBaAFLvZTBeieT0TR5i4fLXtXS3b0X3eMA0GCSqGSIb3DQEBCwUAA4IBAQAWOV/I
6CbhIFL7JTeOqp1sl/uHWhKtLBQ2NShUh2/3spdKbM0wl2yG0DFuRoBpmOx5xqD5
8XWZh0FuP3IeTSRpXj7Kz79RKho17P5cFKVkhYO1EfO8eiS/DfSf2XKEEPCyRiGf
Ibwbi8QDXBZSKowqH91nBlUO+bGpk93Bd/PpdKz8lwA4NGN4dJG4ntMcQb8zshbI
3Hg7YeVll1MKVKxuM6juH/i7MXIWjKUK3XzABIyjDjJzPBPbTvOjan9whYP3w4gg
GuQa/c9dOad5LWhOGf8MucoF5tub7gCOv3GFr/IYfYAIuj9S9v8As1Om/MUPYyZ1
hvcXBKIfbxsEW7jZ
-----END X509 CRL-----
`)
// Truncated Google CRL (GIAG2.crl)
var malformedCRL = decodeBase64(`QEwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2ds
ZSBJbmMxJTAjBgNVBAMTHEdvdZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIXDTE3MDgyNTAxMDAw
MloXDTE3MDkwNDAxMDAwowg4wG4x0pwUxAXDTE3MDgxMDA5NTEwOFowGQIIW+Bf6etm
ZUkXDTE3MDgxMDA5NTExwQIBa7iwOcb8cXDTE3MDgxMDA5NTEyN1owGQIIHboJAg2j0doX
DTE3MDgxMDA5NlowIIAXwMl8WcQXDTE3MDcyNDA4Mzc1MVowDDAKBgNVHRUEAwoBBTAn
Aggx2jOAGCr5cMTYwE1WjAMMAoGA1UdFQQDCgEDoDAwLjAfBgNVHSMEGDAWgBRK
3QYWG7z2aLV2YGu2IaLALBgNVHRQEBAICBmIwDQYJKoZIhvcNAQELBQADggEBAIv5JdgQ
VOw+h2wC06zISmKrTFQA0Gb7S5swsl4k97Y50YM4Q8/CndKKSD6djRB0Z6E8a92yobV5
nRon0VHZNDiWTDY4lPmllTME+EG6mmjpltjYnm4leJ0p4fZDiNh0xsqaU4XqZSqB7PGYp
fRg7V5utNNPw9DrV83uH25Mv7D3ugGDY1KYJ9ilyFfCo1/WUpZEX0flUlylZRxLzGcq
j1+o6Qk3XcMvojICog0hhQV9R+mst4kP9myNsT7l4QMC3ijyv+BPRkwoK/R6Q3Q72W4jB6Lg
KO92SkGoL376BzINiuZr/Esd3b4nv4=
`)
// Truncated Google CRL in PEM (GIAG2.crl)
var malformedPEMCRL = []byte(`-----BEGIN X509 CRL-----
DQYJKoZIhvcNAQELBQAwSTELMAkGA1UEBhMCVVMxEzARBgNV
BAoTCkdvb2dsZSJbmMxMTHEdvb2dsZSBJbnRlcm5dCBBdXRob3Jp
dHkgRzIXDTE3MDTAxDAwMloXDTE3MDkwNDAxMDAwlowgb4wGQIII134x0pw
xAXDTE3MDgxMDA5EwFowGQII+f6etmZUkXDTE3MDMDA5NTExOFowGQII
Ta7iwOcb8cXDTE3MgxA5NTEy1wGQIIHboJAg2j0oXDTE3MDgxMDA5NTEz
NowJwIIAX6wMgl8WQXTE3MDcyNAMzc1MVowDDABNVHRUEAwoBBTAnAggx
2jAGCr5shcNMTYwOE1jAyMjEzWjMMAoGA1UdFQDCgEDoDAwLjAfBgNVHSME
GDAgBRK3QYWG7z2a2u2IaulqBLzABgNVHRQEAICBmIwDQYJKoZIhvcN
AQELQDggEBAIvJdgQOw+h2wC06zIOmrTPFe2bQWZA0Gb7S5swsl4k97Y5
0YM4Q/ndKKSD6jBZ6E8a92yobV5nRonVNiWhDY45lPfmqNUnllTME+
EG6mmjljYn4epfZDiNh0xsqaU4XqZSqB7PYpRg7V5utNNPwsk9vyPBy
DSrVw83u25v7D3uGDY1KYJ9ilyFfCo1/WUpEflUlylZRxLzGcqj1+o6Qk3
XcMvOojIfzog0hh9+t4kP9myNsT7l4QMC3ijv+BPRkwoK/R6Q3Q72W4j
B6LgKO92SkGoL376RzINiuZr/Esd3b4nv4=
-----END X509 CRL-----
`)
// Expired CRL from BELA/mb-linux-msli on unibe.ch:
// https://goo.gl/gVVJ21
var expiredCRL = unsafePEMToDER(`-----BEGIN X509 CRL-----
MIIBsjCBmzANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJDQTEQMA4GA1UECBMH
T250YXJpbzERMA8GA1UEChMIT3BlbnN3YW4xGDAWBgNVBAMTD2NhLm9wZW5zd2Fu
Lm9yZzEeMBwGCSqGSIb3DQEJARYPY2FAb3BlbnN3YW4ub3JnFw0wNDA1MjgxNjI4
MzBaFw0wNDA1MzAxNjI4MzBaMA0GCSqGSIb3DQEBBAUAA4IBAQCfZgIequGYqYgj
hUDMIesKoTu8AoUywWpLBr+wAzcZhWRyfE3neSTP0ObqNX3XFPAtSd+KuiDr31GS
jTPMNbjcZusdvd5IoWXRWARYp3301nvZ6K0AupTm0XCmhKNJ6R65Elsbml8WOAy7
23wkIne/SZ11bg+hBKTYkS3jV3c1KsN/h98TETWwgncr590t3v8zu0WP7YAofYFJ
WZbyLjf3VkX7ShyksO5RLoFmGonPqvxV2KM5+4TAOvJ5i4uee+BW52/kwHSPz8oe
rPZ3i33nzEqAyRlnIJDQuaVqKVEk5zvNQLJKzGugyVaMdKcfbteXALmvy/c4gPlJ
vX7UjFFR
-----END X509 CRL-----
`)
func TestFetchCRL(t *testing.T) {
t.Run("Valid DER CRL", testFetchCRLWithValidCRL)
t.Run("Valid PEM CRL", testFetchCRLWithValidPEMCRL)
t.Run("Invalid DER CRL", testFetchCRLWithInvalidCRL)
t.Run("Invalid PEM CRL", testFetchCRLWithInvalidPEMCRL)
t.Run("Invalid URL", testFetchCRLWithInvalidURL)
t.Run("HTTP Error", testFetchCRLWithHTTPError)
t.Run("Expired CRL", testFetchCRLWithExpiredCRL)
}
func testFetchCRLWithValidCRL(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(derCRL)
}))
defer ts.Close()
crl, err := fetchCRL(ts.URL)
if err != nil {
t.Fatalf("fetchCRL: unexpected error %q", err.Error())
}
if !bytes.Equal(crl, pemCRL) {
t.Errorf("fetchCRL: got \"%s\"; want \"%s\"", crl, pemCRL)
}
}
func testFetchCRLWithValidPEMCRL(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(pemCRL)
}))
defer ts.Close()
crl, err := fetchCRL(ts.URL)
if err != nil {
t.Fatalf("fetchCRL: unexpected error %q", err.Error())
}
if !bytes.Equal(crl, pemCRL) {
t.Errorf("fetchCRL: got \"%s\"; want \"%s\"", crl, pemCRL)
}
}
func testFetchCRLWithInvalidCRL(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(malformedCRL)
}))
defer ts.Close()
_, err := fetchCRL(ts.URL)
switch err {
case nil:
t.Error("fetchCRL: expected error; got nil")
default:
wantErr := "cannot parse crl: asn1: structure error: tags don't match (16 vs {class:1 tag:0 length:76 isCompound:false}) {optional:false explicit:false application:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} CertificateList @2"
if got := err.Error(); got != wantErr {
t.Errorf("fetchCRL: got error %q; want %q", got, wantErr)
}
}
}
func testFetchCRLWithInvalidPEMCRL(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(malformedPEMCRL)
}))
defer ts.Close()
_, err := fetchCRL(ts.URL)
switch err {
case nil:
t.Error("fetchCRL: expected error; got nil")
default:
wantErr := "cannot convert crl from pem to der: failed to decode PEM block containing X.509 CRL"
if got := err.Error(); got != wantErr {
t.Errorf("fetchCRL: got error %q; want %q", got, wantErr)
}
}
}
func testFetchCRLWithInvalidURL(t *testing.T) {
_, err := fetchCRL("some-invalid-url")
switch err {
case nil:
t.Error("fetchCRL: expected error; got nil")
default:
wantErr := "cannot fetch crl: Get some-invalid-url: unsupported protocol scheme \"\""
if got := err.Error(); got != wantErr {
t.Errorf("fetchCRL: got error %q; want %q", got, wantErr)
}
}
}
func testFetchCRLWithHTTPError(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "not found", http.StatusNotFound)
}))
defer ts.Close()
_, err := fetchCRL(ts.URL)
switch err {
case nil:
t.Error("fetchCRL: expected error; got nil")
default:
wantErr := "cannot fetch crl due to http error: 404 Not Found"
if got := err.Error(); got != wantErr {
t.Errorf("fetchCRL: got error %q; want %q", got, wantErr)
}
}
}
func testFetchCRLWithExpiredCRL(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(expiredCRL)
}))
defer ts.Close()
_, err := fetchCRL(ts.URL)
switch err {
case nil:
t.Error("fetchCRL: expected error; got nil")
default:
wantErr := "crl has expired"
if got := err.Error(); got != wantErr {
t.Errorf("fetchCRL: got error %q; want %q", got, wantErr)
}
}
}
func TestIsPEM(t *testing.T) {
type testCase struct {
data []byte
want bool
}
tests := []testCase{
{
// PEM encoded CRL
data: []byte(`-----BEGIN X509 CRL-----
MIICGTCCAQECAQEwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UEBhMCVVMxEzARBgNV
BAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3Jp
dHkgRzIXDTE3MDIxMDAxMDAwMloXDTE3MDIyMDAxMDAwMlowUjAnAgh2S+3Tiv1R
9xcNMTcwMTEzMTQxODU4WjAMMAoGA1UdFQQDCgEDMCcCCDHaM4AYKvmyFw0xNjA5
MTUyMDIyMTNaMAwwCgYDVR0VBAMKAQOgMDAuMB8GA1UdIwQYMBaAFErdBhYbvPZo
tXb1gba7Yhq6WoEvMAsGA1UdFAQEAgIFhzANBgkqhkiG9w0BAQsFAAOCAQEAIWoB
ZnlsB4dumhCVwjEq7d1vSDD+2sFaO1DJYCVrOBuksPzjgChhgGqh/d1ExpAU3D/v
tCoaiMWJ9wXGrwiYj1SZ6fxARsgGe0BKWaDbqj4A+YICnck6o/hgs+KF8j2FXWcE
Rk//LG2JIt6mNeHm5uf5mv4h2mYi72VG7SZTCeHYl2mvEeO5qU/1gckmvRi1F60P
I1oSIz8b19jNDSN7SSupnMIwLR/XJ1ImpxtzZ/LlPr4aXDcFaV/4m9bSkzpOt8Cw
4CtDQ7yD7klQQYVUzWPEHXVqkkkh7hJKISg7+y288SITmUQhGKePI9BoiOaozj7p
fq9l6po4XF96Hhazvw==
-----END X509 CRL-----
`),
want: true,
},
{
// DER encoded CRL
data: derCRL,
want: false,
},
}
for i, test := range tests {
if got := isPEM(test.data); got != test.want {
t.Errorf("%d. isPEM: got %v, want %v", i, got, test.want)
}
}
}
func TestConvertPEMToDER(t *testing.T) {
type testCase struct {
data []byte
want []byte
wantErr error
}
tests := []testCase{
{
data: pemCRL,
want: derCRL,
wantErr: nil,
},
{
data: nil,
want: nil,
wantErr: errors.New("failed to decode PEM block containing X.509 CRL"),
},
{
data: []byte(`-----BEGIN CERTIFICATE-----
MIIFGDCCBACgAwIBAgIQYwJwLrQW+AG/bY22XF7RSjANBgkqhkiG9w0BAQsFADBE
MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMU
R2VvVHJ1c3QgU1NMIENBIC0gRzMwHhcNMTUwMjExMDAwMDAwWhcNMTgwMjEwMjM1
OTU5WjCBhTELMAkGA1UEBhMCQ0gxDzANBgNVBAgTBkdlbmV2YTEYMBYGA1UEBxQP
UGxhbi1sZXMtT3VhdGVzMR0wGwYDVQQKFBRlLVhwZXJ0IFNvbHV0aW9ucyBTQTEL
MAkGA1UECxQCSVQxHzAdBgNVBAMUFiouZS14cGVydHNvbHV0aW9ucy5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtt7JUybK63uC3YW2YzxxLsKRJ
OEMZV3tqz5uQsqu/NZY4gICtQciGWEShaDxezbXmtUffJLs3NHPCSMS8IcYXk1OM
ywOcvcaQ1OYZNpr0uxftIRU2+7e0WYN6o4MAvpguo/F5Vh8kMsuhxGHWv7zBS3Le
IZgkAafUwEl4lHuv9sj/K0IiszSJVwrMrgb36XfObWoHCGAz+YTdqNRP4tpCgUDg
HTjy6pGMtYFoOj6OQIJybv2Tnk/UWSs6PIgus31Pj92Kz5G+ZfNyDZssd3SR3U18
xBczw71h3xGhmD0bzdW3HA7atz7a+p6SQDDi9UItnJgc97oELUl5Wu0rck8FAgMB
AAGjggHCMIIBvjA3BgNVHREEMDAughYqLmUteHBlcnRzb2x1dGlvbnMuY29tghRl
LXhwZXJ0c29sdXRpb25zLmNvbTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIFoDAr
BgNVHR8EJDAiMCCgHqAchhpodHRwOi8vZ24uc3ltY2IuY29tL2duLmNybDCBoQYD
VR0gBIGZMIGWMIGTBgpghkgBhvhFAQc2MIGEMD8GCCsGAQUFBwIBFjNodHRwczov
L3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL3JlcG9zaXRvcnkvbGVnYWwwQQYI
KwYBBQUHAgIwNQwzaHR0cHM6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9y
ZXBvc2l0b3J5L2xlZ2FsMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAf
BgNVHSMEGDAWgBTSb/eW9IU/cjwwfSPahXibo3xafDBXBggrBgEFBQcBAQRLMEkw
HwYIKwYBBQUHMAGGE2h0dHA6Ly9nbi5zeW1jZC5jb20wJgYIKwYBBQUHMAKGGmh0
dHA6Ly9nbi5zeW1jYi5jb20vZ24uY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQCPQHYD
uSdXgDw/wUAfIADGSdZVsLI5jkCVLPmLv4vYpIjRF9hle0QiUMZ7nGHgPlnpF6f1
Mw3M/DPumdlY94SqxlO8p+P7E16PLnXgq4m8oDMFr3Iryd7nxQqHVdv7oyAjkZMn
52cTEUw4Uz9Oa7A3jzE4irZxLAb9U0dtmff+BRi7QqpGmu0unlyG6ErIhLnZEUA8
/TRzmVynEvorGZ9nsSv50mqVQkwHCYrX9NBN59G2/IQ1K3SxTC9yYXH37u+zhRXB
092dihU7Kn8pm1Z037NyYdePW1i+k9ruf44ySBqe3mHLwgp3uhCy3ek/lSeHfC4X
ofPxDc9Ze169o1Js
-----END CERTIFICATE-----
`),
want: nil,
wantErr: errors.New("failed to decode PEM block containing X.509 CRL"),
},
}
for i, test := range tests {
got, err := convertPEMToDER(test.data)
if err != nil {
if test.wantErr != nil && err.Error() != test.wantErr.Error() {
t.Errorf("%d. convertPEMToDER: got error %q; want %q", i, err.Error(), test.wantErr.Error())
}
continue
}
if !bytes.Equal(got, test.want) {
t.Errorf("%d. convertPEMToDER: got \"%v\"; want \"%v\"", i, got, test.want)
}
}
}
func TestIsNotFoundError(t *testing.T) {
tests := map[string]bool{
"01020036:3: The requested ClientSSL Profile (/Common/clientssl-notexist) was not found. (code: 404)": true,
"Forbidden. (code: 403)": false,
"": false,
}
for input, want := range tests {
if got := isNotFoundError(errors.New(input)); got != want {
t.Errorf("isNotFoundError(%q): got %v; want %v", input, got, want)
}
}
}