5 unstable releases

0.3.0 Sep 20, 2024
0.2.1 Aug 1, 2024
0.2.0 Jul 26, 2024
0.1.1 Sep 25, 2023
0.1.0 Dec 15, 2022

#1092 in Cryptography

Download history 658/week @ 2024-07-29 511/week @ 2024-08-05 1082/week @ 2024-08-12 872/week @ 2024-08-19 941/week @ 2024-08-26 809/week @ 2024-09-02 1333/week @ 2024-09-09 1314/week @ 2024-09-16 1688/week @ 2024-09-23 850/week @ 2024-09-30 1324/week @ 2024-10-07 725/week @ 2024-10-14 886/week @ 2024-10-21 830/week @ 2024-10-28 690/week @ 2024-11-04 759/week @ 2024-11-11

3,189 downloads per month
Used in 42 crates (18 directly)

Apache-2.0 and maybe GPL-3.0

320KB
7K SLoC

JSON Web Signature (JWS) implementation following RFC 7515 and RFC 7797 (Unencoded Payload Option).

Usage

The entry point to store and verify JWS is the [&Jws][Jws] type, borrowing the JWS, just like a &str borrows a text string. The JwsBuf type is the owned version of this type, owning the JWS, just like a String owns a text string.

Decoding & Verification

Use JwsSlice::verify to decode a JWS.

use serde_json::json;
use ssi_jwk::JWK;
use ssi_jws::Jws;

let jws = Jws::new(b"eyJhbGciOiJFUzI1NiJ9.cGF5bG9hZA.LW6XkHmgfNnb2CA-2qdeMVGpekAoxRNsAHoeLpnton3QMaQ3dMj-5G9SlP8dHj7cHf2HtRPdy6-9LbxYKvumKw").unwrap();

let jwk: JWK = json!({
    "kty": "EC",
    "use": "sig",
    "crv": "P-256",
    "x": "dxdB360AJqJFYhdctoKZD_a_P6vLGAxtEVaCLnyraXQ",
    "y": "iH6o0l5AECsfRuEw2Eghbrp-6Fob3j98-1Cbe1YOmwM",
    "alg": "ES256"
}).try_into().unwrap();

assert!(jws.verify(&jwk).await.unwrap().is_ok());

Internally JwsSlice::verify uses JwsSlice::decode to decode the JWS, then DecodedJws::verify to validate the signature.

let decoded_jws = jws.to_decoded().unwrap();
let verifiable_jws = decoded_jws.into_verifiable().await.unwrap();
assert_eq!(verifiable_jws.verify(&jwk).await.unwrap().is_ok());

You can use this method to decode the payload before the verification (using DecodedJws::try_map for instance) so it can be verified along the signature.

Signature

Use the JwsPayload::sign method to sign a payload into a compact JWS.

use serde_json::json;
use ssi_jwk::JWK;
use ssi_jws::JwsPayload;

let jwk: JWK = json!({
    "kty": "EC",
    "d": "3KSLs0_obYeQXfEI9I3BBH5y7aOm028bEx3rW6i5UN4",
    "use": "sig",
    "crv": "P-256",
    "x": "dxdB360AJqJFYhdctoKZD_a_P6vLGAxtEVaCLnyraXQ",
    "y": "iH6o0l5AECsfRuEw2Eghbrp-6Fob3j98-1Cbe1YOmwM",
    "alg": "ES256"
}).try_into().unwrap();

let jwt = "payload".sign(&jwk).await.unwrap();
assert_eq!(jwt, "eyJhbGciOiJFUzI1NiJ9.cGF5bG9hZA.LW6XkHmgfNnb2CA-2qdeMVGpekAoxRNsAHoeLpnton3QMaQ3dMj-5G9SlP8dHj7cHf2HtRPdy6-9LbxYKvumKw")

URL safety and JWS types

RFC 7515 originally defines JWS as URL safe strings due to the payload being base64 URL-safe encoded. However, RFC 7797 introduces a b64 header option that makes this encoding optional. If set to false, the JWS may not be URL-safe. In fact it may not be UTF-8 encoded at all.

To deal with these different encoding expectations this library provides three families of types for representing JWS:

  • [Jws] and JwsBuf: This is the most common type family that follows RFC 7515 to the letter, expecting an URL-safe JWS. It is still possible to use the b64 header to embed unencoded payloads but those payloads must use URL-safe base64 bytes/characters.
  • JwsStr and JwsString: This family relaxes the URL-safe payload constraint. Unencoded payloads may use bytes outside of the URL-safe base64 alphabet, but they must be valid UTF-8 strings. This guarantees that the overall JWS is a valid UTF-8 string, even if it is not URL-safe.
  • JwsSlice and JwsVec: This family does not imposes any constraint on unencoded payloads. There is no guaranty that the overall JWS will be an UTF-8 string.

Dependencies

~22–40MB
~658K SLoC