1 package jwt
2
3 import (
4 "strings"
5 "testing"
6 "time"
7
8 "github.com/stretchr/testify/assert"
9 "github.com/stretchr/testify/require"
10 "gopkg.in/square/go-jose.v2"
11 "gopkg.in/square/go-jose.v2/jwt"
12
13 "crypto/rand"
14 "crypto/rsa"
15 "crypto/x509"
16 "encoding/pem"
17 "fmt"
18 )
19
20 func TestUnsignedToken(t *testing.T) {
21 key := UnsafeAllowNoneSignatureType
22 token := NewWithClaims(SigningMethodNone, MapClaims{
23 "aud": "foo",
24 "exp": time.Now().UTC().Add(time.Hour).Unix(),
25 "iat": time.Now().UTC().Unix(),
26 "sub": "nestor",
27 })
28 rawToken, err := token.SignedString(key)
29 require.NoError(t, err)
30 require.NotEmpty(t, rawToken)
31 parts := strings.Split(rawToken, ".")
32 require.Len(t, parts, 3)
33 require.Empty(t, parts[2])
34 tk, err := jwt.ParseSigned(rawToken)
35 require.NoError(t, err)
36 require.Len(t, tk.Headers, 1)
37 require.Equal(t, "JWT", tk.Headers[0].ExtraHeaders[jose.HeaderKey("typ")])
38 }
39
40 func TestJWTHeaders(t *testing.T) {
41 rawToken := makeSampleToken(nil, jose.RS256, MustRSAKey())
42 tk, err := jwt.ParseSigned(rawToken)
43 require.NoError(t, err)
44 require.Len(t, tk.Headers, 1)
45 require.Equal(t, tk.Headers[0].Algorithm, "RS256")
46 require.Equal(t, "JWT", tk.Headers[0].ExtraHeaders[jose.HeaderKey("typ")])
47 }
48
49 var keyFuncError error = fmt.Errorf("error loading key")
50 var (
51 jwtTestDefaultKey *rsa.PublicKey = parseRSAPublicKeyFromPEM(defaultPubKeyPEM)
52 defaultKeyFunc Keyfunc = func(t *Token) (interface{}, error) { return jwtTestDefaultKey, nil }
53 emptyKeyFunc Keyfunc = func(t *Token) (interface{}, error) { return nil, nil }
54 errorKeyFunc Keyfunc = func(t *Token) (interface{}, error) { return nil, keyFuncError }
55 nilKeyFunc Keyfunc = nil
56 )
57
58
59
60
61 func TestParser_Parse(t *testing.T) {
62 var (
63 defaultES256PrivateKey = MustECDSAKey()
64 defaultSigningKey = parseRSAPrivateKeyFromPEM(defaultPrivateKeyPEM)
65 publicECDSAKey = func(*Token) (interface{}, error) { return &defaultES256PrivateKey.PublicKey, nil }
66 noneKey = func(*Token) (interface{}, error) { return UnsafeAllowNoneSignatureType, nil }
67 randomKey = func(*Token) (interface{}, error) {
68 k, err := rsa.GenerateKey(rand.Reader, 2048)
69 require.NoError(t, err)
70 return &k.PublicKey, nil
71 }
72 )
73 type expected struct {
74 errors uint32
75 keyFunc Keyfunc
76 valid bool
77 claims MapClaims
78 }
79 type generate struct {
80 claims MapClaims
81 signingKey interface{}
82 method jose.SignatureAlgorithm
83 }
84 type given struct {
85 name string
86 tokenString string
87 generate *generate
88 }
89 var jwtTestData = []struct {
90 expected
91 given
92 }{
93 {
94 given: given{
95 name: "basic",
96 tokenString: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
97 },
98 expected: expected{
99 keyFunc: defaultKeyFunc,
100 claims: MapClaims{"foo": "bar"},
101 valid: true,
102 errors: 0,
103 },
104 },
105 {
106 given: given{
107 name: "basic expired",
108 generate: &generate{
109 claims: MapClaims{"foo": "bar", "exp": time.Now().Unix() - 100},
110 },
111 },
112 expected: expected{
113 keyFunc: defaultKeyFunc,
114 claims: MapClaims{"foo": "bar", "exp": time.Now().Unix() - 100},
115 valid: false,
116 errors: ValidationErrorExpired,
117 },
118 },
119 {
120 given: given{
121 name: "basic nbf",
122 generate: &generate{
123 claims: MapClaims{"foo": "bar", "nbf": time.Now().Unix() + 100},
124 },
125 },
126 expected: expected{
127 keyFunc: defaultKeyFunc,
128 claims: MapClaims{"foo": "bar", "nbf": time.Now().Unix() + 100},
129 valid: false,
130 errors: ValidationErrorNotValidYet,
131 },
132 },
133 {
134 given: given{
135 name: "expired and nbf",
136 generate: &generate{
137 claims: MapClaims{"foo": "bar", "nbf": time.Now().Unix() + 100, "exp": time.Now().Unix() - 100},
138 },
139 },
140 expected: expected{
141 keyFunc: defaultKeyFunc,
142 claims: MapClaims{"foo": "bar", "nbf": time.Now().Unix() + 100, "exp": time.Now().Unix() - 100},
143 valid: false,
144 errors: ValidationErrorNotValidYet | ValidationErrorExpired,
145 },
146 },
147 {
148 given: given{
149 name: "basic invalid",
150 tokenString: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
151 },
152 expected: expected{
153 keyFunc: defaultKeyFunc,
154 claims: MapClaims{"foo": "bar"},
155 valid: false,
156 errors: ValidationErrorSignatureInvalid,
157 },
158 },
159 {
160 given: given{
161 name: "basic nokeyfunc",
162 tokenString: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
163 },
164 expected: expected{
165 keyFunc: nilKeyFunc,
166 claims: MapClaims{"foo": "bar"},
167 valid: false,
168 errors: ValidationErrorUnverifiable,
169 },
170 },
171 {
172 given: given{
173 name: "basic nokey",
174 tokenString: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
175 },
176 expected: expected{
177 keyFunc: emptyKeyFunc,
178 claims: MapClaims{"foo": "bar"},
179 valid: false,
180 errors: ValidationErrorSignatureInvalid,
181 },
182 },
183 {
184 given: given{
185 name: "basic errorkey",
186 tokenString: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
187 generate: &generate{
188 claims: MapClaims{"foo": "bar"},
189 },
190 },
191 expected: expected{
192 keyFunc: errorKeyFunc,
193 claims: MapClaims{"foo": "bar"},
194 valid: false,
195 errors: ValidationErrorUnverifiable,
196 },
197 },
198 {
199 given: given{
200 name: "valid signing method",
201 generate: &generate{
202 claims: MapClaims{"foo": "bar"},
203 },
204 },
205 expected: expected{
206 keyFunc: defaultKeyFunc,
207 claims: MapClaims{"foo": "bar"},
208 valid: true,
209 errors: 0,
210 },
211 },
212 {
213 given: given{
214 name: "invalid",
215 tokenString: "foo_invalid_token",
216 },
217 expected: expected{
218 keyFunc: defaultKeyFunc,
219 claims: MapClaims(nil),
220 valid: false,
221 errors: ValidationErrorMalformed,
222 },
223 },
224 {
225 given: given{
226 name: "valid format invalid content",
227 tokenString: "foo.bar.baz",
228 },
229 expected: expected{
230 keyFunc: defaultKeyFunc,
231 claims: MapClaims(nil),
232 valid: false,
233 errors: ValidationErrorMalformed,
234 },
235 },
236 {
237 given: given{
238 name: "wrong key, expected ECDSA got RSA",
239 tokenString: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
240 },
241 expected: expected{
242 keyFunc: publicECDSAKey,
243 claims: MapClaims{"foo": "bar"},
244 valid: false,
245 errors: ValidationErrorSignatureInvalid,
246 },
247 },
248 {
249 given: given{
250 name: "should fail, got RSA but found no key",
251 tokenString: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
252 },
253 expected: expected{
254 keyFunc: emptyKeyFunc,
255 claims: MapClaims{"foo": "bar"},
256 valid: false,
257 errors: ValidationErrorSignatureInvalid,
258 },
259 },
260 {
261 given: given{
262 name: "key does not match",
263 tokenString: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg",
264 },
265 expected: expected{
266 keyFunc: randomKey,
267 claims: MapClaims{"foo": "bar"},
268 valid: false,
269 errors: ValidationErrorSignatureInvalid,
270 },
271 },
272 {
273 given: given{
274 name: "used before issued",
275 generate: &generate{
276 claims: MapClaims{"foo": "bar", "iat": time.Now().Unix() + 500},
277 },
278 },
279 expected: expected{
280 keyFunc: defaultKeyFunc,
281 claims: MapClaims{"foo": "bar", "iat": time.Now().Unix() + 500},
282 valid: false,
283 errors: ValidationErrorIssuedAt,
284 },
285 },
286 {
287 given: given{
288 name: "valid ECDSA signing method",
289 generate: &generate{
290 claims: MapClaims{"foo": "bar"},
291 signingKey: defaultES256PrivateKey,
292 method: jose.ES256,
293 },
294 },
295 expected: expected{
296 keyFunc: publicECDSAKey,
297 claims: MapClaims{"foo": "bar"},
298 valid: true,
299 errors: 0,
300 },
301 },
302 {
303 given: given{
304 name: "should pass, valid NONE signing method",
305 generate: &generate{
306 claims: MapClaims{"foo": "bar"},
307 signingKey: UnsafeAllowNoneSignatureType,
308 method: SigningMethodNone,
309 },
310 },
311 expected: expected{
312 keyFunc: noneKey,
313 claims: MapClaims{"foo": "bar"},
314 valid: true,
315 errors: 0,
316 },
317 },
318 {
319 given: given{
320 name: "should fail, expected RS256 but got NONE",
321 generate: &generate{
322 claims: MapClaims{"foo": "bar"},
323 signingKey: UnsafeAllowNoneSignatureType,
324 method: SigningMethodNone,
325 },
326 },
327 expected: expected{
328 keyFunc: defaultKeyFunc,
329 claims: MapClaims{"foo": "bar"},
330 valid: false,
331 errors: ValidationErrorSignatureInvalid,
332 },
333 },
334 {
335 given: given{
336 name: "should fail, expected ECDSA but got NONE",
337 generate: &generate{
338 claims: MapClaims{"foo": "bar"},
339 signingKey: UnsafeAllowNoneSignatureType,
340 method: SigningMethodNone,
341 },
342 },
343 expected: expected{
344 keyFunc: publicECDSAKey,
345 claims: MapClaims{"foo": "bar"},
346 valid: false,
347 errors: ValidationErrorSignatureInvalid,
348 },
349 },
350 }
351
352
353 for _, data := range jwtTestData {
354 t.Run(data.name, func(t *testing.T) {
355 if data.generate != nil {
356 signingKey := data.generate.signingKey
357 method := data.generate.method
358 if signingKey == nil {
359
360 signingKey = defaultSigningKey
361 method = jose.RS256
362 }
363 data.tokenString = makeSampleToken(data.generate.claims, method, signingKey)
364 }
365
366
367 var token *Token
368 var err error
369
370
371 token, err = ParseWithClaims(data.tokenString, MapClaims{}, data.keyFunc)
372
373 assert.EqualValues(t, data.claims, token.Claims)
374 if data.valid && err != nil {
375 t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err)
376 }
377
378 if !data.valid && err == nil {
379 t.Errorf("[%v] Invalid token passed validation", data.name)
380 }
381
382 if (err == nil && !token.Valid()) || (err != nil && token.Valid()) {
383 t.Errorf("[%v] Inconsistent behavior between returned error and token.Valid", data.name)
384 }
385
386 if data.errors != 0 {
387 if err == nil {
388 t.Errorf("[%v] Expecting error. Didn't get one.", data.name)
389 } else {
390
391 ve := err.(*ValidationError)
392
393 if e := ve.Errors; e != data.errors {
394 t.Errorf("[%v] Errors don't match expectation. %v != %v", data.name, e, data.errors)
395 }
396
397 if err.Error() == keyFuncError.Error() && ve.Inner != keyFuncError {
398 t.Errorf("[%v] Inner error does not match expectation. %v != %v", data.name, ve.Inner, keyFuncError)
399 }
400 }
401 }
402 })
403 }
404 }
405
406 func makeSampleToken(c MapClaims, m jose.SignatureAlgorithm, key interface{}) string {
407 token := NewWithClaims(m, c)
408 s, e := token.SignedString(key)
409
410 if e != nil {
411 panic(e.Error())
412 }
413
414 return s
415 }
416
417 func parseRSAPublicKeyFromPEM(key []byte) *rsa.PublicKey {
418 var err error
419
420
421 var block *pem.Block
422 if block, _ = pem.Decode(key); block == nil {
423 panic("not possible to decode")
424 }
425
426
427 var parsedKey interface{}
428 if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
429 if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
430 parsedKey = cert.PublicKey
431 } else {
432 panic(err)
433 }
434 }
435
436 var pkey *rsa.PublicKey
437 var ok bool
438 if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
439 panic("not an *rsa.PublicKey")
440 }
441
442 return pkey
443 }
444
445 func parseRSAPrivateKeyFromPEM(key []byte) *rsa.PrivateKey {
446 var err error
447
448
449 var block *pem.Block
450 if block, _ = pem.Decode(key); block == nil {
451 panic("unable to decode")
452 }
453
454 var parsedKey interface{}
455 if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
456 if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
457 panic(err)
458 }
459 }
460
461 var pkey *rsa.PrivateKey
462 var ok bool
463 if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
464 panic("not an rsa private key")
465 }
466
467 return pkey
468 }
469
470 var (
471 defaultPubKeyPEM = []byte(`
472 -----BEGIN PUBLIC KEY-----
473 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41
474 fGnJm6gOdrj8ym3rFkEU/wT8RDtnSgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7
475 mCpz9Er5qLaMXJwZxzHzAahlfA0icqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBp
476 HssPnpYGIn20ZZuNlX2BrClciHhCPUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2
477 XrHhR+1DcKJzQBSTAGnpYVaqpsARap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3b
478 ODIRe1AuTyHceAbewn8b462yEWKARdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy
479 7wIDAQAB
480 -----END PUBLIC KEY-----`)
481 defaultPrivateKeyPEM = []byte(`
482 -----BEGIN RSA PRIVATE KEY-----
483 MIIEowIBAAKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtn
484 SgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7mCpz9Er5qLaMXJwZxzHzAahlfA0i
485 cqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBpHssPnpYGIn20ZZuNlX2BrClciHhC
486 PUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2XrHhR+1DcKJzQBSTAGnpYVaqpsAR
487 ap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3bODIRe1AuTyHceAbewn8b462yEWKA
488 Rdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy7wIDAQABAoIBAQCwia1k7+2oZ2d3
489 n6agCAbqIE1QXfCmh41ZqJHbOY3oRQG3X1wpcGH4Gk+O+zDVTV2JszdcOt7E5dAy
490 MaomETAhRxB7hlIOnEN7WKm+dGNrKRvV0wDU5ReFMRHg31/Lnu8c+5BvGjZX+ky9
491 POIhFFYJqwCRlopGSUIxmVj5rSgtzk3iWOQXr+ah1bjEXvlxDOWkHN6YfpV5ThdE
492 KdBIPGEVqa63r9n2h+qazKrtiRqJqGnOrHzOECYbRFYhexsNFz7YT02xdfSHn7gM
493 IvabDDP/Qp0PjE1jdouiMaFHYnLBbgvlnZW9yuVf/rpXTUq/njxIXMmvmEyyvSDn
494 FcFikB8pAoGBAPF77hK4m3/rdGT7X8a/gwvZ2R121aBcdPwEaUhvj/36dx596zvY
495 mEOjrWfZhF083/nYWE2kVquj2wjs+otCLfifEEgXcVPTnEOPO9Zg3uNSL0nNQghj
496 FuD3iGLTUBCtM66oTe0jLSslHe8gLGEQqyMzHOzYxNqibxcOZIe8Qt0NAoGBAO+U
497 I5+XWjWEgDmvyC3TrOSf/KCGjtu0TSv30ipv27bDLMrpvPmD/5lpptTFwcxvVhCs
498 2b+chCjlghFSWFbBULBrfci2FtliClOVMYrlNBdUSJhf3aYSG2Doe6Bgt1n2CpNn
499 /iu37Y3NfemZBJA7hNl4dYe+f+uzM87cdQ214+jrAoGAXA0XxX8ll2+ToOLJsaNT
500 OvNB9h9Uc5qK5X5w+7G7O998BN2PC/MWp8H+2fVqpXgNENpNXttkRm1hk1dych86
501 EunfdPuqsX+as44oCyJGFHVBnWpm33eWQw9YqANRI+pCJzP08I5WK3osnPiwshd+
502 hR54yjgfYhBFNI7B95PmEQkCgYBzFSz7h1+s34Ycr8SvxsOBWxymG5zaCsUbPsL0
503 4aCgLScCHb9J+E86aVbbVFdglYa5Id7DPTL61ixhl7WZjujspeXZGSbmq0Kcnckb
504 mDgqkLECiOJW2NHP/j0McAkDLL4tysF8TLDO8gvuvzNC+WQ6drO2ThrypLVZQ+ry
505 eBIPmwKBgEZxhqa0gVvHQG/7Od69KWj4eJP28kq13RhKay8JOoN0vPmspXJo1HY3
506 CKuHRG+AP579dncdUnOMvfXOtkdM4vk0+hWASBQzM9xzVcztCa+koAugjVaLS9A+
507 9uQoqEeVNTckxx0S2bYevRy7hGQmUJTyQm3j1zEUR5jpdbL83Fbq
508 -----END RSA PRIVATE KEY-----`)
509 )
510
View as plain text