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

Upgrade to SD-JWT v12 & API rework #14

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open

Upgrade to SD-JWT v12 & API rework #14

wants to merge 30 commits into from

Conversation

UMR1352
Copy link
Contributor

@UMR1352 UMR1352 commented Sep 13, 2024

Updated the code base to support SD-JWT version 12 and modified the API to make it simpler and more ergonomic.

Major changes

  • SdObjectEncoder / SdObjectDecoder are not public anymore, and are only used internally.
  • SdJwt can only be constructed by parsing a string or through the new SdJwtBuilder.
  • Added SdJwtBuilder which has the same functionalities of SdObjectEncoder but:
    • SdObjectEncoder::conceal becomes SdJwtBuilder::make_concealable.
    • SdJwtBuilder::finish returns a whole and valid SdJwt instead of a plaintext object and disclosures.
  • Added JwsSigner trait, to create a JWS from header & payload.
  • Added SdJwtPresentationBuilder which wraps an SdJwt and provides methods to easily conceal disclosable claims and attaching a KeyBinding JWT (KB-JWT).
  • Added KeyBindingJwtBuilder to simplify the creation of KB-JWTs.
  • Added RequiredKeyBinding to model a proof of possession for a given key through JWT's ctf claim.

Fixes

  • Multibase-base64Url encoding was mistakenly used instead of Base64Url.
  • Multiple hashers (to compute disclosure's digests) were allowed but that goes against the spec.

@UMR1352 UMR1352 added the enhancement New feature or request label Sep 13, 2024
@UMR1352 UMR1352 requested a review from a team September 13, 2024 07:47
@UMR1352 UMR1352 self-assigned this Sep 13, 2024
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
```

Now `encoder.object()?` will return the encoded object.
Internally, builder's object now looks like:

```json

Choose a reason for hiding this comment

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

(nitpicking)

Should we use align the example calls with the example output to keep them talking about the same data? E.g. the example calls only hide /phone/0 but the example shows more phone entries as hidden, and the _sd array has 7 entries, though it should have 6?

We could also re-use the example code for the readme and use output from it, might be easier to keep in sync. ^^

src/sd_jwt.rs Outdated Show resolved Hide resolved
Copy link

@wulfraem wulfraem left a comment

Choose a reason for hiding this comment

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

According to spec about the _sd array: "The array MAY be empty in case the Issuer decided not to selectively disclose any of the claims at that level. However, it is RECOMMENDED to omit the _sd key in this case to save space."

Wanted to test this behavior, but ran into issues, when creating a SD-JWT without any concealable properties. The serialized object had two of the tilde characters directly following another, which should not be the case according to the ABNF (SD-JWT = JWT "~" *[DISCLOSURE "~"]). This broke the parsing a step, that comes afterwards in the example. Removing them by hand lead to another error when parsing the SD-JWT without disclosures.

@wulfraem
Copy link

According to spec about the _sd array entries: "The Issuer MUST hide the original order of the claims in the array. To ensure this, it is RECOMMENDED to shuffle the array of hashes, e.g., by sorting it alphanumerically or randomly, after potentially adding decoy digests as described in Section 5.2.5. The precise method does not matter as long as it does not depend on the original order of elements."

I think, currently the order depends on the order the properties are marked as concealable or decoys are added. The shuffling could be done via calling the builder functions in a random order and only adding one decoy at a time per level, but as the spec also lists sorting the hashes alphabetically, sorting them when adding or serializing might be a nice way to make sure that their order is "shuffled".

@wulfraem
Copy link

Couldn't find a definitive answer in the spec, but when an issuer uses the .require_key_binding to add the cnf with the ref to the holder, should the holder be able to create a presentation without key binding? Currently, our example does this, but it feels off. If adding the KB-JWT would not be required in this case someone could just strip off the KB-JWT and present the SD-JWT without it, e.g. if not in the possession of the key mentioned in the SD-JWT.

But then again, the spec shifts the responsibility for deciding whether the KB-JWT is required or entirely to the verifier, but imho it sounds weird to present a SD-JWT with cnf without a KB-JWT.

@wulfraem
Copy link

Could we fix the "erros" -> "errors" typo in the bug_report.yml when being at it as well? Don't think, we'll need an extra PR for this. :D

@wulfraem
Copy link

I guess, we'll have to update the CI for the Windows build. Does not seem to be a temporary thing. >.<

UMR1352 and others added 4 commits September 26, 2024 11:22
Co-authored-by: wulfraem <[email protected]>
Co-authored-by: wulfraem <[email protected]>
Co-authored-by: wulfraem <[email protected]>
Co-authored-by: wulfraem <[email protected]>
@UMR1352
Copy link
Contributor Author

UMR1352 commented Sep 26, 2024

Thank you @wulfraem for being the best reviewer ever. Going through your comments RN.

@UMR1352
Copy link
Contributor Author

UMR1352 commented Sep 26, 2024

According to spec about the _sd array: "The array MAY be empty in case the Issuer decided not to selectively disclose any of the claims at that level. However, it is RECOMMENDED to omit the _sd key in this case to save space."

Wanted to test this behavior, but ran into issues, when creating a SD-JWT without any concealable properties. The serialized object had two of the tilde characters directly following another, which should not be the case according to the ABNF (SD-JWT = JWT "~" *[DISCLOSURE "~"]). This broke the parsing a step, that comes afterwards in the example. Removing them by hand lead to another error when parsing the SD-JWT without disclosures.

I fixed this and added a test that makes sure an SD-JWT with 0 disclosure is properly serialized / deserialized even when a KB-JWT is present.

}

/// Creates an SD-JWT with the provided data.
pub async fn finish<S>(self, signer: &S, alg: &str) -> Result<SdJwt>

Choose a reason for hiding this comment

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

NIT:

When using the Builder pattern, I think it is more standard to name this function as build

src/builder.rs Outdated Show resolved Hide resolved
src/sd_jwt.rs Outdated Show resolved Hide resolved
src/sd_jwt.rs Outdated Show resolved Hide resolved
src/key_binding_jwt_claims.rs Show resolved Hide resolved
src/builder.rs Outdated Show resolved Hide resolved
src/builder.rs Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants