github.com/trustbloc/kms-go@v1.1.2/crypto/webkms/remotecrypto.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package webkms 8 9 import ( 10 "bytes" 11 "crypto/sha256" 12 "encoding/json" 13 "errors" 14 "fmt" 15 "io" 16 "io/ioutil" 17 "log" 18 "net/http" 19 "os" 20 "strings" 21 "time" 22 23 "github.com/bluele/gcache" 24 "github.com/google/tink/go/keyset" 25 26 cryptoapi "github.com/trustbloc/kms-go/spi/crypto" 27 28 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite/keyio" 29 webkmsimpl "github.com/trustbloc/kms-go/kms/webkms" 30 ) 31 32 const ( 33 logPrefix = " [kms-go/crypto/webkms] " 34 ) 35 36 var errorLogger = log.New(os.Stderr, logPrefix, log.Ldate|log.Ltime|log.LUTC) 37 var debugLogger = log.New(io.Discard, logPrefix, log.Ldate|log.Ltime|log.LUTC) 38 39 // SetDebugOutput used to set output of debug logs. 40 func SetDebugOutput(out io.Writer) { 41 debugLogger.SetOutput(out) 42 } 43 44 // HTTPClient interface for the http client. 45 type HTTPClient interface { 46 Do(req *http.Request) (*http.Response, error) 47 } 48 49 type encryptReq struct { 50 Message []byte `json:"message"` 51 AssociatedData []byte `json:"associated_data,omitempty"` 52 } 53 54 type encryptResp struct { 55 Ciphertext []byte `json:"ciphertext"` 56 Nonce []byte `json:"nonce"` 57 } 58 59 type decryptReq struct { 60 Ciphertext []byte `json:"ciphertext"` 61 AssociatedData []byte `json:"associated_data,omitempty"` 62 Nonce []byte `json:"nonce"` 63 } 64 65 type decryptResp struct { 66 Plaintext []byte `json:"plaintext"` 67 } 68 69 type signReq struct { 70 Message []byte `json:"message"` 71 } 72 73 type signResp struct { 74 Signature []byte `json:"signature"` 75 } 76 77 type signMultiReq struct { 78 Messages [][]byte `json:"messages"` 79 } 80 81 type deriveProofReq struct { 82 Messages [][]byte `json:"messages"` 83 Signature []byte `json:"signature"` 84 Nonce []byte `json:"nonce"` 85 RevealedIndexes []int `json:"revealed_indexes"` 86 } 87 88 type deriveProofResp struct { 89 Proof []byte `json:"proof"` 90 } 91 92 type verifyReq struct { 93 Signature []byte `json:"signature"` 94 Message []byte `json:"message"` 95 } 96 97 type verifyProofReq struct { 98 Proof []byte `json:"proof"` 99 Messages [][]byte `json:"messages"` 100 Nonce []byte `json:"nonce"` 101 } 102 103 type verifyMultiReq struct { 104 Signature []byte `json:"signature"` 105 Messages [][]byte `json:"messages"` 106 } 107 108 type computeMACReq struct { 109 Data []byte `json:"data"` 110 } 111 112 type computeMACResp struct { 113 MAC []byte `json:"mac"` 114 } 115 116 type verifyMACReq struct { 117 MAC []byte `json:"mac"` 118 Data []byte `json:"data"` 119 } 120 121 // wrapKeyReq serializable WrapKey request. 122 type wrapKeyReq struct { 123 CEK []byte `json:"cek"` 124 APU []byte `json:"apu"` 125 APV []byte `json:"apv"` 126 RecipientPubKey *cryptoapi.PublicKey `json:"recipient_pub_key"` 127 Tag []byte `json:"tag,omitempty"` 128 } 129 130 // wrapKeyResp serializable WrapKey response. 131 type wrapKeyResp struct { 132 cryptoapi.RecipientWrappedKey 133 } 134 135 // unwrapKeyReq serializable UnwrapKey request. 136 type unwrapKeyReq struct { 137 WrappedKey cryptoapi.RecipientWrappedKey `json:"wrapped_key"` 138 SenderPubKey *cryptoapi.PublicKey `json:"sender_pub_key,omitempty"` 139 Tag []byte `json:"tag,omitempty"` 140 } 141 142 // unwrapKeyResp serializable UnwrapKey response. 143 type unwrapKeyResp struct { 144 Key []byte `json:"key"` 145 } 146 147 type marshalFunc func(interface{}) ([]byte, error) 148 149 type unmarshalFunc func([]byte, interface{}) error 150 151 // RemoteCrypto implementation of kms.KeyManager api. 152 type RemoteCrypto struct { 153 httpClient HTTPClient 154 keystoreURL string 155 marshalFunc marshalFunc 156 unmarshalFunc unmarshalFunc 157 opts *webkmsimpl.Opts 158 } 159 160 const ( 161 keysURI = "/keys" 162 encryptURI = "/encrypt" 163 decryptURI = "/decrypt" 164 signURI = "/sign" 165 verifyURI = "/verify" 166 computeMACURI = "/computemac" 167 verifyMACURI = "/verifymac" 168 wrapURI = "/wrap" 169 unwrapURI = "/unwrap" 170 171 // multi signatures/selective disclosure crypto (eg BBS+) endpoints. 172 signMultiURI = "/signmulti" 173 verifyMultiURI = "/verifymulti" 174 deriveProofURI = "/deriveproof" 175 verifyProofURI = "/verifyproof" 176 ) 177 178 // New creates a new remoteCrypto instance using http client connecting to keystoreURL. 179 func New(keystoreURL string, client HTTPClient, opts ...webkmsimpl.Opt) *RemoteCrypto { 180 rOpts := webkmsimpl.NewOpt() 181 182 for _, opt := range opts { 183 opt(rOpts) 184 } 185 186 return &RemoteCrypto{ 187 httpClient: client, 188 keystoreURL: keystoreURL, 189 marshalFunc: json.Marshal, 190 unmarshalFunc: json.Unmarshal, 191 opts: rOpts, 192 } 193 } 194 195 func (r *RemoteCrypto) postHTTPRequest(destination string, mReq []byte) (*http.Response, error) { 196 return r.doHTTPRequest(http.MethodPost, destination, mReq) 197 } 198 199 func (r *RemoteCrypto) doHTTPRequest(method, destination string, mReq []byte) (*http.Response, error) { 200 start := time.Now() 201 202 var body io.Reader 203 204 if mReq != nil { 205 body = bytes.NewBuffer(mReq) 206 } 207 208 httpReq, err := http.NewRequest(method, destination, body) 209 if err != nil { 210 return nil, fmt.Errorf("build request error: %w", err) 211 } 212 213 if method == http.MethodPost { 214 httpReq.Header.Set("Content-Type", webkmsimpl.ContentType) 215 } 216 217 if r.opts.HeadersFunc != nil { 218 httpHeaders, e := r.opts.HeadersFunc(httpReq) 219 if e != nil { 220 return nil, fmt.Errorf("add optional request headers error: %w", e) 221 } 222 223 if httpHeaders != nil { 224 httpReq.Header = httpHeaders.Clone() 225 } 226 } 227 228 resp, err := r.httpClient.Do(httpReq) 229 230 debugLogger.Printf(" HTTP %s %s call duration: %s", method, destination, time.Since(start)) 231 232 return resp, err 233 } 234 235 // Encrypt will remotely encrypt msg and aad using a matching AEAD primitive in a remote key handle at keyURL of 236 // a public key. 237 // returns: 238 // 239 // cipherText in []byte 240 // nonce in []byte 241 // error in case of errors during encryption 242 func (r *RemoteCrypto) Encrypt(msg, aad []byte, keyURL interface{}) ([]byte, []byte, error) { 243 startEncrypt := time.Now() 244 destination := fmt.Sprintf("%s", keyURL) + encryptURI 245 246 eReq := encryptReq{ 247 Message: msg, 248 AssociatedData: aad, 249 } 250 251 httpReqBytes, err := r.marshalFunc(eReq) 252 if err != nil { 253 return nil, nil, fmt.Errorf("marshal encryption request for Encrypt failed [%s, %w]", destination, err) 254 } 255 256 resp, err := r.postHTTPRequest(destination, httpReqBytes) 257 if err != nil { 258 return nil, nil, fmt.Errorf("posting Encrypt plaintext failed [%s, %w]", destination, err) 259 } 260 261 // handle response 262 defer closeResponseBody(resp.Body, "Encrypt") 263 264 if resp.StatusCode != http.StatusOK { 265 return nil, nil, fmt.Errorf("posting Encrypt returned http error: %s", resp.Status) 266 } 267 268 respBody, err := ioutil.ReadAll(resp.Body) 269 if err != nil { 270 return nil, nil, fmt.Errorf("read encryption response for Encrypt failed [%s, %w]", destination, err) 271 } 272 273 httpResp := &encryptResp{} 274 275 err = r.unmarshalFunc(respBody, httpResp) 276 if err != nil { 277 return nil, nil, fmt.Errorf("unmarshal encryption for Encrypt failed [%s, %w]", destination, err) 278 } 279 280 debugLogger.Printf("overall Encrypt duration: %s", time.Since(startEncrypt)) 281 282 return httpResp.Ciphertext, httpResp.Nonce, nil 283 } 284 285 // Decrypt will remotely decrypt cipher with aad and given nonce using a matching AEAD primitive in a remote key handle 286 // at keyURL of a private key. 287 // returns: 288 // 289 // plainText in []byte 290 // error in case of errors 291 func (r *RemoteCrypto) Decrypt(cipher, aad, nonce []byte, keyURL interface{}) ([]byte, error) { 292 startDecrypt := time.Now() 293 destination := fmt.Sprintf("%s", keyURL) + decryptURI 294 295 dReq := decryptReq{ 296 Ciphertext: cipher, 297 Nonce: nonce, 298 AssociatedData: aad, 299 } 300 301 httpReqBytes, err := r.marshalFunc(dReq) 302 if err != nil { 303 return nil, fmt.Errorf("marshal decryption request for Decrypt failed [%s, %w]", destination, err) 304 } 305 306 resp, err := r.postHTTPRequest(destination, httpReqBytes) 307 if err != nil { 308 return nil, fmt.Errorf("posting Decrypt ciphertext failed [%s, %w]", destination, err) 309 } 310 311 // handle response 312 defer closeResponseBody(resp.Body, "Decrypt") 313 314 if resp.StatusCode != http.StatusOK { 315 return nil, fmt.Errorf("posting Decrypt returned http error: %s", resp.Status) 316 } 317 318 respBody, err := ioutil.ReadAll(resp.Body) 319 if err != nil { 320 return nil, fmt.Errorf("read decryption response for Decrypt failed [%s, %w]", destination, err) 321 } 322 323 httpResp := &decryptResp{} 324 325 err = r.unmarshalFunc(respBody, httpResp) 326 if err != nil { 327 return nil, fmt.Errorf("unmarshal decryption for Decrypt failed [%s, %w]", destination, err) 328 } 329 330 debugLogger.Printf("overall Decrypt duration: %s", time.Since(startDecrypt)) 331 332 return httpResp.Plaintext, nil 333 } 334 335 // Sign will remotely sign msg using a matching signature primitive in remote kh key handle at keyURL of a private key. 336 // returns: 337 // 338 // signature in []byte 339 // error in case of errors 340 func (r *RemoteCrypto) Sign(msg []byte, keyURL interface{}) ([]byte, error) { 341 startSign := time.Now() 342 destination := fmt.Sprintf("%s", keyURL) + signURI 343 344 sReq := signReq{ 345 Message: msg, 346 } 347 348 httpReqBytes, err := r.marshalFunc(sReq) 349 if err != nil { 350 return nil, fmt.Errorf("marshal signature request for Sign failed [%s, %w]", destination, err) 351 } 352 353 resp, err := r.postHTTPRequest(destination, httpReqBytes) 354 if err != nil { 355 return nil, fmt.Errorf("posting Sign message failed [%s, %w]", destination, err) 356 } 357 358 // handle response 359 defer closeResponseBody(resp.Body, "Sign") 360 361 if resp.StatusCode != http.StatusOK { 362 return nil, fmt.Errorf("posting Sign returned http error: %s", resp.Status) 363 } 364 365 respBody, err := ioutil.ReadAll(resp.Body) 366 if err != nil { 367 return nil, fmt.Errorf("read signature response for Sign failed [%s, %w]", destination, err) 368 } 369 370 httpResp := &signResp{} 371 372 err = r.unmarshalFunc(respBody, httpResp) 373 if err != nil { 374 return nil, fmt.Errorf("unmarshal signature for Sign failed [%s, %w]", destination, err) 375 } 376 377 debugLogger.Printf("overall Sign duration: %s", time.Since(startSign)) 378 379 return httpResp.Signature, nil 380 } 381 382 // Verify will remotely verify a signature for the given msg using a matching signature primitive in a remote key 383 // handle at keyURL of a public key. 384 // returns: 385 // 386 // error in case of errors or nil if signature verification was successful 387 func (r *RemoteCrypto) Verify(signature, msg []byte, keyURL interface{}) error { 388 startVerify := time.Now() 389 destination := fmt.Sprintf("%s", keyURL) + verifyURI 390 391 vReq := verifyReq{ 392 Message: msg, 393 Signature: signature, 394 } 395 396 httpReqBytes, err := r.marshalFunc(vReq) 397 if err != nil { 398 return fmt.Errorf("marshal verify request for Verify failed [%s, %w]", destination, err) 399 } 400 401 resp, err := r.postHTTPRequest(destination, httpReqBytes) 402 if err != nil { 403 return fmt.Errorf("posting Verify signature failed [%s, %w]", destination, err) 404 } 405 406 // handle response 407 defer closeResponseBody(resp.Body, "Verify") 408 409 if resp.StatusCode != http.StatusOK { 410 return fmt.Errorf("posting Verify signature returned http error: %s", resp.Status) 411 } 412 413 debugLogger.Printf("overall Verify duration: %s", time.Since(startVerify)) 414 415 return nil 416 } 417 418 // ComputeMAC remotely computes message authentication code (MAC) for code data with key at keyURL. 419 // using a matching MAC primitive in kh key handle. 420 func (r *RemoteCrypto) ComputeMAC(data []byte, keyURL interface{}) ([]byte, error) { // nolint:gocyclo 421 keyHash := string(sha256.New().Sum([]byte(fmt.Sprintf("%s_%s", keyURL, data)))) 422 423 if r.opts.ComputeMACCache != nil { 424 v, err := r.opts.ComputeMACCache.Get(keyHash) 425 if err == nil { 426 return v.([]byte), nil 427 } 428 429 if !errors.Is(err, gcache.KeyNotFoundError) { 430 return nil, err 431 } 432 } 433 434 startComputeMAC := time.Now() 435 destination := fmt.Sprintf("%s", keyURL) + computeMACURI 436 437 mReq := computeMACReq{ 438 Data: data, 439 } 440 441 httpReqBytes, err := r.marshalFunc(mReq) 442 if err != nil { 443 return nil, fmt.Errorf("marshal request for ComputeMAC failed [%s, %w]", destination, err) 444 } 445 446 resp, err := r.postHTTPRequest(destination, httpReqBytes) 447 if err != nil { 448 return nil, fmt.Errorf("posting ComputeMAC request failed [%s, %w]", destination, err) 449 } 450 451 // handle response 452 defer closeResponseBody(resp.Body, "ComputeMAC") 453 454 if resp.StatusCode != http.StatusOK { 455 return nil, fmt.Errorf("posting ComputeMAC request returned http error: %s", resp.Status) 456 } 457 458 respBody, err := ioutil.ReadAll(resp.Body) 459 if err != nil { 460 return nil, fmt.Errorf("read response for ComputeMAC failed [%s, %w]", destination, err) 461 } 462 463 httpResp := &computeMACResp{} 464 465 err = r.unmarshalFunc(respBody, httpResp) 466 if err != nil { 467 return nil, fmt.Errorf("unmarshal ComputeMAC response failed [%s, %w]", destination, err) 468 } 469 470 if r.opts.ComputeMACCache != nil { 471 if err := r.opts.ComputeMACCache.Set(keyHash, httpResp.MAC); err != nil { 472 return nil, fmt.Errorf("failed to store in cache: %w", err) 473 } 474 } 475 476 debugLogger.Printf("overall ComputeMAC duration: %s", time.Since(startComputeMAC)) 477 478 return httpResp.MAC, nil 479 } 480 481 // VerifyMAC remotely determines if mac is a correct authentication code (MAC) for data using a key at KeyURL 482 // using a matching MAC primitive in kh key handle and returns nil if so, otherwise it returns an error. 483 func (r *RemoteCrypto) VerifyMAC(mac, data []byte, keyURL interface{}) error { 484 startVerifyMAC := time.Now() 485 destination := fmt.Sprintf("%s", keyURL) + verifyMACURI 486 487 vReq := verifyMACReq{ 488 MAC: mac, 489 Data: data, 490 } 491 492 httpReqBytes, err := r.marshalFunc(vReq) 493 if err != nil { 494 return fmt.Errorf("marshal request for VerifyMAC failed [%s, %w]", destination, err) 495 } 496 497 resp, err := r.postHTTPRequest(destination, httpReqBytes) 498 if err != nil { 499 return fmt.Errorf("posting VerifyMAC request failed [%s, %w]", destination, err) 500 } 501 502 // handle response 503 defer closeResponseBody(resp.Body, "VerifyMAC") 504 505 if resp.StatusCode != http.StatusOK { 506 return fmt.Errorf("posting VerifyMAC request returned http error: %s", resp.Status) 507 } 508 509 debugLogger.Printf("overall VerifyMAC duration: %s", time.Since(startVerifyMAC)) 510 511 return nil 512 } 513 514 // WrapKey will remotely execute key wrapping of cek using apu, apv and recipient public key 'recPubKey'. 515 // 'opts' allows setting the option sender key handle using WithSender() option where the sender key handle consists 516 // of a remote key located in the option as a keyURL. This option allows ECDH-1PU key wrapping (aka Authcrypt). 517 // The absence of this option uses ECDH-ES key wrapping (aka Anoncrypt). 518 // 519 // RecipientWrappedKey containing the wrapped cek value 520 // error in case of errors 521 func (r *RemoteCrypto) WrapKey(cek, apu, apv []byte, recPubKey *cryptoapi.PublicKey, // nolint:funlen 522 opts ...cryptoapi.WrapKeyOpts) (*cryptoapi.RecipientWrappedKey, error) { 523 startWrapKey := time.Now() 524 destination := r.keystoreURL + wrapURI 525 526 pOpts := cryptoapi.NewOpt() 527 528 for _, opt := range opts { 529 opt(pOpts) 530 } 531 532 senderURL := pOpts.SenderKey() 533 wReq := &wrapKeyReq{ 534 CEK: cek, 535 APU: apu, 536 APV: apv, 537 RecipientPubKey: recPubKey, 538 Tag: pOpts.Tag(), 539 } 540 541 if senderURL != nil { 542 senderURLStr, ok := senderURL.(string) 543 544 if !ok { 545 return nil, fmt.Errorf("wrapKey invalid senderKey type, should be string with key URL") 546 } 547 548 // if senderURL is set, extract keyID and add it to the request url (for ECDH-1PU wrapping) 549 if senderURLStr != "" { 550 parts := strings.Split(senderURLStr, "/") 551 senderKID := parts[len(parts)-1] 552 destination = r.keystoreURL + keysURI + "/" + senderKID + wrapURI 553 } 554 } 555 556 httpReqBytes, err := r.marshalFunc(wReq) 557 if err != nil { 558 return nil, fmt.Errorf("marshal wrapKeyReq for WrapKey failed [%s, %w]", destination, err) 559 } 560 561 resp, err := r.postHTTPRequest(destination, httpReqBytes) 562 if err != nil { 563 return nil, fmt.Errorf("posting WrapKey failed [%s, %w]", destination, err) 564 } 565 566 // handle response 567 defer closeResponseBody(resp.Body, "WrapKey") 568 569 if resp.StatusCode != http.StatusOK { 570 return nil, fmt.Errorf("posting WrapKey returned http error: %s", resp.Status) 571 } 572 573 respBody, err := ioutil.ReadAll(resp.Body) 574 if err != nil { 575 return nil, fmt.Errorf("read wrap key response for WrapKey failed [%s, %w]", destination, err) 576 } 577 578 rwk, err := r.buildWrappedKeyResponse(respBody, destination) 579 580 debugLogger.Printf("overall WrapKey duration: %s", time.Since(startWrapKey)) 581 582 return rwk, err 583 } 584 585 func (r *RemoteCrypto) buildWrappedKeyResponse(respBody []byte, dest string) (*cryptoapi.RecipientWrappedKey, error) { 586 httpResp := &wrapKeyResp{} 587 588 err := r.unmarshalFunc(respBody, httpResp) 589 if err != nil { 590 return nil, fmt.Errorf("unmarshal wrapKeyResp for WrapKey failed [%s, %w]", dest, err) 591 } 592 593 return &httpResp.RecipientWrappedKey, nil 594 } 595 596 // UnwrapKey remotely unwraps a key in recWK using recipient private key found at keyURL. 597 // 'opts' allows setting the option sender key handle using WithSender() optionwhere the sender key handle consists 598 // of a remote key located in the option as a keyURL. This options allows ECDH-1PU key unwrapping (aka Authcrypt). 599 // The absence of this option uses ECDH-ES key unwrapping (aka Anoncrypt). 600 // returns: 601 // 602 // unwrapped key in raw bytes 603 // error in case of errors 604 func (r *RemoteCrypto) UnwrapKey(recWK *cryptoapi.RecipientWrappedKey, keyURL interface{}, 605 opts ...cryptoapi.WrapKeyOpts) ([]byte, error) { 606 startUnwrapKey := time.Now() 607 destination := fmt.Sprintf("%s", keyURL) + unwrapURI 608 609 pOpts := cryptoapi.NewOpt() 610 611 for _, opt := range opts { 612 opt(pOpts) 613 } 614 615 uReq := unwrapKeyReq{ 616 WrappedKey: *recWK, 617 Tag: pOpts.Tag(), 618 } 619 620 if pOpts.SenderKey() != nil { 621 sk, err := ksToCryptoPublicKey(pOpts.SenderKey()) 622 if err != nil { 623 return nil, err 624 } 625 626 uReq.SenderPubKey = sk 627 } 628 629 httpReqBytes, err := r.marshalFunc(uReq) 630 if err != nil { 631 return nil, fmt.Errorf("marshal unwrapKeyReq for UnwrapKey failed [%s, %w]", destination, err) 632 } 633 634 resp, err := r.postHTTPRequest(destination, httpReqBytes) 635 if err != nil { 636 return nil, fmt.Errorf("posting UnwrapKey failed [%s, %w]", destination, err) 637 } 638 639 // handle response 640 defer closeResponseBody(resp.Body, "UnwrapKey") 641 642 if resp.StatusCode != http.StatusOK { 643 return nil, fmt.Errorf("posting UnwrapKey returned http error: %s", resp.Status) 644 } 645 646 respBody, err := ioutil.ReadAll(resp.Body) 647 if err != nil { 648 return nil, fmt.Errorf("read unwrapped key response for UnwrapKey failed [%s, %w]", destination, err) 649 } 650 651 httpResp := &unwrapKeyResp{} 652 653 err = r.unmarshalFunc(respBody, httpResp) 654 if err != nil { 655 return nil, fmt.Errorf("unmarshal unwrapKeyResp for UnwrapKey failed [%s, %w]", destination, err) 656 } 657 658 debugLogger.Printf("overall UnwrapKey duration: %s", time.Since(startUnwrapKey)) 659 660 return httpResp.Key, err 661 } 662 663 func ksToCryptoPublicKey(ks interface{}) (*cryptoapi.PublicKey, error) { 664 switch kst := ks.(type) { 665 case *keyset.Handle: 666 sPubKey, err := keyio.ExtractPrimaryPublicKey(kst) 667 if err != nil { 668 return nil, fmt.Errorf("ksToCryptoPublicKey: failed to extract public key from keyset handle: %w", err) 669 } 670 671 return sPubKey, nil 672 case *cryptoapi.PublicKey: 673 return kst, nil 674 default: 675 return nil, fmt.Errorf("ksToCryptoPublicKey: unsupported keyset type %+v", kst) 676 } 677 } 678 679 // SignMulti will create a BBS+ signature of messages using the signer's private key handle found at signerKeyURL. 680 // returns: 681 // 682 // signature in []byte 683 // error in case of errors 684 func (r *RemoteCrypto) SignMulti(messages [][]byte, signerKeyURL interface{}) ([]byte, error) { 685 startSign := time.Now() 686 destination := fmt.Sprintf("%s", signerKeyURL) + signMultiURI 687 688 sReq := signMultiReq{ 689 Messages: messages, 690 } 691 692 httpReqBytes, err := r.marshalFunc(sReq) 693 if err != nil { 694 return nil, fmt.Errorf("marshal signature request for BBS+ Sign failed [%s, %w]", destination, err) 695 } 696 697 resp, err := r.postHTTPRequest(destination, httpReqBytes) 698 if err != nil { 699 return nil, fmt.Errorf("posting BBS+ Sign message failed [%s, %w]", destination, err) 700 } 701 702 // handle response 703 defer closeResponseBody(resp.Body, "BBS+ Sign") 704 705 if resp.StatusCode != http.StatusOK { 706 return nil, fmt.Errorf("posting BBS+ sign returned http error: %s", resp.Status) 707 } 708 709 respBody, err := ioutil.ReadAll(resp.Body) 710 if err != nil { 711 return nil, fmt.Errorf("read signature response for BBS+ Sign failed [%s, %w]", destination, err) 712 } 713 714 httpResp := &signResp{} 715 716 err = r.unmarshalFunc(respBody, httpResp) 717 if err != nil { 718 return nil, fmt.Errorf("unmarshal signature for BBS+ Sign failed [%s, %w]", destination, err) 719 } 720 721 debugLogger.Printf("overall BBS+ Sign duration: %s", time.Since(startSign)) 722 723 return httpResp.Signature, nil 724 } 725 726 // VerifyMulti will BBS+ verify a signature of messages against the signer's public key handle found at signerKeyURL. 727 // returns: 728 // 729 // error in case of errors or nil if signature verification was successful 730 func (r *RemoteCrypto) VerifyMulti(messages [][]byte, signature []byte, signerKeyURL interface{}) error { 731 startVerify := time.Now() 732 destination := fmt.Sprintf("%s", signerKeyURL) + verifyMultiURI 733 734 vReq := verifyMultiReq{ 735 Messages: messages, 736 Signature: signature, 737 } 738 739 httpReqBytes, err := r.marshalFunc(vReq) 740 if err != nil { 741 return fmt.Errorf("marshal verify request for BBS+ Verify failed [%s, %w]", destination, err) 742 } 743 744 resp, err := r.postHTTPRequest(destination, httpReqBytes) 745 if err != nil { 746 return fmt.Errorf("posting BBS+ Verify signature failed [%s, %w]", destination, err) 747 } 748 749 // handle response 750 defer closeResponseBody(resp.Body, "BBS+ Verify") 751 752 if resp.StatusCode != http.StatusOK { 753 return fmt.Errorf("posting BBS+ Verify signature returned http error: %s", resp.Status) 754 } 755 756 debugLogger.Printf("overall BBS+ Verify duration: %s", time.Since(startVerify)) 757 758 return nil 759 } 760 761 // VerifyProof will verify a BBS+ signature proof (generated e.g. by Verifier's DeriveProof() call) for revealedMessages 762 // with the signer's public key handle found at signerKeyURL. 763 // returns: 764 // 765 // error in case of errors or nil if signature proof verification was successful 766 func (r *RemoteCrypto) VerifyProof(revealedMessages [][]byte, proof, nonce []byte, signerKeyURL interface{}) error { 767 startVerifyProof := time.Now() 768 destination := fmt.Sprintf("%s", signerKeyURL) + verifyProofURI 769 770 vReq := verifyProofReq{ 771 Messages: revealedMessages, 772 Proof: proof, 773 Nonce: nonce, 774 } 775 776 httpReqBytes, err := r.marshalFunc(vReq) 777 if err != nil { 778 return fmt.Errorf("marshal request for BBS+ Verify proof failed [%s, %w]", destination, err) 779 } 780 781 resp, err := r.postHTTPRequest(destination, httpReqBytes) 782 if err != nil { 783 return fmt.Errorf("posting BBS+ Verify proof failed [%s, %w]", destination, err) 784 } 785 786 // handle response 787 defer closeResponseBody(resp.Body, "BBS+ Verify Proof") 788 789 if resp.StatusCode != http.StatusOK { 790 return fmt.Errorf("posting BBS+ Verify proof returned http error: %s", resp.Status) 791 } 792 793 debugLogger.Printf("overall BBS+ Verify proof duration: %s", time.Since(startVerifyProof)) 794 795 return nil 796 } 797 798 // DeriveProof will create a BBS+ signature proof for a list of revealed messages using BBS signature (can be built 799 // using a Signer's SignMulti() call) and the signer's public key handle found at signerKeyURL. 800 // returns: 801 // 802 // signature proof in []byte 803 // error in case of errors 804 func (r *RemoteCrypto) DeriveProof(messages [][]byte, bbsSignature, nonce []byte, revealedIndexes []int, 805 signerKeyURL interface{}) ([]byte, error) { 806 startDeriveProof := time.Now() 807 destination := fmt.Sprintf("%s", signerKeyURL) + deriveProofURI 808 809 sReq := deriveProofReq{ 810 Messages: messages, 811 Signature: bbsSignature, 812 Nonce: nonce, 813 RevealedIndexes: revealedIndexes, 814 } 815 816 httpReqBytes, err := r.marshalFunc(sReq) 817 if err != nil { 818 return nil, fmt.Errorf("marshal request for BBS+ Derive proof failed [%s, %w]", destination, err) 819 } 820 821 resp, err := r.postHTTPRequest(destination, httpReqBytes) 822 if err != nil { 823 return nil, fmt.Errorf("posting BBS+ Derive proof message failed [%s, %w]", destination, err) 824 } 825 826 // handle response 827 defer closeResponseBody(resp.Body, "BBS+ Derive Proof") 828 829 if resp.StatusCode != http.StatusOK { 830 return nil, fmt.Errorf("posting BBS+ Derive proof returned http error: %s", resp.Status) 831 } 832 833 respBody, err := ioutil.ReadAll(resp.Body) 834 if err != nil { 835 return nil, fmt.Errorf("read signature response for BBS+ Derive proof failed [%s, %w]", destination, err) 836 } 837 838 httpResp := &deriveProofResp{} 839 840 err = r.unmarshalFunc(respBody, httpResp) 841 if err != nil { 842 return nil, fmt.Errorf("unmarshal request for BBS+ Derive proof failed [%s, %w]", destination, err) 843 } 844 845 debugLogger.Printf("overall BBS+ Derive proof duration: %s", time.Since(startDeriveProof)) 846 847 return httpResp.Proof, nil 848 } 849 850 // closeResponseBody closes the response body. 851 func closeResponseBody(respBody io.Closer, action string) { 852 err := respBody.Close() 853 if err != nil { 854 errorLogger.Printf("Failed to close response body for '%s' REST call: %s", action, err.Error()) 855 } 856 }