diff --git a/credential/exchange/submission_test.go b/credential/exchange/submission_test.go index f8acef9c..cfcf0ef6 100644 --- a/credential/exchange/submission_test.go +++ b/credential/exchange/submission_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/TBD54566975/ssi-sdk/cryptosuite/jws2020" "github.com/goccy/go-json" "github.com/oliveagle/jsonpath" "github.com/stretchr/testify/assert" @@ -51,7 +52,7 @@ func TestBuildPresentationSubmission(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } submissionBytes, err := BuildPresentationSubmission(*signer, signer.ID, def, []PresentationClaim{presentationClaim}, JWTVPTarget) assert.NoError(tt, err) @@ -136,7 +137,7 @@ func TestBuildPresentationSubmissionVP(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim}) assert.NoError(tt, err) @@ -230,7 +231,7 @@ func TestBuildPresentationSubmissionVP(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim}) assert.NoError(tt, err) @@ -301,7 +302,7 @@ func TestBuildPresentationSubmissionVP(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } testVCJWT := getTestJWTVerifiableCredential() presentationClaimJWT := PresentationClaim{ @@ -367,7 +368,7 @@ func TestProcessInputDescriptor(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim}) assert.NoError(tt, err) @@ -400,7 +401,7 @@ func TestProcessInputDescriptor(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim}) assert.NoError(tt, err) @@ -427,7 +428,7 @@ func TestProcessInputDescriptor(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim}) assert.NoError(tt, err) @@ -450,7 +451,7 @@ func TestProcessInputDescriptor(t *testing.T) { }, Format: &ClaimFormat{ LDP: &LDPType{ - ProofType: []cryptosuite.SignatureType{cryptosuite.JSONWebSignature2020}, + ProofType: []cryptosuite.SignatureType{jws2020.JSONWebSignature2020}, }, }, } @@ -458,7 +459,7 @@ func TestProcessInputDescriptor(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim}) assert.NoError(tt, err) @@ -481,7 +482,7 @@ func TestProcessInputDescriptor(t *testing.T) { }, Format: &ClaimFormat{ LDPVC: &LDPType{ - ProofType: []cryptosuite.SignatureType{cryptosuite.JSONWebSignature2020}, + ProofType: []cryptosuite.SignatureType{jws2020.JSONWebSignature2020}, }, }, } @@ -489,7 +490,7 @@ func TestProcessInputDescriptor(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim}) assert.NoError(tt, err) @@ -758,7 +759,7 @@ func TestNormalizePresentationClaims(t *testing.T) { presentationClaim := PresentationClaim{ Presentation: &vpClaim, LDPFormat: LDPVP.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim}) @@ -767,7 +768,7 @@ func TestNormalizePresentationClaims(t *testing.T) { assert.True(tt, len(normalized) == 1) assert.NotEmpty(tt, normalized[0].Data) assert.EqualValues(tt, LDPVP, normalized[0].Format) - assert.EqualValues(tt, string(cryptosuite.JSONWebSignature2020), normalized[0].AlgOrProofType) + assert.EqualValues(tt, string(jws2020.JSONWebSignature2020), normalized[0].AlgOrProofType) }) t.Run("Normalize VC Claim", func(tt *testing.T) { @@ -777,7 +778,7 @@ func TestNormalizePresentationClaims(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &vcClaim, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim}) @@ -786,7 +787,7 @@ func TestNormalizePresentationClaims(t *testing.T) { assert.True(tt, len(normalized) == 1) assert.NotEmpty(tt, normalized[0].Data) assert.EqualValues(tt, LDPVC, normalized[0].Format) - assert.EqualValues(tt, string(cryptosuite.JSONWebSignature2020), normalized[0].AlgOrProofType) + assert.EqualValues(tt, string(jws2020.JSONWebSignature2020), normalized[0].AlgOrProofType) }) } diff --git a/credential/exchange/verification_test.go b/credential/exchange/verification_test.go index aea76bb5..e10a7cae 100644 --- a/credential/exchange/verification_test.go +++ b/credential/exchange/verification_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/TBD54566975/ssi-sdk/cryptosuite/jws2020" "github.com/stretchr/testify/assert" "github.com/TBD54566975/ssi-sdk/crypto/jwx" @@ -12,7 +13,6 @@ import ( "github.com/TBD54566975/ssi-sdk/util" "github.com/TBD54566975/ssi-sdk/credential" - "github.com/TBD54566975/ssi-sdk/cryptosuite" ) func TestVerifyPresentationSubmission(t *testing.T) { @@ -98,7 +98,7 @@ func TestVerifyPresentationSubmission(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } submissionBytes, err := BuildPresentationSubmission(*signer, verifier.ID, def, []PresentationClaim{presentationClaim}, JWTVPTarget) assert.NoError(tt, err) @@ -176,7 +176,7 @@ func TestVerifyPresentationSubmissionVP(t *testing.T) { presentationClaim := PresentationClaim{ Credential: &testVC, LDPFormat: LDPVC.Ptr(), - SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020), + SignatureAlgorithmOrProofType: string(jws2020.JSONWebSignature2020), } submissionBytes, err := BuildPresentationSubmission(*signer, "requester", def, []PresentationClaim{presentationClaim}, JWTVPTarget) assert.NoError(tt, err) diff --git a/credential/manifest/validation_test.go b/credential/manifest/validation_test.go index 54bf754e..8920de8a 100644 --- a/credential/manifest/validation_test.go +++ b/credential/manifest/validation_test.go @@ -8,6 +8,7 @@ import ( "github.com/TBD54566975/ssi-sdk/crypto" "github.com/TBD54566975/ssi-sdk/crypto/jwx" "github.com/TBD54566975/ssi-sdk/cryptosuite" + "github.com/TBD54566975/ssi-sdk/cryptosuite/jws2020" "github.com/goccy/go-json" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -215,7 +216,7 @@ func TestIsValidCredentialApplicationForManifest(t *testing.T) { cm, ca := getValidTestCredManifestCredApplication(tt) cm.PresentationDefinition.InputDescriptors[0].Format = &exchange.ClaimFormat{ - LDP: &exchange.LDPType{ProofType: []cryptosuite.SignatureType{cryptosuite.JSONWebSignature2020}}, + LDP: &exchange.LDPType{ProofType: []cryptosuite.SignatureType{jws2020.JSONWebSignature2020}}, } credAppRequestBytes, err := json.Marshal(ca) diff --git a/credential/signature.go b/credential/signature.go index 824a0314..0c78c514 100644 --- a/credential/signature.go +++ b/credential/signature.go @@ -22,9 +22,9 @@ func VerifyCredentialSignature(ctx context.Context, genericCred any, r resolutio if r == nil { return false, errors.New("resolution cannot be empty") } - switch genericCred.(type) { + switch typedCred := genericCred.(type) { case *VerifiableCredential, VerifiableCredential, map[string]any: - _, token, cred, err := ToCredential(genericCred) + _, token, cred, err := ToCredential(typedCred) if err != nil { return false, errors.Wrap(err, "error converting credential from generic type") } @@ -40,16 +40,16 @@ func VerifyCredentialSignature(ctx context.Context, genericCred any, r resolutio return false, errors.New("data integrity signature verification not yet implemented") case []byte: // turn it into a string and try again - return VerifyCredentialSignature(ctx, string(genericCred.([]byte)), r) + return VerifyCredentialSignature(ctx, string(typedCred), r) case string: // could be a Data Integrity credential var cred VerifiableCredential - if err := json.Unmarshal([]byte(genericCred.(string)), &cred); err == nil { + if err := json.Unmarshal([]byte(typedCred), &cred); err == nil { return VerifyCredentialSignature(ctx, cred, r) } // could be a JWT - return VerifyJWTCredential(genericCred.(string), r) + return VerifyJWTCredential(typedCred, r) } return false, fmt.Errorf("invalid credential type: %s", reflect.TypeOf(genericCred).Kind().String()) } diff --git a/credential/util.go b/credential/util.go index 32aa1144..bf1db825 100644 --- a/credential/util.go +++ b/credential/util.go @@ -13,10 +13,10 @@ import ( // ToCredential turn a generic cred into its known object model func ToCredential(genericCred any) (jws.Headers, jwt.Token, *VerifiableCredential, error) { - switch genericCred.(type) { + switch typedCred := genericCred.(type) { case []byte: // could be a JWT - headers, token, vcFromJWT, err := ToCredential(string(genericCred.([]byte))) + headers, token, vcFromJWT, err := ToCredential(string(typedCred)) if err == nil { return headers, token, vcFromJWT, err } @@ -28,18 +28,21 @@ func ToCredential(genericCred any) (jws.Headers, jwt.Token, *VerifiableCredentia } return ToCredential(cred) case *VerifiableCredential: - return nil, nil, genericCred.(*VerifiableCredential), nil + return nil, nil, typedCred, nil case VerifiableCredential: - verifiableCredential := genericCred.(VerifiableCredential) - return nil, nil, &verifiableCredential, nil + return nil, nil, &typedCred, nil case string: - // TODO(gabe) support the case where the string is a json representation of an LD credential - // JWT - return ParseVerifiableCredentialFromJWT(genericCred.(string)) + // first try the case where the string is JSON of a VC object + var cred VerifiableCredential + if err := json.Unmarshal([]byte(typedCred), &cred); err == nil { + return nil, nil, &cred, nil + } + + // next try it as a JWT + return ParseVerifiableCredentialFromJWT(typedCred) case map[string]any: // VC or JWTVC JSON - credJSON := genericCred.(map[string]any) - credMapBytes, err := json.Marshal(credJSON) + credMapBytes, err := json.Marshal(typedCred) if err != nil { return nil, nil, nil, errors.Wrap(err, "marshalling credential map") } @@ -62,26 +65,31 @@ func ToCredential(genericCred any) (jws.Headers, jwt.Token, *VerifiableCredentia // ToCredentialJSONMap turn a generic cred into a JSON object func ToCredentialJSONMap(genericCred any) (map[string]any, error) { - switch genericCred.(type) { + switch typedCred := genericCred.(type) { case []byte: // could be a JWT - credJSON, err := ToCredentialJSONMap(string(genericCred.([]byte))) + credJSON, err := ToCredentialJSONMap(string(typedCred)) if err == nil { return credJSON, err } // could also be a vc var cred VerifiableCredential - if err = json.Unmarshal(genericCred.([]byte), &cred); err != nil { + if err = json.Unmarshal(typedCred, &cred); err != nil { return nil, errors.Wrap(err, "unmarshalling credential object") } return ToCredentialJSONMap(cred) case map[string]any: - return genericCred.(map[string]any), nil + return typedCred, nil case string: - // TODO(gabe) support the case where the string is a json representation of an LD credential - // JWT - _, token, _, err := ParseVerifiableCredentialFromJWT(genericCred.(string)) + // first try the case where the string is JSON of a VC object + var credJSON map[string]any + if err := json.Unmarshal([]byte(typedCred), &credJSON); err == nil { + return credJSON, nil + } + + // next try it as a JWT + _, token, _, err := ParseVerifiableCredentialFromJWT(typedCred) if err != nil { return nil, errors.Wrap(err, "parsing credential from JWT") } @@ -90,18 +98,17 @@ func ToCredentialJSONMap(genericCred any) (map[string]any, error) { if err != nil { return nil, errors.Wrap(err, "marshaling credential JWT") } - var credJSON map[string]any - if err := json.Unmarshal(tokenJSONBytes, &credJSON); err != nil { + if err = json.Unmarshal(tokenJSONBytes, &credJSON); err != nil { return nil, errors.Wrap(err, "unmarshalling credential JWT") } return credJSON, nil case VerifiableCredential, *VerifiableCredential: - credJSONBytes, err := json.Marshal(genericCred) + credJSONBytes, err := json.Marshal(typedCred) if err != nil { return nil, errors.Wrap(err, "marshalling credential object") } var credJSON map[string]any - if err := json.Unmarshal(credJSONBytes, &credJSON); err != nil { + if err = json.Unmarshal(credJSONBytes, &credJSON); err != nil { return nil, errors.Wrap(err, "unmarshalling credential object") } return credJSON, nil diff --git a/credential/util_test.go b/credential/util_test.go index 59325897..d17ebec0 100644 --- a/credential/util_test.go +++ b/credential/util_test.go @@ -5,6 +5,8 @@ import ( "github.com/TBD54566975/ssi-sdk/crypto/jwx" "github.com/TBD54566975/ssi-sdk/cryptosuite" + "github.com/TBD54566975/ssi-sdk/cryptosuite/jws2020" + "github.com/goccy/go-json" "github.com/stretchr/testify/assert" ) @@ -34,7 +36,7 @@ func TestCredentialsFromInterface(t *testing.T) { }) t.Run("Data Integrity Cred", func(tt *testing.T) { - knownJWK := cryptosuite.JSONWebKey2020{ + knownJWK := jws2020.JSONWebKey2020{ ID: "did:example:123#key-0", PublicKeyJWK: jwx.PublicKeyJWK{ KID: "key-0", @@ -51,10 +53,10 @@ func TestCredentialsFromInterface(t *testing.T) { }, } - signer, err := cryptosuite.NewJSONWebKeySigner("issuer-id", knownJWK.PrivateKeyJWK, cryptosuite.AssertionMethod) + signer, err := jws2020.NewJSONWebKeySigner("issuer-id", knownJWK.PrivateKeyJWK, cryptosuite.AssertionMethod) assert.NoError(t, err) - suite := cryptosuite.GetJSONWebSignature2020Suite() + suite := jws2020.GetJSONWebSignature2020Suite() testCred := getTestCredential() err = suite.Sign(signer, &testCred) @@ -71,6 +73,48 @@ func TestCredentialsFromInterface(t *testing.T) { assert.Equal(tt, parsedCred.Issuer, genericCred["issuer"]) }) + t.Run("Data Integrity Cred as a JSON string", func(tt *testing.T) { + knownJWK := jws2020.JSONWebKey2020{ + ID: "did:example:123#key-0", + PublicKeyJWK: jwx.PublicKeyJWK{ + KID: "key-0", + KTY: "OKP", + CRV: "Ed25519", + X: "JYCAGl6C7gcDeKbNqtXBfpGzH0f5elifj7L6zYNj_Is", + }, + PrivateKeyJWK: jwx.PrivateKeyJWK{ + KID: "key-0", + KTY: "OKP", + CRV: "Ed25519", + X: "JYCAGl6C7gcDeKbNqtXBfpGzH0f5elifj7L6zYNj_Is", + D: "pLMxJruKPovJlxF3Lu_x9Aw3qe2wcj5WhKUAXYLBjwE", + }, + } + + signer, err := jws2020.NewJSONWebKeySigner("issuer-id", knownJWK.PrivateKeyJWK, cryptosuite.AssertionMethod) + assert.NoError(t, err) + + suite := jws2020.GetJSONWebSignature2020Suite() + + testCred := getTestCredential() + err = suite.Sign(signer, &testCred) + assert.NoError(t, err) + + credBytes, err := json.Marshal(testCred) + assert.NoError(t, err) + credJSON := string(credBytes) + + _, _, parsedCred, err := ToCredential(credJSON) + assert.NoError(tt, err) + assert.NotEmpty(tt, parsedCred) + assert.Equal(tt, testCred.Issuer, parsedCred.Issuer) + + genericCred, err := ToCredentialJSONMap(credJSON) + assert.NoError(tt, err) + assert.NotEmpty(tt, genericCred) + assert.Equal(tt, parsedCred.Issuer, genericCred["issuer"]) + }) + t.Run("JWT Cred", func(tt *testing.T) { knownJWK := jwx.PrivateKeyJWK{ KID: "key-0", diff --git a/cryptosuite/bbsplussignatureproofsuite.go b/cryptosuite/bbs/bbsplussignatureproofsuite.go similarity index 88% rename from cryptosuite/bbsplussignatureproofsuite.go rename to cryptosuite/bbs/bbsplussignatureproofsuite.go index 4667fe8e..aab2adc2 100644 --- a/cryptosuite/bbsplussignatureproofsuite.go +++ b/cryptosuite/bbs/bbsplussignatureproofsuite.go @@ -1,4 +1,4 @@ -package cryptosuite +package bbs import ( gocrypto "crypto" @@ -6,13 +6,14 @@ import ( "strings" "github.com/TBD54566975/ssi-sdk/crypto" + "github.com/TBD54566975/ssi-sdk/cryptosuite" . "github.com/TBD54566975/ssi-sdk/util" "github.com/goccy/go-json" "github.com/pkg/errors" ) const ( - BBSPlusSignatureProof2020 SignatureType = "BbsBlsSignatureProof2020" + BBSPlusSignatureProof2020 cryptosuite.SignatureType = "BbsBlsSignatureProof2020" ) type BBSPlusSignatureProofSuite struct{} @@ -23,13 +24,13 @@ func GetBBSPlusSignatureProofSuite() *BBSPlusSignatureProofSuite { // CryptoSuiteInfo interface -var _ CryptoSuiteInfo = (*BBSPlusSignatureProofSuite)(nil) +var _ cryptosuite.CryptoSuiteInfo = (*BBSPlusSignatureProofSuite)(nil) func (BBSPlusSignatureProofSuite) ID() string { return BBSPlusSignatureSuiteID } -func (BBSPlusSignatureProofSuite) Type() LDKeyType { +func (BBSPlusSignatureProofSuite) Type() cryptosuite.LDKeyType { return BBSPlusSignatureSuiteType } @@ -41,7 +42,7 @@ func (BBSPlusSignatureProofSuite) MessageDigestAlgorithm() gocrypto.Hash { return BBSPlusSignatureSuiteDigestAlgorithm } -func (BBSPlusSignatureProofSuite) SignatureAlgorithm() SignatureType { +func (BBSPlusSignatureProofSuite) SignatureAlgorithm() cryptosuite.SignatureType { return BBSPlusSignatureProof2020 } @@ -49,8 +50,8 @@ func (BBSPlusSignatureProofSuite) RequiredContexts() []string { return []string{BBSSecurityContext} } -// SelectivelyDisclose takes in a credential (parameter `p` that's Provable) and a map of fields to disclose as an LD frame, and produces a map of the JSON representation of the derived credential. The derived credential only contains the information that was specified in the LD frame, and a proof that's derived from the original credential. Note that a requirement for `p` is that the property `"proof"` must be present when it's marshaled to JSON, and it's value MUST be an object that conforms to a `BBSPlusProof`. -func (b BBSPlusSignatureProofSuite) SelectivelyDisclose(v BBSPlusVerifier, p Provable, toDiscloseFrame map[string]any, nonce []byte) (map[string]any, error) { +// SelectivelyDisclose takes in a credential (parameter `p` that's WithEmbeddedProof) and a map of fields to disclose as an LD frame, and produces a map of the JSON representation of the derived credential. The derived credential only contains the information that was specified in the LD frame, and a proof that's derived from the original credential. Note that a requirement for `p` is that the property `"proof"` must be present when it's marshaled to JSON, and it's value MUST be an object that conforms to a `BBSPlusProof`. +func (b BBSPlusSignatureProofSuite) SelectivelyDisclose(v BBSPlusVerifier, p cryptosuite.WithEmbeddedProof, toDiscloseFrame map[string]any, nonce []byte) (map[string]any, error) { // first compact the document with the security context compactProvable, compactProof, err := b.compactProvable(p) if err != nil { @@ -99,7 +100,7 @@ func (b BBSPlusSignatureProofSuite) SelectivelyDisclose(v BBSPlusVerifier, p Pro return derivedCred, nil } -func (BBSPlusSignatureProofSuite) compactProvable(p Provable) (Provable, *crypto.Proof, error) { +func (BBSPlusSignatureProofSuite) compactProvable(p cryptosuite.WithEmbeddedProof) (cryptosuite.WithEmbeddedProof, *crypto.Proof, error) { var genericProvable map[string]any provableBytes, err := json.Marshal(p) if err != nil { @@ -108,7 +109,7 @@ func (BBSPlusSignatureProofSuite) compactProvable(p Provable) (Provable, *crypto if err = json.Unmarshal(provableBytes, &genericProvable); err != nil { return nil, nil, errors.Wrap(err, "unmarshalling provable to generic map") } - compactProvable, err := LDCompact(genericProvable, W3CSecurityContext) + compactProvable, err := LDCompact(genericProvable, cryptosuite.W3CSecurityContext) if err != nil { return nil, nil, errors.Wrap(err, "compacting provable") } @@ -122,7 +123,7 @@ func (BBSPlusSignatureProofSuite) compactProvable(p Provable) (Provable, *crypto if err != nil { return nil, nil, err } - var genericCred GenericProvable + var genericCred cryptosuite.GenericProvable if err = json.Unmarshal(compactedProvableBytes, &genericCred); err != nil { return nil, nil, errors.Wrap(err, "unmarshalling compacted provable to generic credential") } @@ -173,7 +174,7 @@ func (b BBSPlusSignatureProofSuite) prepareBLSProof(bbsPlusProof BBSPlusSignatur if err = json.Unmarshal(marshaledProof, &genericProof); err != nil { return nil, err } - genericProof["@context"] = W3CSecurityContext + genericProof["@context"] = cryptosuite.W3CSecurityContext proofBytes, err := json.Marshal(genericProof) if err != nil { @@ -259,7 +260,7 @@ func (b BBSPlusSignatureProofSuite) CreateDeriveProof(inputProofDocument any, re } // Verify verifies a BBS Plus derived proof. Note that the underlying value for `v` must be of type `*BBSPlusVerifier`. Bug here: https://github.com/w3c-ccg/ldp-bbs2020/issues/62 -func (b BBSPlusSignatureProofSuite) Verify(v Verifier, p Provable) error { +func (b BBSPlusSignatureProofSuite) Verify(v cryptosuite.Verifier, p cryptosuite.WithEmbeddedProof) error { proof := p.GetProof() gotProof, err := BBSPlusProofFromGenericProof(*proof) if err != nil { @@ -280,14 +281,14 @@ func (b BBSPlusSignatureProofSuite) Verify(v Verifier, p Provable) error { gotProof.SetProofValue("") // prepare proof options - contexts, err := GetContextsFromProvable(p) + contexts, err := cryptosuite.GetContextsFromProvable(p) if err != nil { return errors.Wrap(err, "getting contexts from provable") } // make sure the suite's context(s) are included - contexts = ensureRequiredContexts(contexts, b.RequiredContexts()) - opts := &ProofOptions{Contexts: contexts} + contexts = cryptosuite.EnsureRequiredContexts(contexts, b.RequiredContexts()) + opts := &cryptosuite.ProofOptions{Contexts: contexts} // run the create verify hash algorithm on both provable and the proof var genericProvable map[string]any @@ -320,7 +321,7 @@ func (b BBSPlusSignatureProofSuite) Verify(v Verifier, p Provable) error { // CryptoSuiteProofType interface -var _ CryptoSuiteProofType = (*BBSPlusSignatureProofSuite)(nil) +var _ cryptosuite.CryptoSuiteProofType = (*BBSPlusSignatureProofSuite)(nil) func (BBSPlusSignatureProofSuite) Marshal(data any) ([]byte, error) { // JSONify the provable object @@ -358,7 +359,7 @@ func canonicalizedLDToStatements(canonicalized string) []string { // CreateVerifyHash https://w3c-ccg.github.io/data-integrity-spec/#create-verify-hash-algorithm // augmented by https://w3c-ccg.github.io/ldp-bbs2020/#create-verify-data-algorithm -func (b BBSPlusSignatureProofSuite) CreateVerifyHash(doc map[string]any, proof crypto.Proof, opts *ProofOptions) ([]byte, error) { +func (b BBSPlusSignatureProofSuite) CreateVerifyHash(doc map[string]any, proof crypto.Proof, opts *cryptosuite.ProofOptions) ([]byte, error) { // first, make sure "created" exists in the proof and insert an LD context property for the proof vocabulary preparedProof, err := b.prepareProof(proof, opts) if err != nil { @@ -408,7 +409,7 @@ func (b BBSPlusSignatureProofSuite) CreateVerifyHash(doc map[string]any, proof c return output, nil } -func (b BBSPlusSignatureProofSuite) prepareProof(proof crypto.Proof, opts *ProofOptions) (*crypto.Proof, error) { +func (b BBSPlusSignatureProofSuite) prepareProof(proof crypto.Proof, opts *cryptosuite.ProofOptions) (*crypto.Proof, error) { proofBytes, err := json.Marshal(proof) if err != nil { return nil, err diff --git a/cryptosuite/bbsplussignatureproofsuite_test.go b/cryptosuite/bbs/bbsplussignatureproofsuite_test.go similarity index 94% rename from cryptosuite/bbsplussignatureproofsuite_test.go rename to cryptosuite/bbs/bbsplussignatureproofsuite_test.go index 30ac08f3..544621f4 100644 --- a/cryptosuite/bbsplussignatureproofsuite_test.go +++ b/cryptosuite/bbs/bbsplussignatureproofsuite_test.go @@ -1,10 +1,11 @@ -package cryptosuite +package bbs import ( "embed" "encoding/base64" "testing" + "github.com/TBD54566975/ssi-sdk/cryptosuite" "github.com/goccy/go-json" bbsg2 "github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub" "github.com/mr-tron/base58" @@ -40,11 +41,11 @@ func TestBBSPlusSignatureProofSuite(t *testing.T) { "id": "did:example:abcd", }, } - key, err := GenerateBLSKey2020(BLS12381G2Key2020) + key, err := GenerateBLSKey2020(cryptosuite.BLS12381G2Key2020) assert.NoError(t, err) privKey, err := key.GetPrivateKey() assert.NoError(t, err) - signer := NewBBSPlusSigner("test-key-1", privKey, AssertionMethod) + signer := NewBBSPlusSigner("test-key-1", privKey, cryptosuite.AssertionMethod) err = suite.Sign(signer, &testCred) assert.NoError(t, err) @@ -64,7 +65,7 @@ func TestBBSPlusSignatureProofSuite(t *testing.T) { assert.NotEmpty(tt, selectiveDisclosure) // now verify the derived credential - genericCred := GenericProvable(selectiveDisclosure) + genericCred := cryptosuite.GenericProvable(selectiveDisclosure) err = proofSuite.Verify(verifier, &genericCred) assert.NoError(tt, err) }) @@ -110,7 +111,7 @@ func TestBBSPlusSignatureProofSuite(t *testing.T) { assert.NotEmpty(tt, selectiveDisclosure) // now verify the derived credential - genericCred := GenericProvable(selectiveDisclosure) + genericCred := cryptosuite.GenericProvable(selectiveDisclosure) err = proofSuite.Verify(verifier, &genericCred) assert.NoError(tt, err) }) @@ -120,7 +121,7 @@ func TestBBSPlusSignatureProofSuite(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, revealedDoc) - var genericCred GenericProvable + var genericCred cryptosuite.GenericProvable err = json.Unmarshal([]byte(revealedDoc), &genericCred) assert.NoError(tt, err) @@ -182,7 +183,7 @@ func TestBBSPlusSignatureProofSuite(t *testing.T) { credBytes, err := json.Marshal(selectivelyDisclosedCred) assert.NoError(tt, err) - var genericCred GenericProvable + var genericCred cryptosuite.GenericProvable err = json.Unmarshal(credBytes, &genericCred) assert.NoError(tt, err) diff --git a/cryptosuite/bbsplussignaturesuite.go b/cryptosuite/bbs/bbsplussignaturesuite.go similarity index 77% rename from cryptosuite/bbsplussignaturesuite.go rename to cryptosuite/bbs/bbsplussignaturesuite.go index c66a1102..69127b91 100644 --- a/cryptosuite/bbsplussignaturesuite.go +++ b/cryptosuite/bbs/bbsplussignaturesuite.go @@ -1,40 +1,41 @@ -package cryptosuite +package bbs import ( gocrypto "crypto" "encoding/base64" "github.com/TBD54566975/ssi-sdk/crypto" + "github.com/TBD54566975/ssi-sdk/cryptosuite" . "github.com/TBD54566975/ssi-sdk/util" "github.com/goccy/go-json" "github.com/pkg/errors" ) const ( - BBSSecurityContext string = "https://w3c.github.io/vc-di-bbs/contexts/v1" - BBSPlusSignature2020 SignatureType = "BbsBlsSignature2020" - BBSPlusSignatureSuiteID string = "https://w3c-ccg.github.io/ldp-bbs2020/#the-bbs-signature-suite-2020" - BBSPlusSignatureSuiteType LDKeyType = BLS12381G2Key2020 - BBSPlusSignatureSuiteCanonicalizationAlgorithm string = "https://w3id.org/security#URDNA2015" + BBSSecurityContext string = "https://w3c.github.io/vc-di-bbs/contexts/v1" + BBSPlusSignature2020 cryptosuite.SignatureType = "BbsBlsSignature2020" + BBSPlusSignatureSuiteID string = "https://w3c-ccg.github.io/ldp-bbs2020/#the-bbs-signature-suite-2020" + BBSPlusSignatureSuiteType = cryptosuite.BLS12381G2Key2020 + BBSPlusSignatureSuiteCanonicalizationAlgorithm string = "https://w3id.org/security#URDNA2015" // BBSPlusSignatureSuiteDigestAlgorithm uses https://www.rfc-editor.org/rfc/rfc4634 BBSPlusSignatureSuiteDigestAlgorithm gocrypto.Hash = gocrypto.BLAKE2b_384 ) type BBSPlusSignatureSuite struct{} -func GetBBSPlusSignatureSuite() CryptoSuite { +func GetBBSPlusSignatureSuite() cryptosuite.CryptoSuite { return new(BBSPlusSignatureSuite) } // CryptoSuiteInfo interface -var _ CryptoSuiteInfo = (*BBSPlusSignatureSuite)(nil) +var _ cryptosuite.CryptoSuiteInfo = (*BBSPlusSignatureSuite)(nil) func (BBSPlusSignatureSuite) ID() string { return BBSPlusSignatureSuiteID } -func (BBSPlusSignatureSuite) Type() LDKeyType { +func (BBSPlusSignatureSuite) Type() cryptosuite.LDKeyType { return BBSPlusSignatureSuiteType } @@ -46,7 +47,7 @@ func (BBSPlusSignatureSuite) MessageDigestAlgorithm() gocrypto.Hash { return BBSPlusSignatureSuiteDigestAlgorithm } -func (BBSPlusSignatureSuite) SignatureAlgorithm() SignatureType { +func (BBSPlusSignatureSuite) SignatureAlgorithm() cryptosuite.SignatureType { return BBSPlusSignature2020 } @@ -54,20 +55,20 @@ func (BBSPlusSignatureSuite) RequiredContexts() []string { return []string{BBSSecurityContext} } -func (b BBSPlusSignatureSuite) Sign(s Signer, p Provable) error { +func (b BBSPlusSignatureSuite) Sign(s cryptosuite.Signer, p cryptosuite.WithEmbeddedProof) error { // create proof before running the create verify hash algorithm // TODO(gabe) support required reveal values proof := b.createProof(s.GetKeyID(), s.GetProofPurpose(), nil) // prepare proof options - contexts, err := GetContextsFromProvable(p) + contexts, err := cryptosuite.GetContextsFromProvable(p) if err != nil { return errors.Wrap(err, "getting contexts from provable") } // make sure the suite's context(s) are included - contexts = ensureRequiredContexts(contexts, b.RequiredContexts()) - opts := &ProofOptions{Contexts: contexts} + contexts = cryptosuite.EnsureRequiredContexts(contexts, b.RequiredContexts()) + opts := &cryptosuite.ProofOptions{Contexts: contexts} // 3. tbs value as a result of create verify hash var genericProvable map[string]any @@ -96,7 +97,7 @@ func (b BBSPlusSignatureSuite) Sign(s Signer, p Provable) error { return nil } -func (b BBSPlusSignatureSuite) prepareProof(proof crypto.Proof, opts *ProofOptions) (*crypto.Proof, error) { +func (b BBSPlusSignatureSuite) prepareProof(proof crypto.Proof, opts *cryptosuite.ProofOptions) (*crypto.Proof, error) { proofBytes, err := json.Marshal(proof) if err != nil { return nil, err @@ -128,7 +129,7 @@ func (b BBSPlusSignatureSuite) prepareProof(proof crypto.Proof, opts *ProofOptio return &p, nil } -func (b BBSPlusSignatureSuite) Verify(v Verifier, p Provable) error { +func (b BBSPlusSignatureSuite) Verify(v cryptosuite.Verifier, p cryptosuite.WithEmbeddedProof) error { proof := p.GetProof() gotProof, err := BBSPlusProofFromGenericProof(*proof) if err != nil { @@ -149,14 +150,14 @@ func (b BBSPlusSignatureSuite) Verify(v Verifier, p Provable) error { gotProof.SetProofValue("") // prepare proof options - contexts, err := GetContextsFromProvable(p) + contexts, err := cryptosuite.GetContextsFromProvable(p) if err != nil { return errors.Wrap(err, "getting contexts from provable") } // make sure the suite's context(s) are included - contexts = ensureRequiredContexts(contexts, b.RequiredContexts()) - opts := &ProofOptions{Contexts: contexts} + contexts = cryptosuite.EnsureRequiredContexts(contexts, b.RequiredContexts()) + opts := &cryptosuite.ProofOptions{Contexts: contexts} // run the create verify hash algorithm on both provable and the proof var genericProvable map[string]any @@ -194,7 +195,7 @@ func decodeProofValue(proofValue string) ([]byte, error) { // CryptoSuiteProofType interface -var _ CryptoSuiteProofType = (*BBSPlusSignatureSuite)(nil) +var _ cryptosuite.CryptoSuiteProofType = (*BBSPlusSignatureSuite)(nil) func (BBSPlusSignatureSuite) Marshal(data any) ([]byte, error) { // JSONify the provable object @@ -221,7 +222,7 @@ func (BBSPlusSignatureSuite) Canonicalize(marshaled []byte) (*string, error) { // CreateVerifyHash https://w3c-ccg.github.io/data-integrity-spec/#create-verify-hash-algorithm // augmented by https://w3c-ccg.github.io/ldp-bbs2020/#create-verify-data-algorithm -func (b BBSPlusSignatureSuite) CreateVerifyHash(doc map[string]any, proof crypto.Proof, opts *ProofOptions) ([]byte, error) { +func (b BBSPlusSignatureSuite) CreateVerifyHash(doc map[string]any, proof crypto.Proof, opts *cryptosuite.ProofOptions) ([]byte, error) { // first, make sure "created" exists in the proof and insert an LD context property for the proof vocabulary preparedProof, err := b.prepareProof(proof, opts) if err != nil { @@ -276,7 +277,7 @@ func (BBSPlusSignatureSuite) Digest(tbd []byte) ([]byte, error) { return tbd, nil } -func (b BBSPlusSignatureSuite) createProof(verificationMethod string, purpose ProofPurpose, requiredRevealStatements []int) BBSPlusSignature2020Proof { +func (b BBSPlusSignatureSuite) createProof(verificationMethod string, purpose cryptosuite.ProofPurpose, requiredRevealStatements []int) BBSPlusSignature2020Proof { return BBSPlusSignature2020Proof{ Type: b.SignatureAlgorithm(), Created: GetRFC3339Timestamp(), @@ -287,13 +288,13 @@ func (b BBSPlusSignatureSuite) createProof(verificationMethod string, purpose Pr } type BBSPlusSignature2020Proof struct { - Type SignatureType `json:"type,omitempty"` - Created string `json:"created,omitempty"` - VerificationMethod string `json:"verificationMethod,omitempty"` - ProofPurpose ProofPurpose `json:"proofPurpose,omitempty"` - ProofValue string `json:"proofValue,omitempty"` - Nonce string `json:"nonce,omitempty"` - RequiredRevealStatements []int `json:"requiredRevealStatements,omitempty"` + Type cryptosuite.SignatureType `json:"type,omitempty"` + Created string `json:"created,omitempty"` + VerificationMethod string `json:"verificationMethod,omitempty"` + ProofPurpose cryptosuite.ProofPurpose `json:"proofPurpose,omitempty"` + ProofValue string `json:"proofValue,omitempty"` + Nonce string `json:"nonce,omitempty"` + RequiredRevealStatements []int `json:"requiredRevealStatements,omitempty"` } func (b *BBSPlusSignature2020Proof) SetProofValue(proofValue string) { @@ -301,7 +302,7 @@ func (b *BBSPlusSignature2020Proof) SetProofValue(proofValue string) { } // BBSPlusProofFromGenericProof accepts either a slice with exactly one element, or a single element and creates a -// BBSPlusProofFromGenericProof by unmarshaling the JSON marshaled representation of the element found in `p`. +// BBSPlusSignature2020Proof by unmarshaling the JSON marshaled representation of the element found in `p`. func BBSPlusProofFromGenericProof(p crypto.Proof) (*BBSPlusSignature2020Proof, error) { // check if the proof is an array if proofArray, ok := p.([]any); ok { diff --git a/cryptosuite/bbsplussignaturesuite_test.go b/cryptosuite/bbs/bbsplussignaturesuite_test.go similarity index 91% rename from cryptosuite/bbsplussignaturesuite_test.go rename to cryptosuite/bbs/bbsplussignaturesuite_test.go index df1efcc0..94e6908f 100644 --- a/cryptosuite/bbsplussignaturesuite_test.go +++ b/cryptosuite/bbs/bbsplussignaturesuite_test.go @@ -1,9 +1,10 @@ -package cryptosuite +package bbs import ( "testing" "github.com/TBD54566975/ssi-sdk/crypto" + "github.com/TBD54566975/ssi-sdk/cryptosuite" "github.com/goccy/go-json" bbs "github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub" "github.com/mr-tron/base58" @@ -27,7 +28,7 @@ func TestBBSPlusSignatureSuite(t *testing.T) { }, } - key, err := GenerateBLSKey2020(BLS12381G2Key2020) + key, err := GenerateBLSKey2020(cryptosuite.BLS12381G2Key2020) assert.NoError(t, err) assert.NotEmpty(t, key) @@ -35,7 +36,7 @@ func TestBBSPlusSignatureSuite(t *testing.T) { assert.NoError(t, err) assert.NotEmpty(t, privKey) - signer := NewBBSPlusSigner("test-key-1", privKey, Authentication) + signer := NewBBSPlusSigner("test-key-1", privKey, cryptosuite.Authentication) assert.NotEmpty(t, signer) err = suite.Sign(signer, &testCred) diff --git a/cryptosuite/bls12381g2key2020.go b/cryptosuite/bbs/bls12381g2key2020.go similarity index 73% rename from cryptosuite/bls12381g2key2020.go rename to cryptosuite/bbs/bls12381g2key2020.go index c5656e1c..6d939a95 100644 --- a/cryptosuite/bls12381g2key2020.go +++ b/cryptosuite/bbs/bls12381g2key2020.go @@ -1,24 +1,26 @@ -package cryptosuite +package bbs import ( "fmt" "github.com/TBD54566975/ssi-sdk/crypto" + "github.com/TBD54566975/ssi-sdk/cryptosuite" + "github.com/TBD54566975/ssi-sdk/cryptosuite/jws2020" bbs "github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub" "github.com/mr-tron/base58" ) const ( - G1 CRV = "BLS12381_G1" - G2 CRV = "BLS12381_G2" + G1 jws2020.CRV = "BLS12381_G1" + G2 jws2020.CRV = "BLS12381_G2" ) type BLSKey2020 struct { - ID string `json:"id,omitempty"` - Type LDKeyType `json:"type,omitempty"` - Controller string `json:"controller,omitempty"` - PublicKeyBase58 string `json:"publicKeyBase58,omitempty"` - PrivateKeyBase58 string `json:"privateKeyBase58,omitempty"` + ID string `json:"id,omitempty"` + Type cryptosuite.LDKeyType `json:"type,omitempty"` + Controller string `json:"controller,omitempty"` + PublicKeyBase58 string `json:"publicKeyBase58,omitempty"` + PrivateKeyBase58 string `json:"privateKeyBase58,omitempty"` } func (b BLSKey2020) GetPublicKey() (*bbs.PublicKey, error) { @@ -46,8 +48,8 @@ func (b BLSKey2020) GetPrivateKey() (*bbs.PrivateKey, error) { } // GenerateBLSKey2020 https://w3c-ccg.github.io/vc-di-bbs/#bls12-381 -func GenerateBLSKey2020(keyType LDKeyType) (*BLSKey2020, error) { - if keyType != BLS12381G2Key2020 { +func GenerateBLSKey2020(keyType cryptosuite.LDKeyType) (*BLSKey2020, error) { + if keyType != cryptosuite.BLS12381G2Key2020 { return nil, fmt.Errorf("unsupported key type %s", keyType) } pubKey, privKey, err := crypto.GenerateBBSKeyPair() @@ -72,11 +74,11 @@ func GenerateBLSKey2020(keyType LDKeyType) (*BLSKey2020, error) { type BBSPlusSigner struct { *crypto.BBSPlusSigner *crypto.BBSPlusVerifier - purpose ProofPurpose - format PayloadFormat + purpose cryptosuite.ProofPurpose + format cryptosuite.PayloadFormat } -func NewBBSPlusSigner(kid string, privKey *bbs.PrivateKey, purpose ProofPurpose) *BBSPlusSigner { +func NewBBSPlusSigner(kid string, privKey *bbs.PrivateKey, purpose cryptosuite.ProofPurpose) *BBSPlusSigner { signer := crypto.NewBBSPlusSigner(kid, privKey) return &BBSPlusSigner{ BBSPlusSigner: signer, @@ -93,7 +95,7 @@ func (s *BBSPlusSigner) GetKeyID() string { return s.BBSPlusSigner.GetKeyID() } -func (*BBSPlusSigner) GetSignatureType() SignatureType { +func (*BBSPlusSigner) GetSignatureType() cryptosuite.SignatureType { return BBSPlusSignature2020 } @@ -101,19 +103,19 @@ func (*BBSPlusSigner) GetSigningAlgorithm() string { return string(BBSPlusSignature2020) } -func (s *BBSPlusSigner) SetProofPurpose(purpose ProofPurpose) { +func (s *BBSPlusSigner) SetProofPurpose(purpose cryptosuite.ProofPurpose) { s.purpose = purpose } -func (s *BBSPlusSigner) GetProofPurpose() ProofPurpose { +func (s *BBSPlusSigner) GetProofPurpose() cryptosuite.ProofPurpose { return s.purpose } -func (s *BBSPlusSigner) SetPayloadFormat(format PayloadFormat) { +func (s *BBSPlusSigner) SetPayloadFormat(format cryptosuite.PayloadFormat) { s.format = format } -func (s *BBSPlusSigner) GetPayloadFormat() PayloadFormat { +func (s *BBSPlusSigner) GetPayloadFormat() cryptosuite.PayloadFormat { return s.format } diff --git a/cryptosuite/testdata/case16_reveal_doc.jsonld b/cryptosuite/bbs/testdata/case16_reveal_doc.jsonld similarity index 100% rename from cryptosuite/testdata/case16_reveal_doc.jsonld rename to cryptosuite/bbs/testdata/case16_reveal_doc.jsonld diff --git a/cryptosuite/testdata/case16_revealed.jsonld b/cryptosuite/bbs/testdata/case16_revealed.jsonld similarity index 100% rename from cryptosuite/testdata/case16_revealed.jsonld rename to cryptosuite/bbs/testdata/case16_revealed.jsonld diff --git a/cryptosuite/testdata/case16_vc.jsonld b/cryptosuite/bbs/testdata/case16_vc.jsonld similarity index 100% rename from cryptosuite/testdata/case16_vc.jsonld rename to cryptosuite/bbs/testdata/case16_vc.jsonld diff --git a/cryptosuite/testdata/case18_reveal_doc.jsonld b/cryptosuite/bbs/testdata/case18_reveal_doc.jsonld similarity index 100% rename from cryptosuite/testdata/case18_reveal_doc.jsonld rename to cryptosuite/bbs/testdata/case18_reveal_doc.jsonld diff --git a/cryptosuite/testdata/case18_vc.jsonld b/cryptosuite/bbs/testdata/case18_vc.jsonld similarity index 100% rename from cryptosuite/testdata/case18_vc.jsonld rename to cryptosuite/bbs/testdata/case18_vc.jsonld diff --git a/cryptosuite/testdata/vc_test_vector.jsonld b/cryptosuite/bbs/testdata/vc_test_vector.jsonld similarity index 100% rename from cryptosuite/testdata/vc_test_vector.jsonld rename to cryptosuite/bbs/testdata/vc_test_vector.jsonld diff --git a/cryptosuite/testutil_test.go b/cryptosuite/bbs/testutil_test.go similarity index 98% rename from cryptosuite/testutil_test.go rename to cryptosuite/bbs/testutil_test.go index 09d0d2c6..0a70ebb3 100644 --- a/cryptosuite/testutil_test.go +++ b/cryptosuite/bbs/testutil_test.go @@ -1,4 +1,4 @@ -package cryptosuite +package bbs import ( "github.com/TBD54566975/ssi-sdk/crypto" diff --git a/cryptosuite/cryptosuite.go b/cryptosuite/cryptosuite.go index cc3c5b2d..b6bcad30 100644 --- a/cryptosuite/cryptosuite.go +++ b/cryptosuite/cryptosuite.go @@ -22,9 +22,9 @@ type CryptoSuite interface { // Sign https://w3c-ccg.github.io/data-integrity-spec/#proof-algorithm // this method mutates the provided provable object, adding a `proof` block` - Sign(s Signer, p Provable) error + Sign(s Signer, p WithEmbeddedProof) error // Verify https://w3c-ccg.github.io/data-integrity-spec/#proof-verification-algorithm - Verify(v Verifier, p Provable) error + Verify(v Verifier, p WithEmbeddedProof) error } type CryptoSuiteInfo interface { @@ -50,7 +50,8 @@ type CryptoSuiteProofType interface { Digest(tbd []byte) ([]byte, error) } -type Provable interface { +// WithEmbeddedProof is an interface that defines functionality needed to get/set proofs on objects with embedded proofs +type WithEmbeddedProof interface { GetProof() *crypto.Proof SetProof(p *crypto.Proof) } @@ -109,7 +110,7 @@ func (g *GenericProvable) SetProof(p *crypto.Proof) { // GetContextsFromProvable searches from a Linked Data `@context` property in the document and returns the value // associated with the context, if it exists. -func GetContextsFromProvable(p Provable) ([]any, error) { +func GetContextsFromProvable(p WithEmbeddedProof) ([]any, error) { provableBytes, err := json.Marshal(p) if err != nil { return nil, err @@ -129,8 +130,8 @@ func GetContextsFromProvable(p Provable) ([]any, error) { return interfaceContexts, nil } -// attempt to verify that string context(s) exist in the context interface -func ensureRequiredContexts(context []any, requiredContexts []string) []any { +// EnsureRequiredContexts attempt to verify that string context(s) exist in the context interface +func EnsureRequiredContexts(context []any, requiredContexts []string) []any { required := make(map[string]bool) for _, v := range requiredContexts { required[v] = true diff --git a/cryptosuite/jsonwebkey2020.go b/cryptosuite/jws2020/jsonwebkey2020.go similarity index 85% rename from cryptosuite/jsonwebkey2020.go rename to cryptosuite/jws2020/jsonwebkey2020.go index eebc5d2b..71cbd5ae 100644 --- a/cryptosuite/jsonwebkey2020.go +++ b/cryptosuite/jws2020/jsonwebkey2020.go @@ -1,4 +1,4 @@ -package cryptosuite +package jws2020 import ( gocrypto "crypto" @@ -6,6 +6,7 @@ import ( "github.com/TBD54566975/ssi-sdk/crypto" "github.com/TBD54566975/ssi-sdk/crypto/jwx" + "github.com/TBD54566975/ssi-sdk/cryptosuite" "github.com/TBD54566975/ssi-sdk/util" "github.com/lestrrat-go/jwx/v2/jwa" "github.com/lestrrat-go/jwx/v2/jws" @@ -13,10 +14,9 @@ import ( ) type ( - KTY string - CRV string - ALG string - LDKeyType string + KTY string + CRV string + ALG string ) const ( @@ -37,9 +37,9 @@ const ( // JSONWebKey2020 complies with https://w3c-ccg.github.io/lds-jws2020/#json-web-key-2020 type JSONWebKey2020 struct { - ID string `json:"id,omitempty"` - Type LDKeyType `json:"type,omitempty"` - Controller string `json:"controller,omitempty"` + ID string `json:"id,omitempty"` + Type cryptosuite.LDKeyType `json:"type,omitempty"` + Controller string `json:"controller,omitempty"` jwx.PrivateKeyJWK `json:"privateKeyJwk,omitempty"` jwx.PublicKeyJWK `json:"publicKeyJwk,omitempty"` } @@ -48,10 +48,6 @@ func (jwk *JSONWebKey2020) IsValid() error { return util.NewValidator().Struct(jwk) } -func (ld LDKeyType) String() string { - return string(ld) -} - // GenerateJSONWebKey2020 The JSONWebKey2020 type specifies a number of key type and curve pairs to enable JOSE conformance // these pairs are supported in this library and generated via the function below // https://w3c-ccg.github.io/lds-jws2020/#dfn-jsonwebkey2020 @@ -98,7 +94,7 @@ func JSONWebKey2020FromPrivateKey(key gocrypto.PrivateKey) (*JSONWebKey2020, err return nil, err } return &JSONWebKey2020{ - Type: JSONWebKey2020Type, + Type: cryptosuite.JSONWebKey2020Type, PrivateKeyJWK: *privKeyJWK, PublicKeyJWK: *pubKeyJWK, }, nil @@ -172,8 +168,8 @@ func GenerateP384JSONWebKey2020() (*JSONWebKey2020, error) { // a message and provide a valid JSON Web Signature (JWS) value as a result. type JSONWebKeySigner struct { jwx.Signer - purpose ProofPurpose - format PayloadFormat + purpose cryptosuite.ProofPurpose + format cryptosuite.PayloadFormat } // Sign returns a byte array signature value for a message `tbs` @@ -193,7 +189,7 @@ func (s *JSONWebKeySigner) GetKeyID() string { return s.KID } -func (*JSONWebKeySigner) GetSignatureType() SignatureType { +func (*JSONWebKeySigner) GetSignatureType() cryptosuite.SignatureType { return JSONWebSignature2020 } @@ -201,23 +197,23 @@ func (s *JSONWebKeySigner) GetSigningAlgorithm() string { return s.ALG } -func (s *JSONWebKeySigner) SetProofPurpose(purpose ProofPurpose) { +func (s *JSONWebKeySigner) SetProofPurpose(purpose cryptosuite.ProofPurpose) { s.purpose = purpose } -func (s *JSONWebKeySigner) GetProofPurpose() ProofPurpose { +func (s *JSONWebKeySigner) GetProofPurpose() cryptosuite.ProofPurpose { return s.purpose } -func (s *JSONWebKeySigner) SetPayloadFormat(format PayloadFormat) { +func (s *JSONWebKeySigner) SetPayloadFormat(format cryptosuite.PayloadFormat) { s.format = format } -func (s *JSONWebKeySigner) GetPayloadFormat() PayloadFormat { +func (s *JSONWebKeySigner) GetPayloadFormat() cryptosuite.PayloadFormat { return s.format } -func NewJSONWebKeySigner(id string, key jwx.PrivateKeyJWK, purpose ProofPurpose) (*JSONWebKeySigner, error) { +func NewJSONWebKeySigner(id string, key jwx.PrivateKeyJWK, purpose cryptosuite.ProofPurpose) (*JSONWebKeySigner, error) { signer, err := jwx.NewJWXSignerFromJWK(id, key) if err != nil { return nil, err @@ -260,17 +256,17 @@ func NewJSONWebKeyVerifier(id string, key jwx.PublicKeyJWK) (*JSONWebKeyVerifier // PubKeyBytesToTypedKey converts a public key byte slice to a crypto.PublicKey based on a given key type, merging // both LD key types and JWK key types -func PubKeyBytesToTypedKey(keyBytes []byte, kt LDKeyType) (gocrypto.PublicKey, error) { +func PubKeyBytesToTypedKey(keyBytes []byte, kt cryptosuite.LDKeyType) (gocrypto.PublicKey, error) { var convertedKeyType crypto.KeyType switch kt.String() { - case JSONWebKey2020Type.String(): + case cryptosuite.JSONWebKey2020Type.String(): // we cannot know this key type based on the bytes alone return keyBytes, nil - case crypto.Ed25519.String(), Ed25519VerificationKey2018.String(), Ed25519VerificationKey2020.String(): + case crypto.Ed25519.String(), cryptosuite.Ed25519VerificationKey2018.String(), cryptosuite.Ed25519VerificationKey2020.String(): convertedKeyType = crypto.Ed25519 - case crypto.X25519.String(), X25519KeyAgreementKey2019.String(), X25519KeyAgreementKey2020.String(): + case crypto.X25519.String(), cryptosuite.X25519KeyAgreementKey2019.String(), cryptosuite.X25519KeyAgreementKey2020.String(): convertedKeyType = crypto.X25519 - case crypto.SECP256k1.String(), ECDSASECP256k1VerificationKey2019.String(): + case crypto.SECP256k1.String(), cryptosuite.ECDSASECP256k1VerificationKey2019.String(): convertedKeyType = crypto.SECP256k1 default: return nil, fmt.Errorf("unsupported key type: %s", kt) diff --git a/cryptosuite/jsonwebkey2020_test.go b/cryptosuite/jws2020/jsonwebkey2020_test.go similarity index 92% rename from cryptosuite/jsonwebkey2020_test.go rename to cryptosuite/jws2020/jsonwebkey2020_test.go index e3dd13f7..fdae48b4 100644 --- a/cryptosuite/jsonwebkey2020_test.go +++ b/cryptosuite/jws2020/jsonwebkey2020_test.go @@ -1,8 +1,9 @@ -package cryptosuite +package jws2020 import ( "testing" + "github.com/TBD54566975/ssi-sdk/cryptosuite" "github.com/stretchr/testify/assert" ) @@ -46,7 +47,7 @@ func TestJSONWebKey2020SignerVerifier(t *testing.T) { assert.NoError(t, err) assert.NotEmpty(t, jwk) - signer, err := NewJSONWebKeySigner(signerID, jwk.PrivateKeyJWK, AssertionMethod) + signer, err := NewJSONWebKeySigner(signerID, jwk.PrivateKeyJWK, cryptosuite.AssertionMethod) assert.NoError(t, err) testMessage := []byte("my name is satoshi") diff --git a/cryptosuite/jwssignaturesuite.go b/cryptosuite/jws2020/jwssignaturesuite.go similarity index 77% rename from cryptosuite/jwssignaturesuite.go rename to cryptosuite/jws2020/jwssignaturesuite.go index 33fc4367..091f6e21 100644 --- a/cryptosuite/jwssignaturesuite.go +++ b/cryptosuite/jws2020/jwssignaturesuite.go @@ -1,4 +1,4 @@ -package cryptosuite +package jws2020 import ( gocrypto "crypto" @@ -8,20 +8,21 @@ import ( "strings" "github.com/TBD54566975/ssi-sdk/crypto" + "github.com/TBD54566975/ssi-sdk/cryptosuite" . "github.com/TBD54566975/ssi-sdk/util" "github.com/goccy/go-json" "github.com/google/uuid" "github.com/pkg/errors" ) -// https://w3c-ccg.github.io/ld-cryptosuite-registry/#jsonwebsignature2020 +// https://w3c.github.io/vc-jws-2020/ const ( - JSONWebSignature2020Context string = "https://w3id.org/security/suites/jws-2020/v1" - JSONWebSignature2020 SignatureType = "JsonWebSignature2020" - JWSSignatureSuiteID string = "https://w3c-ccg.github.io/security-vocab/#JsonWebSignature2020" - JWSSignatureSuiteType LDKeyType = JSONWebKey2020Type - JWSSignatureSuiteCanonicalizationAlgorithm string = "https://w3id.org/security#URDNA2015" + JSONWebSignature2020Context string = "https://w3id.org/security/suites/jws-2020/v1" + JSONWebSignature2020 cryptosuite.SignatureType = "JsonWebSignature2020" + JWSSignatureSuiteID string = "https://w3c-ccg.github.io/security-vocab/#JsonWebSignature2020" + JWSSignatureSuiteType = cryptosuite.JSONWebKey2020Type + JWSSignatureSuiteCanonicalizationAlgorithm string = "https://w3id.org/security#URDNA2015" // JWSSignatureSuiteDigestAlgorithm uses https://www.rfc-editor.org/rfc/rfc4634 JWSSignatureSuiteDigestAlgorithm gocrypto.Hash = gocrypto.SHA256 // JWSSignatureSuiteProofAlgorithm uses https://www.rfc-editor.org/rfc/rfc7797 @@ -30,19 +31,19 @@ const ( type JWSSignatureSuite struct{} -func GetJSONWebSignature2020Suite() CryptoSuite { +func GetJSONWebSignature2020Suite() cryptosuite.CryptoSuite { return new(JWSSignatureSuite) } // CryptoSuiteInfo interface -var _ CryptoSuiteInfo = (*JWSSignatureSuite)(nil) +var _ cryptosuite.CryptoSuiteInfo = (*JWSSignatureSuite)(nil) func (JWSSignatureSuite) ID() string { return JWSSignatureSuiteID } -func (JWSSignatureSuite) Type() LDKeyType { +func (JWSSignatureSuite) Type() cryptosuite.LDKeyType { return JWSSignatureSuiteType } @@ -54,7 +55,7 @@ func (JWSSignatureSuite) MessageDigestAlgorithm() gocrypto.Hash { return JWSSignatureSuiteDigestAlgorithm } -func (JWSSignatureSuite) SignatureAlgorithm() SignatureType { +func (JWSSignatureSuite) SignatureAlgorithm() cryptosuite.SignatureType { return JWSSignatureSuiteProofAlgorithm } @@ -62,19 +63,19 @@ func (JWSSignatureSuite) RequiredContexts() []string { return []string{JSONWebSignature2020Context} } -func (j JWSSignatureSuite) Sign(s Signer, p Provable) error { +func (j JWSSignatureSuite) Sign(s cryptosuite.Signer, p cryptosuite.WithEmbeddedProof) error { // create proof before running the create verify hash algorithm proof := j.createProof(s.GetKeyID(), s.GetProofPurpose()) // prepare proof options - contexts, err := GetContextsFromProvable(p) + contexts, err := cryptosuite.GetContextsFromProvable(p) if err != nil { return errors.Wrap(err, "could not get contexts from provable") } // make sure the suite's context(s) are included - contexts = ensureRequiredContexts(contexts, j.RequiredContexts()) - opts := &ProofOptions{Contexts: contexts} + contexts = cryptosuite.EnsureRequiredContexts(contexts, j.RequiredContexts()) + opts := &cryptosuite.ProofOptions{Contexts: contexts} // 3. tbs value as a result of create verify hash var genericProvable map[string]any @@ -83,7 +84,7 @@ func (j JWSSignatureSuite) Sign(s Signer, p Provable) error { return errors.Wrap(err, "marshaling provable") } if err = json.Unmarshal(pBytes, &genericProvable); err != nil { - return errors.Wrap(err, "unmarshaling provable") + return errors.Wrap(err, "unmarshalling provable") } tbs, err := j.CreateVerifyHash(genericProvable, proof, opts) if err != nil { @@ -103,7 +104,7 @@ func (j JWSSignatureSuite) Sign(s Signer, p Provable) error { return nil } -func (j JWSSignatureSuite) Verify(v Verifier, p Provable) error { +func (j JWSSignatureSuite) Verify(v cryptosuite.Verifier, p cryptosuite.WithEmbeddedProof) error { proof := p.GetProof() gotProof, err := JSONWebSignatureProofFromGenericProof(*proof) if err != nil { @@ -121,23 +122,23 @@ func (j JWSSignatureSuite) Verify(v Verifier, p Provable) error { gotProof.SetDetachedJWS("") // prepare proof options - contexts, err := GetContextsFromProvable(p) + contexts, err := cryptosuite.GetContextsFromProvable(p) if err != nil { return errors.Wrap(err, "could not get contexts from provable") } // make sure the suite's context(s) are included - contexts = ensureRequiredContexts(contexts, j.RequiredContexts()) - opts := &ProofOptions{Contexts: contexts} + contexts = cryptosuite.EnsureRequiredContexts(contexts, j.RequiredContexts()) + opts := &cryptosuite.ProofOptions{Contexts: contexts} // run the create verify hash algorithm on both provable and the proof var genericProvable map[string]any pBytes, err := json.Marshal(p) if err != nil { - return errors.Wrap(err, "marshaling provable") + return errors.Wrap(err, "marshalling provable") } if err = json.Unmarshal(pBytes, &genericProvable); err != nil { - return errors.Wrap(err, "unmarshaling provable") + return errors.Wrap(err, "unmarshalling provable") } tbv, err := j.CreateVerifyHash(genericProvable, gotProof, opts) if err != nil { @@ -152,7 +153,7 @@ func (j JWSSignatureSuite) Verify(v Verifier, p Provable) error { // CryptoSuiteProofType interface -var _ CryptoSuiteProofType = (*JWSSignatureSuite)(nil) +var _ cryptosuite.CryptoSuiteProofType = (*JWSSignatureSuite)(nil) func (JWSSignatureSuite) Marshal(data any) ([]byte, error) { // JSONify the provable object @@ -177,7 +178,7 @@ func (JWSSignatureSuite) Canonicalize(marshaled []byte) (*string, error) { return &canonicalString, nil } -func (j JWSSignatureSuite) CreateVerifyHash(doc map[string]any, proof crypto.Proof, opts *ProofOptions) ([]byte, error) { +func (j JWSSignatureSuite) CreateVerifyHash(doc map[string]any, proof crypto.Proof, opts *cryptosuite.ProofOptions) ([]byte, error) { // first, make sure "created" exists in the proof and insert an LD context property for the proof vocabulary preparedProof, err := j.prepareProof(proof, opts) if err != nil { @@ -235,7 +236,7 @@ func (j JWSSignatureSuite) Digest(tbd []byte) ([]byte, error) { return hash[:], nil } -func (j JWSSignatureSuite) prepareProof(proof crypto.Proof, opts *ProofOptions) (*crypto.Proof, error) { +func (j JWSSignatureSuite) prepareProof(proof crypto.Proof, opts *cryptosuite.ProofOptions) (*crypto.Proof, error) { proofBytes, err := json.Marshal(proof) if err != nil { return nil, err @@ -268,12 +269,12 @@ func (j JWSSignatureSuite) prepareProof(proof crypto.Proof, opts *ProofOptions) } type JSONWebSignature2020Proof struct { - Type SignatureType `json:"type,omitempty"` - Created string `json:"created,omitempty"` - JWS string `json:"jws,omitempty"` - ProofPurpose ProofPurpose `json:"proofPurpose,omitempty"` - Challenge string `json:"challenge,omitempty"` - VerificationMethod string `json:"verificationMethod,omitempty"` + Type cryptosuite.SignatureType `json:"type,omitempty"` + Created string `json:"created,omitempty"` + JWS string `json:"jws,omitempty"` + ProofPurpose cryptosuite.ProofPurpose `json:"proofPurpose,omitempty"` + Challenge string `json:"challenge,omitempty"` + VerificationMethod string `json:"verificationMethod,omitempty"` } func JSONWebSignatureProofFromGenericProof(p crypto.Proof) (*JSONWebSignature2020Proof, error) { @@ -316,9 +317,9 @@ func (j *JSONWebSignature2020Proof) DecodeJWS() ([]byte, error) { return base64.RawURLEncoding.DecodeString(jwsParts[2]) } -func (j JWSSignatureSuite) createProof(verificationMethod string, purpose ProofPurpose) JSONWebSignature2020Proof { +func (j JWSSignatureSuite) createProof(verificationMethod string, purpose cryptosuite.ProofPurpose) JSONWebSignature2020Proof { var challenge string - if purpose == Authentication { + if purpose == cryptosuite.Authentication { challenge = uuid.NewString() } return JSONWebSignature2020Proof{ diff --git a/cryptosuite/jwssignaturesuite_test.go b/cryptosuite/jws2020/jwssignaturesuite_test.go similarity index 94% rename from cryptosuite/jwssignaturesuite_test.go rename to cryptosuite/jws2020/jwssignaturesuite_test.go index 4cf46455..2473187b 100644 --- a/cryptosuite/jwssignaturesuite_test.go +++ b/cryptosuite/jws2020/jwssignaturesuite_test.go @@ -1,10 +1,11 @@ -package cryptosuite +package jws2020 import ( "testing" "github.com/TBD54566975/ssi-sdk/crypto" "github.com/TBD54566975/ssi-sdk/crypto/jwx" + "github.com/TBD54566975/ssi-sdk/cryptosuite" "github.com/TBD54566975/ssi-sdk/util" "github.com/stretchr/testify/assert" @@ -12,7 +13,7 @@ import ( func TestJSONWebKey2020ToJWK(t *testing.T) { // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-0-ed25519.json - signer, jwk := getTestVectorKey0Signer(t, AssertionMethod) + signer, jwk := getTestVectorKey0Signer(t, cryptosuite.AssertionMethod) verifier, err := NewJSONWebKeyVerifier("verifier-id", jwk.PublicKeyJWK) assert.NoError(t, err) @@ -106,7 +107,7 @@ func TestJsonWebSignature2020AllKeyTypes(t *testing.T) { jwk, err := GenerateJSONWebKey2020(test.kty, test.crv) if !test.expectErr { - signer, err := NewJSONWebKeySigner(issuerID, jwk.PrivateKeyJWK, AssertionMethod) + signer, err := NewJSONWebKeySigner(issuerID, jwk.PrivateKeyJWK, cryptosuite.AssertionMethod) assert.NoError(tt, err) // pin to avoid ptr shadowing @@ -163,7 +164,7 @@ func TestCredentialLDProof(t *testing.T) { jwk.ID = issuer jwk.PrivateKeyJWK.KID = issuer - signer, err := NewJSONWebKeySigner(issuer, jwk.PrivateKeyJWK, AssertionMethod) + signer, err := NewJSONWebKeySigner(issuer, jwk.PrivateKeyJWK, cryptosuite.AssertionMethod) assert.NoError(t, err) assert.NotEmpty(t, signer) @@ -202,7 +203,7 @@ func TestCredentialLDProof(t *testing.T) { // https://github.com/decentralized-identity/JWS-Test-Suite func TestJSONWebSignature2020TestVectorCredential0(t *testing.T) { // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-0-ed25519.json - signer, jwk := getTestVectorKey0Signer(t, AssertionMethod) + signer, jwk := getTestVectorKey0Signer(t, cryptosuite.AssertionMethod) // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/credentials/credential-0.json knownCred := TestCredential{ @@ -243,7 +244,7 @@ func TestJSONWebSignature2020TestVectorCredential0(t *testing.T) { func TestJSONWebSignature2020TestVectorsCredential1(t *testing.T) { // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-0-ed25519.json - signer, jwk := getTestVectorKey0Signer(t, AssertionMethod) + signer, jwk := getTestVectorKey0Signer(t, cryptosuite.AssertionMethod) // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/credentials/credential-1.json knownCred := TestCredential{ @@ -270,7 +271,7 @@ func TestJSONWebSignature2020TestVectorsCredential1(t *testing.T) { assert.NoError(t, err) } -var _ Provable = (*TestVerifiablePresentation)(nil) +var _ cryptosuite.WithEmbeddedProof = (*TestVerifiablePresentation)(nil) type TestVerifiablePresentation struct { Context any `json:"@context,omitempty"` @@ -292,7 +293,7 @@ func (t *TestVerifiablePresentation) SetProof(p *crypto.Proof) { func TestJSONWebSignature2020TestVectorPresentation0(t *testing.T) { // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-0-ed25519.json - signer, jwk := getTestVectorKey0Signer(t, Authentication) + signer, jwk := getTestVectorKey0Signer(t, cryptosuite.Authentication) // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/presentations/presentation-0.json knownPres := TestVerifiablePresentation{ @@ -334,7 +335,7 @@ func TestJSONWebSignature2020TestVectorPresentation0(t *testing.T) { // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-0-ed25519.json func TestJSONWebSignature2020TestVectorPresentation1(t *testing.T) { - signer, jwk := getTestVectorKey0Signer(t, Authentication) + signer, jwk := getTestVectorKey0Signer(t, cryptosuite.Authentication) // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/presentations/presentation-1.json var credProof crypto.Proof = map[string]any{ @@ -416,7 +417,7 @@ func TestJSONWebSignature2020TestVectorPresentation1(t *testing.T) { assert.NoError(t, err) } -func getTestVectorKey0Signer(t *testing.T, purpose ProofPurpose) (JSONWebKeySigner, JSONWebKey2020) { +func getTestVectorKey0Signer(t *testing.T, purpose cryptosuite.ProofPurpose) (JSONWebKeySigner, JSONWebKey2020) { // https://github.com/decentralized-identity/JWS-Test-Suite/blob/main/data/keys/key-0-ed25519.json knownJWK := JSONWebKey2020{ ID: "did:example:123#key-0", diff --git a/cryptosuite/jws2020/testutil_test.go b/cryptosuite/jws2020/testutil_test.go new file mode 100644 index 00000000..e28b1570 --- /dev/null +++ b/cryptosuite/jws2020/testutil_test.go @@ -0,0 +1,32 @@ +package jws2020 + +import ( + "github.com/TBD54566975/ssi-sdk/crypto" +) + +type TestCredential struct { + Context any `json:"@context" validate:"required"` + ID string `json:"id,omitempty"` + Identifier string `json:"identifier,omitempty"` + Type any `json:"type" validate:"required"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Issuer any `json:"issuer" validate:"required"` + IssuanceDate string `json:"issuanceDate" validate:"required"` + ExpirationDate string `json:"expirationDate,omitempty"` + CredentialStatus any `json:"credentialStatus,omitempty" validate:"omitempty,dive"` + CredentialSubject any `json:"credentialSubject" validate:"required"` + CredentialSchema any `json:"credentialSchema,omitempty" validate:"omitempty,dive"` + RefreshService any `json:"refreshService,omitempty" validate:"omitempty,dive"` + TermsOfUse []any `json:"termsOfUse,omitempty" validate:"omitempty,dive"` + Evidence []any `json:"evidence,omitempty" validate:"omitempty,dive"` + Proof *crypto.Proof `json:"proof,omitempty"` +} + +func (t *TestCredential) GetProof() *crypto.Proof { + return t.Proof +} + +func (t *TestCredential) SetProof(p *crypto.Proof) { + t.Proof = p +} diff --git a/cryptosuite/model.go b/cryptosuite/model.go index 71ad9f1d..60e36660 100644 --- a/cryptosuite/model.go +++ b/cryptosuite/model.go @@ -4,8 +4,13 @@ type ( SignatureType string ProofPurpose string PayloadFormat string + LDKeyType string ) +func (ld LDKeyType) String() string { + return string(ld) +} + const ( W3CSecurityContext string = "https://w3id.org/security/v2" Ed25519VerificationKey2020Context string = "https://w3id.org/security/suites/ed25519-2020/v1" diff --git a/did/builder.go b/did/builder.go index 9dbb8ff2..32cf4b38 100644 --- a/did/builder.go +++ b/did/builder.go @@ -9,8 +9,8 @@ import ( "github.com/TBD54566975/ssi-sdk/util" ) -// DIDDocumentBuilder contexts and types are kept to avoid having cast to/from any values -type DIDDocumentBuilder struct { +// DocumentBuilder contexts and types are kept to avoid having cast to/from any values +type DocumentBuilder struct { contexts []string types []string *Document @@ -23,10 +23,10 @@ const ( ) // NewDIDDocumentBuilder Creates a new DID Document Builder -func NewDIDDocumentBuilder() DIDDocumentBuilder { +func NewDIDDocumentBuilder() DocumentBuilder { contexts := []string{DIDDocumentLDContext} types := []string{DIDDocumentType} - return DIDDocumentBuilder{ + return DocumentBuilder{ contexts: contexts, types: types, Document: &Document{ @@ -37,7 +37,7 @@ func NewDIDDocumentBuilder() DIDDocumentBuilder { } // Build builds the DID Document -func (builder *DIDDocumentBuilder) Build() (*Document, error) { +func (builder *DocumentBuilder) Build() (*Document, error) { if builder.IsEmpty() { return nil, errors.New(BuilderEmptyError) } @@ -49,14 +49,14 @@ func (builder *DIDDocumentBuilder) Build() (*Document, error) { return builder.Document, nil } -func (builder *DIDDocumentBuilder) IsEmpty() bool { +func (builder *DocumentBuilder) IsEmpty() bool { if builder == nil || builder.Document == nil { return true } - return reflect.DeepEqual(builder, &DIDDocumentBuilder{}) + return reflect.DeepEqual(builder, &DocumentBuilder{}) } -func (builder *DIDDocumentBuilder) AddContext(context any) error { +func (builder *DocumentBuilder) AddContext(context any) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -70,7 +70,7 @@ func (builder *DIDDocumentBuilder) AddContext(context any) error { return nil } -func (builder *DIDDocumentBuilder) SetID(id string) error { +func (builder *DocumentBuilder) SetID(id string) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -79,7 +79,7 @@ func (builder *DIDDocumentBuilder) SetID(id string) error { return nil } -func (builder *DIDDocumentBuilder) SetAlsoKnownAs(name string) error { +func (builder *DocumentBuilder) SetAlsoKnownAs(name string) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -87,7 +87,7 @@ func (builder *DIDDocumentBuilder) SetAlsoKnownAs(name string) error { return nil } -func (builder *DIDDocumentBuilder) SetController(controller string) error { +func (builder *DocumentBuilder) SetController(controller string) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -96,7 +96,7 @@ func (builder *DIDDocumentBuilder) SetController(controller string) error { } // AddVerificationMethod Note: Not thread safe -func (builder *DIDDocumentBuilder) AddVerificationMethod(m VerificationMethod) error { +func (builder *DocumentBuilder) AddVerificationMethod(m VerificationMethod) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -105,7 +105,7 @@ func (builder *DIDDocumentBuilder) AddVerificationMethod(m VerificationMethod) e } // AddAuthenticationMethod Note: Not thread safe -func (builder *DIDDocumentBuilder) AddAuthenticationMethod(m VerificationMethodSet) error { +func (builder *DocumentBuilder) AddAuthenticationMethod(m VerificationMethodSet) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -114,7 +114,7 @@ func (builder *DIDDocumentBuilder) AddAuthenticationMethod(m VerificationMethodS } // AddAssertionMethod Note: Not thread safe -func (builder *DIDDocumentBuilder) AddAssertionMethod(m VerificationMethodSet) error { +func (builder *DocumentBuilder) AddAssertionMethod(m VerificationMethodSet) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -123,7 +123,7 @@ func (builder *DIDDocumentBuilder) AddAssertionMethod(m VerificationMethodSet) e } // AddKeyAgreement Note: Not thread safe -func (builder *DIDDocumentBuilder) AddKeyAgreement(m VerificationMethodSet) error { +func (builder *DocumentBuilder) AddKeyAgreement(m VerificationMethodSet) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -132,7 +132,7 @@ func (builder *DIDDocumentBuilder) AddKeyAgreement(m VerificationMethodSet) erro } // AddCapabilityInvocation Note: Not thread safe -func (builder *DIDDocumentBuilder) AddCapabilityInvocation(m VerificationMethodSet) error { +func (builder *DocumentBuilder) AddCapabilityInvocation(m VerificationMethodSet) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -141,7 +141,7 @@ func (builder *DIDDocumentBuilder) AddCapabilityInvocation(m VerificationMethodS } // AddCapabilityDelegation Note: Not thread safe -func (builder *DIDDocumentBuilder) AddCapabilityDelegation(m VerificationMethodSet) error { +func (builder *DocumentBuilder) AddCapabilityDelegation(m VerificationMethodSet) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } @@ -150,7 +150,7 @@ func (builder *DIDDocumentBuilder) AddCapabilityDelegation(m VerificationMethodS } // AddService Note: Not thread safe -func (builder *DIDDocumentBuilder) AddService(s Service) error { +func (builder *DocumentBuilder) AddService(s Service) error { if builder.IsEmpty() { return errors.New(BuilderEmptyError) } diff --git a/did/builder_test.go b/did/builder_test.go index 3ae31ea6..fd19fbe2 100644 --- a/did/builder_test.go +++ b/did/builder_test.go @@ -59,7 +59,7 @@ func TestDIDDocumentBuilder(t *testing.T) { "publicKeyMultibase": "z9hFgmPVfmBZwRvFEyniQDBkz9LmV7gDEqytWyGZLmDXE", } - var builderBad DIDDocumentBuilder + var builderBad DocumentBuilder _, err := builderBad.Build() assert.Error(t, err) notReadyErr := "builder cannot be empty" diff --git a/did/jwk/jwk_test.go b/did/jwk/jwk_test.go index 8206b085..b1c08ddd 100644 --- a/did/jwk/jwk_test.go +++ b/did/jwk/jwk_test.go @@ -5,12 +5,12 @@ import ( "strings" "testing" + "github.com/TBD54566975/ssi-sdk/cryptosuite/jws2020" "github.com/goccy/go-json" "github.com/stretchr/testify/assert" "github.com/TBD54566975/ssi-sdk/crypto" "github.com/TBD54566975/ssi-sdk/crypto/jwx" - "github.com/TBD54566975/ssi-sdk/cryptosuite" "github.com/TBD54566975/ssi-sdk/did" ) @@ -131,7 +131,7 @@ func TestGenerateDIDJWK(t *testing.T) { return } - jsonWebKey, err := cryptosuite.JSONWebKey2020FromPrivateKey(privKey) + jsonWebKey, err := jws2020.JSONWebKey2020FromPrivateKey(privKey) assert.NoError(t, err) assert.NotEmpty(t, jsonWebKey) diff --git a/did/key/key.go b/did/key/key.go index 8b055af0..1517034d 100644 --- a/did/key/key.go +++ b/did/key/key.go @@ -6,6 +6,7 @@ import ( "fmt" "strings" + "github.com/TBD54566975/ssi-sdk/cryptosuite/jws2020" "github.com/TBD54566975/ssi-sdk/did" "github.com/jorrizza/ed2curve25519" "github.com/mr-tron/base58" @@ -263,7 +264,7 @@ func (d DIDKey) Expand(opts ...Option) (*did.Document, error) { // X25519 doesn't have any property except key agreement isVerificationMethodX25519Key := false - if (publicKeyFormat == cryptosuite.JSONWebKey2020Type && verificationMethod.PublicKeyJWK.CRV == string(cryptosuite.X25519)) || + if (publicKeyFormat == cryptosuite.JSONWebKey2020Type && verificationMethod.PublicKeyJWK.CRV == string(jws2020.X25519)) || (publicKeyFormat == cryptosuite.MultikeyType && (verificationMethod.Type == cryptosuite.X25519KeyAgreementKey2020 || verificationMethod.Type == cryptosuite.X25519KeyAgreementKey2019)) { isVerificationMethodX25519Key = true @@ -311,8 +312,8 @@ func generateKeyAgreementVerificationMethod(vm did.VerificationMethod) (*did.Ver verificationMethod, vmErr = did.ConstructMultibaseVerificationMethod(id, vm.Controller, x25519Key, cryptosuite.X25519KeyAgreementKey2020) verificationMethodSet = []did.VerificationMethodSet{id} return verificationMethod, verificationMethodSet, vmErr - } else if vm.Type == cryptosuite.JSONWebKey2020Type && vm.PublicKeyJWK.KTY == string(cryptosuite.OKP) && - vm.PublicKeyJWK.CRV == string(cryptosuite.Ed25519) { + } else if vm.Type == cryptosuite.JSONWebKey2020Type && vm.PublicKeyJWK.KTY == string(jws2020.OKP) && + vm.PublicKeyJWK.CRV == string(jws2020.Ed25519) { // convert key to X25519 ed25519PubKey, err := vm.PublicKeyJWK.ToPublicKey() if err != nil { diff --git a/did/pkh/pkh.go b/did/pkh/pkh.go index 79e56a22..9a0072c9 100644 --- a/did/pkh/pkh.go +++ b/did/pkh/pkh.go @@ -6,9 +6,9 @@ import ( "regexp" "strings" + "github.com/TBD54566975/ssi-sdk/cryptosuite" "github.com/pkg/errors" - "github.com/TBD54566975/ssi-sdk/cryptosuite" "github.com/TBD54566975/ssi-sdk/did" "github.com/TBD54566975/ssi-sdk/util" ) diff --git a/did/util.go b/did/util.go index 2c5fd49c..83869a18 100644 --- a/did/util.go +++ b/did/util.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" + "github.com/TBD54566975/ssi-sdk/cryptosuite/jws2020" "github.com/lestrrat-go/jwx/v2/jwk" "github.com/mr-tron/base58" "github.com/multiformats/go-multibase" @@ -74,13 +75,13 @@ func extractKeyFromVerificationMethod(method VerificationMethod) (gocrypto.Publi if multiBaseErr != nil { return nil, errors.Wrap(multiBaseErr, "converting multibase key") } - return cryptosuite.PubKeyBytesToTypedKey(pubKeyBytes, method.Type) + return jws2020.PubKeyBytesToTypedKey(pubKeyBytes, method.Type) case method.PublicKeyBase58 != "": pubKeyDecoded, b58Err := base58.Decode(method.PublicKeyBase58) if b58Err != nil { return nil, errors.Wrap(b58Err, "decoding base58 key") } - return cryptosuite.PubKeyBytesToTypedKey(pubKeyDecoded, method.Type) + return jws2020.PubKeyBytesToTypedKey(pubKeyDecoded, method.Type) case method.PublicKeyJWK != nil: jwkBytes, jwkErr := json.Marshal(method.PublicKeyJWK) if jwkErr != nil { diff --git a/did/web/resolver.go b/did/web/resolver.go index ee2e2bfc..32cad947 100644 --- a/did/web/resolver.go +++ b/did/web/resolver.go @@ -22,7 +22,7 @@ func (Resolver) Methods() []did.Method { // Resolve fetches and returns the Document from the expected URL // specification: https://w3c-ccg.github.io/did-method-web/#read-resolve func (Resolver) Resolve(_ context.Context, id string, _ ...resolution.Option) (*resolution.Result, error) { - if !strings.HasPrefix(id, WebPrefix) { + if !strings.HasPrefix(id, Prefix) { return nil, fmt.Errorf("not a did:web DID: %s", id) } didWeb := DIDWeb(id) diff --git a/did/web/web.go b/did/web/web.go index 138bf44e..25718ce4 100644 --- a/did/web/web.go +++ b/did/web/web.go @@ -24,9 +24,9 @@ type ( ) const ( - WebWellKnownURLPath = ".well-known/" - WebDIDDocFilename = "did.json" - WebPrefix = "did:web" + WellKnownURLPath = ".well-known/" + DIDDocFilename = "did.json" + Prefix = "did:web" ) func (d DIDWeb) IsValid() bool { @@ -39,7 +39,7 @@ func (d DIDWeb) String() string { } func (d DIDWeb) Suffix() (string, error) { - split := strings.Split(d.String(), WebPrefix+":") + split := strings.Split(d.String(), Prefix+":") if len(split) != 2 { return "", errors.Wrap(util.InvalidFormatError, "did is malformed") } @@ -89,8 +89,8 @@ func (d DIDWeb) CreateDocBytes(kt crypto.KeyType, publicKey []byte) ([]byte, err // optional path supported func (d DIDWeb) GetDocURL() (string, error) { // DIDWeb must be prefixed with d:web: - if !strings.HasPrefix(string(d), WebPrefix) { - return "", fmt.Errorf("did:web DID %+v is missing prefix %s", d, WebPrefix) + if !strings.HasPrefix(string(d), Prefix) { + return "", fmt.Errorf("did:web DID %+v is missing prefix %s", d, Prefix) } subStrs := strings.Split(string(d), ":") @@ -110,7 +110,7 @@ func (d DIDWeb) GetDocURL() (string, error) { if numSubStrs == 3 { // 4. If no path has been specified in the URL, append /.well-known. // 5. Append /d.json to complete the URL. - urlStr := "https://" + decodedDomain + "/" + WebWellKnownURLPath + WebDIDDocFilename + urlStr := "https://" + decodedDomain + "/" + WellKnownURLPath + DIDDocFilename return urlStr, nil } @@ -129,7 +129,7 @@ func (d DIDWeb) GetDocURL() (string, error) { return "", err } } - if _, err := sb.WriteString(WebDIDDocFilename); err != nil { + if _, err := sb.WriteString(DIDDocFilename); err != nil { return "", err } return sb.String(), nil diff --git a/example/presentation/presentation.go b/example/presentation/presentation.go index 91d27f47..bc77436a 100644 --- a/example/presentation/presentation.go +++ b/example/presentation/presentation.go @@ -12,11 +12,11 @@ import ( "fmt" "github.com/TBD54566975/ssi-sdk/crypto/jwx" + "github.com/TBD54566975/ssi-sdk/cryptosuite/jws2020" "github.com/goccy/go-json" "github.com/TBD54566975/ssi-sdk/credential/exchange" "github.com/TBD54566975/ssi-sdk/crypto" - "github.com/TBD54566975/ssi-sdk/cryptosuite" "github.com/TBD54566975/ssi-sdk/example" "github.com/TBD54566975/ssi-sdk/util" ) @@ -55,7 +55,7 @@ func makePresentationRequest(requesterID string, presentationData exchange.Prese // Generate JSON Web Key // The JSONWebKey2020 type specifies a number of key type and curve pairs to enable JOSE conformance // https://w3c-ccg.github.io/lds-jws2020/#dfn-jsonwebkey2020 - jwk, err := cryptosuite.GenerateJSONWebKey2020(cryptosuite.OKP, cryptosuite.Ed25519) + jwk, err := jws2020.GenerateJSONWebKey2020(jws2020.OKP, jws2020.Ed25519) if err != nil { return nil, err } @@ -78,7 +78,7 @@ func makePresentationRequest(requesterID string, presentationData exchange.Prese // TODO: Add better documentation on the verification process // Seems like needed to know more of: https://github.com/lestrrat-go/jwx/tree/develop/v2/jwt - verifier, err := cryptosuite.NewJSONWebKeyVerifier(audience, jwk.PublicKeyJWK) + verifier, err := jws2020.NewJSONWebKeyVerifier(audience, jwk.PublicKeyJWK) if err != nil { return nil, err }