-
Notifications
You must be signed in to change notification settings - Fork 57
Add signature checks for Verifiable Presentations #353
Conversation
|
||
// VerifyCredentialSignature verifies the signature of a credential of any type | ||
// TODO(gabe) support other types of credentials https://github.com/TBD54566975/ssi-sdk/issues/352 | ||
func VerifyCredentialSignature(ctx context.Context, genericCred any, resolver did.Resolver) (bool, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
important stuff here
Codecov Report
@@ Coverage Diff @@
## main #353 +/- ##
==========================================
+ Coverage 57.38% 57.80% +0.42%
==========================================
Files 51 52 +1
Lines 6410 6566 +156
==========================================
+ Hits 3678 3795 +117
- Misses 2032 2063 +31
- Partials 700 708 +8
|
credential/exchange/verification.go
Outdated
return fmt.Errorf("verifier<%T> is not a JWT verifier", verifier) | ||
} | ||
// verify the VP, which in turn verifies all credentials in it | ||
_, _, vp, err := credential.VerifyVerifiablePresentationJWT(context.Background(), jwtVerifier, resolver, string(submission)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eventually context.background should be top level
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I will make it top level here
// After decoding the signature of each credential in the presentation is verified. If there are any issues during | ||
// decoding or signature validation, an error is returned. As a result, a successfully decoded VerifiablePresentation | ||
// object is returned. | ||
func VerifyVerifiablePresentationJWT(ctx context.Context, verifier crypto.JWTVerifier, resolver did.Resolver, token string) (jws.Headers, jwt.Token, *VerifiablePresentation, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
if genericCred == nil { | ||
return false, errors.New("credential cannot be empty") | ||
} | ||
if resolver == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the resolver was empty could there be a default one we load?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we should, because that would imply supporting DID methods that the caller may not want to resolve
credential/signature.go
Outdated
case *VerifiableCredential: | ||
return VerifyCredentialSignature(ctx, *genericCred.(*VerifiableCredential), resolver) | ||
case VerifiableCredential: | ||
cred := genericCred.(VerifiableCredential) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no ok checking here?
cred, ok := genericCred.(VerifiableCredential)
I guess we know the type so not needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah since the switch was hit we know the type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how to make it nicer without some crazy generic stuff
credential/signature.go
Outdated
|
||
// if that fails, try as a JWT | ||
if _, _, _, err := VCJWTJSONToVC(credMapBytes); err == nil { | ||
return false, errors.New("JWT credentials must include a signature to be verified") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the right error message here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could just be an invalid map[string]any
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed this bit
) | ||
|
||
// ToCredential turn a generic cred into its known object model | ||
func ToCredential(genericCred any) (jws.Headers, jwt.Token, *VerifiableCredential, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of code reuse, would it be possible to Call this funciton in the signature.go VerifyCredentialSignature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea, I think it can be used for everything but the JWT case
_, _, vp, err := signing.VerifyVerifiablePresentationJWT(verifier, string(credBytes)) | ||
// 1. That the VP is valid | ||
// 2. All VCs in the VP are valid | ||
// 2. That the VC was issued by a trusted entity (implied by the presentation, according to the Presentation Definition) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Just a few spots to look over and think about:
Biggest stuff is perhaps infinite loop / stack overflow problem if we are not careful with the return VerifyCredentialSignature
With the context, I wonder if we can extract it away and it will only be created once in the resolver or something
credential/signature.go
Outdated
} | ||
switch genericCred.(type) { | ||
case *VerifiableCredential: | ||
return VerifyCredentialSignature(ctx, *genericCred.(*VerifiableCredential), resolver) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure we won't run into an infinite loop problem here or at the other
return VerifyCredentialSignature spots?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure...maybe not. I have each case covered in a test that should be "good enough"
Fixes #71