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

have manifest code check for kid in jws header #157

Merged
merged 3 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.19

require (
github.com/BurntSushi/toml v1.2.1
github.com/TBD54566975/ssi-sdk v0.0.2-alpha.0.20221027011419-39fefd7f233c
github.com/TBD54566975/ssi-sdk v0.0.2-alpha.0.20221101200844-4aaa87cf0001
github.com/ardanlabs/conf v1.5.0
github.com/dimfeld/httptreemux/v5 v5.5.0
github.com/go-playground/locales v0.14.0
Expand All @@ -30,8 +30,10 @@ require (
)

require (
github.com/buger/jsonparser v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/flowstack-com/jsonschema v0.1.2 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/validator/v10 v10.11.1 // indirect
Expand All @@ -51,6 +53,7 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
golang.org/x/net v0.1.0 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/term v0.1.0 // indirect
golang.org/x/text v0.4.0 // indirect
Expand Down
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/TBD54566975/ssi-sdk v0.0.2-alpha.0.20221027011419-39fefd7f233c h1:tMbaOaxyjlhV4X0ojUHVUS/Fa+/OQf8i1/V23uqdhmo=
github.com/TBD54566975/ssi-sdk v0.0.2-alpha.0.20221027011419-39fefd7f233c/go.mod h1:Uvgv4WK66gwiV76SpWe6EUnUSwyH7r9EFqP0tTSDP18=
github.com/TBD54566975/ssi-sdk v0.0.2-alpha.0.20221101200844-4aaa87cf0001 h1:FxNNYtGZSwoAz3NhphlANaETYiBq07j0e2tB8LhMXBs=
github.com/TBD54566975/ssi-sdk v0.0.2-alpha.0.20221101200844-4aaa87cf0001/go.mod h1:Uvgv4WK66gwiV76SpWe6EUnUSwyH7r9EFqP0tTSDP18=
github.com/ardanlabs/conf v1.5.0 h1:5TwP6Wu9Xi07eLFEpiCUF3oQXh9UzHMDVnD3u/I5d5c=
github.com/ardanlabs/conf v1.5.0/go.mod h1:ILsMo9dMqYzCxDjDXTiwMI0IgxOJd0MOiucbQY2wlJw=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand All @@ -14,6 +18,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/dimfeld/httptreemux/v5 v5.5.0 h1:p8jkiMrCuZ0CmhwYLcbNbl7DDo21fozhKHQ2PccwOFQ=
github.com/dimfeld/httptreemux/v5 v5.5.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
github.com/flowstack-com/jsonschema v0.1.2 h1:qO2Ed0OHxY88yqqfNwUGfWxF64rVQCdbJ68lmlHSIXs=
github.com/flowstack-com/jsonschema v0.1.2/go.mod h1:Ce82M1ocyTfow5soqyAcHShvlSUqM8odW0UZVIIK4pQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
Expand Down Expand Up @@ -125,7 +131,10 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
11 changes: 11 additions & 0 deletions internal/credential/verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,23 @@ func (v Verifier) VerifyJWTCredential(token keyaccess.JWT) error {
return util.LoggingErrorMsg(err, "could not parse credential from JWT")
}

// TODO(gabe) support resolving keys by ID
jwtKID, err := util.GetKeyIDFromJWT(token)
if err != nil {
return util.LoggingErrorMsg(err, "could not get key ID from JWT")
}

// resolve the issuer's key material
kid, pubKey, err := v.resolveCredentialIssuerKey(*cred)
if err != nil {
return util.LoggingError(err)
}

if jwtKID != kid {
errMsg := fmt.Sprintf("JWT<%s> and credential<%s> key IDs do not match", jwtKID, kid)
return util.LoggingErrorMsg(err, errMsg)
}

// construct a signature verifier from the verification information
verifier, err := keyaccess.NewJWKKeyAccessVerifier(kid, pubKey)
if err != nil {
Expand Down
41 changes: 41 additions & 0 deletions internal/util/jwt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package util

import (
"fmt"

"github.com/lestrrat-go/jwx/jws"
"github.com/lestrrat-go/jwx/jwt"

"github.com/tbd54566975/ssi-service/internal/keyaccess"
)

// ParseJWT parses a JWT token and returns the jws signature and jwt claims
func ParseJWT(token keyaccess.JWT) (*jws.Signature, jwt.Token, error) {
tokenBytes := []byte(token)
parsedJWS, err := jws.Parse(tokenBytes)
if err != nil {
return nil, nil, err
}
signatures := parsedJWS.Signatures()
if len(signatures) != 1 {
return nil, nil, fmt.Errorf("expected 1 signature, got %d", len(signatures))
}
parsedJWT, err := jwt.Parse(tokenBytes)
if err != nil {
return nil, nil, err
}
return signatures[0], parsedJWT, nil
}

func GetKeyIDFromJWT(token keyaccess.JWT) (string, error) {
tokenBytes := []byte(token)
parsedJWS, err := jws.Parse(tokenBytes)
if err != nil {
return "", err
}
signatures := parsedJWS.Signatures()
if len(signatures) != 1 {
return "", fmt.Errorf("expected 1 signature, got %d", len(signatures))
}
return signatures[0].ProtectedHeaders().KeyID(), nil
}
27 changes: 14 additions & 13 deletions pkg/server/router/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import (
"github.com/TBD54566975/ssi-sdk/credential/exchange"
manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
"github.com/goccy/go-json"
"github.com/lestrrat-go/jwx/jwk"
"github.com/lestrrat-go/jwx/jwt"

"github.com/tbd54566975/ssi-service/internal/credential"
"github.com/tbd54566975/ssi-service/internal/keyaccess"
"github.com/tbd54566975/ssi-service/internal/util"
"github.com/tbd54566975/ssi-service/pkg/service/manifest"

"github.com/pkg/errors"
Expand Down Expand Up @@ -220,21 +219,23 @@ const (
)

func (sar SubmitApplicationRequest) ToServiceRequest() (*manifest.SubmitApplicationRequest, error) {
parsed, err := jwt.Parse([]byte(sar.ApplicationJWT))
signature, token, err := util.ParseJWT(sar.ApplicationJWT)
if err != nil {
return nil, errors.Wrap(err, "could not parse Credential Application token")
logrus.WithError(err).Error("could not parse application JWT")
return nil, err
}

// make sure the known properties are present (Application and Credentials)
kid, ok := parsed.Get(jwk.KeyIDKey)
if !ok || kid == "" {
kid := signature.ProtectedHeaders().KeyID()
if kid == "" {
return nil, errors.New("Credential Application token missing kid")
}

// make sure the known properties are present (Application and Credentials)

var creds []interface{}
credentials, ok := parsed.Get(vcsJSONProperty)
credentials, ok := token.Get(vcsJSONProperty)
if !ok {
logrus.Warn("could not find vc in Credential Application token, looking for `verifiableCredentials`")
if credentials, ok = parsed.Get(verifiableCredentialsJSONProperty); !ok {
if credentials, ok = token.Get(verifiableCredentialsJSONProperty); !ok {
return nil, errors.New("could not find vc or verifiableCredentials in Credential Application token")
}
}
Expand All @@ -246,7 +247,7 @@ func (sar SubmitApplicationRequest) ToServiceRequest() (*manifest.SubmitApplicat
}

// marshal known properties into their respective types
credAppJSON, ok := parsed.Get(manifestsdk.CredentialApplicationJSONProperty)
credAppJSON, ok := token.Get(manifestsdk.CredentialApplicationJSONProperty)
if !ok {
return nil, errors.New("could not find credential_application in Credential Application token")
}
Expand All @@ -266,11 +267,11 @@ func (sar SubmitApplicationRequest) ToServiceRequest() (*manifest.SubmitApplicat
return nil, errors.Wrap(err, "could not parse submitted credentials")
}
return &manifest.SubmitApplicationRequest{
ApplicantDID: kid.(string),
ApplicantDID: kid,
Application: application,
Credentials: credContainer,
ApplicationJWT: sar.ApplicationJWT,
ApplicationJSON: parsed.PrivateClaims(),
ApplicationJSON: token.PrivateClaims(),
}, nil
}

Expand Down