Skip to content
This repository has been archived by the owner on Mar 27, 2024. It is now read-only.

Commit

Permalink
CL Anoncreds Remote KMS/Crypto
Browse files Browse the repository at this point in the history
* added client calls to CL methods in remote crypto
* added attrs propagation for remote kms
* added unit tests for remote kms/crypto
* added more failed cases for localkms ursa tests

Signed-off-by: konstantin.goncharov <[email protected]>
  • Loading branch information
konstantin.goncharov committed Aug 19, 2022
1 parent 730ac30 commit 8eacdba
Show file tree
Hide file tree
Showing 8 changed files with 583 additions and 57 deletions.
12 changes: 8 additions & 4 deletions pkg/crypto/tinkcrypto/cl_crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions pkg/crypto/tinkcrypto/cl_crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)

Expand Down
345 changes: 345 additions & 0 deletions pkg/crypto/webkms/cl_remotecrypto_test.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 8eacdba

Please sign in to comment.