Skip to content

Commit

Permalink
update to latest vc-jwt spec; differentiate between id and key id (#341)
Browse files Browse the repository at this point in the history
* update to latest vc-jwt spec; differentiate between id and key id

* lint

* up go version
  • Loading branch information
decentralgabe authored Apr 7, 2023
1 parent 025a20e commit 08475b4
Show file tree
Hide file tree
Showing 29 changed files with 275 additions and 295 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.20.2
go-version: 1.20.3

- name: Install Mage
run: go install github.com/magefile/mage
Expand All @@ -38,7 +38,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.20.2
go-version: 1.20.3

- name: Install Mage
run: go install github.com/magefile/mage
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.20.2
go-version: 1.20.3
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This guide is for you.

| Requirement | Tested Version | Installation Instructions |
|-------------|----------------|--------------------------------------------------------|
| Go | 1.20.2 | [go.dev](https://go.dev/doc/tutorial/compile-install) |
| Go | 1.20.3 | [go.dev](https://go.dev/doc/tutorial/compile-install) |
| Mage | 1.13.0-6 | [magefile.org](https://magefile.org/) |

### Go
Expand All @@ -25,7 +25,7 @@ You may verify your `go` installation via the terminal:

```
$> go version
go version go1.20.2 darwin/amd64
go version go1.20.3 darwin/amd64
```

If you do not have go, we recommend installing it by:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[![godoc ssi-sdk](https://img.shields.io/badge/godoc-ssi--sdk-blue)](https://pkg.go.dev/github.com/TBD54566975/ssi-sdk)
[![go version 1.20.2](https://img.shields.io/badge/go_version-1.20.2-brightgreen)](https://golang.org/)
[![go version 1.20.3](https://img.shields.io/badge/go_version-1.20.3-brightgreen)](https://golang.org/)
[![Go Report Card A+](https://goreportcard.com/badge/github.com/TBD54566975/ssi-sdk)](https://goreportcard.com/report/github.com/TBD54566975/ssi-sdk)
[![license Apache 2](https://img.shields.io/badge/license-Apache%202-black)](https://github.com/TBD54566975/ssi-sdk/blob/main/LICENSE)
[![issues](https://img.shields.io/github/issues/TBD54566975/ssi-sdk)](https://github.com/TBD54566975/ssi-sdk/issues)
Expand Down
2 changes: 1 addition & 1 deletion credential/exchange/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func BuildPresentationRequest(signer any, pt PresentationRequestType, def Presen
func BuildJWTPresentationRequest(signer crypto.JWTSigner, def PresentationDefinition, target string) ([]byte, error) {
jwtValues := map[string]any{
jwt.JwtIDKey: uuid.NewString(),
jwt.IssuerKey: signer.KeyID(),
jwt.IssuerKey: signer.ID,
jwt.AudienceKey: target,
PresentationDefinitionKey: def,
}
Expand Down
6 changes: 3 additions & 3 deletions credential/exchange/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func TestBuildPresentationRequest(t *testing.T) {
_, privKey, err := crypto.GenerateEd25519Key()
assert.NoError(t, err)

signer, err := crypto.NewJWTSigner("test-id", privKey)
signer, err := crypto.NewJWTSigner("test-id", "test-kid", privKey)
assert.NoError(t, err)

testDef := getDummyPresentationDefinition()
Expand All @@ -36,7 +36,7 @@ func TestBuildPresentationRequest(t *testing.T) {
_, privKey, err := crypto.GenerateEd25519Key()
assert.NoError(t, err)

signer, err := crypto.NewJWTSigner("test-id", privKey)
signer, err := crypto.NewJWTSigner("test-id", "test-kid", privKey)
assert.NoError(t, err)

testDef := getDummyPresentationDefinition()
Expand All @@ -59,7 +59,7 @@ func TestBuildPresentationRequest(t *testing.T) {
_, privKey, err := crypto.GenerateEd25519Key()
assert.NoError(t, err)

signer, err := crypto.NewJWTSigner("test-id", privKey)
signer, err := crypto.NewJWTSigner("test-id", "test-kid", privKey)
assert.NoError(t, err)

testDef := getDummyPresentationDefinition()
Expand Down
11 changes: 7 additions & 4 deletions credential/exchange/submission.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (pc *PresentationClaim) GetClaimJSON() (map[string]any, error) {
// https://identity.foundation/presentation-exchange/#presentation-submission
// Note: this method does not support LD cryptosuites, and prefers JWT representations. Future refactors
// may include an analog method for LD suites.
func BuildPresentationSubmission(signer crypto.JWTSigner, def PresentationDefinition, claims []PresentationClaim, et EmbedTarget) ([]byte, error) {
func BuildPresentationSubmission(signer crypto.JWTSigner, requester string, def PresentationDefinition, claims []PresentationClaim, et EmbedTarget) ([]byte, error) {
if !IsSupportedEmbedTarget(et) {
return nil, fmt.Errorf("unsupported presentation submission embed target type: %s", et)
}
Expand All @@ -137,11 +137,11 @@ func BuildPresentationSubmission(signer crypto.JWTSigner, def PresentationDefini
}
switch et {
case JWTVPTarget:
vpSubmission, err := BuildPresentationSubmissionVP(def, normalizedClaims)
vpSubmission, err := BuildPresentationSubmissionVP(signer.ID, def, normalizedClaims)
if err != nil {
return nil, errors.Wrap(err, "unable to fulfill presentation definition with given credentials")
}
return signing.SignVerifiablePresentationJWT(signer, *vpSubmission)
return signing.SignVerifiablePresentationJWT(signer, signing.JWTVVPParameters{Audience: requester}, *vpSubmission)
default:
return nil, fmt.Errorf("presentation submission embed target <%s> is not implemented", et)
}
Expand Down Expand Up @@ -203,7 +203,7 @@ type processedClaim struct {
// BuildPresentationSubmissionVP takes a presentation definition and a set of claims. According to the presentation
// definition, and the algorithm defined - https://identity.foundation/presentation-exchange/#input-evaluation - in
// the specification, a presentation submission is constructed as a Verifiable Presentation.
func BuildPresentationSubmissionVP(def PresentationDefinition, claims []NormalizedClaim) (*credential.VerifiablePresentation, error) {
func BuildPresentationSubmissionVP(submitter string, def PresentationDefinition, claims []NormalizedClaim) (*credential.VerifiablePresentation, error) {
if err := canProcessDefinition(def); err != nil {
return nil, errors.Wrap(err, "feature not supported in processing given presentation definition")
}
Expand All @@ -214,6 +214,9 @@ func BuildPresentationSubmissionVP(def PresentationDefinition, claims []Normaliz
if err := builder.AddType(PresentationSubmissionType); err != nil {
return nil, err
}
if err := builder.SetHolder(submitter); err != nil {
return nil, err
}

submission := PresentationSubmission{
ID: uuid.NewString(),
Expand Down
17 changes: 9 additions & 8 deletions credential/exchange/submission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (

func TestBuildPresentationSubmission(t *testing.T) {
t.Run("Unsupported embed target", func(tt *testing.T) {
_, err := BuildPresentationSubmission(crypto.JWTSigner{}, PresentationDefinition{}, nil, "badEmbedTarget")
_, err := BuildPresentationSubmission(crypto.JWTSigner{}, "requester", PresentationDefinition{}, nil, "badEmbedTarget")
assert.Error(tt, err)
assert.Contains(tt, err.Error(), "unsupported presentation submission embed target type")
})
Expand Down Expand Up @@ -50,11 +50,11 @@ func TestBuildPresentationSubmission(t *testing.T) {
LDPFormat: LDPVC.Ptr(),
SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020),
}
submissionBytes, err := BuildPresentationSubmission(*signer, def, []PresentationClaim{presentationClaim}, JWTVPTarget)
submissionBytes, err := BuildPresentationSubmission(*signer, "requester", def, []PresentationClaim{presentationClaim}, JWTVPTarget)
assert.NoError(tt, err)
assert.NotEmpty(tt, submissionBytes)

vp, err := signing.VerifyVerifiablePresentationJWT(*verifier, string(submissionBytes))
_, vp, err := signing.VerifyVerifiablePresentationJWT(*verifier, string(submissionBytes))
assert.NoError(tt, err)

assert.NoError(tt, vp.IsValid())
Expand Down Expand Up @@ -91,7 +91,7 @@ func TestBuildPresentationSubmissionVP(t *testing.T) {
}
normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim})
assert.NoError(tt, err)
vp, err := BuildPresentationSubmissionVP(def, normalized)
vp, err := BuildPresentationSubmissionVP("submitter", def, normalized)
assert.NoError(tt, err)
assert.NotEmpty(tt, vp)

Expand Down Expand Up @@ -139,7 +139,7 @@ func TestBuildPresentationSubmissionVP(t *testing.T) {
}

assert.NoError(tt, def.IsValid())
vp, err := BuildPresentationSubmissionVP(def, nil)
vp, err := BuildPresentationSubmissionVP("submitter", def, nil)
assert.Error(tt, err)
assert.Contains(tt, err.Error(), "no claims match the required format, and signing alg/proof type requirements for input descriptor")
assert.Empty(tt, vp)
Expand Down Expand Up @@ -185,7 +185,7 @@ func TestBuildPresentationSubmissionVP(t *testing.T) {
}
normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim})
assert.NoError(tt, err)
vp, err := BuildPresentationSubmissionVP(def, normalized)
vp, err := BuildPresentationSubmissionVP("submitter", def, normalized)
assert.NoError(tt, err)
assert.NotEmpty(tt, vp)

Expand Down Expand Up @@ -259,7 +259,7 @@ func TestBuildPresentationSubmissionVP(t *testing.T) {

normalized, err := normalizePresentationClaims([]PresentationClaim{presentationClaim, presentationClaimJWT})
assert.NoError(tt, err)
vp, err := BuildPresentationSubmissionVP(def, normalized)
vp, err := BuildPresentationSubmissionVP("submitter", def, normalized)
assert.NoError(tt, err)
assert.NotEmpty(tt, vp)

Expand Down Expand Up @@ -801,8 +801,9 @@ func getJWKSignerVerifier(t *testing.T) (*crypto.JWTSigner, *crypto.JWTVerifier)
key, err := jwk.FromRaw(privKey)
require.NoError(t, err)

id := "test-id"
kid := "test-key"
signer, err := crypto.NewJWTSignerFromKey(kid, key)
signer, err := crypto.NewJWTSignerFromKey(id, kid, key)
require.NoError(t, err)

verifier, err := signer.ToVerifier()
Expand Down
2 changes: 1 addition & 1 deletion credential/exchange/verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func VerifyPresentationSubmission(verifier crypto.JWTVerifier, et EmbedTarget, d
}
switch et {
case JWTVPTarget:
vp, err := signing.VerifyVerifiablePresentationJWT(verifier, string(submission))
_, vp, err := signing.VerifyVerifiablePresentationJWT(verifier, string(submission))
if err != nil {
return errors.Wrap(err, "verification of the presentation submission failed")
}
Expand Down
6 changes: 3 additions & 3 deletions credential/exchange/verification_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func TestVerifyPresentationSubmission(t *testing.T) {
LDPFormat: LDPVC.Ptr(),
SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020),
}
submissionBytes, err := BuildPresentationSubmission(*signer, def, []PresentationClaim{presentationClaim}, JWTVPTarget)
submissionBytes, err := BuildPresentationSubmission(*signer, "requester", def, []PresentationClaim{presentationClaim}, JWTVPTarget)
assert.NoError(tt, err)
assert.NotEmpty(tt, submissionBytes)

Expand Down Expand Up @@ -107,11 +107,11 @@ func TestVerifyPresentationSubmissionVP(t *testing.T) {
LDPFormat: LDPVC.Ptr(),
SignatureAlgorithmOrProofType: string(cryptosuite.JSONWebSignature2020),
}
submissionBytes, err := BuildPresentationSubmission(*signer, def, []PresentationClaim{presentationClaim}, JWTVPTarget)
submissionBytes, err := BuildPresentationSubmission(*signer, "requester", def, []PresentationClaim{presentationClaim}, JWTVPTarget)
assert.NoError(tt, err)
assert.NotEmpty(tt, submissionBytes)

verifiablePresentation, err := signing.ParseVerifiablePresentationFromJWT(string(submissionBytes))
_, verifiablePresentation, err := signing.ParseVerifiablePresentationFromJWT(string(submissionBytes))
assert.NoError(tt, err)

err = VerifyPresentationSubmissionVP(def, *verifiablePresentation)
Expand Down
2 changes: 1 addition & 1 deletion credential/manifest/testdata/full-credential.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"EUDriversLicense"
],
"issuer": "did:example:123",
"issuanceDate": "2010-01-01T19:73:24Z",
"issuanceDate": "2010-01-01T19:23:24Z",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"givenName": "ricky bobby",
Expand Down
2 changes: 1 addition & 1 deletion credential/manifest/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ func getValidTestCredManifestCredApplicationJWTCred(t *testing.T) (CredentialMan
// turn into a jwt
_, privKey, err := crypto.GenerateEd25519Key()
require.NoError(t, err)
signer, err := crypto.NewJWTSigner("test-kid", privKey)
signer, err := crypto.NewJWTSigner("test-id", "test-kid", privKey)
require.NoError(t, err)
jwt, err := signing.SignVerifiableCredentialJWT(*signer, vc)
require.NoError(t, err)
Expand Down
15 changes: 8 additions & 7 deletions credential/signing/jws.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ func SignVerifiableCredentialJWS(signer crypto.JWTSigner, cred credential.Verifi
// ParseVerifiableCredentialFromJWS parses a JWS. Depending on the `cty` header value, it parses as a JWT or simply
// decodes the payload.
// This is currently an experimental. It's unstable and subject to change. Use at your own peril.
func ParseVerifiableCredentialFromJWS(token string) (*credential.VerifiableCredential, error) {
func ParseVerifiableCredentialFromJWS(token string) (*jws.Message, *credential.VerifiableCredential, error) {
parsed, err := jws.Parse([]byte(token))
if err != nil {
return nil, errors.Wrap(err, "parsing token")
return nil, nil, errors.Wrap(err, "parsing JWS")
}

var signature *jws.Signature
Expand All @@ -50,23 +50,24 @@ func ParseVerifiableCredentialFromJWS(token string) (*credential.VerifiableCrede
}
}
if signature == nil {
return ParseVerifiableCredentialFromJWT(token)
_, cred, err := ParseVerifiableCredentialFromJWT(token)
return parsed, cred, err
}

var cred credential.VerifiableCredential
if err = json.Unmarshal(parsed.Payload(), &cred); err != nil {
return nil, errors.Wrap(err, "reconstructing Verifiable Credential")
return nil, nil, errors.Wrap(err, "reconstructing Verifiable Credential")
}

return &cred, nil
return parsed, &cred, nil
}

// VerifyVerifiableCredentialJWS verifies the signature validity on the token and parses
// the token in a verifiable credential.
// This is currently an experimental. It's unstable and subject to change. Use at your own peril.
func VerifyVerifiableCredentialJWS(verifier crypto.JWTVerifier, token string) (*credential.VerifiableCredential, error) {
func VerifyVerifiableCredentialJWS(verifier crypto.JWTVerifier, token string) (*jws.Message, *credential.VerifiableCredential, error) {
if err := verifier.VerifyJWS(token); err != nil {
return nil, errors.Wrap(err, "verifying JWT")
return nil, nil, errors.Wrap(err, "verifying JWS")
}
return ParseVerifiableCredentialFromJWS(token)
}
9 changes: 6 additions & 3 deletions credential/signing/jws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ func TestVerifiableCredentialJWS(t *testing.T) {
assert.NoError(t, err)

token := string(signedJWT)
parsedCred, err := ParseVerifiableCredentialFromJWS(token)
jws, parsedCred, err := ParseVerifiableCredentialFromJWS(token)
assert.NoError(t, err)
assert.NotEmpty(t, jws)
assert.Equal(t, &testCredential, parsedCred)
})

Expand Down Expand Up @@ -58,8 +59,9 @@ func TestVerifiableCredentialJWS(t *testing.T) {
assert.NoError(t, err)

token := string(signed)
cred, err := VerifyVerifiableCredentialJWS(*verifier, token)
jws, cred, err := VerifyVerifiableCredentialJWS(*verifier, token)
assert.NoError(t, err)
assert.NotEmpty(t, jws)
assert.Equal(t, &testCredential, cred)
})

Expand All @@ -68,8 +70,9 @@ func TestVerifiableCredentialJWS(t *testing.T) {
assert.NoError(t, err)

token := string(signedJWT)
parsedCred, err := ParseVerifiableCredentialFromJWS(token)
jws, parsedCred, err := ParseVerifiableCredentialFromJWS(token)
assert.NoError(t, err)
assert.NotEmpty(t, jws)
assert.Equal(t, &testCredential, parsedCred)
})
}
Loading

0 comments on commit 08475b4

Please sign in to comment.