Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VerifiablePresentation Creation, Signing, and Verification #184

Merged
merged 4 commits into from
Jan 17, 2024

Conversation

nitro-neal
Copy link
Contributor

Overview

Add VerifiablePresentation Creation, Signing, and Verification

Description

This provides functionalities to sign, verify, and create presentations, offering a concise API to work with JWT representations of verifiable presentations and ensuring that the signatures and claims within those JWTs can be validated.

Create VP Example:

    /**
     * Create a [VerifiablePresentation] based on the provided parameters.
     *
     * @param type The type of the presentation, as a [String].
     * @param holder The holder URI of the presentation, as a [String].
     * @param vcJwts The credentials used in the presentation, as a [String].
     * @param additionalData The presentation data, as a generic mapping [Map<String, Any>].
     * @return A [VerifiablePresentation] instance.
     *
     * Example:
     * ```
     *     val vp = VerifiablePresentation.create(
     *       vcJwts = vcJwts,
     *       holder = holderDid.uri,
     *       type = "PresentationSubmission",
     *       additionalData = mapOf("presentation_submission" to presentationSubmission)
     *     )
     * ```
     */

Sign VP Example:

val vpJwt = vp.sign(holderDid)

After signing this will create a vp that looks something like this:

eyJraWQiOiJkaWQ6a2V5OnpRM3NoYURtR0szdHlBRmpLY3BLZjRTRGUyNnZzcjJRV2JzaWpXckJpRXdpeEZTRDkjelEzc2hhRG1HSzN0eUFGaktjcEtmNFNEZTI2dnNyMlFXYnNpaldyQmlFd2l4RlNEOSIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2SyJ9.eyJpc3MiOiJkaWQ6a2V5OnpRM3NoYURtR0szdHlBRmpLY3BLZjRTRGUyNnZzcjJRV2JzaWpXckJpRXdpeEZTRDkiLCJ2cCI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVQcmVzZW50YXRpb24iLCJQcmVzZW50YXRpb25TdWJtaXNzaW9uIl0sImlkIjoidXJuOnV1aWQ6ZTcyMjAxNjMtYWFmMy00MWFkLWJkYjUtZWM5NGZmODZiMzQ5IiwicHJlc2VudGF0aW9uX3N1Ym1pc3Npb24iOnsiaWQiOiJwcmVzZW50YXRpb25TdWJtaXNzaW9uSWQiLCJkZWZpbml0aW9uSWQiOiJkZWZpbml0aW9uSWQiLCJkZXNjcmlwdG9yTWFwIjpbeyJpZCI6ImRlc2NyaXB0b3JJZCIsImZvcm1hdCI6ImZvcm1hdCIsInBhdGgiOiJwYXRoIiwicGF0aE5lc3RlZCI6bnVsbH1dfSwidmVyaWZpYWJsZUNyZWRlbnRpYWwiOlsidmNqd3QxIiwidmNqd3QyIl0sImhvbGRlciI6ImRpZDprZXk6elEzc2hhRG1HSzN0eUFGaktjcEtmNFNEZTI2dnNyMlFXYnNpaldyQmlFd2l4RlNEOSJ9LCJpYXQiOjE3MDQ5MDczMTh9.9_l88r2RSN23-xW8XyT19K3mH8GCLIwWi50eECPUCtwRkZHrL4KLtvLFBx1w_SVnLrn98QWQ9jspxpIJtrgyeQ

Copy link

codecov bot commented Jan 10, 2024

Codecov Report

Merging #184 (bec2043) into main (06a879c) will increase coverage by 0.68%.
Report is 1 commits behind head on main.
The diff coverage is 83.14%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #184      +/-   ##
==========================================
+ Coverage   78.96%   79.65%   +0.68%     
==========================================
  Files          33       36       +3     
  Lines        1930     2079     +149     
  Branches      265      309      +44     
==========================================
+ Hits         1524     1656     +132     
- Misses        274      281       +7     
- Partials      132      142      +10     
Components Coverage Δ
credentials 82.77% <83.14%> (+2.09%) ⬆️
crypto 38.07% <ø> (ø)
dids 89.59% <ø> (ø)
common 80.44% <ø> (ø)

Copy link
Contributor

@andresuribe87 andresuribe87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff!

Would suggest increasing coverage for edge cases/errors.

additionalData?.plus("verifiableCredential" to vcJwts) ?: mapOf("verifiableCredential" to vcJwts)

val vpDataModel = VpDataModel.builder()
.id(URI.create("urn:uuid:${UUID.randomUUID()}"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we following this id pattern everywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup its on the vc id too

* }
* ```
*/
public fun verify(vpJwt: String) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might have some complexity. for example, I could make a presentation definition where I'm specifically requesting expired credentials. this check would fail, since JWT validation fails if the exp property is in the past

I don't think you need to worry about this now, but it may be worth adding a note

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm good to think about..
we could just simply throw in an acceptExpired flag but we should find all the edge cases

import web5.sdk.dids.findAssertionMethodById
import java.security.SignatureException

private const val JsonWebKey2020 = "JsonWebKey2020"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be updated to JsonWebKey TBD54566975/web5-spec#73

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I'll make another PR that does this, since we will need to update lots of test vectors too

val didResolutionResult = DidResolvers.resolve(did.uri)
val assertionMethod = didResolutionResult.didDocument.findAssertionMethodById(assertionMethodId)

// TODO: ensure that publicKeyJwk is not null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todos with issue tags or add the require?

val algorithm = publicKeyJwk.algorithm
val jwsAlgorithm = JWSAlgorithm.parse(algorithm.toString())

val kid = when (assertionMethod.id.isAbsolute) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this be a ternary statement?

"Signature verification failed: Expected JWS header to contain alg and kid"
}

val verificationMethodId = jwt.header.keyID
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noting that these can be different

for example we may have a key id as a JWK thumbprint but a verification method ID as did:example:abcd#key-1

Copy link
Member

@decentralgabe decentralgabe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few not blocking comments, nice job!

@nitro-neal
Copy link
Contributor Author

Added sign comments in its own issue - #190

@nitro-neal nitro-neal merged commit cebc961 into main Jan 17, 2024
6 of 8 checks passed
@nitro-neal nitro-neal deleted the vp-impl branch January 17, 2024 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants