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 support for COSE for VCs. #593

Merged
merged 13 commits into from
Aug 26, 2024
Merged

Add support for COSE for VCs. #593

merged 13 commits into from
Aug 26, 2024

Conversation

timothee-haudebourg
Copy link
Contributor

@timothee-haudebourg timothee-haudebourg commented Aug 8, 2024

This PR adds basic support for COSE_Sign1 and COSE keys using coset and ciborium and implements the COSE part of the JOSE-COSE spec.

Since I needed the base64 library I also upgraded it to the latest version.

Copy link
Member

@sbihel sbihel left a comment

Choose a reason for hiding this comment

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

I would like to see more tests with more key types.

Also, do you think you can try and have a go adding https://github.com/w3c/vc-jose-cose-test-suite/ to didkit-http?

Cargo.toml Show resolved Hide resolved
crates/claims/crates/cose/src/sign1.rs Show resolved Hide resolved

/// Public key.
#[non_exhaustive]
pub enum PublicKey {
Copy link
Member

Choose a reason for hiding this comment

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

Was it necessary to start refactoring ssi_crypto in the PR? Now we have multiple keys/signing/verification implementations, and depending on the credential format it will use one of the other

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did not refactor it pre se, but I added support for crypto keys and crypto algorithms. Currently all of that is done exclusively by the ssi-jwk and ssi-jws libraries, I would have had to basically copy everything for COSE. Instead I decided to make a common foundation that can be used by both JOSE and COSE. For now of course only COSE uses it, but in the future I imagine the JOSE part using it as a foundation as well (same for verification methods) so we can avoid redundancies.

Comment on lines +18 to +21
pub trait CoseKeyResolver {
/// Fetches the COSE key associated to the give identifier.
#[allow(async_fn_in_trait)]
async fn fetch_public_cose_key(
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be better to "new-type" CoseKey, rather than use traits to add implementation? I'm particularly concerned about traits with async methods like this causing issues downstream due to the lack of Send on the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rust is able to tell if the future of an async function implementation like this implements Send or not. Its not like a dyn Future where you have to make the Send bound explicit.

The advantage of the trait is that you don't even have to new-type CoseKey. Since it implements CoseKeyResolver you can use it directly. It makes the interface with coset seamless.

Copy link
Member

Choose a reason for hiding this comment

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

But it does add another layer of indirection which can be confusing. In this regard, it doesn't seem to be re-exporting coset at the moment?

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 coset is publicly re-exported in ssi-cose, along with a few important types defined in coset like CoseKey, CoseSign1, Header, etc.

Comment on lines 8 to 13
/// CBOR-encoded `COSE_Sign1` object.
///
/// This is the borrowed equivalent of [`CompactCoseSign1Buf`].
#[derive(Debug)]
#[repr(transparent)]
pub struct CompactCoseSign1([u8]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you give a bit more description on what the difference is between this and coset::CoseSign1, i.e. what makes it "Compact"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yes, I'll take some time to improve the documentation. It's basically a serialized CoseSign1. I tried to reflect the JOSE implementation. With JOSE they call the serialized form of a JWS, a "compact JWS" that's why I'm reusing this vocabulary, but I agree its unclear by itself.

Copy link
Member

Choose a reason for hiding this comment

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

I'm a bit weary of us inventing our own terms, even if they're borrowed from other specs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm open to finding a better name. Some ideas: SerializedCoseSign1, CoseSign1Bytes, CoseSign1Slice.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've opted for CoseSign1Bytes for now.

Comment on lines +231 to +242
/// `COSE_Sign1` object without the signature.
#[derive(Clone, PartialEq)]
pub struct UnsignedCoseSign1<T> {
/// Protected header.
pub protected: ProtectedHeader,

/// Unprotected header.
pub unprotected: Header,

/// Payload.
pub payload: PayloadBytes<T>,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add support for detached payloads?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I feel this should be provided by another type.

Copy link
Contributor

@cobward cobward left a comment

Choose a reason for hiding this comment

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

Could you also ensure that there are sufficient doc comments for every struct/enum/trait/method, high-level examples in the top-level module documentation for ssi-cose, and good unit test coverage?

@timothee-haudebourg
Copy link
Contributor Author

I've added more doc comments, a couple of examples, and more COSE-key encoding/decoding tests (which is the real addition from coset). I'll try to add the vc-jose-cose-test-suite to didkit-http before the PR is merged, but I'm not against a new review round.

@timothee-haudebourg timothee-haudebourg self-assigned this Aug 23, 2024
@sbihel
Copy link
Member

sbihel commented Aug 26, 2024

Also, do you think you can try and have a go adding https://github.com/w3c/vc-jose-cose-test-suite/ to didkit-http?

It turns out this test suite hadn't been updated in a while and doesn't use the same system as the other test suites.

...and `CompactCoseSign1Buf` into `CoseSign1BytesBuf`.
@timothee-haudebourg timothee-haudebourg merged commit 099293a into main Aug 26, 2024
4 checks passed
@timothee-haudebourg timothee-haudebourg deleted the vc-jose-cose-cose branch August 26, 2024 13:26
@scouten-adobe
Copy link

Very happy to see this landed. Could you cut a new release with this? (I did my own version, but it was very hacky.)

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.

4 participants