From d1c97731e7e0dd115484eda3ae893e1904345e26 Mon Sep 17 00:00:00 2001 From: Volodymyr Kubiv Date: Fri, 20 May 2022 11:35:56 +0300 Subject: [PATCH] feat: add support of multibase encoding for proofValue. Signed-off-by: Volodymyr Kubiv --- pkg/doc/did/doc.go | 7 ++-- pkg/doc/did/doc_test.go | 2 +- .../did/testdata/valid_doc_with_base.jsonld | 2 +- pkg/doc/signature/proof/proof.go | 32 ++++++++++++++- pkg/doc/signature/proof/proof_test.go | 41 ++++++++++++++++--- .../testdata/doc_with_many_proofs.jsonld | 2 +- 6 files changed, 73 insertions(+), 13 deletions(-) diff --git a/pkg/doc/did/doc.go b/pkg/doc/did/doc.go index 5406db69b8..334a3dd6cf 100644 --- a/pkg/doc/did/doc.go +++ b/pkg/doc/did/doc.go @@ -24,6 +24,7 @@ import ( "github.com/hyperledger/aries-framework-go/pkg/common/model" "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk" "github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld" + sigproof "github.com/hyperledger/aries-framework-go/pkg/doc/signature/proof" "github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier" ) @@ -597,9 +598,9 @@ func populateProofs(context, didID, baseURI string, rawProofs []interface{}) ([] proofKey = jsonldSignatureValue } - proofValue, err := base64.RawURLEncoding.DecodeString(stringEntry(emap[proofKey])) + proofValue, err := sigproof.DecodeProofValue(stringEntry(emap[proofKey]), stringEntry(emap[jsonldType])) if err != nil { - return nil, err + return nil, errors.New("unsupported encoding") } nonce, err := base64.RawURLEncoding.DecodeString(stringEntry(emap[jsonldNonce])) @@ -1438,7 +1439,7 @@ func populateRawProofs(context, didID, baseURI string, proofs []Proof) []interfa jsonldType: p.Type, jsonldCreated: p.Created, jsonldCreator: creator, - k: base64.RawURLEncoding.EncodeToString(p.ProofValue), + k: sigproof.EncodeProofValue(p.ProofValue, p.Type), jsonldDomain: p.Domain, jsonldNonce: base64.RawURLEncoding.EncodeToString(p.Nonce), jsonldProofPurpose: p.ProofPurpose, diff --git a/pkg/doc/did/doc_test.go b/pkg/doc/did/doc_test.go index 775cac4b6e..aabb06b5d9 100644 --- a/pkg/doc/did/doc_test.go +++ b/pkg/doc/did/doc_test.go @@ -357,7 +357,7 @@ func TestInvalidEncodingInProof(t *testing.T) { doc, err = populateProofs(c, "", "", rawProofs) require.NotNil(t, err) require.Nil(t, doc) - require.Contains(t, err.Error(), "illegal base64 data") + require.Contains(t, err.Error(), "unsupported encoding") } } diff --git a/pkg/doc/did/testdata/valid_doc_with_base.jsonld b/pkg/doc/did/testdata/valid_doc_with_base.jsonld index a2c73b3445..286702a7ac 100644 --- a/pkg/doc/did/testdata/valid_doc_with_base.jsonld +++ b/pkg/doc/did/testdata/valid_doc_with_base.jsonld @@ -49,7 +49,7 @@ "creator": "#key-5", "domain": "", "nonce": "", - "proofValue": "6mdES87erjP5r1qCSRW__otj-A_Rj0YgRO7XU_0Amhwdfa7AAmtGUSFGflR_fZqPYrY9ceLRVQCJ49s0q7-LBA", + "proofValue": "u6mdES87erjP5r1qCSRW__otj-A_Rj0YgRO7XU_0Amhwdfa7AAmtGUSFGflR_fZqPYrY9ceLRVQCJ49s0q7-LBA", "type": "Ed25519Signature2018" }], "created": "2002-10-10T17:00:00Z" diff --git a/pkg/doc/signature/proof/proof.go b/pkg/doc/signature/proof/proof.go index cde8182b1c..c2f0a0e9a3 100644 --- a/pkg/doc/signature/proof/proof.go +++ b/pkg/doc/signature/proof/proof.go @@ -10,6 +10,8 @@ import ( "errors" "fmt" + "github.com/multiformats/go-multibase" + "github.com/hyperledger/aries-framework-go/pkg/doc/util" ) @@ -36,6 +38,8 @@ const ( jsonldChallenge = "challenge" // jsonldCapabilityChain is a key for capabilityChain. jsonldCapabilityChain = "capabilityChain" + + ed25519Signature2020 = "Ed25519Signature2020" ) // Proof is cryptographic proof of the integrity of the DID Document. @@ -71,7 +75,7 @@ func NewProof(emap map[string]interface{}) (*Proof, error) { ) if generalProof, ok := emap[jsonldProofValue]; ok { - proofValue, err = decodeBase64(stringEntry(generalProof)) + proofValue, err = DecodeProofValue(stringEntry(generalProof), stringEntry(emap[jsonldType])) if err != nil { return nil, err } @@ -143,6 +147,20 @@ func decodeBase64(s string) ([]byte, error) { return nil, errors.New("unsupported encoding") } +// DecodeProofValue decodes proofValue basing on proof type. +func DecodeProofValue(s, proofType string) ([]byte, error) { + if proofType == ed25519Signature2020 { + _, value, err := multibase.Decode(s) + if err == nil { + return value, nil + } + + return nil, errors.New("unsupported encoding") + } + + return decodeBase64(s) +} + // stringEntry. func stringEntry(entry interface{}) string { if entry == nil { @@ -170,7 +188,7 @@ func (p *Proof) JSONLdObject() map[string]interface{} { // nolint:gocyclo } if len(p.ProofValue) > 0 { - emap[jsonldProofValue] = base64.RawURLEncoding.EncodeToString(p.ProofValue) + emap[jsonldProofValue] = EncodeProofValue(p.ProofValue, p.Type) } if len(p.JWS) > 0 { @@ -200,6 +218,16 @@ func (p *Proof) JSONLdObject() map[string]interface{} { // nolint:gocyclo return emap } +// EncodeProofValue decodes proofValue basing on proof type. +func EncodeProofValue(proofValue []byte, proofType string) string { + if proofType == ed25519Signature2020 { + encoded, _ := multibase.Encode(multibase.Base58BTC, proofValue) //nolint: errcheck + return encoded + } + + return base64.RawURLEncoding.EncodeToString(proofValue) +} + // PublicKeyID provides ID of public key to be used to independently verify the proof. // "verificationMethod" field is checked first. If not empty, its value is returned. // Otherwise, "creator" field is returned if not empty. Otherwise, error is returned. diff --git a/pkg/doc/signature/proof/proof_test.go b/pkg/doc/signature/proof/proof_test.go index 0a841aa0c8..e7e9fad627 100644 --- a/pkg/doc/signature/proof/proof_test.go +++ b/pkg/doc/signature/proof/proof_test.go @@ -10,12 +10,16 @@ import ( "testing" "time" + "github.com/multiformats/go-multibase" "github.com/stretchr/testify/require" "github.com/hyperledger/aries-framework-go/pkg/doc/util" ) -const proofValueBase64 = "6mdES87erjP5r1qCSRW__otj-A_Rj0YgRO7XU_0Amhwdfa7AAmtGUSFGflR_fZqPYrY9ceLRVQCJ49s0q7-LBA" +const ( + proofValueBase64 = "6mdES87erjP5r1qCSRW__otj-A_Rj0YgRO7XU_0Amhwdfa7AAmtGUSFGflR_fZqPYrY9ceLRVQCJ49s0q7-LBA" + proofValueMultibase = "z5gpJQZoaLUXevXk2mYYbQE9krfaJYBBwQcJhhAvX3zs6daJ2Eb6VJoU46WkUYN8R1vgX7o8ktuUkzpRJS5aJRQyh" +) func TestProof(t *testing.T) { p, err := NewProof(map[string]interface{}{ @@ -44,6 +48,33 @@ func TestProof(t *testing.T) { require.Equal(t, []byte(""), p.Nonce) require.Equal(t, proofValueBytes, p.ProofValue) + // test proof with multibase encoding + p, err = NewProof(map[string]interface{}{ + "type": "Ed25519Signature2020", + "creator": "didID", + "verificationMethod": "did:example:123456#key1", + "created": "2018-03-15T00:00:00Z", + "domain": "abc.com", + "nonce": "", + "proofValue": proofValueMultibase, + }) + require.NoError(t, err) + + // test proof + created, err = time.Parse(time.RFC3339, "2018-03-15T00:00:00Z") + require.NoError(t, err) + + _, proofValueBytes, err = multibase.Decode(proofValueMultibase) + require.NoError(t, err) + + require.Equal(t, "Ed25519Signature2020", p.Type) + require.Equal(t, "didID", p.Creator) + require.Equal(t, "did:example:123456#key1", p.VerificationMethod) + require.Equal(t, created, p.Created.Time) + require.Equal(t, "abc.com", p.Domain) + require.Equal(t, []byte(""), p.Nonce) + require.Equal(t, proofValueBytes, p.ProofValue) + // test created time with milliseconds section p, err = NewProof(map[string]interface{}{ "type": "type", @@ -164,7 +195,7 @@ func TestInvalidNonce(t *testing.T) { func TestProof_JSONLdObject(t *testing.T) { r := require.New(t) - proofValueBytes, err := base64.RawURLEncoding.DecodeString(proofValueBase64) + _, proofValueBytes, err := multibase.Decode(proofValueMultibase) r.NoError(err) nonceBase64, err := base64.RawURLEncoding.DecodeString("abc") @@ -174,7 +205,7 @@ func TestProof_JSONLdObject(t *testing.T) { r.NoError(err) p := &Proof{ - Type: "Ed25519Signature2018", + Type: "Ed25519Signature2020", Created: util.NewTime(created), Creator: "creator", ProofValue: proofValueBytes, @@ -186,10 +217,10 @@ func TestProof_JSONLdObject(t *testing.T) { } pJSONLd := p.JSONLdObject() - r.Equal("Ed25519Signature2018", pJSONLd["type"]) + r.Equal("Ed25519Signature2020", pJSONLd["type"]) r.Equal("2018-03-15T00:00:00Z", pJSONLd["created"]) r.Equal("creator", pJSONLd["creator"]) - r.Equal(proofValueBase64, pJSONLd["proofValue"]) + r.Equal(proofValueMultibase, pJSONLd["proofValue"]) r.Equal("test.jws.value", pJSONLd["jws"]) r.Equal("assertionMethod", pJSONLd["proofPurpose"]) r.Equal("internal", pJSONLd["domain"]) diff --git a/pkg/doc/signature/suite/bbsblssignatureproof2020/testdata/doc_with_many_proofs.jsonld b/pkg/doc/signature/suite/bbsblssignatureproof2020/testdata/doc_with_many_proofs.jsonld index 49236bb07f..5e0f4ce12d 100644 --- a/pkg/doc/signature/suite/bbsblssignatureproof2020/testdata/doc_with_many_proofs.jsonld +++ b/pkg/doc/signature/suite/bbsblssignatureproof2020/testdata/doc_with_many_proofs.jsonld @@ -37,7 +37,7 @@ "type": "BbsBlsSignature2020", "created": "2020-12-06T19:23:10Z", "proofPurpose": "assertionMethod", - "proofValue": "jj3Xd3+KxmbQo85PFDjQJ7dAZlhj8A8W1Um8Vk7Xoiv6+jWRx5d8s0rgPk5dAXy6HwaJ4fQOde/MBb7E4QaGMlfK6y5eEKDUYzoGG0DScWIvaGcSZug6DwvWVXi+214P5MtlKnNwO6gJdemEgj8T/A==", + "proofValue": "mjj3Xd3+KxmbQo85PFDjQJ7dAZlhj8A8W1Um8Vk7Xoiv6+jWRx5d8s0rgPk5dAXy6HwaJ4fQOde/MBb7E4QaGMlfK6y5eEKDUYzoGG0DScWIvaGcSZug6DwvWVXi+214P5MtlKnNwO6gJdemEgj8T/A==", "verificationMethod": "did:example:489398593#test" }, {