1package transit 2 3import ( 4 "context" 5 "encoding/base64" 6 "fmt" 7 "strconv" 8 "strings" 9 "testing" 10 11 "golang.org/x/crypto/ed25519" 12 13 "github.com/hashicorp/vault/sdk/helper/keysutil" 14 "github.com/hashicorp/vault/sdk/logical" 15 "github.com/mitchellh/mapstructure" 16) 17 18// The outcome of processing a request includes 19// the possibility that the request is incomplete or incorrect, 20// or that the request is well-formed but the signature (for verification) 21// is invalid, or that the signature is valid, but the key is not. 22type signOutcome struct { 23 requestOk bool 24 valid bool 25 keyValid bool 26} 27 28func TestTransit_SignVerify_ECDSA(t *testing.T) { 29 t.Run("256", func(t *testing.T) { 30 testTransit_SignVerify_ECDSA(t, 256) 31 }) 32 t.Run("384", func(t *testing.T) { 33 testTransit_SignVerify_ECDSA(t, 384) 34 }) 35 t.Run("521", func(t *testing.T) { 36 testTransit_SignVerify_ECDSA(t, 521) 37 }) 38} 39 40func testTransit_SignVerify_ECDSA(t *testing.T, bits int) { 41 b, storage := createBackendWithSysView(t) 42 43 // First create a key 44 req := &logical.Request{ 45 Storage: storage, 46 Operation: logical.UpdateOperation, 47 Path: "keys/foo", 48 Data: map[string]interface{}{ 49 "type": fmt.Sprintf("ecdsa-p%d", bits), 50 }, 51 } 52 _, err := b.HandleRequest(context.Background(), req) 53 if err != nil { 54 t.Fatal(err) 55 } 56 57 // Now, change the key value to something we control 58 p, _, err := b.lm.GetPolicy(context.Background(), keysutil.PolicyRequest{ 59 Storage: storage, 60 Name: "foo", 61 }, b.GetRandomReader()) 62 if err != nil { 63 t.Fatal(err) 64 } 65 66 // Useful code to output a key for openssl verification 67 /* 68 if bits == 384 { 69 var curve elliptic.Curve 70 switch bits { 71 case 521: 72 curve = elliptic.P521() 73 case 384: 74 curve = elliptic.P384() 75 default: 76 curve = elliptic.P256() 77 } 78 key := p.Keys[strconv.Itoa(p.LatestVersion)] 79 keyBytes, _ := x509.MarshalECPrivateKey(&ecdsa.PrivateKey{ 80 PublicKey: ecdsa.PublicKey{ 81 Curve: curve, 82 X: key.EC_X, 83 Y: key.EC_Y, 84 }, 85 D: key.EC_D, 86 }) 87 pemBlock := &pem.Block{ 88 Type: "EC PRIVATE KEY", 89 Bytes: keyBytes, 90 } 91 pemBytes := pem.EncodeToMemory(pemBlock) 92 t.Fatalf("X: %s, Y: %s, D: %s, marshaled: %s", key.EC_X.Text(16), key.EC_Y.Text(16), key.EC_D.Text(16), string(pemBytes)) 93 } 94 */ 95 96 var xString, yString, dString string 97 switch bits { 98 case 384: 99 xString = "703457a84e48bfcb037cfb509f1870d2aa5b74c109c2f24624ab21444492575229f8711453e5c656dab596b4e26db30e" 100 yString = "411c5b7092a893dc8b7af39de3d21d1c26f45b27616baeac4c479ef3c9f21c194b5ac501dee47ba2b2cb243a54256524" 101 dString = "3de3e4fd2ecbc490e956f41f5003a1e57a84763cec7b722fa3427cf461a1148ea4d5206023bcce0422289f6633730759" 102 /* 103 -----BEGIN EC PRIVATE KEY----- 104 MIGkAgEBBDA94+T9LsvEkOlW9B9QA6HleoR2POx7ci+jQnz0YaEUjqTVIGAjvM4E 105 IiifZjNzB1mgBwYFK4EEACKhZANiAARwNFeoTki/ywN8+1CfGHDSqlt0wQnC8kYk 106 qyFERJJXUin4cRRT5cZW2rWWtOJtsw5BHFtwkqiT3It6853j0h0cJvRbJ2FrrqxM 107 R57zyfIcGUtaxQHe5HuissskOlQlZSQ= 108 -----END EC PRIVATE KEY----- 109 */ 110 case 521: 111 xString = "1913f75fc044fe5d1f871c2629a377462fd819b174a41d3ec7d04ebd5ae35475ff8de544f4e19a9aa6b16a8f67af479be6884e00ca3147dc24d5924d66ac395e04b" 112 yString = "4919406b90d8323fdb5c9c4f48259c56ebcea37b40ad1a82bbbfad62a9b9c2dce515772274b84725471c7d0b7c62e10c23296b1a9d2b2586ada67735ff5d9fffc4" 113 dString = "1867d0fcd9bac4c5821b70a6b13117499438f8c274579c0aba254fbd85fa98892c3608576197d5534366a9aab0f904155bec46d800d23a57f7f053d91526568b09" 114 /* 115 -----BEGIN EC PRIVATE KEY----- 116 MIHcAgEBBEIAGGfQ/Nm6xMWCG3CmsTEXSZQ4+MJ0V5wKuiVPvYX6mIksNghXYZfV 117 U0Nmqaqw+QQVW+xG2ADSOlf38FPZFSZWiwmgBwYFK4EEACOhgYkDgYYABAGRP3X8 118 BE/l0fhxwmKaN3Ri/YGbF0pB0+x9BOvVrjVHX/jeVE9OGamqaxao9nr0eb5ohOAM 119 oxR9wk1ZJNZqw5XgSwBJGUBrkNgyP9tcnE9IJZxW686je0CtGoK7v61iqbnC3OUV 120 dyJ0uEclRxx9C3xi4QwjKWsanSslhq2mdzX/XZ//xA== 121 -----END EC PRIVATE KEY----- 122 */ 123 default: 124 xString = "7336010a6da5935113d26d9ea4bb61b3b8d102c9a8083ed432f9b58fd7e80686" 125 yString = "4040aa31864691a8a9e7e3ec9250e85425b797ad7be34ba8df62bfbad45ebb0e" 126 dString = "99e5569be8683a2691dfc560ca9dfa71e887867a3af60635a08a3e3655aba3ef" 127 } 128 129 keyEntry := p.Keys[strconv.Itoa(p.LatestVersion)] 130 _, ok := keyEntry.EC_X.SetString(xString, 16) 131 if !ok { 132 t.Fatal("could not set X") 133 } 134 _, ok = keyEntry.EC_Y.SetString(yString, 16) 135 if !ok { 136 t.Fatal("could not set Y") 137 } 138 _, ok = keyEntry.EC_D.SetString(dString, 16) 139 if !ok { 140 t.Fatal("could not set D") 141 } 142 p.Keys[strconv.Itoa(p.LatestVersion)] = keyEntry 143 if err = p.Persist(context.Background(), storage); err != nil { 144 t.Fatal(err) 145 } 146 req.Data = map[string]interface{}{ 147 "input": "dGhlIHF1aWNrIGJyb3duIGZveA==", 148 } 149 150 signRequest := func(req *logical.Request, errExpected bool, postpath string) string { 151 t.Helper() 152 req.Path = "sign/foo" + postpath 153 resp, err := b.HandleRequest(context.Background(), req) 154 if err != nil && !errExpected { 155 t.Fatal(err) 156 } 157 if resp == nil { 158 t.Fatal("expected non-nil response") 159 } 160 if errExpected { 161 if !resp.IsError() { 162 t.Fatalf("bad: should have gotten error response: %#v", *resp) 163 } 164 return "" 165 } 166 if resp.IsError() { 167 t.Fatalf("bad: got error response: %#v", *resp) 168 } 169 value, ok := resp.Data["signature"] 170 if !ok { 171 t.Fatalf("no signature key found in returned data, got resp data %#v", resp.Data) 172 } 173 return value.(string) 174 } 175 176 verifyRequest := func(req *logical.Request, errExpected bool, postpath, sig string) { 177 t.Helper() 178 req.Path = "verify/foo" + postpath 179 req.Data["signature"] = sig 180 resp, err := b.HandleRequest(context.Background(), req) 181 if err != nil && !errExpected { 182 t.Fatalf("got error: %v, sig was %v", err, sig) 183 } 184 if errExpected { 185 if resp != nil && !resp.IsError() { 186 t.Fatalf("bad: should have gotten error response: %#v", *resp) 187 } 188 return 189 } 190 if resp == nil { 191 t.Fatal("expected non-nil response") 192 } 193 if resp.IsError() { 194 t.Fatalf("bad: got error response: %#v", *resp) 195 } 196 value, ok := resp.Data["valid"] 197 if !ok { 198 t.Fatalf("no valid key found in returned data, got resp data %#v", resp.Data) 199 } 200 if !value.(bool) && !errExpected { 201 t.Fatalf("verification failed; req was %#v, resp is %#v", *req, *resp) 202 } 203 } 204 205 // Comparisons are against values generated via openssl 206 207 // Test defaults -- sha2-256 208 sig := signRequest(req, false, "") 209 verifyRequest(req, false, "", sig) 210 211 // Test a bad signature 212 verifyRequest(req, true, "", sig[0:len(sig)-2]) 213 214 // Test a signature generated with the same key by openssl 215 switch bits { 216 case 384: 217 sig = `vault:v1:MGUCMHHZLRN/3ehWuWACfSCMLtFtNEAdx6Rkwon2Lx6FWCyXCXqH6A8Pz8er0Qkgvm2ElQIxAO922LmUeYzHmDSfC5is/TjFu3b4Fb+1XtoBXncc2u4t2vSuTAxEv7WMh2D2YDdxeA==` 218 case 521: 219 sig = `vault:v1:MIGIAkIBYhspOgSs/K/NUWtlBN+CfYe1IVFpUbQNSqdjT7s+QKcr6GKmdGLIQAXw0q6K0elBgzi1wgLjxwdscwMeW7tm/QQCQgDzdITGlUEd9Z7DOfLCnDP4X8pGsfO60Tvsh/BN44drZsHLtXYBXLczB/XZfIWAsPMuI5F7ExwVNbmQP0FBVri/QQ==` 220 default: 221 sig = `vault:v1:MEUCIAgnEl9V8P305EBAlz68Nq4jZng5fE8k6MactcnlUw9dAiEAvJVePg3dazW6MaW7lRAVtEz82QJDVmR98tXCl8Pc7DA=` 222 } 223 verifyRequest(req, false, "", sig) 224 225 // Test algorithm selection in the path 226 sig = signRequest(req, false, "/sha2-224") 227 verifyRequest(req, false, "/sha2-224", sig) 228 229 // Reset and test algorithm selection in the data 230 req.Data["hash_algorithm"] = "sha2-224" 231 sig = signRequest(req, false, "") 232 verifyRequest(req, false, "", sig) 233 234 req.Data["hash_algorithm"] = "sha2-384" 235 sig = signRequest(req, false, "") 236 verifyRequest(req, false, "", sig) 237 238 req.Data["prehashed"] = true 239 sig = signRequest(req, false, "") 240 verifyRequest(req, false, "", sig) 241 delete(req.Data, "prehashed") 242 243 // Test marshaling selection 244 // Bad value 245 req.Data["marshaling_algorithm"] = "asn2" 246 sig = signRequest(req, true, "") 247 // Use the default, verify we can't validate with jws 248 req.Data["marshaling_algorithm"] = "asn1" 249 sig = signRequest(req, false, "") 250 req.Data["marshaling_algorithm"] = "jws" 251 verifyRequest(req, true, "", sig) 252 // Sign with jws, verify we can validate 253 sig = signRequest(req, false, "") 254 verifyRequest(req, false, "", sig) 255 // If we change marshaling back to asn1 we shouldn't be able to verify 256 delete(req.Data, "marshaling_algorithm") 257 verifyRequest(req, true, "", sig) 258 259 // Test 512 and save sig for later to ensure we can't validate once min 260 // decryption version is set 261 req.Data["hash_algorithm"] = "sha2-512" 262 sig = signRequest(req, false, "") 263 verifyRequest(req, false, "", sig) 264 265 v1sig := sig 266 267 // Test bad algorithm 268 req.Data["hash_algorithm"] = "foobar" 269 signRequest(req, true, "") 270 271 // Test bad input 272 req.Data["hash_algorithm"] = "sha2-256" 273 req.Data["input"] = "foobar" 274 signRequest(req, true, "") 275 276 // Rotate and set min decryption version 277 err = p.Rotate(context.Background(), storage, b.GetRandomReader()) 278 if err != nil { 279 t.Fatal(err) 280 } 281 err = p.Rotate(context.Background(), storage, b.GetRandomReader()) 282 if err != nil { 283 t.Fatal(err) 284 } 285 286 p.MinDecryptionVersion = 2 287 if err = p.Persist(context.Background(), storage); err != nil { 288 t.Fatal(err) 289 } 290 291 req.Data["input"] = "dGhlIHF1aWNrIGJyb3duIGZveA==" 292 req.Data["hash_algorithm"] = "sha2-256" 293 // Make sure signing still works fine 294 sig = signRequest(req, false, "") 295 verifyRequest(req, false, "", sig) 296 // Now try the v1 297 verifyRequest(req, true, "", v1sig) 298} 299 300func validatePublicKey(t *testing.T, in string, sig string, pubKeyRaw []byte, expectValid bool, postpath string, b *backend) { 301 t.Helper() 302 input, _ := base64.StdEncoding.DecodeString(in) 303 splitSig := strings.Split(sig, ":") 304 signature, _ := base64.StdEncoding.DecodeString(splitSig[2]) 305 valid := ed25519.Verify(ed25519.PublicKey(pubKeyRaw), input, signature) 306 if valid != expectValid { 307 t.Fatalf("status of signature: expected %v. Got %v", valid, expectValid) 308 } 309 if !valid { 310 return 311 } 312 313 keyReadReq := &logical.Request{ 314 Operation: logical.ReadOperation, 315 Path: "keys/" + postpath, 316 } 317 keyReadResp, err := b.HandleRequest(context.Background(), keyReadReq) 318 if err != nil { 319 t.Fatal(err) 320 } 321 val := keyReadResp.Data["keys"].(map[string]map[string]interface{})[strings.TrimPrefix(splitSig[1], "v")] 322 var ak asymKey 323 if err := mapstructure.Decode(val, &ak); err != nil { 324 t.Fatal(err) 325 } 326 if ak.PublicKey != "" { 327 t.Fatal("got non-empty public key") 328 } 329 keyReadReq.Data = map[string]interface{}{ 330 "context": "abcd", 331 } 332 keyReadResp, err = b.HandleRequest(context.Background(), keyReadReq) 333 if err != nil { 334 t.Fatal(err) 335 } 336 val = keyReadResp.Data["keys"].(map[string]map[string]interface{})[strings.TrimPrefix(splitSig[1], "v")] 337 if err := mapstructure.Decode(val, &ak); err != nil { 338 t.Fatal(err) 339 } 340 if ak.PublicKey != base64.StdEncoding.EncodeToString(pubKeyRaw) { 341 t.Fatalf("got incorrect public key; got %q, expected %q\nasymKey struct is\n%#v", ak.PublicKey, pubKeyRaw, ak) 342 } 343} 344 345func TestTransit_SignVerify_ED25519(t *testing.T) { 346 b, storage := createBackendWithSysView(t) 347 348 // First create a key 349 req := &logical.Request{ 350 Storage: storage, 351 Operation: logical.UpdateOperation, 352 Path: "keys/foo", 353 Data: map[string]interface{}{ 354 "type": "ed25519", 355 }, 356 } 357 _, err := b.HandleRequest(context.Background(), req) 358 if err != nil { 359 t.Fatal(err) 360 } 361 362 // Now create a derived key" 363 req = &logical.Request{ 364 Storage: storage, 365 Operation: logical.UpdateOperation, 366 Path: "keys/bar", 367 Data: map[string]interface{}{ 368 "type": "ed25519", 369 "derived": true, 370 }, 371 } 372 _, err = b.HandleRequest(context.Background(), req) 373 if err != nil { 374 t.Fatal(err) 375 } 376 377 // Get the keys for later 378 fooP, _, err := b.lm.GetPolicy(context.Background(), keysutil.PolicyRequest{ 379 Storage: storage, 380 Name: "foo", 381 }, b.GetRandomReader()) 382 if err != nil { 383 t.Fatal(err) 384 } 385 386 barP, _, err := b.lm.GetPolicy(context.Background(), keysutil.PolicyRequest{ 387 Storage: storage, 388 Name: "bar", 389 }, b.GetRandomReader()) 390 if err != nil { 391 t.Fatal(err) 392 } 393 394 signRequest := func(req *logical.Request, errExpected bool, postpath string) []string { 395 t.Helper() 396 // Delete any key that exists in the request 397 delete(req.Data, "public_key") 398 req.Path = "sign/" + postpath 399 resp, err := b.HandleRequest(context.Background(), req) 400 if err != nil { 401 if !errExpected { 402 t.Fatal(err) 403 } 404 return nil 405 } 406 if resp == nil { 407 t.Fatal("expected non-nil response") 408 } 409 if errExpected { 410 if resp.IsError() { 411 return nil 412 } 413 t.Fatalf("bad: expected error response, got: %#v", *resp) 414 } 415 if resp.IsError() { 416 t.Fatalf("bad: got error response: %#v", *resp) 417 } 418 // memoize any pubic key 419 if key, ok := resp.Data["public_key"]; ok { 420 req.Data["public_key"] = key 421 } 422 // batch_input supplied 423 if _, ok := req.Data["batch_input"]; ok { 424 batchRequestItems := req.Data["batch_input"].([]batchRequestSignItem) 425 426 batchResults, ok := resp.Data["batch_results"] 427 if !ok { 428 t.Fatalf("no batch_results in returned data, got resp data %#v", resp.Data) 429 } 430 batchResponseItems := batchResults.([]batchResponseSignItem) 431 if len(batchResponseItems) != len(batchRequestItems) { 432 t.Fatalf("Expected %d items in response. Got %d: %#v", len(batchRequestItems), len(batchResponseItems), resp) 433 } 434 if len(batchRequestItems) == 0 { 435 return nil 436 } 437 ret := make([]string, len(batchRequestItems)) 438 for i, v := range batchResponseItems { 439 ret[i] = v.Signature 440 } 441 return ret 442 } 443 444 // input supplied 445 value, ok := resp.Data["signature"] 446 if !ok { 447 t.Fatalf("no signature key found in returned data, got resp data %#v", resp.Data) 448 } 449 return []string{value.(string)} 450 } 451 452 verifyRequest := func(req *logical.Request, errExpected bool, outcome []signOutcome, postpath string, sig []string, attachSig bool) { 453 t.Helper() 454 req.Path = "verify/" + postpath 455 if _, ok := req.Data["batch_input"]; ok && attachSig { 456 batchRequestItems := req.Data["batch_input"].([]batchRequestSignItem) 457 if len(batchRequestItems) != len(sig) { 458 t.Fatalf("number of requests in batch(%d) != number of signatures(%d)", len(batchRequestItems), len(sig)) 459 } 460 for i, v := range sig { 461 batchRequestItems[i]["signature"] = v 462 } 463 } else if attachSig { 464 req.Data["signature"] = sig[0] 465 } 466 resp, err := b.HandleRequest(context.Background(), req) 467 if err != nil && !errExpected { 468 t.Fatalf("got error: %v, sig was %v", err, sig) 469 } 470 if errExpected { 471 if resp != nil && !resp.IsError() { 472 t.Fatalf("bad: expected error response, got: %#v\n%#v", *resp, req) 473 } 474 return 475 } 476 if resp == nil { 477 t.Fatal("expected non-nil response") 478 } 479 if resp.IsError() { 480 t.Fatalf("bad: got error response: %#v", *resp) 481 } 482 483 // batch_input field supplied 484 if _, ok := req.Data["batch_input"]; ok { 485 batchRequestItems := req.Data["batch_input"].([]batchRequestSignItem) 486 487 batchResults, ok := resp.Data["batch_results"] 488 if !ok { 489 t.Fatalf("no batch_results in returned data, got resp data %#v", resp.Data) 490 } 491 batchResponseItems := batchResults.([]batchResponseVerifyItem) 492 if len(batchResponseItems) != len(batchRequestItems) { 493 t.Fatalf("Expected %d items in response. Got %d: %#v", len(batchRequestItems), len(batchResponseItems), resp) 494 } 495 if len(batchRequestItems) == 0 { 496 return 497 } 498 for i, v := range batchResponseItems { 499 if v.Error != "" && outcome[i].requestOk { 500 t.Fatalf("verification failed; req was %#v, resp is %#v", *req, *resp) 501 } 502 if v.Error != "" { 503 continue 504 } 505 if v.Valid != outcome[i].valid { 506 t.Fatalf("verification failed; req was %#v, resp is %#v", *req, *resp) 507 } 508 if !v.Valid { 509 continue 510 } 511 if pubKeyRaw, ok := req.Data["public_key"]; ok { 512 validatePublicKey(t, batchRequestItems[i]["input"], sig[i], pubKeyRaw.([]byte), outcome[i].keyValid, postpath, b) 513 } 514 } 515 return 516 } 517 518 // input field supplied 519 value, ok := resp.Data["valid"] 520 if !ok { 521 t.Fatalf("no valid key found in returned data, got resp data %#v", resp.Data) 522 } 523 valid := value.(bool) 524 if valid != outcome[0].valid { 525 t.Fatalf("verification failed; req was %#v, resp is %#v", *req, *resp) 526 } 527 if !valid { 528 return 529 } 530 531 if pubKeyRaw, ok := req.Data["public_key"]; ok { 532 validatePublicKey(t, req.Data["input"].(string), sig[0], pubKeyRaw.([]byte), outcome[0].keyValid, postpath, b) 533 } 534 } 535 536 req.Data = map[string]interface{}{ 537 "input": "dGhlIHF1aWNrIGJyb3duIGZveA==", 538 "context": "abcd", 539 } 540 541 outcome := []signOutcome{{requestOk: true, valid: true, keyValid: true}} 542 // Test defaults 543 sig := signRequest(req, false, "foo") 544 verifyRequest(req, false, outcome, "foo", sig, true) 545 546 sig = signRequest(req, false, "bar") 547 verifyRequest(req, false, outcome, "bar", sig, true) 548 549 // Verify with incorrect key 550 outcome[0].valid = false 551 verifyRequest(req, false, outcome, "foo", sig, true) 552 553 // Verify with missing signatures 554 delete(req.Data, "signature") 555 verifyRequest(req, true, outcome, "foo", sig, false) 556 557 // Test a bad signature 558 badsig := sig[0] 559 badsig = badsig[:len(badsig)-2] 560 verifyRequest(req, true, outcome, "bar", []string{badsig}, true) 561 562 v1sig := sig 563 564 // Test a missing context 565 delete(req.Data, "context") 566 sig = signRequest(req, true, "bar") 567 568 // Rotate and set min decryption version 569 err = fooP.Rotate(context.Background(), storage, b.GetRandomReader()) 570 if err != nil { 571 t.Fatal(err) 572 } 573 err = fooP.Rotate(context.Background(), storage, b.GetRandomReader()) 574 if err != nil { 575 t.Fatal(err) 576 } 577 fooP.MinDecryptionVersion = 2 578 if err = fooP.Persist(context.Background(), storage); err != nil { 579 t.Fatal(err) 580 } 581 err = barP.Rotate(context.Background(), storage, b.GetRandomReader()) 582 if err != nil { 583 t.Fatal(err) 584 } 585 err = barP.Rotate(context.Background(), storage, b.GetRandomReader()) 586 if err != nil { 587 t.Fatal(err) 588 } 589 barP.MinDecryptionVersion = 2 590 if err = barP.Persist(context.Background(), storage); err != nil { 591 t.Fatal(err) 592 } 593 594 req.Data = map[string]interface{}{ 595 "input": "dGhlIHF1aWNrIGJyb3duIGZveA==", 596 "context": "abcd", 597 } 598 599 // Make sure signing still works fine 600 sig = signRequest(req, false, "foo") 601 outcome[0].valid = true 602 verifyRequest(req, false, outcome, "foo", sig, true) 603 // Now try the v1 604 verifyRequest(req, true, outcome, "foo", v1sig, true) 605 606 // Repeat with the other key 607 sig = signRequest(req, false, "bar") 608 verifyRequest(req, false, outcome, "bar", sig, true) 609 verifyRequest(req, true, outcome, "bar", v1sig, true) 610 611 // Test Batch Signing 612 batchInput := []batchRequestSignItem{ 613 {"context": "abcd", "input": "dGhlIHF1aWNrIGJyb3duIGZveA=="}, 614 {"context": "efgh", "input": "dGhlIHF1aWNrIGJyb3duIGZveA=="}, 615 } 616 617 req.Data = map[string]interface{}{ 618 "batch_input": batchInput, 619 } 620 621 outcome = []signOutcome{{requestOk: true, valid: true, keyValid: true}, {requestOk: true, valid: true, keyValid: true}} 622 623 sig = signRequest(req, false, "foo") 624 verifyRequest(req, false, outcome, "foo", sig, true) 625 626 goodsig := signRequest(req, false, "bar") 627 verifyRequest(req, false, outcome, "bar", goodsig, true) 628 629 // key doesn't match signatures 630 outcome[0].valid = false 631 outcome[1].valid = false 632 verifyRequest(req, false, outcome, "foo", goodsig, true) 633 634 // Test a bad signature 635 badsig = sig[0] 636 badsig = badsig[:len(badsig)-2] 637 // matching key, but first signature is corrupted 638 outcome[0].requestOk = false 639 outcome[1].valid = true 640 verifyRequest(req, false, outcome, "bar", []string{badsig, goodsig[1]}, true) 641 642 // Verify with missing signatures 643 outcome[0].valid = false 644 outcome[1].valid = false 645 delete(batchInput[0], "signature") 646 delete(batchInput[1], "signature") 647 verifyRequest(req, true, outcome, "foo", sig, false) 648 649 // Test missing context 650 batchInput = []batchRequestSignItem{ 651 {"context": "abcd", "input": "dGhlIHF1aWNrIGJyb3duIGZveA=="}, 652 {"input": "dGhlIHF1aWNrIGJyb3duIGZveA=="}, 653 } 654 655 req.Data = map[string]interface{}{ 656 "batch_input": batchInput, 657 } 658 659 sig = signRequest(req, false, "bar") 660 661 outcome[0].requestOk = true 662 outcome[0].valid = true 663 outcome[1].requestOk = false 664 verifyRequest(req, false, outcome, "bar", goodsig, true) 665 666 // Test incorrect context 667 batchInput = []batchRequestSignItem{ 668 {"context": "abca", "input": "dGhlIHF1aWNrIGJyb3duIGZveA=="}, 669 {"context": "efga", "input": "dGhlIHF1aWNrIGJyb3duIGZveA=="}, 670 } 671 req.Data = map[string]interface{}{ 672 "batch_input": batchInput, 673 } 674 675 outcome[0].requestOk = true 676 outcome[0].valid = false 677 outcome[1].requestOk = true 678 outcome[1].valid = false 679 verifyRequest(req, false, outcome, "bar", goodsig, true) 680} 681