1
2
3
4
5 package pem
6
7 import (
8 "bytes"
9 "io"
10 "reflect"
11 "strings"
12 "testing"
13 "testing/quick"
14 )
15
16 type GetLineTest struct {
17 in, out1, out2 string
18 }
19
20 var getLineTests = []GetLineTest{
21 {"abc", "abc", ""},
22 {"abc\r", "abc\r", ""},
23 {"abc\n", "abc", ""},
24 {"abc\r\n", "abc", ""},
25 {"abc\nd", "abc", "d"},
26 {"abc\r\nd", "abc", "d"},
27 {"\nabc", "", "abc"},
28 {"\r\nabc", "", "abc"},
29 {"abc\t \nd", "abc", "d"},
30 {"\t abc\nd", "\t abc", "d"},
31 {"abc\n\t d", "abc", "\t d"},
32 {"abc\nd\t ", "abc", "d\t "},
33 }
34
35 func TestGetLine(t *testing.T) {
36 for i, test := range getLineTests {
37 x, y, _ := getLine([]byte(test.in))
38 if string(x) != test.out1 || string(y) != test.out2 {
39 t.Errorf("#%d got:%+v,%+v want:%s,%s", i, x, y, test.out1, test.out2)
40 }
41 }
42 }
43
44 func TestDecode(t *testing.T) {
45 result, remainder := Decode([]byte(pemData))
46 if !reflect.DeepEqual(result, certificate) {
47 t.Errorf("#0 got:%#v want:%#v", result, certificate)
48 }
49
50 result, remainder = Decode(remainder)
51 if !reflect.DeepEqual(result, privateKey) {
52 t.Errorf("#1 got:%#v want:%#v", result, privateKey)
53 }
54
55 isEmpty := func(block *Block) bool {
56 return block != nil && block.Type == "EMPTY" && len(block.Headers) == 0 && len(block.Bytes) == 0
57 }
58 result, remainder = Decode(remainder)
59 if !isEmpty(result) {
60 t.Errorf("#2 should be empty but got:%#v", result)
61 }
62 result, remainder = Decode(remainder)
63 if !isEmpty(result) {
64 t.Errorf("#3 should be empty but got:%#v", result)
65 }
66 result, remainder = Decode(remainder)
67 if !isEmpty(result) {
68 t.Errorf("#4 should be empty but got:%#v", result)
69 }
70
71 result, remainder = Decode(remainder)
72 if result == nil || result.Type != "VALID HEADERS" || len(result.Headers) != 1 {
73 t.Errorf("#5 expected single header block but got :%v", result)
74 }
75
76 if len(remainder) != 0 {
77 t.Errorf("expected nothing remaining of pemData, but found %s", string(remainder))
78 }
79
80 result, _ = Decode([]byte(pemPrivateKey2))
81 if !reflect.DeepEqual(result, privateKey2) {
82 t.Errorf("#2 got:%#v want:%#v", result, privateKey2)
83 }
84 }
85
86 const pemTooFewEndingDashes = `
87 -----BEGIN FOO-----
88 dGVzdA==
89 -----END FOO----`
90
91 const pemTooManyEndingDashes = `
92 -----BEGIN FOO-----
93 dGVzdA==
94 -----END FOO------`
95
96 const pemTrailingNonWhitespace = `
97 -----BEGIN FOO-----
98 dGVzdA==
99 -----END FOO----- .`
100
101 const pemWrongEndingType = `
102 -----BEGIN FOO-----
103 dGVzdA==
104 -----END BAR-----`
105
106 const pemMissingEndingSpace = `
107 -----BEGIN FOO-----
108 dGVzdA==
109 -----ENDBAR-----`
110
111 const pemMissingEndLine = `
112 -----BEGIN FOO-----
113 Header: 1`
114
115 var pemRepeatingBegin = strings.Repeat("-----BEGIN \n", 10)
116
117 var badPEMTests = []struct {
118 name string
119 input string
120 }{
121 {
122 "too few trailing dashes",
123 pemTooFewEndingDashes,
124 },
125 {
126 "too many trailing dashes",
127 pemTooManyEndingDashes,
128 },
129 {
130 "trailing non-whitespace",
131 pemTrailingNonWhitespace,
132 },
133 {
134 "incorrect ending type",
135 pemWrongEndingType,
136 },
137 {
138 "missing ending space",
139 pemMissingEndingSpace,
140 },
141 {
142 "repeating begin",
143 pemRepeatingBegin,
144 },
145 {
146 "missing end line",
147 pemMissingEndLine,
148 },
149 }
150
151 func TestBadDecode(t *testing.T) {
152 for _, test := range badPEMTests {
153 result, rest := Decode([]byte(test.input))
154 if result != nil {
155 t.Errorf("unexpected success while parsing %q", test.name)
156 }
157 if string(rest) != test.input {
158 t.Errorf("unexpected rest: %q; want = %q", rest, test.input)
159 }
160 }
161 }
162
163 func TestCVE202224675(t *testing.T) {
164
165 input := []byte(strings.Repeat("-----BEGIN \n", 10000000))
166 result, rest := Decode(input)
167 if result != nil || !bytes.Equal(rest, input) {
168 t.Errorf("Encode of %#v decoded as %#v", input, rest)
169 }
170 }
171
172 func TestEncode(t *testing.T) {
173 r := EncodeToMemory(privateKey2)
174 if string(r) != pemPrivateKey2 {
175 t.Errorf("got:%s want:%s", r, pemPrivateKey2)
176 }
177 }
178
179 type lineBreakerTest struct {
180 in, out string
181 }
182
183 const sixtyFourCharString = "0123456789012345678901234567890123456789012345678901234567890123"
184
185 var lineBreakerTests = []lineBreakerTest{
186 {"", ""},
187 {"a", "a\n"},
188 {"ab", "ab\n"},
189 {sixtyFourCharString, sixtyFourCharString + "\n"},
190 {sixtyFourCharString + "X", sixtyFourCharString + "\nX\n"},
191 {sixtyFourCharString + sixtyFourCharString, sixtyFourCharString + "\n" + sixtyFourCharString + "\n"},
192 }
193
194 func TestLineBreaker(t *testing.T) {
195 for i, test := range lineBreakerTests {
196 buf := new(strings.Builder)
197 var breaker lineBreaker
198 breaker.out = buf
199 _, err := breaker.Write([]byte(test.in))
200 if err != nil {
201 t.Errorf("#%d: error from Write: %s", i, err)
202 continue
203 }
204 err = breaker.Close()
205 if err != nil {
206 t.Errorf("#%d: error from Close: %s", i, err)
207 continue
208 }
209
210 if got := buf.String(); got != test.out {
211 t.Errorf("#%d: got:%s want:%s", i, got, test.out)
212 }
213 }
214
215 for i, test := range lineBreakerTests {
216 buf := new(strings.Builder)
217 var breaker lineBreaker
218 breaker.out = buf
219
220 for i := 0; i < len(test.in); i++ {
221 _, err := breaker.Write([]byte(test.in[i : i+1]))
222 if err != nil {
223 t.Errorf("#%d: error from Write (byte by byte): %s", i, err)
224 continue
225 }
226 }
227 err := breaker.Close()
228 if err != nil {
229 t.Errorf("#%d: error from Close (byte by byte): %s", i, err)
230 continue
231 }
232
233 if got := buf.String(); got != test.out {
234 t.Errorf("#%d: (byte by byte) got:%s want:%s", i, got, test.out)
235 }
236 }
237 }
238
239 func TestFuzz(t *testing.T) {
240
241
242 isBad := func(s string) bool {
243 return strings.ContainsAny(s, "\r\n") || strings.TrimSpace(s) != s
244 }
245
246 testRoundtrip := func(block Block) bool {
247
248
249 if isBad(block.Type) || strings.Contains(block.Type, ":") {
250 return true
251 }
252 for key, val := range block.Headers {
253
254
255 if isBad(key) || isBad(val) || strings.Contains(key, ":") {
256 return true
257 }
258 }
259
260 var buf bytes.Buffer
261 if err := Encode(&buf, &block); err != nil {
262 t.Errorf("Encode of %#v resulted in error: %s", &block, err)
263 return false
264 }
265 decoded, rest := Decode(buf.Bytes())
266 if block.Headers == nil {
267
268 block.Headers = make(map[string]string)
269 }
270 if block.Bytes == nil {
271
272 block.Bytes = make([]byte, 0)
273 }
274 if !reflect.DeepEqual(decoded, &block) {
275 t.Errorf("Encode of %#v decoded as %#v", &block, decoded)
276 return false
277 }
278 if len(rest) != 0 {
279 t.Errorf("Encode of %#v decoded correctly, but with %x left over", block, rest)
280 return false
281 }
282 return true
283 }
284
285
286 if !testRoundtrip(Block{
287 Type: "EMPTY",
288 Headers: make(map[string]string),
289 Bytes: []byte{},
290 }) {
291 return
292 }
293
294 quick.Check(testRoundtrip, nil)
295 }
296
297 func BenchmarkEncode(b *testing.B) {
298 data := &Block{Bytes: make([]byte, 65536)}
299 b.SetBytes(int64(len(data.Bytes)))
300 for i := 0; i < b.N; i++ {
301 Encode(io.Discard, data)
302 }
303 }
304
305 func BenchmarkDecode(b *testing.B) {
306 block := &Block{Bytes: make([]byte, 65536)}
307 data := EncodeToMemory(block)
308 b.SetBytes(int64(len(data)))
309 b.ResetTimer()
310 for i := 0; i < b.N; i++ {
311 Decode(data)
312 }
313 }
314
315 var pemData = testingKey(`verify return:0
316 -----BEGIN CERTIFICATE-----
317 sdlfkjskldfj
318 -----BEGIN CERTIFICATE-----
319 ---
320 Certificate chain
321 0 s:/C=AU/ST=Somewhere/L=Someplace/O=Foo Bar/CN=foo.example.com
322 i:/C=ZA/O=CA Inc./CN=CA Inc
323 -----BEGIN CERTIFICATE-----
324 testing
325 -----BEGIN CERTIFICATE-----
326 -----BEGIN CERTIFICATE-----
327 MIID6TCCA1ICAQEwDQYJKoZIhvcNAQEFBQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYD
328 VQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQK
329 EwtHb29nbGUgSW5jLjEMMAoGA1UECxMDRW5nMQwwCgYDVQQDEwNhZ2wxHTAbBgkq
330 hkiG9w0BCQEWDmFnbEBnb29nbGUuY29tMB4XDTA5MDkwOTIyMDU0M1oXDTEwMDkw
331 OTIyMDU0M1owajELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAf
332 BgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEjMCEGA1UEAxMaZXVyb3Bh
333 LnNmby5jb3JwLmdvb2dsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
334 AoICAQC6pgYt7/EibBDumASF+S0qvqdL/f+nouJw2T1Qc8GmXF/iiUcrsgzh/Fd8
335 pDhz/T96Qg9IyR4ztuc2MXrmPra+zAuSf5bevFReSqvpIt8Duv0HbDbcqs/XKPfB
336 uMDe+of7a9GCywvAZ4ZUJcp0thqD9fKTTjUWOBzHY1uNE4RitrhmJCrbBGXbJ249
337 bvgmb7jgdInH2PU7PT55hujvOoIsQW2osXBFRur4pF1wmVh4W4lTLD6pjfIMUcML
338 ICHEXEN73PDic8KS3EtNYCwoIld+tpIBjE1QOb1KOyuJBNW6Esw9ALZn7stWdYcE
339 qAwvv20egN2tEXqj7Q4/1ccyPZc3PQgC3FJ8Be2mtllM+80qf4dAaQ/fWvCtOrQ5
340 pnfe9juQvCo8Y0VGlFcrSys/MzSg9LJ/24jZVgzQved/Qupsp89wVidwIzjt+WdS
341 fyWfH0/v1aQLvu5cMYuW//C0W2nlYziL5blETntM8My2ybNARy3ICHxCBv2RNtPI
342 WQVm+E9/W5rwh2IJR4DHn2LHwUVmT/hHNTdBLl5Uhwr4Wc7JhE7AVqb14pVNz1lr
343 5jxsp//ncIwftb7mZQ3DF03Yna+jJhpzx8CQoeLT6aQCHyzmH68MrHHT4MALPyUs
344 Pomjn71GNTtDeWAXibjCgdL6iHACCF6Htbl0zGlG0OAK+bdn0QIDAQABMA0GCSqG
345 SIb3DQEBBQUAA4GBAOKnQDtqBV24vVqvesL5dnmyFpFPXBn3WdFfwD6DzEb21UVG
346 5krmJiu+ViipORJPGMkgoL6BjU21XI95VQbun5P8vvg8Z+FnFsvRFY3e1CCzAVQY
347 ZsUkLw2I7zI/dNlWdB8Xp7v+3w9sX5N3J/WuJ1KOO5m26kRlHQo7EzT3974g
348 -----END CERTIFICATE-----
349 1 s:/C=ZA/O=Ca Inc./CN=CA Inc
350
351 -----BEGIN RSA TESTING KEY-----
352 Proc-Type: 4,ENCRYPTED
353 DEK-Info: DES-EDE3-CBC,80C7C7A09690757A
354
355 eQp5ZkH6CyHBz7BZfUPxyLCCmftsBJ7HlqGb8Ld21cSwnzWZ4/SIlhyrUtsfw7VR
356 2TTwA+odo9ex7GdxOTaH8oZFumIRoiEjHsk8U7Bhntp+ekkPP79xunnN7hb7hkhr
357 yGDQZgA7s2cQHQ71v3gwT2BACAft26jCjbM1wgNzBnJ8M0Rzn68YWqaPtdBu8qb/
358 zVR5JB1mnqvTSbFsfF5yMc6o2WQ9jJCl6KypnMl+BpL+dlvdjYVK4l9lYsB1Hs3d
359 +zDBbWxos818zzhS8/y6eIfiSG27cqrbhURbmgiSfDXjncK4m/pLcQ7mmBL6mFOr
360 3Pj4jepzgOiFRL6MKE//h62fZvI1ErYr8VunHEykgKNhChDvb1RO6LEfqKBu+Ivw
361 TB6fBhW3TCLMnVPYVoYwA+fHNTmZZm8BEonlIMfI+KktjWUg4Oia+NI6vKcPpFox
362 hSnlGgCtvfEaq5/H4kHJp95eOpnFsLviw2seHNkz/LxJMRP1X428+DpYW/QD/0JU
363 tJSuC/q9FUHL6RI3u/Asrv8pCb4+D7i1jW/AMIdJTtycOGsbPxQA7yHMWujHmeb1
364 BTiHcL3s3KrJu1vDVrshvxfnz71KTeNnZH8UbOqT5i7fPGyXtY1XJddcbI/Q6tXf
365 wHFsZc20TzSdsVLBtwksUacpbDogcEVMctnNrB8FIrB3vZEv9Q0Z1VeY7nmTpF+6
366 a+z2P7acL7j6A6Pr3+q8P9CPiPC7zFonVzuVPyB8GchGR2hytyiOVpuD9+k8hcuw
367 ZWAaUoVtWIQ52aKS0p19G99hhb+IVANC4akkdHV4SP8i7MVNZhfUmg==
368 -----END RSA TESTING KEY-----
369
370
371 -----BEGIN EMPTY-----
372 -----END EMPTY-----
373
374 -----BEGIN EMPTY-----
375
376 -----END EMPTY-----
377
378 -----BEGIN EMPTY-----
379
380
381 -----END EMPTY-----
382
383 # This shouldn't be recognised because of the missing newline after the
384 headers.
385 -----BEGIN INVALID HEADERS-----
386 Header: 1
387 -----END INVALID HEADERS-----
388
389 # This should be valid, however.
390 -----BEGIN VALID HEADERS-----
391 Header: 1
392
393 -----END VALID HEADERS-----`)
394
395 var certificate = &Block{Type: "CERTIFICATE",
396 Headers: map[string]string{},
397 Bytes: []uint8{0x30, 0x82, 0x3, 0xe9, 0x30, 0x82, 0x3, 0x52, 0x2, 0x1,
398 0x1, 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd,
399 0x1, 0x1, 0x5, 0x5, 0x0, 0x30, 0x81, 0x8b, 0x31, 0xb, 0x30,
400 0x9, 0x6, 0x3, 0x55, 0x4, 0x6, 0x13, 0x2, 0x55, 0x53, 0x31,
401 0x13, 0x30, 0x11, 0x6, 0x3, 0x55, 0x4, 0x8, 0x13, 0xa, 0x43,
402 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31,
403 0x16, 0x30, 0x14, 0x6, 0x3, 0x55, 0x4, 0x7, 0x13, 0xd, 0x53,
404 0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73,
405 0x63, 0x6f, 0x31, 0x14, 0x30, 0x12, 0x6, 0x3, 0x55, 0x4, 0xa,
406 0x13, 0xb, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49,
407 0x6e, 0x63, 0x2e, 0x31, 0xc, 0x30, 0xa, 0x6, 0x3, 0x55, 0x4,
408 0xb, 0x13, 0x3, 0x45, 0x6e, 0x67, 0x31, 0xc, 0x30, 0xa, 0x6,
409 0x3, 0x55, 0x4, 0x3, 0x13, 0x3, 0x61, 0x67, 0x6c, 0x31, 0x1d,
410 0x30, 0x1b, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1,
411 0x9, 0x1, 0x16, 0xe, 0x61, 0x67, 0x6c, 0x40, 0x67, 0x6f, 0x6f,
412 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17,
413 0xd, 0x30, 0x39, 0x30, 0x39, 0x30, 0x39, 0x32, 0x32, 0x30,
414 0x35, 0x34, 0x33, 0x5a, 0x17, 0xd, 0x31, 0x30, 0x30, 0x39,
415 0x30, 0x39, 0x32, 0x32, 0x30, 0x35, 0x34, 0x33, 0x5a, 0x30,
416 0x6a, 0x31, 0xb, 0x30, 0x9, 0x6, 0x3, 0x55, 0x4, 0x6, 0x13,
417 0x2, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x6, 0x3, 0x55, 0x4,
418 0x8, 0x13, 0xa, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
419 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x6, 0x3, 0x55, 0x4, 0xa,
420 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
421 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
422 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30, 0x21,
423 0x6, 0x3, 0x55, 0x4, 0x3, 0x13, 0x1a, 0x65, 0x75, 0x72, 0x6f,
424 0x70, 0x61, 0x2e, 0x73, 0x66, 0x6f, 0x2e, 0x63, 0x6f, 0x72,
425 0x70, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63,
426 0x6f, 0x6d, 0x30, 0x82, 0x2, 0x22, 0x30, 0xd, 0x6, 0x9, 0x2a,
427 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0x1, 0x5, 0x0, 0x3,
428 0x82, 0x2, 0xf, 0x0, 0x30, 0x82, 0x2, 0xa, 0x2, 0x82, 0x2, 0x1,
429 0x0, 0xba, 0xa6, 0x6, 0x2d, 0xef, 0xf1, 0x22, 0x6c, 0x10, 0xee,
430 0x98, 0x4, 0x85, 0xf9, 0x2d, 0x2a, 0xbe, 0xa7, 0x4b, 0xfd,
431 0xff, 0xa7, 0xa2, 0xe2, 0x70, 0xd9, 0x3d, 0x50, 0x73, 0xc1,
432 0xa6, 0x5c, 0x5f, 0xe2, 0x89, 0x47, 0x2b, 0xb2, 0xc, 0xe1,
433 0xfc, 0x57, 0x7c, 0xa4, 0x38, 0x73, 0xfd, 0x3f, 0x7a, 0x42,
434 0xf, 0x48, 0xc9, 0x1e, 0x33, 0xb6, 0xe7, 0x36, 0x31, 0x7a,
435 0xe6, 0x3e, 0xb6, 0xbe, 0xcc, 0xb, 0x92, 0x7f, 0x96, 0xde,
436 0xbc, 0x54, 0x5e, 0x4a, 0xab, 0xe9, 0x22, 0xdf, 0x3, 0xba,
437 0xfd, 0x7, 0x6c, 0x36, 0xdc, 0xaa, 0xcf, 0xd7, 0x28, 0xf7,
438 0xc1, 0xb8, 0xc0, 0xde, 0xfa, 0x87, 0xfb, 0x6b, 0xd1, 0x82,
439 0xcb, 0xb, 0xc0, 0x67, 0x86, 0x54, 0x25, 0xca, 0x74, 0xb6,
440 0x1a, 0x83, 0xf5, 0xf2, 0x93, 0x4e, 0x35, 0x16, 0x38, 0x1c,
441 0xc7, 0x63, 0x5b, 0x8d, 0x13, 0x84, 0x62, 0xb6, 0xb8, 0x66,
442 0x24, 0x2a, 0xdb, 0x4, 0x65, 0xdb, 0x27, 0x6e, 0x3d, 0x6e,
443 0xf8, 0x26, 0x6f, 0xb8, 0xe0, 0x74, 0x89, 0xc7, 0xd8, 0xf5,
444 0x3b, 0x3d, 0x3e, 0x79, 0x86, 0xe8, 0xef, 0x3a, 0x82, 0x2c,
445 0x41, 0x6d, 0xa8, 0xb1, 0x70, 0x45, 0x46, 0xea, 0xf8, 0xa4,
446 0x5d, 0x70, 0x99, 0x58, 0x78, 0x5b, 0x89, 0x53, 0x2c, 0x3e,
447 0xa9, 0x8d, 0xf2, 0xc, 0x51, 0xc3, 0xb, 0x20, 0x21, 0xc4, 0x5c,
448 0x43, 0x7b, 0xdc, 0xf0, 0xe2, 0x73, 0xc2, 0x92, 0xdc, 0x4b,
449 0x4d, 0x60, 0x2c, 0x28, 0x22, 0x57, 0x7e, 0xb6, 0x92, 0x1,
450 0x8c, 0x4d, 0x50, 0x39, 0xbd, 0x4a, 0x3b, 0x2b, 0x89, 0x4,
451 0xd5, 0xba, 0x12, 0xcc, 0x3d, 0x0, 0xb6, 0x67, 0xee, 0xcb,
452 0x56, 0x75, 0x87, 0x4, 0xa8, 0xc, 0x2f, 0xbf, 0x6d, 0x1e, 0x80,
453 0xdd, 0xad, 0x11, 0x7a, 0xa3, 0xed, 0xe, 0x3f, 0xd5, 0xc7,
454 0x32, 0x3d, 0x97, 0x37, 0x3d, 0x8, 0x2, 0xdc, 0x52, 0x7c, 0x5,
455 0xed, 0xa6, 0xb6, 0x59, 0x4c, 0xfb, 0xcd, 0x2a, 0x7f, 0x87,
456 0x40, 0x69, 0xf, 0xdf, 0x5a, 0xf0, 0xad, 0x3a, 0xb4, 0x39,
457 0xa6, 0x77, 0xde, 0xf6, 0x3b, 0x90, 0xbc, 0x2a, 0x3c, 0x63,
458 0x45, 0x46, 0x94, 0x57, 0x2b, 0x4b, 0x2b, 0x3f, 0x33, 0x34,
459 0xa0, 0xf4, 0xb2, 0x7f, 0xdb, 0x88, 0xd9, 0x56, 0xc, 0xd0,
460 0xbd, 0xe7, 0x7f, 0x42, 0xea, 0x6c, 0xa7, 0xcf, 0x70, 0x56,
461 0x27, 0x70, 0x23, 0x38, 0xed, 0xf9, 0x67, 0x52, 0x7f, 0x25,
462 0x9f, 0x1f, 0x4f, 0xef, 0xd5, 0xa4, 0xb, 0xbe, 0xee, 0x5c,
463 0x31, 0x8b, 0x96, 0xff, 0xf0, 0xb4, 0x5b, 0x69, 0xe5, 0x63,
464 0x38, 0x8b, 0xe5, 0xb9, 0x44, 0x4e, 0x7b, 0x4c, 0xf0, 0xcc,
465 0xb6, 0xc9, 0xb3, 0x40, 0x47, 0x2d, 0xc8, 0x8, 0x7c, 0x42, 0x6,
466 0xfd, 0x91, 0x36, 0xd3, 0xc8, 0x59, 0x5, 0x66, 0xf8, 0x4f,
467 0x7f, 0x5b, 0x9a, 0xf0, 0x87, 0x62, 0x9, 0x47, 0x80, 0xc7,
468 0x9f, 0x62, 0xc7, 0xc1, 0x45, 0x66, 0x4f, 0xf8, 0x47, 0x35,
469 0x37, 0x41, 0x2e, 0x5e, 0x54, 0x87, 0xa, 0xf8, 0x59, 0xce,
470 0xc9, 0x84, 0x4e, 0xc0, 0x56, 0xa6, 0xf5, 0xe2, 0x95, 0x4d,
471 0xcf, 0x59, 0x6b, 0xe6, 0x3c, 0x6c, 0xa7, 0xff, 0xe7, 0x70,
472 0x8c, 0x1f, 0xb5, 0xbe, 0xe6, 0x65, 0xd, 0xc3, 0x17, 0x4d,
473 0xd8, 0x9d, 0xaf, 0xa3, 0x26, 0x1a, 0x73, 0xc7, 0xc0, 0x90,
474 0xa1, 0xe2, 0xd3, 0xe9, 0xa4, 0x2, 0x1f, 0x2c, 0xe6, 0x1f,
475 0xaf, 0xc, 0xac, 0x71, 0xd3, 0xe0, 0xc0, 0xb, 0x3f, 0x25, 0x2c,
476 0x3e, 0x89, 0xa3, 0x9f, 0xbd, 0x46, 0x35, 0x3b, 0x43, 0x79,
477 0x60, 0x17, 0x89, 0xb8, 0xc2, 0x81, 0xd2, 0xfa, 0x88, 0x70,
478 0x2, 0x8, 0x5e, 0x87, 0xb5, 0xb9, 0x74, 0xcc, 0x69, 0x46, 0xd0,
479 0xe0, 0xa, 0xf9, 0xb7, 0x67, 0xd1, 0x2, 0x3, 0x1, 0x0, 0x1,
480 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1,
481 0x1, 0x5, 0x5, 0x0, 0x3, 0x81, 0x81, 0x0, 0xe2, 0xa7, 0x40,
482 0x3b, 0x6a, 0x5, 0x5d, 0xb8, 0xbd, 0x5a, 0xaf, 0x7a, 0xc2,
483 0xf9, 0x76, 0x79, 0xb2, 0x16, 0x91, 0x4f, 0x5c, 0x19, 0xf7,
484 0x59, 0xd1, 0x5f, 0xc0, 0x3e, 0x83, 0xcc, 0x46, 0xf6, 0xd5,
485 0x45, 0x46, 0xe6, 0x4a, 0xe6, 0x26, 0x2b, 0xbe, 0x56, 0x28,
486 0xa9, 0x39, 0x12, 0x4f, 0x18, 0xc9, 0x20, 0xa0, 0xbe, 0x81,
487 0x8d, 0x4d, 0xb5, 0x5c, 0x8f, 0x79, 0x55, 0x6, 0xee, 0x9f,
488 0x93, 0xfc, 0xbe, 0xf8, 0x3c, 0x67, 0xe1, 0x67, 0x16, 0xcb,
489 0xd1, 0x15, 0x8d, 0xde, 0xd4, 0x20, 0xb3, 0x1, 0x54, 0x18,
490 0x66, 0xc5, 0x24, 0x2f, 0xd, 0x88, 0xef, 0x32, 0x3f, 0x74,
491 0xd9, 0x56, 0x74, 0x1f, 0x17, 0xa7, 0xbb, 0xfe, 0xdf, 0xf,
492 0x6c, 0x5f, 0x93, 0x77, 0x27, 0xf5, 0xae, 0x27, 0x52, 0x8e,
493 0x3b, 0x99, 0xb6, 0xea, 0x44, 0x65, 0x1d, 0xa, 0x3b, 0x13,
494 0x34, 0xf7, 0xf7, 0xbe, 0x20,
495 },
496 }
497
498 var privateKey = &Block{Type: "RSA PRIVATE KEY",
499 Headers: map[string]string{"DEK-Info": "DES-EDE3-CBC,80C7C7A09690757A", "Proc-Type": "4,ENCRYPTED"},
500 Bytes: []uint8{0x79, 0xa, 0x79, 0x66, 0x41, 0xfa, 0xb,
501 0x21, 0xc1, 0xcf, 0xb0, 0x59, 0x7d, 0x43, 0xf1, 0xc8, 0xb0,
502 0x82, 0x99, 0xfb, 0x6c, 0x4, 0x9e, 0xc7, 0x96, 0xa1, 0x9b,
503 0xf0, 0xb7, 0x76, 0xd5, 0xc4, 0xb0, 0x9f, 0x35, 0x99, 0xe3,
504 0xf4, 0x88, 0x96, 0x1c, 0xab, 0x52, 0xdb, 0x1f, 0xc3, 0xb5,
505 0x51, 0xd9, 0x34, 0xf0, 0x3, 0xea, 0x1d, 0xa3, 0xd7, 0xb1,
506 0xec, 0x67, 0x71, 0x39, 0x36, 0x87, 0xf2, 0x86, 0x45, 0xba,
507 0x62, 0x11, 0xa2, 0x21, 0x23, 0x1e, 0xc9, 0x3c, 0x53, 0xb0,
508 0x61, 0x9e, 0xda, 0x7e, 0x7a, 0x49, 0xf, 0x3f, 0xbf, 0x71,
509 0xba, 0x79, 0xcd, 0xee, 0x16, 0xfb, 0x86, 0x48, 0x6b, 0xc8,
510 0x60, 0xd0, 0x66, 0x0, 0x3b, 0xb3, 0x67, 0x10, 0x1d, 0xe,
511 0xf5, 0xbf, 0x78, 0x30, 0x4f, 0x60, 0x40, 0x8, 0x7, 0xed,
512 0xdb, 0xa8, 0xc2, 0x8d, 0xb3, 0x35, 0xc2, 0x3, 0x73, 0x6,
513 0x72, 0x7c, 0x33, 0x44, 0x73, 0x9f, 0xaf, 0x18, 0x5a, 0xa6,
514 0x8f, 0xb5, 0xd0, 0x6e, 0xf2, 0xa6, 0xff, 0xcd, 0x54, 0x79,
515 0x24, 0x1d, 0x66, 0x9e, 0xab, 0xd3, 0x49, 0xb1, 0x6c, 0x7c,
516 0x5e, 0x72, 0x31, 0xce, 0xa8, 0xd9, 0x64, 0x3d, 0x8c, 0x90,
517 0xa5, 0xe8, 0xac, 0xa9, 0x9c, 0xc9, 0x7e, 0x6, 0x92, 0xfe,
518 0x76, 0x5b, 0xdd, 0x8d, 0x85, 0x4a, 0xe2, 0x5f, 0x65, 0x62,
519 0xc0, 0x75, 0x1e, 0xcd, 0xdd, 0xfb, 0x30, 0xc1, 0x6d, 0x6c,
520 0x68, 0xb3, 0xcd, 0x7c, 0xcf, 0x38, 0x52, 0xf3, 0xfc, 0xba,
521 0x78, 0x87, 0xe2, 0x48, 0x6d, 0xbb, 0x72, 0xaa, 0xdb, 0x85,
522 0x44, 0x5b, 0x9a, 0x8, 0x92, 0x7c, 0x35, 0xe3, 0x9d, 0xc2,
523 0xb8, 0x9b, 0xfa, 0x4b, 0x71, 0xe, 0xe6, 0x98, 0x12, 0xfa,
524 0x98, 0x53, 0xab, 0xdc, 0xf8, 0xf8, 0x8d, 0xea, 0x73, 0x80,
525 0xe8, 0x85, 0x44, 0xbe, 0x8c, 0x28, 0x4f, 0xff, 0x87, 0xad,
526 0x9f, 0x66, 0xf2, 0x35, 0x12, 0xb6, 0x2b, 0xf1, 0x5b, 0xa7,
527 0x1c, 0x4c, 0xa4, 0x80, 0xa3, 0x61, 0xa, 0x10, 0xef, 0x6f,
528 0x54, 0x4e, 0xe8, 0xb1, 0x1f, 0xa8, 0xa0, 0x6e, 0xf8, 0x8b,
529 0xf0, 0x4c, 0x1e, 0x9f, 0x6, 0x15, 0xb7, 0x4c, 0x22, 0xcc,
530 0x9d, 0x53, 0xd8, 0x56, 0x86, 0x30, 0x3, 0xe7, 0xc7, 0x35,
531 0x39, 0x99, 0x66, 0x6f, 0x1, 0x12, 0x89, 0xe5, 0x20, 0xc7,
532 0xc8, 0xf8, 0xa9, 0x2d, 0x8d, 0x65, 0x20, 0xe0, 0xe8, 0x9a,
533 0xf8, 0xd2, 0x3a, 0xbc, 0xa7, 0xf, 0xa4, 0x5a, 0x31, 0x85,
534 0x29, 0xe5, 0x1a, 0x0, 0xad, 0xbd, 0xf1, 0x1a, 0xab, 0x9f,
535 0xc7, 0xe2, 0x41, 0xc9, 0xa7, 0xde, 0x5e, 0x3a, 0x99, 0xc5,
536 0xb0, 0xbb, 0xe2, 0xc3, 0x6b, 0x1e, 0x1c, 0xd9, 0x33, 0xfc,
537 0xbc, 0x49, 0x31, 0x13, 0xf5, 0x5f, 0x8d, 0xbc, 0xf8, 0x3a,
538 0x58, 0x5b, 0xf4, 0x3, 0xff, 0x42, 0x54, 0xb4, 0x94, 0xae,
539 0xb, 0xfa, 0xbd, 0x15, 0x41, 0xcb, 0xe9, 0x12, 0x37, 0xbb,
540 0xf0, 0x2c, 0xae, 0xff, 0x29, 0x9, 0xbe, 0x3e, 0xf, 0xb8,
541 0xb5, 0x8d, 0x6f, 0xc0, 0x30, 0x87, 0x49, 0x4e, 0xdc, 0x9c,
542 0x38, 0x6b, 0x1b, 0x3f, 0x14, 0x0, 0xef, 0x21, 0xcc, 0x5a,
543 0xe8, 0xc7, 0x99, 0xe6, 0xf5, 0x5, 0x38, 0x87, 0x70, 0xbd,
544 0xec, 0xdc, 0xaa, 0xc9, 0xbb, 0x5b, 0xc3, 0x56, 0xbb, 0x21,
545 0xbf, 0x17, 0xe7, 0xcf, 0xbd, 0x4a, 0x4d, 0xe3, 0x67, 0x64,
546 0x7f, 0x14, 0x6c, 0xea, 0x93, 0xe6, 0x2e, 0xdf, 0x3c, 0x6c,
547 0x97, 0xb5, 0x8d, 0x57, 0x25, 0xd7, 0x5c, 0x6c, 0x8f, 0xd0,
548 0xea, 0xd5, 0xdf, 0xc0, 0x71, 0x6c, 0x65, 0xcd, 0xb4, 0x4f,
549 0x34, 0x9d, 0xb1, 0x52, 0xc1, 0xb7, 0x9, 0x2c, 0x51, 0xa7,
550 0x29, 0x6c, 0x3a, 0x20, 0x70, 0x45, 0x4c, 0x72, 0xd9, 0xcd,
551 0xac, 0x1f, 0x5, 0x22, 0xb0, 0x77, 0xbd, 0x91, 0x2f, 0xf5,
552 0xd, 0x19, 0xd5, 0x57, 0x98, 0xee, 0x79, 0x93, 0xa4, 0x5f,
553 0xba, 0x6b, 0xec, 0xf6, 0x3f, 0xb6, 0x9c, 0x2f, 0xb8, 0xfa,
554 0x3, 0xa3, 0xeb, 0xdf, 0xea, 0xbc, 0x3f, 0xd0, 0x8f, 0x88,
555 0xf0, 0xbb, 0xcc, 0x5a, 0x27, 0x57, 0x3b, 0x95, 0x3f, 0x20,
556 0x7c, 0x19, 0xc8, 0x46, 0x47, 0x68, 0x72, 0xb7, 0x28, 0x8e,
557 0x56, 0x9b, 0x83, 0xf7, 0xe9, 0x3c, 0x85, 0xcb, 0xb0, 0x65,
558 0x60, 0x1a, 0x52, 0x85, 0x6d, 0x58, 0x84, 0x39, 0xd9, 0xa2,
559 0x92, 0xd2, 0x9d, 0x7d, 0x1b, 0xdf, 0x61, 0x85, 0xbf, 0x88,
560 0x54, 0x3, 0x42, 0xe1, 0xa9, 0x24, 0x74, 0x75, 0x78, 0x48,
561 0xff, 0x22, 0xec, 0xc5, 0x4d, 0x66, 0x17, 0xd4, 0x9a,
562 },
563 }
564
565 var privateKey2 = &Block{
566 Type: "RSA PRIVATE KEY",
567 Headers: map[string]string{
568 "Proc-Type": "4,ENCRYPTED",
569 "DEK-Info": "AES-128-CBC,BFCD243FEDBB40A4AA6DDAA1335473A4",
570 "Content-Domain": "RFC822",
571 },
572 Bytes: []uint8{
573 0xa8, 0x35, 0xcc, 0x2b, 0xb9, 0xcb, 0x21, 0xab, 0xc0,
574 0x9d, 0x76, 0x61, 0x0, 0xf4, 0x81, 0xad, 0x69, 0xd2,
575 0xc0, 0x42, 0x41, 0x3b, 0xe4, 0x3c, 0xaf, 0x59, 0x5e,
576 0x6d, 0x2a, 0x3c, 0x9c, 0xa1, 0xa4, 0x5e, 0x68, 0x37,
577 0xc4, 0x8c, 0x70, 0x1c, 0xa9, 0x18, 0xe6, 0xc2, 0x2b,
578 0x8a, 0x91, 0xdc, 0x2d, 0x1f, 0x8, 0x23, 0x39, 0xf1,
579 0x4b, 0x8b, 0x1b, 0x2f, 0x46, 0xb, 0xb2, 0x26, 0xba,
580 0x4f, 0x40, 0x80, 0x39, 0xc4, 0xb1, 0xcb, 0x3b, 0xb4,
581 0x65, 0x3f, 0x1b, 0xb2, 0xf7, 0x8, 0xd2, 0xc6, 0xd5,
582 0xa8, 0x9f, 0x23, 0x69, 0xb6, 0x3d, 0xf9, 0xac, 0x1c,
583 0xb3, 0x13, 0x87, 0x64, 0x4, 0x37, 0xdb, 0x40, 0xc8,
584 0x82, 0xc, 0xd0, 0xf8, 0x21, 0x7c, 0xdc, 0xbd, 0x9, 0x4,
585 0x20, 0x16, 0xb0, 0x97, 0xe2, 0x6d, 0x56, 0x1d, 0xe3,
586 0xec, 0xf0, 0xfc, 0xe2, 0x56, 0xad, 0xa4, 0x3, 0x70,
587 0x6d, 0x63, 0x3c, 0x1, 0xbe, 0x3e, 0x28, 0x38, 0x6f,
588 0xc0, 0xe6, 0xfd, 0x85, 0xd1, 0x53, 0xa8, 0x9b, 0xcb,
589 0xd4, 0x4, 0xb1, 0x73, 0xb9, 0x73, 0x32, 0xd6, 0x7a,
590 0xc6, 0x29, 0x25, 0xa5, 0xda, 0x17, 0x93, 0x7a, 0x10,
591 0xe8, 0x41, 0xfb, 0xa5, 0x17, 0x20, 0xf8, 0x4e, 0xe9,
592 0xe3, 0x8f, 0x51, 0x20, 0x13, 0xbb, 0xde, 0xb7, 0x93,
593 0xae, 0x13, 0x8a, 0xf6, 0x9, 0xf4, 0xa6, 0x41, 0xe0,
594 0x2b, 0x51, 0x1a, 0x30, 0x38, 0xd, 0xb1, 0x3b, 0x67,
595 0x87, 0x64, 0xf5, 0xca, 0x32, 0x67, 0xd1, 0xc8, 0xa5,
596 0x3d, 0x23, 0x72, 0xc4, 0x6, 0xaf, 0x8f, 0x7b, 0x26,
597 0xac, 0x3c, 0x75, 0x91, 0xa1, 0x0, 0x13, 0xc6, 0x5c,
598 0x49, 0xd5, 0x3c, 0xe7, 0xb2, 0xb2, 0x99, 0xe0, 0xd5,
599 0x25, 0xfa, 0xe2, 0x12, 0x80, 0x37, 0x85, 0xcf, 0x92,
600 0xca, 0x1b, 0x9f, 0xf3, 0x4e, 0xd8, 0x80, 0xef, 0x3c,
601 0xce, 0xcd, 0xf5, 0x90, 0x9e, 0xf9, 0xa7, 0xb2, 0xc,
602 0x49, 0x4, 0xf1, 0x9, 0x8f, 0xea, 0x63, 0xd2, 0x70,
603 0xbb, 0x86, 0xbf, 0x34, 0xab, 0xb2, 0x3, 0xb1, 0x59,
604 0x33, 0x16, 0x17, 0xb0, 0xdb, 0x77, 0x38, 0xf4, 0xb4,
605 0x94, 0xb, 0x25, 0x16, 0x7e, 0x22, 0xd4, 0xf9, 0x22,
606 0xb9, 0x78, 0xa3, 0x4, 0x84, 0x4, 0xd2, 0xda, 0x84,
607 0x2d, 0x63, 0xdd, 0xf8, 0x50, 0x6a, 0xf6, 0xe3, 0xf5,
608 0x65, 0x40, 0x7c, 0xa9,
609 },
610 }
611
612 var pemPrivateKey2 = testingKey(`-----BEGIN RSA TESTING KEY-----
613 Proc-Type: 4,ENCRYPTED
614 Content-Domain: RFC822
615 DEK-Info: AES-128-CBC,BFCD243FEDBB40A4AA6DDAA1335473A4
616
617 qDXMK7nLIavAnXZhAPSBrWnSwEJBO+Q8r1lebSo8nKGkXmg3xIxwHKkY5sIripHc
618 LR8IIznxS4sbL0YLsia6T0CAOcSxyzu0ZT8bsvcI0sbVqJ8jabY9+awcsxOHZAQ3
619 20DIggzQ+CF83L0JBCAWsJfibVYd4+zw/OJWraQDcG1jPAG+Pig4b8Dm/YXRU6ib
620 y9QEsXO5czLWesYpJaXaF5N6EOhB+6UXIPhO6eOPUSATu963k64TivYJ9KZB4CtR
621 GjA4DbE7Z4dk9coyZ9HIpT0jcsQGr497Jqw8dZGhABPGXEnVPOeyspng1SX64hKA
622 N4XPksobn/NO2IDvPM7N9ZCe+aeyDEkE8QmP6mPScLuGvzSrsgOxWTMWF7Dbdzj0
623 tJQLJRZ+ItT5Irl4owSEBNLahC1j3fhQavbj9WVAfKk=
624 -----END RSA TESTING KEY-----
625 `)
626
627 func TestBadEncode(t *testing.T) {
628 b := &Block{Type: "BAD", Headers: map[string]string{"X:Y": "Z"}}
629 var buf bytes.Buffer
630 if err := Encode(&buf, b); err == nil {
631 t.Fatalf("Encode did not report invalid header")
632 }
633 if buf.Len() != 0 {
634 t.Fatalf("Encode wrote data before reporting invalid header")
635 }
636 if data := EncodeToMemory(b); data != nil {
637 t.Fatalf("EncodeToMemory returned non-nil data")
638 }
639 }
640
641 func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
642
643 func TestDecodeStrangeCases(t *testing.T) {
644 sentinelType := "TEST BLOCK"
645 sentinelBytes := []byte("hello")
646 for _, tc := range []struct {
647 name string
648 pem string
649 }{
650 {
651 name: "invalid section (not base64)",
652 pem: `-----BEGIN COMMENT-----
653 foo foo foo
654 -----END COMMENT-----
655 -----BEGIN TEST BLOCK-----
656 aGVsbG8=
657 -----END TEST BLOCK-----`,
658 },
659 {
660 name: "leading garbage on block",
661 pem: `foo foo foo-----BEGIN CERTIFICATE-----
662 MCowBQYDK2VwAyEApVjJeLW5MoP6uR3+OeITokM+rBDng6dgl1vvhcy+wws=
663 -----END PUBLIC KEY-----
664 -----BEGIN TEST BLOCK-----
665 aGVsbG8=
666 -----END TEST BLOCK-----`,
667 },
668 {
669 name: "leading garbage",
670 pem: `foo foo foo
671 -----BEGIN TEST BLOCK-----
672 aGVsbG8=
673 -----END TEST BLOCK-----`,
674 },
675 {
676 name: "leading partial block",
677 pem: `foo foo foo
678 -----END COMMENT-----
679 -----BEGIN TEST BLOCK-----
680 aGVsbG8=
681 -----END TEST BLOCK-----`,
682 },
683 {
684 name: "multiple BEGIN",
685 pem: `-----BEGIN TEST BLOCK-----
686 -----BEGIN TEST BLOCK-----
687 -----BEGIN TEST BLOCK-----
688 aGVsbG8=
689 -----END TEST BLOCK-----`,
690 },
691 {
692 name: "multiple END",
693 pem: `-----BEGIN TEST BLOCK-----
694 aGVsbG8=
695 -----END TEST BLOCK-----
696 -----END TEST BLOCK-----
697 -----END TEST BLOCK-----`,
698 },
699 {
700 name: "leading malformed BEGIN",
701 pem: `-----BEGIN PUBLIC KEY
702 aGVsbG8=
703 -----END PUBLIC KEY-----
704 -----BEGIN TEST BLOCK-----
705 aGVsbG8=
706 -----END TEST BLOCK-----`,
707 },
708 } {
709 t.Run(tc.name, func(t *testing.T) {
710 block, _ := Decode([]byte(tc.pem))
711 if block == nil {
712 t.Fatal("expected valid block")
713 }
714 if block.Type != sentinelType {
715 t.Fatalf("unexpected block returned, got type %q, want type %q", block.Type, sentinelType)
716 }
717 if !bytes.Equal(block.Bytes, sentinelBytes) {
718 t.Fatalf("unexpected block content, got %x, want %x", block.Bytes, sentinelBytes)
719 }
720 })
721 }
722 }
723
724 func TestJustEnd(t *testing.T) {
725 pemData := `
726 -----END PUBLIC KEY-----`
727
728 block, _ := Decode([]byte(pemData))
729 if block != nil {
730 t.Fatal("unexpected block")
731 }
732 }
733
734 func FuzzDecode(f *testing.F) {
735 f.Fuzz(func(t *testing.T, data []byte) {
736 Decode(data)
737 })
738 }
739
740 func TestMissingEndTrailer(t *testing.T) {
741 Decode([]byte{0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20})
742 }
743
View as plain text