diff --git a/pkg/crypto/tinkcrypto/cl_crypto.go b/pkg/crypto/tinkcrypto/cl_crypto.go index 486963d4d..3cb155890 100644 --- a/pkg/crypto/tinkcrypto/cl_crypto.go +++ b/pkg/crypto/tinkcrypto/cl_crypto.go @@ -44,18 +44,22 @@ func (t *Crypto) Blind(kh interface{}, values ...map[string]interface{}) ([][]by return [][]byte{blinded}, nil } - blindedList := make([][]byte, len(values)) + var blindeds [][]byte - for i, val := range values { + if len(values) == 0 { + values = []map[string]interface{}{} + } + + for _, val := range values { blinded, err := blinder.Blind(val) if err != nil { return nil, err } - blindedList[i] = blinded + blindeds = append(blindeds, blinded) } - return blindedList, nil + return blindeds, nil } // GetCorrectnessProof will return correctness proof for a public key handle diff --git a/pkg/crypto/tinkcrypto/cl_crypto_test.go b/pkg/crypto/tinkcrypto/cl_crypto_test.go index 8adbed5e6..683114509 100644 --- a/pkg/crypto/tinkcrypto/cl_crypto_test.go +++ b/pkg/crypto/tinkcrypto/cl_crypto_test.go @@ -14,7 +14,6 @@ import ( "github.com/google/tink/go/keyset" "github.com/hyperledger/ursa-wrapper-go/pkg/libursa/ursa" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" bld "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/cl/blinder" @@ -161,7 +160,7 @@ func generateBlindedSecretsWithNonces( _offerNonce, err := ursa.NewNonce() require.NoError(t, err) _blindedSecrets, err := ursa.BlindCredentialSecrets(_pubKey, _correctnessProof, _offerNonce, _blindedVals) - assert.NoError(t, err) + require.NoError(t, err) _requestNonce, err := ursa.NewNonce() require.NoError(t, err) diff --git a/pkg/crypto/webkms/cl_remotecrypto_test.go b/pkg/crypto/webkms/cl_remotecrypto_test.go new file mode 100644 index 000000000..c38de11e4 --- /dev/null +++ b/pkg/crypto/webkms/cl_remotecrypto_test.go @@ -0,0 +1,345 @@ +//go:build ursa +// +build ursa + +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package webkms + +import ( + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" + + "github.com/google/tink/go/keyset" + "github.com/hyperledger/ursa-wrapper-go/pkg/libursa/ursa" + "github.com/stretchr/testify/require" + + bld "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/cl/blinder" + sgn "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/cl/signer" + webkmsimpl "github.com/hyperledger/aries-framework-go/pkg/kms/webkms" +) + +func TestClMethods(t *testing.T) { + sgnKh, err := keyset.NewHandle(sgn.CredDefKeyTemplate([]string{"attr1", "attr2"})) + require.NoError(t, err) + + bldKh, err := keyset.NewHandle(bld.MasterSecretKeyTemplate()) + require.NoError(t, err) + + pubKh, err := sgnKh.Public() + require.NoError(t, err) + + pubKey, err := sgn.ExportCredDefPubKey(pubKh) + require.NoError(t, err) + + hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err = processClRequest(w, r, sgnKh, bldKh) + require.NoError(t, err) + }) + + server, url, client := CreateMockHTTPServerAndClient(t, hf) + + defer func() { + e := server.Close() + require.NoError(t, e) + }() + + defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(webkmsimpl.KeystoreEndpoint, + "{serverEndpoint}", url), defaultKeyStoreID) + sgnKeyURL := defaultKeystoreURL + "/keys/SGN" + bldKeyURL := defaultKeystoreURL + "/keys/BLD" + rCrypto := New(defaultKeystoreURL, client) + + // test successful CL methods usage + blinded, err := rCrypto.Blind(bldKeyURL, map[string]interface{}{"attr1": 1, "attr2": "aaa"}) + require.NoError(t, err) + require.NotEmpty(t, blinded) + + // blind should work with no parameters + _, err = rCrypto.Blind(bldKeyURL) + require.NoError(t, err) + + correctnessProof, err := rCrypto.GetCorrectnessProof(sgnKeyURL) + require.NoError(t, err) + require.NotEmpty(t, correctnessProof) + + secrets, secretsProof, offerNonce, requestNonce := generateBlindedSecretsWithNonces(t, + pubKey, + correctnessProof, + blinded[0], + ) + + sig, sigProof, err := rCrypto.SignWithSecrets(sgnKeyURL, + map[string]interface{}{"attr1": 1, "attr2": "aaa"}, + secrets, + secretsProof, + [][]byte{offerNonce, requestNonce}, + "did:example:id", + ) + require.NoError(t, err) + require.NotEmpty(t, sig) + require.NotEmpty(t, sigProof) + + t.Run("CL request failure", func(t *testing.T) { + blankClient := &http.Client{} + tmpCrypto := New(defaultKeystoreURL, blankClient) + + var err error + + _, err = tmpCrypto.Blind(bldKeyURL) + require.Error(t, err) + + _, err = tmpCrypto.GetCorrectnessProof(sgnKeyURL) + require.Error(t, err) + + _, _, err = tmpCrypto.SignWithSecrets(sgnKeyURL, + map[string]interface{}{}, + nil, + nil, + nil, + "", + ) + require.Error(t, err) + }) + + t.Run("CL json marshal failure", func(t *testing.T) { + remoteCrypto2 := New(defaultKeystoreURL, client) + + remoteCrypto2.marshalFunc = failingMarshal + + var err error + _, err = remoteCrypto2.Blind(bldKeyURL, map[string]interface{}{"attr1": 1, "attr2": "aaa"}) + require.Error(t, err) + + _, _, err = remoteCrypto2.SignWithSecrets(sgnKeyURL, + map[string]interface{}{"attr1": 1, "attr2": "aaa"}, + secrets, + secretsProof, + [][]byte{offerNonce, requestNonce}, + "did:example:id", + ) + require.Error(t, err) + }) + + t.Run("CL json unmarshal failure", func(t *testing.T) { + remoteCrypto2 := New(defaultKeystoreURL, client) + + remoteCrypto2.unmarshalFunc = failingUnmarshal + + var err error + _, err = remoteCrypto2.Blind(bldKeyURL, map[string]interface{}{"attr1": 1, "attr2": "aaa"}) + require.Error(t, err) + + _, err = remoteCrypto2.GetCorrectnessProof(sgnKeyURL) + require.Error(t, err) + + _, _, err = remoteCrypto2.SignWithSecrets(sgnKeyURL, + map[string]interface{}{"attr1": 1, "attr2": "aaa"}, + secrets, + secretsProof, + [][]byte{offerNonce, requestNonce}, + "did:example:id", + ) + require.Error(t, err) + }) +} + +func processClRequest(w http.ResponseWriter, r *http.Request, sgnKh, bldKh *keyset.Handle) error { + if valid := validateHTTPMethod(w, r); !valid { + return errors.New("http method invalid") + } + + if valid := validatePostPayload(r, w); !valid { + return errors.New("http request body invalid") + } + + reqBody, err := ioutil.ReadAll(r.Body) + if err != nil { + return err + } + + if matchPath(r, blindURI) { + err = clBlindPOSTHandle(w, reqBody, bldKh) + if err != nil { + return err + } + } + + if matchPath(r, correctnessProofURI) { + err = clCorrectnessProofGETHandle(w, sgnKh) + if err != nil { + return err + } + } + + if matchPath(r, signWithSecretsURI) { + err = clSignWithSecretsPOSTHandle(w, reqBody, sgnKh) + if err != nil { + return err + } + } + + return nil +} + +func clBlindPOSTHandle(w http.ResponseWriter, reqBody []byte, kh *keyset.Handle) error { + req := &blindReq{} + + err := json.Unmarshal(reqBody, req) + if err != nil { + return err + } + + blinder, err := bld.NewBlinder(kh) + if err != nil { + return fmt.Errorf("create new CL blinder: %w", err) + } + + defer blinder.Free() // nolint: errcheck + + vals := req.Values + if len(vals) == 0 { + vals = []map[string]interface{}{} + } + + var blindeds [][]byte + + for _, val := range vals { + blinded, e := blinder.Blind(val) + if e != nil { + return e + } + + blindeds = append(blindeds, blinded) + } + + resp := &blindResp{ + Blinded: blindeds, + } + + mResp, err := json.Marshal(resp) + if err != nil { + return err + } + + _, err = w.Write(mResp) + if err != nil { + return err + } + + return nil +} + +func clCorrectnessProofGETHandle(w http.ResponseWriter, kh *keyset.Handle) error { + signer, err := sgn.NewSigner(kh) + if err != nil { + return fmt.Errorf("create new CL signer: %w", err) + } + + defer signer.Free() // nolint: errcheck + + correctnessProof, err := signer.GetCorrectnessProof() + if err != nil { + return fmt.Errorf("CL correctness proof msg: %w", err) + } + + resp := &correctnessProofResp{ + CorrectnessProof: correctnessProof, + } + + mResp, err := json.Marshal(resp) + if err != nil { + return err + } + + _, err = w.Write(mResp) + if err != nil { + return err + } + + return nil +} + +func clSignWithSecretsPOSTHandle(w http.ResponseWriter, reqBody []byte, kh *keyset.Handle) error { + req := &signWithSecretsReq{} + + err := json.Unmarshal(reqBody, req) + if err != nil { + return err + } + + signer, err := sgn.NewSigner(kh) + if err != nil { + return fmt.Errorf("create new CL signer: %w", err) + } + + defer signer.Free() // nolint: errcheck + + signature, correctnessProof, err := signer.Sign( + req.Values, + req.Secrets, + req.CorrectnessProof, + req.Nonces, + req.DID, + ) + if err != nil { + return fmt.Errorf("CL sign msg: %w", err) + } + + resp := &signWithSecretsResp{ + Signature: signature, + CorrectnessProof: correctnessProof, + } + + mResp, err := json.Marshal(resp) + if err != nil { + return err + } + + _, err = w.Write(mResp) + if err != nil { + return err + } + + return nil +} + +func generateBlindedSecretsWithNonces( + t *testing.T, + pubKey []byte, + correctnessProof []byte, + blindedVals []byte, +) ([]byte, []byte, []byte, []byte) { + _pubKey, err := ursa.CredentialPublicKeyFromJSON(pubKey) + require.NoError(t, err) + _correctnessProof, err := ursa.CredentialKeyCorrectnessProofFromJSON(correctnessProof) + require.NoError(t, err) + _blindedVals, err := ursa.CredentialValuesFromJSON(blindedVals) + require.NoError(t, err) + + _offerNonce, err := ursa.NewNonce() + require.NoError(t, err) + _blindedSecrets, err := ursa.BlindCredentialSecrets(_pubKey, _correctnessProof, _offerNonce, _blindedVals) + require.NoError(t, err) + _requestNonce, err := ursa.NewNonce() + require.NoError(t, err) + + secrets, err := _blindedSecrets.Handle.ToJSON() + require.NoError(t, err) + secretsProof, err := _blindedSecrets.CorrectnessProof.ToJSON() + require.NoError(t, err) + offerNonce, err := _offerNonce.ToJSON() + require.NoError(t, err) + requestNonce, err := _requestNonce.ToJSON() + require.NoError(t, err) + + return secrets, secretsProof, offerNonce, requestNonce +} diff --git a/pkg/crypto/webkms/remotecrypto.go b/pkg/crypto/webkms/remotecrypto.go index 975754803..5535f51db 100644 --- a/pkg/crypto/webkms/remotecrypto.go +++ b/pkg/crypto/webkms/remotecrypto.go @@ -133,6 +133,36 @@ type unwrapKeyResp struct { Key []byte `json:"key"` } +// blindReq serializable Blind request. +type blindReq struct { + Values []map[string]interface{} `json:"values,omitempty"` +} + +// blindResp serializable Blind response. +type blindResp struct { + Blinded [][]byte `json:"blinded"` +} + +// correctnessProofResp serializable GetCorrectnessProof response. +type correctnessProofResp struct { + CorrectnessProof []byte `json:"correctness_proof"` +} + +// signWithSecretsReq serializable SignWithSecrets request. +type signWithSecretsReq struct { + Values map[string]interface{} `json:"values"` + Secrets []byte `json:"secrets"` + CorrectnessProof []byte `json:"correctness_proof"` + Nonces [][]byte `json:"nonces"` + DID string `json:"did"` +} + +// blindResp serializable Blind response. +type signWithSecretsResp struct { + Signature []byte `json:"signature"` + CorrectnessProof []byte `json:"correctness_proof"` +} + type marshalFunc func(interface{}) ([]byte, error) type unmarshalFunc func([]byte, interface{}) error @@ -162,6 +192,11 @@ const ( verifyMultiURI = "/verifymulti" deriveProofURI = "/deriveproof" verifyProofURI = "/verifyproof" + + // cl blind/sign endpoints. + blindURI = "/blind" + correctnessProofURI = "/correctnessproof" + signWithSecretsURI = "/signwithsecrets" ) // New creates a new remoteCrypto instance using http client connecting to keystoreURL. @@ -185,10 +220,20 @@ func (r *RemoteCrypto) postHTTPRequest(destination string, mReq []byte) (*http.R return r.doHTTPRequest(http.MethodPost, destination, mReq) } +func (r *RemoteCrypto) getHTTPRequest(destination string) (*http.Response, error) { + return r.doHTTPRequest(http.MethodGet, destination, nil) +} + func (r *RemoteCrypto) doHTTPRequest(method, destination string, mReq []byte) (*http.Response, error) { start := time.Now() - httpReq, err := http.NewRequest(method, destination, bytes.NewBuffer(mReq)) + var body io.Reader + + if mReq != nil { + body = bytes.NewBuffer(mReq) + } + + httpReq, err := http.NewRequest(method, destination, body) if err != nil { return nil, fmt.Errorf("build request error: %w", err) } @@ -820,30 +865,87 @@ func (r *RemoteCrypto) DeriveProof(messages [][]byte, bbsSignature, nonce []byte return httpResp.Proof, nil } -// closeResponseBody closes the response body. -func closeResponseBody(respBody io.Closer, logger spi.Logger, action string) { - err := respBody.Close() - if err != nil { - logger.Errorf("Failed to close response body for '%s' REST call: %s", action, err.Error()) - } -} - // Blind will blind provided values with MasterSecret provided in a kh // returns: // blinded values in []byte // error in case of errors -// TO BE IMPLEMENTED. func (r *RemoteCrypto) Blind(kh interface{}, values ...map[string]interface{}) ([][]byte, error) { - return nil, errors.New("not implemented") + startBlind := time.Now() + destination := fmt.Sprintf("%s", kh) + blindURI + + bReq := blindReq{ + Values: values, + } + + httpReqBytes, err := r.marshalFunc(bReq) + if err != nil { + return nil, fmt.Errorf("marshal request for CL Blind failed [%s, %w]", destination, err) + } + + resp, err := r.postHTTPRequest(destination, httpReqBytes) + if err != nil { + return nil, fmt.Errorf("posting CL Blind message failed [%s, %w]", destination, err) + } + + // handle response + defer closeResponseBody(resp.Body, logger, "CL Blind") + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("posting CL Blind returned http error: %s", resp.Status) + } + + respBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("read response for CL Blind failed [%s, %w]", destination, err) + } + + httpResp := &blindResp{} + + err = r.unmarshalFunc(respBody, httpResp) + if err != nil { + return nil, fmt.Errorf("unmarshal blinded values for CL Blind failed [%s, %w]", destination, err) + } + + logger.Debugf("overall CL Blind duration: %s", time.Since(startBlind)) + + return httpResp.Blinded, nil } // GetCorrectnessProof will return correctness proof for a public key handle // returns: // correctness proof in []byte // error in case of errors -// TO BE IMPLEMENTED. func (r *RemoteCrypto) GetCorrectnessProof(kh interface{}) ([]byte, error) { - return nil, errors.New("not implemented") + startGet := time.Now() + destination := fmt.Sprintf("%s", kh) + correctnessProofURI + + resp, err := r.getHTTPRequest(destination) + if err != nil { + return nil, fmt.Errorf("getting CL CorrectnessProof message failed [%s, %w]", destination, err) + } + + // handle response + defer closeResponseBody(resp.Body, logger, "CL CorrectnessProof") + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("getting CL CorrectnessProof returned http error: %s", resp.Status) + } + + respBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("read response for CL CorrectnessProof failed [%s, %w]", destination, err) + } + + httpResp := &correctnessProofResp{} + + err = r.unmarshalFunc(respBody, httpResp) + if err != nil { + return nil, fmt.Errorf("unmarshal value for CL CorrectnessProof failed [%s, %w]", destination, err) + } + + logger.Debugf("overall CL CorrectnessProof duration: %s", time.Since(startGet)) + + return httpResp.CorrectnessProof, nil } // SignWithSecrets will generate a signature and related correctness proof @@ -852,8 +954,57 @@ func (r *RemoteCrypto) GetCorrectnessProof(kh interface{}) ([]byte, error) { // signature in []byte // correctness proof in []byte // error in case of errors -// TO BE IMPLEMENTED. func (r *RemoteCrypto) SignWithSecrets(kh interface{}, values map[string]interface{}, secrets []byte, correctnessProof []byte, nonces [][]byte, did string) ([]byte, []byte, error) { - return nil, nil, errors.New("not implemented") + startSign := time.Now() + destination := fmt.Sprintf("%s", kh) + signWithSecretsURI + + sReq := signWithSecretsReq{ + Values: values, + Secrets: secrets, + CorrectnessProof: correctnessProof, + Nonces: nonces, + DID: did, + } + + httpReqBytes, err := r.marshalFunc(sReq) + if err != nil { + return nil, nil, fmt.Errorf("marshal request for CL SignWithSecrets failed [%s, %w]", destination, err) + } + + resp, err := r.postHTTPRequest(destination, httpReqBytes) + if err != nil { + return nil, nil, fmt.Errorf("posting CL SignWithSecrets message failed [%s, %w]", destination, err) + } + + // handle response + defer closeResponseBody(resp.Body, logger, "CL SignWithSecrets") + + if resp.StatusCode != http.StatusOK { + return nil, nil, fmt.Errorf("posting CL SignWithSecrets returned http error: %s", resp.Status) + } + + respBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, nil, fmt.Errorf("read response for CL SignWithSecrets failed [%s, %w]", destination, err) + } + + httpResp := &signWithSecretsResp{} + + err = r.unmarshalFunc(respBody, httpResp) + if err != nil { + return nil, nil, fmt.Errorf("unmarshal values for CL SignWithSecrets failed [%s, %w]", destination, err) + } + + logger.Debugf("overall CL SignWithSecrets duration: %s", time.Since(startSign)) + + return httpResp.Signature, httpResp.CorrectnessProof, nil +} + +// closeResponseBody closes the response body. +func closeResponseBody(respBody io.Closer, logger spi.Logger, action string) { + err := respBody.Close() + if err != nil { + logger.Errorf("Failed to close response body for '%s' REST call: %s", action, err.Error()) + } } diff --git a/pkg/crypto/webkms/remotecrypto_test.go b/pkg/crypto/webkms/remotecrypto_test.go index 59ee6df64..f88a5ed74 100644 --- a/pkg/crypto/webkms/remotecrypto_test.go +++ b/pkg/crypto/webkms/remotecrypto_test.go @@ -154,14 +154,14 @@ func processPOSTEncRequest(w http.ResponseWriter, r *http.Request, encKH *keyset return err } - if strings.LastIndex(r.URL.Path, encryptURI) == len(r.URL.Path)-len(encryptURI) { + if matchPath(r, encryptURI) { err = encryptPOSTHandle(w, reqBody, encKH) if err != nil { return err } } - if strings.LastIndex(r.URL.Path, decryptURI) == len(r.URL.Path)-len(decryptURI) { + if matchPath(r, decryptURI) { err = decryptPOSTHandle(w, reqBody, encKH) if err != nil { return err @@ -354,14 +354,14 @@ func processPOSTSigRequest(w http.ResponseWriter, r *http.Request, sigKH *keyset return err } - if strings.LastIndex(r.URL.Path, signURI) == len(r.URL.Path)-len(signURI) { + if matchPath(r, signURI) { err = signPOSTHandle(w, reqBody, sigKH) if err != nil { return err } } - if strings.LastIndex(r.URL.Path, verifyURI) == len(r.URL.Path)-len(verifyURI) { + if matchPath(r, verifyURI) { err = verifyPOSTHandle(reqBody, sigKH) if err != nil { return err @@ -527,14 +527,14 @@ func processPOSTMACRequest(w http.ResponseWriter, r *http.Request, macKH *keyset return err } - if strings.LastIndex(r.URL.Path, computeMACURI) == len(r.URL.Path)-len(computeMACURI) { + if matchPath(r, computeMACURI) { err = computeMACPOSTHandle(w, reqBody, macKH) if err != nil { return err } } - if strings.LastIndex(r.URL.Path, verifyMACURI) == len(r.URL.Path)-len(verifyMACURI) { + if matchPath(r, verifyMACURI) { err = verifyMACPOSTHandle(reqBody, macKH) if err != nil { return err @@ -833,7 +833,7 @@ func processPOSTWrapRequest(w http.ResponseWriter, r *http.Request, senderKH, re return err } - if strings.LastIndex(r.URL.Path, wrapURI) == len(r.URL.Path)-len(wrapURI) { + if matchPath(r, wrapURI) { if strings.Contains(r.URL.Path, keysURI+"/") { // URL contains sender key id and has form "keystorepath/keys/{senderKeyId}/wrap" err = wrapKeyPostHandle(w, reqBody, senderKH, cr) @@ -846,7 +846,7 @@ func processPOSTWrapRequest(w http.ResponseWriter, r *http.Request, senderKH, re } } - if strings.LastIndex(r.URL.Path, unwrapURI) == len(r.URL.Path)-len(unwrapURI) { + if matchPath(r, unwrapURI) { err = unwrapKeyPostHandle(w, reqBody, senderKH, recKH, cr) if err != nil { return err @@ -1197,35 +1197,28 @@ func TestNonOKStatusCode(t *testing.T) { }, []byte{}, []byte{}, nonOKDefaultKeyURL) require.Contains(t, err.Error(), "501") }) -} - -func TestCLMethods(t *testing.T) { - hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - }) - - server, url, client := CreateMockHTTPServerAndClient(t, hf) - defer func() { - e := server.Close() - require.NoError(t, e) - }() + t.Run("Blind Post request failure 501", func(t *testing.T) { + tmpCrypto := New(nonOKDefaultKeyURL, nonOKClient) - defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(webkmsimpl.KeystoreEndpoint, - "{serverEndpoint}", url), defaultKeyStoreID) - rCrypto := New(defaultKeystoreURL, client) + _, err := tmpCrypto.Blind(nonOKDefaultKeyURL, map[string]interface{}{}) + require.Contains(t, err.Error(), "501") + }) - t.Run("test CL methods return not implemented", func(t *testing.T) { - errNotImplemented := errors.New("not implemented") - var err error + t.Run("CorrectnessProof Get request failure 501", func(t *testing.T) { + tmpCrypto := New(nonOKDefaultKeyURL, nonOKClient) - _, err = rCrypto.GetCorrectnessProof(nil) - require.EqualError(t, err, errNotImplemented.Error()) + _, err := tmpCrypto.GetCorrectnessProof(nonOKDefaultKeyURL) + require.Contains(t, err.Error(), "501") + }) - _, _, err = rCrypto.SignWithSecrets(nil, map[string]interface{}{}, nil, nil, nil, "") - require.EqualError(t, err, errNotImplemented.Error()) + t.Run("SignWithSecrets Post request failure 501", func(t *testing.T) { + tmpCrypto := New(nonOKDefaultKeyURL, nonOKClient) - _, err = rCrypto.Blind(nil, map[string]interface{}{}) - require.EqualError(t, err, errNotImplemented.Error()) + _, _, err := tmpCrypto.SignWithSecrets(nonOKDefaultKeyURL, + map[string]interface{}{}, + nil, nil, nil, "did:example") + require.Contains(t, err.Error(), "501") }) } @@ -1244,28 +1237,28 @@ func processBBSPOSTRequest(w http.ResponseWriter, r *http.Request, sigKH *keyset return err } - if strings.LastIndex(r.URL.Path, signMultiURI) == len(r.URL.Path)-len(signMultiURI) { + if matchPath(r, signMultiURI) { err = bbsSignPOSTHandle(w, reqBody, sigKH) if err != nil { return err } } - if strings.LastIndex(r.URL.Path, verifyMultiURI) == len(r.URL.Path)-len(verifyMultiURI) { + if matchPath(r, verifyMultiURI) { err = bbsVerifyPOSTHandle(reqBody, sigKH) if err != nil { return err } } - if strings.LastIndex(r.URL.Path, deriveProofURI) == len(r.URL.Path)-len(deriveProofURI) { + if matchPath(r, deriveProofURI) { err = bbsDeriveProofPOSTHandle(w, reqBody, sigKH) if err != nil { return err } } - if strings.LastIndex(r.URL.Path, verifyProofURI) == len(r.URL.Path)-len(verifyProofURI) { + if matchPath(r, verifyProofURI) { err = bbsVerifyProofPOSTHandle(reqBody, sigKH) if err != nil { return err @@ -1596,3 +1589,7 @@ var errAddHeadersFunc = errors.New("mockAddHeadersFuncError always fails") func mockAddHeadersFuncError(_ *http.Request) (*http.Header, error) { return nil, errAddHeadersFunc } + +func matchPath(r *http.Request, uri string) bool { + return strings.LastIndex(r.URL.Path, uri) == len(r.URL.Path)-len(uri) +} diff --git a/pkg/kms/localkms/localkms_ursa_test.go b/pkg/kms/localkms/localkms_ursa_test.go index 9600b1c9f..34309b417 100644 --- a/pkg/kms/localkms/localkms_ursa_test.go +++ b/pkg/kms/localkms/localkms_ursa_test.go @@ -49,6 +49,12 @@ func TestLocalKMS_Ursa_Success(t *testing.T) { opts[kms.CLCredDefType] = kms.WithAttrs([]string{"attr1", "attr2"}) for _, v := range keyTemplates { + // test Create() w/o the opts where they're mandatory + if opts[v] != nil { + _, _, e := kmsService.Create(v) + require.Error(t, e) + } + // test Create() a new key keyID, newKeyHandle, e := kmsService.Create(v, opts[v]) require.NoError(t, e, "failed on template %v", v) @@ -82,6 +88,12 @@ func TestLocalKMS_Ursa_Success(t *testing.T) { require.Empty(t, rotatedKeyHandle) require.Empty(t, newKeyID) + // with no parameters if they're mandatory - should fail + if opts[v] != nil { + _, _, e = kmsService.Rotate(v, keyID) + require.Error(t, e) + } + // with valid key type - should succeed newKeyID, rotatedKeyHandle, e = kmsService.Rotate(v, keyID, opts[v]) require.NoError(t, e) @@ -112,6 +124,10 @@ func TestLocalKMS_Ursa_Success(t *testing.T) { // test create and export key in one function _, _, e = kmsService.CreateAndExportPubKeyBytes(v, opts[v]) require.NoError(t, e) + + // if no parameters passed - CreateAndExport should fail + _, _, e = kmsService.CreateAndExportPubKeyBytes(v) + require.Error(t, e) } } } diff --git a/pkg/kms/webkms/remotekms.go b/pkg/kms/webkms/remotekms.go index d7e6a0a01..ccdee39e0 100644 --- a/pkg/kms/webkms/remotekms.go +++ b/pkg/kms/webkms/remotekms.go @@ -60,6 +60,7 @@ type createKeyStoreResp struct { type createKeyReq struct { KeyType kms.KeyType `json:"key_type"` + Attrs []string `json:"attrs,omitempty"` } type createKeyResp struct { @@ -276,11 +277,18 @@ func (r *RemoteKMS) Create(kt kms.KeyType, opts ...kms.KeyOpts) (string, interfa return kid, keyURL, nil } -func (r *RemoteKMS) createKey(kt kms.KeyType, _ ...kms.KeyOpts) (string, []byte, error) { +func (r *RemoteKMS) createKey(kt kms.KeyType, opts ...kms.KeyOpts) (string, []byte, error) { destination := r.keystoreURL + "/keys" + keyOpts := kms.NewKeyOpt() + + for _, opt := range opts { + opt(keyOpts) + } + httpReqJSON := &createKeyReq{ KeyType: kt, + Attrs: keyOpts.Attrs(), } marshaledReq, err := r.marshalFunc(httpReqJSON) diff --git a/pkg/kms/webkms/remotekms_test.go b/pkg/kms/webkms/remotekms_test.go index 2a56298be..aae148d26 100644 --- a/pkg/kms/webkms/remotekms_test.go +++ b/pkg/kms/webkms/remotekms_test.go @@ -266,6 +266,12 @@ func TestCreateKeyWithLocationInResponseBody(t *testing.T) { require.Equal(t, defaultKID, kid1) require.Contains(t, keyURL1, fmt.Sprintf("%s/keys/%s", defaultKeystoreURL, defaultKID)) + // no error if options passed + _, _, err = remoteKMS.Create(kms.ED25519Type, kms.WithAttrs([]string{"attr1"})) + require.NoError(t, err) + _, _, err = remoteKMS.CreateAndExportPubKeyBytes(kms.ED25519Type, kms.WithAttrs([]string{"attr2"})) + require.NoError(t, err) + remoteKMS.unmarshalFunc = failingUnmarshal _, _, err = remoteKMS.Create(kms.ED25519Type) require.Contains(t, err.Error(), "unmarshal failed")