ssi_jws/
lib.rs

1//! JSON Web Signature (JWS) implementation following [RFC 7515] and [RFC 7797]
2//! (Unencoded Payload Option).
3//!
4//! # Usage
5//!
6//! The entry point to store and verify JWS is the [`&Jws`][Jws] type, borrowing
7//! the JWS, just like a `&str` borrows a text string.
8//! The [`JwsBuf`] type is the owned version of this type, owning the JWS,
9//! just like a [`String`] owns a text string.
10//!
11//! # Decoding & Verification
12//!
13//! Use [`JwsSlice::verify`] to decode a JWS.
14//!
15//! ```
16//! # #[cfg(feature = "secp256r1")]
17//! # async_std::task::block_on(async {
18//! use serde_json::json;
19//! use ssi_jwk::JWK;
20//! use ssi_jws::Jws;
21//!
22//! let jws = Jws::new(b"eyJhbGciOiJFUzI1NiJ9.cGF5bG9hZA.LW6XkHmgfNnb2CA-2qdeMVGpekAoxRNsAHoeLpnton3QMaQ3dMj-5G9SlP8dHj7cHf2HtRPdy6-9LbxYKvumKw").unwrap();
23//!
24//! let jwk: JWK = json!({
25//!     "kty": "EC",
26//!     "use": "sig",
27//!     "crv": "P-256",
28//!     "x": "dxdB360AJqJFYhdctoKZD_a_P6vLGAxtEVaCLnyraXQ",
29//!     "y": "iH6o0l5AECsfRuEw2Eghbrp-6Fob3j98-1Cbe1YOmwM",
30//!     "alg": "ES256"
31//! }).try_into().unwrap();
32//!
33//! assert!(jws.verify(&jwk).await.unwrap().is_ok());
34//! # })
35//! ```
36//!
37//! Internally [`JwsSlice::verify`] uses [`JwsSlice::decode`] to decode
38//! the JWS, then [`DecodedJws::verify`] to validate the signature.
39//!
40//! [`DecodedJws::verify`]: DecodedJws::verify
41//!
42//! ```ignore
43//! let decoded_jws = jws.to_decoded().unwrap();
44//! let verifiable_jws = decoded_jws.into_verifiable().await.unwrap();
45//! assert_eq!(verifiable_jws.verify(&jwk).await.unwrap().is_ok());
46//! ```
47//!
48//! You can use this method to decode the payload before the verification
49//! (using [`DecodedJws::try_map`] for instance) so it can be verified along the
50//! signature.
51//!
52//! # Signature
53//!
54//! Use the [`JwsPayload::sign`] method to sign a payload into a compact JWS.
55//!
56//! ```
57//! # #[cfg(feature = "secp256r1")]
58//! # async_std::task::block_on(async {
59//! use serde_json::json;
60//! use ssi_jwk::JWK;
61//! use ssi_jws::JwsPayload;
62//!
63//! let jwk: JWK = json!({
64//!     "kty": "EC",
65//!     "d": "3KSLs0_obYeQXfEI9I3BBH5y7aOm028bEx3rW6i5UN4",
66//!     "use": "sig",
67//!     "crv": "P-256",
68//!     "x": "dxdB360AJqJFYhdctoKZD_a_P6vLGAxtEVaCLnyraXQ",
69//!     "y": "iH6o0l5AECsfRuEw2Eghbrp-6Fob3j98-1Cbe1YOmwM",
70//!     "alg": "ES256"
71//! }).try_into().unwrap();
72//!
73//! let jwt = "payload".sign(&jwk).await.unwrap();
74//! assert_eq!(jwt, "eyJhbGciOiJFUzI1NiJ9.cGF5bG9hZA.LW6XkHmgfNnb2CA-2qdeMVGpekAoxRNsAHoeLpnton3QMaQ3dMj-5G9SlP8dHj7cHf2HtRPdy6-9LbxYKvumKw")
75//! # })
76//! ```
77//!
78//! # URL safety and JWS types
79//!
80//! [RFC 7515] originally defines JWS as URL safe strings due to the payload
81//! being base64 URL-safe encoded.
82//! However, [RFC 7797] introduces a `b64` header option that makes this
83//! encoding optional. If set to `false`, the JWS may not be URL-safe. In fact
84//! it may not be UTF-8 encoded at all.
85//!
86//! To deal with these different encoding expectations this library provides
87//! three families of types for representing JWS:
88//! - [`Jws`] and [`JwsBuf`]: This is the most common type family that follows
89//!   [RFC 7515] to the letter, expecting an URL-safe JWS.
90//!   It is still possible to use the `b64` header to embed unencoded payloads
91//!   but those payloads *must* use URL-safe base64 bytes/characters.
92//! - [`JwsStr`] and [`JwsString`]: This family relaxes the URL-safe payload
93//!   constraint.
94//!   Unencoded payloads may use bytes outside of the URL-safe base64 alphabet,
95//!   but they *must* be valid UTF-8 strings. This guarantees that the overall
96//!   JWS is a valid UTF-8 string, even if it is not URL-safe.
97//! - [`JwsSlice`] and [`JwsVec`]: This family does not imposes any constraint
98//!   on unencoded payloads.
99//!   There is no guaranty that the overall JWS will be an UTF-8 string.
100//!
101//! [RFC 7515]: <https://datatracker.ietf.org/doc/html/rfc7515>
102//! [RFC 7797]: <https://datatracker.ietf.org/doc/html/rfc7797>
103#![cfg_attr(docsrs, feature(doc_auto_cfg))]
104pub mod error;
105pub use base64::DecodeError as Base64DecodeError;
106use base64::Engine;
107pub use error::Error;
108use serde::{Deserialize, Serialize};
109use ssi_claims_core::{
110    ProofValidationError, ResolverProvider, ValidateClaims, VerifiableClaims, Verification,
111};
112use ssi_jwk::{Algorithm, Base64urlUInt, JWKResolver, Params as JWKParams, JWK};
113use std::{borrow::Cow, collections::BTreeMap};
114
115pub type VerificationWarnings = Vec<String>;
116
117pub(crate) mod utils;
118
119mod compact;
120pub use compact::*;
121
122mod signature;
123pub use signature::*;
124
125mod verification;
126pub use verification::*;
127
128/// Decoded JWS parts.
129#[derive(Clone, PartialEq, Eq)]
130pub struct JwsParts<T = Vec<u8>> {
131    /// JOSE Header.
132    pub header: Header,
133
134    /// Payload.
135    pub payload: T,
136
137    /// Signature.
138    pub signature: JwsSignature,
139}
140
141impl<T> JwsParts<T> {
142    pub fn new(header: Header, payload: T, signature: JwsSignature) -> Self {
143        Self {
144            header,
145            payload,
146            signature,
147        }
148    }
149
150    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> JwsParts<U> {
151        JwsParts {
152            header: self.header,
153            payload: f(self.payload),
154            signature: self.signature,
155        }
156    }
157
158    pub fn try_map<U, E>(self, f: impl FnOnce(T) -> Result<U, E>) -> Result<JwsParts<U>, E> {
159        Ok(JwsParts {
160            header: self.header,
161            payload: f(self.payload)?,
162            signature: self.signature,
163        })
164    }
165}
166
167impl<T: ?Sized + ToOwned> JwsParts<Cow<'_, T>> {
168    pub fn into_owned(self) -> JwsParts<T::Owned> {
169        JwsParts::new(self.header, self.payload.into_owned(), self.signature)
170    }
171}
172
173/// Decoded JWS.
174///
175/// JWS with its signing bytes.
176#[derive(Debug, Clone, PartialEq, Eq)]
177pub struct DecodedJws<'a, T = Vec<u8>> {
178    pub signing_bytes: DecodedSigningBytes<'a, T>,
179    pub signature: JwsSignature,
180}
181
182impl<'a, T> DecodedJws<'a, T> {
183    pub fn new(signing_bytes: DecodedSigningBytes<'a, T>, signature: JwsSignature) -> Self {
184        Self {
185            signing_bytes,
186            signature,
187        }
188    }
189
190    pub fn header(&self) -> &Header {
191        &self.signing_bytes.header
192    }
193
194    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> DecodedJws<'a, U> {
195        DecodedJws::new(self.signing_bytes.map(f), self.signature)
196    }
197
198    pub fn try_map<U, E>(self, f: impl FnOnce(T) -> Result<U, E>) -> Result<DecodedJws<'a, U>, E> {
199        Ok(DecodedJws::new(
200            self.signing_bytes.try_map(f)?,
201            self.signature,
202        ))
203    }
204
205    pub fn into_jws(self) -> JwsParts<T> {
206        JwsParts::new(
207            self.signing_bytes.header,
208            self.signing_bytes.payload,
209            self.signature,
210        )
211    }
212
213    pub fn into_jws_and_signing_bytes(self) -> (JwsParts<T>, Cow<'a, [u8]>) {
214        (
215            JwsParts::new(
216                self.signing_bytes.header,
217                self.signing_bytes.payload,
218                self.signature,
219            ),
220            self.signing_bytes.bytes,
221        )
222    }
223
224    pub fn into_encoded(self) -> JwsVec {
225        JwsVec::from_signing_bytes_and_signature(
226            self.signing_bytes.bytes.into_owned(),
227            self.signature.encode().as_bytes(),
228        )
229        .unwrap()
230    }
231
232    /// Verify the JWS signature.
233    ///
234    /// This will check the signature and the validity of the decoded payload.
235    ///
236    /// The `params` argument provides all the verification parameters required
237    /// to validate the claims and proof.
238    ///
239    /// # What verification parameters should I use?
240    ///
241    /// It really depends on the claims type, but `P` must at least provide
242    /// a `JWKResolver` through the `ResolverProvider` trait.
243    /// Notable implementors are:
244    /// - [`VerificationParameters`](ssi_claims_core::VerificationParameters):
245    ///   A good default providing many other common verification parameters that
246    ///   are not necessary here.
247    /// - [`JWK`]: allows you to put a JWK as `params`, which
248    ///   will resolve into itself. Can be useful if you don't need key resolution
249    ///   because you know in advance what key was used to sign the JWS.
250    ///
251    /// # Passing the parameters by reference
252    ///
253    /// If the validation traits are implemented for `P`, they will be
254    /// implemented for `&P` as well. This means the parameters can be passed
255    /// by move *or* by reference.
256    pub async fn verify<P>(&self, params: P) -> Result<Verification, ProofValidationError>
257    where
258        T: ValidateJwsHeader<P> + ValidateClaims<P, JwsSignature>,
259        P: ResolverProvider,
260        P::Resolver: JWKResolver,
261    {
262        VerifiableClaims::verify(self, params).await
263    }
264}
265
266impl<T: ?Sized + ToOwned> DecodedJws<'_, &T> {
267    pub fn to_owned(&self) -> DecodedJws<'static, T::Owned> {
268        DecodedJws {
269            signing_bytes: self.signing_bytes.to_owned(),
270            signature: self.signature.to_owned(),
271        }
272    }
273}
274
275impl<T: ?Sized + ToOwned> DecodedJws<'_, Cow<'_, T>> {
276    pub fn into_owned(self) -> DecodedJws<'static, T::Owned> {
277        DecodedJws::new(self.signing_bytes.into_owned(), self.signature)
278    }
279}
280
281/// JWS decoded signing bytes.
282#[derive(Debug, Clone, PartialEq, Eq)]
283pub struct DecodedSigningBytes<'a, T = Vec<u8>> {
284    /// Encoded bytes.
285    pub bytes: Cow<'a, [u8]>,
286
287    /// Decoded JOSE Header.
288    pub header: Header,
289
290    /// Decoded payload.
291    pub payload: T,
292}
293
294impl<'a, T> DecodedSigningBytes<'a, T> {
295    pub fn new(bytes: Cow<'a, [u8]>, header: Header, payload: T) -> Self {
296        Self {
297            bytes,
298            header,
299            payload,
300        }
301    }
302
303    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> DecodedSigningBytes<'a, U> {
304        DecodedSigningBytes {
305            bytes: self.bytes,
306            header: self.header,
307            payload: f(self.payload),
308        }
309    }
310
311    pub fn try_map<U, E>(
312        self,
313        f: impl FnOnce(T) -> Result<U, E>,
314    ) -> Result<DecodedSigningBytes<'a, U>, E> {
315        Ok(DecodedSigningBytes {
316            bytes: self.bytes,
317            header: self.header,
318            payload: f(self.payload)?,
319        })
320    }
321}
322
323impl<T: ?Sized + ToOwned> DecodedSigningBytes<'_, &T> {
324    pub fn to_owned(&self) -> DecodedSigningBytes<'static, T::Owned> {
325        DecodedSigningBytes {
326            bytes: Cow::Owned(self.bytes.as_ref().to_owned()),
327            header: self.header.clone(),
328            payload: self.payload.to_owned(),
329        }
330    }
331}
332
333impl<T: ?Sized + ToOwned> DecodedSigningBytes<'_, Cow<'_, T>> {
334    pub fn into_owned(self) -> DecodedSigningBytes<'static, T::Owned> {
335        DecodedSigningBytes {
336            bytes: Cow::Owned(self.bytes.into_owned()),
337            header: self.header,
338            payload: self.payload.into_owned(),
339        }
340    }
341}
342
343#[derive(Debug, thiserror::Error)]
344pub enum DecodeError {
345    #[error("invalid header: {0}")]
346    Header(InvalidHeader),
347
348    #[error("invalid payload: {0}")]
349    Payload(Base64DecodeError),
350
351    #[error("invalid signature: {0}")]
352    Signature(Base64DecodeError),
353}
354
355/// JOSE Header.
356#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
357pub struct Header {
358    #[serde(rename = "alg")]
359    pub algorithm: Algorithm,
360
361    #[serde(skip_serializing_if = "Option::is_none")]
362    #[serde(rename = "jku")]
363    pub jwk_set_url: Option<String>,
364
365    #[serde(skip_serializing_if = "Option::is_none")]
366    pub jwk: Option<JWK>,
367
368    #[serde(skip_serializing_if = "Option::is_none")]
369    #[serde(rename = "kid")]
370    pub key_id: Option<String>,
371
372    #[serde(skip_serializing_if = "Option::is_none")]
373    #[serde(rename = "x5u")]
374    pub x509_url: Option<String>,
375
376    #[serde(skip_serializing_if = "Option::is_none")]
377    #[serde(rename = "x5c")]
378    pub x509_certificate_chain: Option<Vec<String>>,
379
380    #[serde(skip_serializing_if = "Option::is_none")]
381    #[serde(rename = "x5t")]
382    pub x509_thumbprint_sha1: Option<Base64urlUInt>,
383
384    #[serde(skip_serializing_if = "Option::is_none")]
385    #[serde(rename = "x5t#S256")]
386    pub x509_thumbprint_sha256: Option<Base64urlUInt>,
387
388    #[serde(skip_serializing_if = "Option::is_none")]
389    #[serde(rename = "typ")]
390    pub type_: Option<String>,
391
392    #[serde(skip_serializing_if = "Option::is_none")]
393    #[serde(rename = "cty")]
394    pub content_type: Option<String>,
395
396    #[serde(skip_serializing_if = "Option::is_none")]
397    #[serde(rename = "crit")]
398    pub critical: Option<Vec<String>>,
399
400    #[serde(skip_serializing_if = "Option::is_none")]
401    #[serde(rename = "b64")]
402    pub base64urlencode_payload: Option<bool>,
403
404    #[serde(skip_serializing_if = "BTreeMap::is_empty")]
405    #[serde(flatten)]
406    pub additional_parameters: BTreeMap<String, serde_json::Value>,
407}
408
409#[derive(Debug, thiserror::Error)]
410pub enum InvalidHeader {
411    #[error(transparent)]
412    Base64(Base64DecodeError),
413
414    #[error(transparent)]
415    Json(serde_json::Error),
416}
417
418impl From<Base64DecodeError> for InvalidHeader {
419    fn from(value: Base64DecodeError) -> Self {
420        InvalidHeader::Base64(value)
421    }
422}
423
424impl From<serde_json::Error> for InvalidHeader {
425    fn from(value: serde_json::Error) -> Self {
426        InvalidHeader::Json(value)
427    }
428}
429
430impl Header {
431    /// Create a new header for a JWS with detached payload.
432    ///
433    /// Unencoded means the payload will not be base64 encoded
434    /// when the `encode_signing_bytes` function is called.
435    /// This is done by setting the `b64` header parameter to `true`,
436    /// while adding `b64` to the list of critical parameters the
437    /// receiver must understand to decode the JWS.
438    pub fn new_unencoded(algorithm: Algorithm, key_id: Option<String>) -> Self {
439        Self {
440            algorithm,
441            key_id,
442            base64urlencode_payload: Some(false),
443            critical: Some(vec!["b64".to_string()]),
444            ..Default::default()
445        }
446    }
447
448    /// Decode a JWS Protected Header.
449    pub fn decode(base_64: &[u8]) -> Result<Self, InvalidHeader> {
450        let header_json = base64::prelude::BASE64_URL_SAFE_NO_PAD.decode(base_64)?;
451        Ok(serde_json::from_slice(&header_json)?)
452    }
453
454    pub fn to_json_string(&self) -> String {
455        serde_json::to_string(self).unwrap()
456    }
457
458    pub fn encode(&self) -> String {
459        base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(self.to_json_string())
460    }
461
462    pub fn encode_signing_bytes(&self, payload: &[u8]) -> Vec<u8> {
463        let mut result = self.encode().into_bytes();
464        result.push(b'.');
465
466        if self.base64urlencode_payload.unwrap_or(true) {
467            let encoded_payload = base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(payload);
468            result.extend(encoded_payload.into_bytes())
469        } else {
470            result.extend(payload)
471        }
472
473        result
474    }
475}
476
477fn base64_encode_json<T: Serialize>(object: &T) -> Result<String, Error> {
478    let json = serde_json::to_string(&object)?;
479    Ok(base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(json))
480}
481
482#[allow(unreachable_code, unused_variables)]
483pub fn sign_bytes(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result<Vec<u8>, Error> {
484    let signature = match &key.params {
485        #[cfg(all(feature = "rsa", feature = "ring"))]
486        JWKParams::RSA(rsa_params) => {
487            rsa_params.validate_key_size()?;
488            let key_pair = ring::signature::RsaKeyPair::try_from(rsa_params)?;
489            let padding_alg: &dyn ring::signature::RsaEncoding = match algorithm {
490                Algorithm::RS256 => &ring::signature::RSA_PKCS1_SHA256,
491                Algorithm::PS256 => &ring::signature::RSA_PSS_SHA256,
492                _ => return Err(Error::AlgorithmNotImplemented(algorithm.to_string())),
493            };
494            let mut sig = vec![0u8; key_pair.public_modulus_len()];
495            let rng = ring::rand::SystemRandom::new();
496            key_pair.sign(padding_alg, &rng, data, &mut sig)?;
497            sig
498        }
499        #[cfg(all(feature = "rsa", not(feature = "ring")))]
500        JWKParams::RSA(rsa_params) => {
501            rsa_params.validate_key_size()?;
502            let private_key = rsa::RsaPrivateKey::try_from(rsa_params)?;
503            let padding;
504            let hashed;
505            match algorithm {
506                Algorithm::RS256 => {
507                    let hash = rsa::hash::Hash::SHA2_256;
508                    padding = rsa::padding::PaddingScheme::new_pkcs1v15_sign(Some(hash));
509                    hashed = ssi_crypto::hashes::sha256::sha256(data);
510                }
511                Algorithm::PS256 => {
512                    let hash = rsa::hash::Hash::SHA2_256;
513                    let rng = rand::rngs::OsRng {};
514                    padding =
515                        rsa::PaddingScheme::new_pss_with_salt::<sha2::Sha256, _>(rng, hash.size());
516                    hashed = ssi_crypto::hashes::sha256::sha256(data);
517                }
518                _ => return Err(Error::AlgorithmNotImplemented(algorithm.to_string())),
519            }
520            private_key
521                .sign(padding, &hashed)
522                .map_err(ssi_jwk::Error::from)?
523        }
524        #[cfg(any(feature = "ring", feature = "ed25519"))]
525        JWKParams::OKP(okp) => {
526            use blake2::digest::{consts::U32, Digest};
527            if algorithm != Algorithm::EdDSA && algorithm != Algorithm::EdBlake2b {
528                return Err(Error::UnsupportedAlgorithm(algorithm.to_string()));
529            }
530            if okp.curve != *"Ed25519" {
531                return Err(ssi_jwk::Error::CurveNotImplemented(okp.curve.to_string()).into());
532            }
533            let hash = match algorithm {
534                Algorithm::EdBlake2b => blake2::Blake2b::<U32>::new_with_prefix(data)
535                    .finalize()
536                    .to_vec(),
537                _ => data.to_vec(),
538            };
539            #[cfg(feature = "ring")]
540            {
541                let key_pair = ring::signature::Ed25519KeyPair::try_from(okp)?;
542                key_pair.sign(&hash).as_ref().to_vec()
543            }
544            // TODO: SymmetricParams
545            #[cfg(all(feature = "ed25519", not(feature = "ring")))]
546            {
547                let secret = ed25519_dalek::SigningKey::try_from(okp)?;
548                use ed25519_dalek::Signer;
549                secret.sign(&hash).to_bytes().to_vec()
550            }
551        }
552        #[allow(unused)]
553        JWKParams::EC(ec) => match algorithm {
554            #[cfg(feature = "secp384r1")]
555            Algorithm::ES384 => {
556                use p384::ecdsa::{signature::Signer, Signature};
557                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
558                let secret_key = p384::SecretKey::try_from(ec)?;
559                let signing_key = p384::ecdsa::SigningKey::from(secret_key);
560                let sig: p384::ecdsa::Signature =
561                    signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?;
562                sig.to_bytes().to_vec()
563            }
564            #[cfg(feature = "secp256r1")]
565            Algorithm::ES256 => {
566                use p256::ecdsa::{signature::Signer, Signature};
567                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
568                let secret_key = p256::SecretKey::try_from(ec)?;
569                let signing_key = p256::ecdsa::SigningKey::from(secret_key);
570                let sig: p256::ecdsa::Signature =
571                    signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; // Uses SHA-256 by default.
572                sig.to_bytes().to_vec()
573            }
574            #[cfg(feature = "secp256k1")]
575            Algorithm::ES256K => {
576                use k256::ecdsa::{signature::Signer, Signature};
577                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
578                let secret_key = k256::SecretKey::try_from(ec)?;
579                let signing_key = k256::ecdsa::SigningKey::from(secret_key);
580                let sig: Signature = signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; // Uses SHA-256 by default.
581                sig.to_bytes().to_vec()
582            }
583            #[cfg(feature = "secp256k1")]
584            Algorithm::ES256KR => {
585                use k256::ecdsa::{
586                    signature::{digest::Digest, Signer},
587                    Signature,
588                };
589                let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?;
590                let secret_key = k256::SecretKey::try_from(ec)?;
591                let signing_key = k256::ecdsa::SigningKey::from(secret_key);
592                // NOTE: in `k256` version 0.11, `recoverable::Signature`
593                //       uses Keccack as default hash function, not sha256.
594                //       See: <https://docs.rs/k256/0.11.0/k256/ecdsa/recoverable/struct.Signature.html#impl-PrehashSignature>
595                let (sig, rec_id) =
596                    signing_key.sign_digest_recoverable(sha2::Sha256::new_with_prefix(data))?;
597                let mut res = sig.to_bytes().to_vec();
598                res.push(rec_id.to_byte());
599                res
600            }
601            #[cfg(feature = "secp256k1")]
602            Algorithm::ESKeccakKR => {
603                use k256::ecdsa::{
604                    signature::{digest::Digest, Signer},
605                    Signature,
606                };
607                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
608                let secret_key = k256::SecretKey::try_from(ec)?;
609                let signing_key = k256::ecdsa::SigningKey::from(secret_key);
610                // NOTE: in `k256` version 0.11, `recoverable::Signature`
611                //       uses Keccack as default hash function, not sha256.
612                //       See: <https://docs.rs/k256/0.11.0/k256/ecdsa/recoverable/struct.Signature.html#impl-PrehashSignature>
613                let (sig, rec_id) = signing_key
614                    .sign_digest_recoverable(sha3::Keccak256::new_with_prefix(data))
615                    .map_err(ssi_jwk::Error::from)?;
616                let mut res = sig.to_bytes().to_vec();
617                res.push(rec_id.to_byte());
618                res
619            }
620            #[cfg(feature = "secp256r1")]
621            Algorithm::ESBlake2b => {
622                use p256::ecdsa::{
623                    signature::{
624                        digest::{consts::U32, Digest},
625                        DigestSigner,
626                    },
627                    Signature,
628                };
629                let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?;
630                let secret_key = p256::SecretKey::try_from(ec)?;
631                let signing_key = p256::ecdsa::SigningKey::from(secret_key);
632                let sig: p256::ecdsa::Signature =
633                    signing_key.try_sign_digest(blake2::Blake2b::<U32>::new_with_prefix(data))?;
634                sig.to_bytes().to_vec()
635            }
636            #[cfg(feature = "secp256k1")]
637            Algorithm::ESBlake2bK => {
638                use k256::ecdsa::{
639                    signature::{
640                        digest::{consts::U32, Digest},
641                        DigestSigner,
642                    },
643                    Signature,
644                };
645                let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?;
646                let secret_key = k256::SecretKey::try_from(ec)?;
647                let signing_key = k256::ecdsa::SigningKey::from(secret_key);
648                let sig: k256::ecdsa::Signature =
649                    signing_key.try_sign_digest(blake2::Blake2b::<U32>::new_with_prefix(data))?;
650                sig.to_bytes().to_vec()
651            }
652            _ => {
653                return Err(Error::UnsupportedAlgorithm(algorithm.to_string()));
654            }
655        },
656        _ => {
657            return Err(Error::Jwk(ssi_jwk::Error::KeyTypeNotImplemented(Box::new(
658                key.to_public(),
659            ))))
660        }
661    };
662    clear_on_drop::clear_stack(1);
663    Ok(signature)
664}
665
666pub fn sign_bytes_b64(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result<String, Error> {
667    let signature = sign_bytes(algorithm, data, key)?;
668    let sig_b64 = base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(signature);
669    Ok(sig_b64)
670}
671
672#[allow(unreachable_code, unused_variables, unused_mut)]
673pub fn verify_bytes_warnable(
674    algorithm: Algorithm,
675    data: &[u8],
676    key: &JWK,
677    signature: &[u8],
678) -> Result<VerificationWarnings, Error> {
679    let mut warnings = VerificationWarnings::default();
680    if let Some(key_algorithm) = key.algorithm {
681        if key_algorithm != algorithm
682            && !(key_algorithm == Algorithm::EdDSA && algorithm == Algorithm::EdBlake2b)
683            && !(key_algorithm == Algorithm::ES256 && algorithm == Algorithm::ESBlake2b)
684            && !(key_algorithm == Algorithm::ES256K && algorithm == Algorithm::ESBlake2bK)
685            && !(key_algorithm == Algorithm::ES256KR && algorithm == Algorithm::ESBlake2bK)
686        {
687            return Err(Error::AlgorithmMismatch);
688        }
689    }
690    match &key.params {
691        #[cfg(all(feature = "rsa", feature = "ring"))]
692        JWKParams::RSA(rsa_params) => {
693            rsa_params.validate_key_size()?;
694            use ring::signature::RsaPublicKeyComponents;
695            let public_key = RsaPublicKeyComponents::try_from(rsa_params)?;
696            let parameters = match algorithm {
697                Algorithm::RS256 => &ring::signature::RSA_PKCS1_2048_8192_SHA256,
698                Algorithm::PS256 => &ring::signature::RSA_PSS_2048_8192_SHA256,
699                _ => return Err(Error::AlgorithmNotImplemented(algorithm.to_string())),
700            };
701            public_key.verify(parameters, data, signature)?
702        }
703        #[cfg(all(feature = "rsa", not(feature = "ring")))]
704        JWKParams::RSA(rsa_params) => {
705            rsa_params.validate_key_size()?;
706            use rsa::PublicKey;
707            let public_key = rsa::RsaPublicKey::try_from(rsa_params)?;
708            let padding;
709            let hashed;
710            match algorithm {
711                Algorithm::RS256 => {
712                    let hash = rsa::hash::Hash::SHA2_256;
713                    padding = rsa::padding::PaddingScheme::new_pkcs1v15_sign(Some(hash));
714                    hashed = ssi_crypto::hashes::sha256::sha256(data);
715                }
716                Algorithm::PS256 => {
717                    let rng = rand::rngs::OsRng {};
718                    padding = rsa::PaddingScheme::new_pss::<sha2::Sha256, _>(rng);
719                    hashed = ssi_crypto::hashes::sha256::sha256(data);
720                }
721                _ => return Err(Error::AlgorithmNotImplemented(algorithm.to_string())),
722            }
723            public_key
724                .verify(padding, &hashed, signature)
725                .map_err(ssi_jwk::Error::from)?;
726        }
727        // TODO: SymmetricParams
728        #[cfg(any(feature = "ring", feature = "ed25519"))]
729        JWKParams::OKP(okp) => {
730            use blake2::digest::{consts::U32, Digest};
731            if okp.curve != *"Ed25519" {
732                return Err(ssi_jwk::Error::CurveNotImplemented(okp.curve.to_string()).into());
733            }
734            let hash = match algorithm {
735                Algorithm::EdBlake2b => <blake2::Blake2b<U32> as Digest>::new_with_prefix(data)
736                    .finalize()
737                    .to_vec(),
738                _ => data.to_vec(),
739            };
740            #[cfg(feature = "ring")]
741            {
742                use ring::signature::UnparsedPublicKey;
743                let verification_algorithm = &ring::signature::ED25519;
744                let public_key = UnparsedPublicKey::new(verification_algorithm, &okp.public_key.0);
745                public_key.verify(&hash, signature)?;
746            }
747            #[cfg(feature = "ed25519")]
748            {
749                use ed25519_dalek::Verifier;
750                let public_key = ed25519_dalek::VerifyingKey::try_from(okp)?;
751                let signature: ed25519_dalek::Signature =
752                    signature.try_into().map_err(ssi_jwk::Error::from)?;
753                public_key
754                    .verify(&hash, &signature)
755                    .map_err(ssi_jwk::Error::from)?;
756            }
757        }
758        #[allow(unused)]
759        JWKParams::EC(ec) => match algorithm {
760            #[cfg(feature = "secp256r1")]
761            Algorithm::ES256 => {
762                use p256::ecdsa::signature::Verifier;
763                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
764                let public_key = p256::PublicKey::try_from(ec)?;
765                let verifying_key = p256::ecdsa::VerifyingKey::from(public_key);
766                let sig =
767                    p256::ecdsa::Signature::try_from(signature).map_err(ssi_jwk::Error::from)?;
768                verifying_key
769                    .verify(data, &sig)
770                    .map_err(ssi_jwk::Error::from)?;
771            }
772            #[cfg(feature = "secp256k1")]
773            Algorithm::ES256K => {
774                use k256::ecdsa::signature::Verifier;
775                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
776                let public_key = k256::PublicKey::try_from(ec)?;
777                let verifying_key = k256::ecdsa::VerifyingKey::from(public_key);
778                let sig =
779                    k256::ecdsa::Signature::try_from(signature).map_err(ssi_jwk::Error::from)?;
780                let normalized_sig = if let Some(s) = sig.normalize_s() {
781                    // For user convenience, output the normalized signature.
782                    let sig_normalized_b64 =
783                        base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(s.to_bytes());
784                    warnings.push(format!(
785                        "Non-normalized ES256K signature. Normalized: {sig_normalized_b64}"
786                    ));
787                    s
788                } else {
789                    sig
790                };
791                verifying_key
792                    .verify(data, &normalized_sig)
793                    .map_err(ssi_jwk::Error::from)?;
794            }
795            #[cfg(feature = "secp256k1")]
796            Algorithm::ES256KR => {
797                use k256::ecdsa::{
798                    signature::{
799                        digest::{consts::U32, Digest},
800                        DigestVerifier, Verifier,
801                    },
802                    RecoveryId, VerifyingKey,
803                };
804                if signature.len() != 65 {
805                    Err(k256::ecdsa::Error::new())?;
806                }
807                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
808                let public_key = k256::PublicKey::try_from(ec)?;
809                let verifying_key = k256::ecdsa::VerifyingKey::from(public_key);
810                let sig = k256::ecdsa::Signature::try_from(&signature[..64])
811                    .map_err(ssi_jwk::Error::from)?;
812                let rec_id = k256::ecdsa::RecoveryId::try_from(signature[64])
813                    .map_err(ssi_jwk::Error::from)?;
814                match VerifyingKey::recover_from_digest(
815                    <sha2::Sha256 as Digest>::new_with_prefix(data),
816                    &sig,
817                    rec_id,
818                ) {
819                    Err(_e) => {
820                        // Legacy mode: allow using Keccak-256 instead of SHA-256
821                        verify_bytes(Algorithm::ESKeccakKR, data, key, signature)?;
822                        warnings.push(
823                            "Signature uses legacy mode ES256K-R with Keccak-256".to_string(),
824                        );
825                    }
826                    Ok(recovered_key) => match recovered_key == verifying_key {
827                        true => (),
828                        false => Err(k256::ecdsa::Error::new())?,
829                    },
830                }
831            }
832            #[cfg(feature = "eip")]
833            Algorithm::ESKeccakKR => {
834                use k256::ecdsa::{
835                    signature::{
836                        digest::{consts::U32, Digest},
837                        DigestVerifier, Verifier,
838                    },
839                    RecoveryId, VerifyingKey,
840                };
841                if signature.len() != 65 {
842                    Err(k256::ecdsa::Error::new())?;
843                }
844                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
845                let public_key = k256::PublicKey::try_from(ec)?;
846                let verifying_key = k256::ecdsa::VerifyingKey::from(public_key);
847                let sig = k256::ecdsa::Signature::try_from(&signature[..64])
848                    .map_err(ssi_jwk::Error::from)?;
849                let rec_id = k256::ecdsa::RecoveryId::try_from(signature[64])
850                    .map_err(ssi_jwk::Error::from)?;
851                let recovered_key = VerifyingKey::recover_from_digest(
852                    sha3::Keccak256::new_with_prefix(data),
853                    &sig,
854                    rec_id,
855                )
856                .map_err(ssi_jwk::Error::from)?;
857                match recovered_key == verifying_key {
858                    true => (),
859                    false => Err(k256::ecdsa::Error::new())?,
860                }
861            }
862            #[cfg(feature = "secp256r1")]
863            Algorithm::ESBlake2b => {
864                use p256::ecdsa::{
865                    signature::{
866                        digest::{consts::U32, Digest},
867                        DigestVerifier,
868                    },
869                    Signature,
870                };
871                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
872                let public_key = p256::PublicKey::try_from(ec)?;
873                let verifying_key = p256::ecdsa::VerifyingKey::from(public_key);
874                let sig =
875                    p256::ecdsa::Signature::try_from(signature).map_err(ssi_jwk::Error::from)?;
876                verifying_key
877                    .verify_digest(
878                        <blake2::Blake2b<U32> as Digest>::new_with_prefix(data),
879                        &sig,
880                    )
881                    .map_err(ssi_jwk::Error::from)?;
882            }
883            #[cfg(feature = "secp256k1")]
884            Algorithm::ESBlake2bK => {
885                use k256::ecdsa::signature::{
886                    digest::{consts::U32, Digest},
887                    DigestVerifier,
888                };
889                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
890                let public_key = k256::PublicKey::try_from(ec)?;
891                let verifying_key = k256::ecdsa::VerifyingKey::from(public_key);
892                let sig =
893                    k256::ecdsa::Signature::try_from(signature).map_err(ssi_jwk::Error::from)?;
894                verifying_key
895                    .verify_digest(
896                        <blake2::Blake2b<U32> as Digest>::new_with_prefix(data),
897                        &sig,
898                    )
899                    .map_err(ssi_jwk::Error::from)?;
900            }
901            #[cfg(feature = "secp384r1")]
902            Algorithm::ES384 => {
903                use p384::ecdsa::signature::Verifier;
904                let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?;
905                let public_key = p384::PublicKey::try_from(ec)?;
906                let verifying_key = p384::ecdsa::VerifyingKey::from(public_key);
907                let sig =
908                    p384::ecdsa::Signature::try_from(signature).map_err(ssi_jwk::Error::from)?;
909                verifying_key
910                    .verify(data, &sig)
911                    .map_err(ssi_jwk::Error::from)?;
912            }
913            _ => {
914                return Err(Error::UnsupportedAlgorithm(algorithm.to_string()));
915            }
916        },
917        _ => {
918            return Err(Error::Jwk(ssi_jwk::Error::KeyTypeNotImplemented(Box::new(
919                key.to_public(),
920            ))))
921        }
922    }
923    Ok(warnings)
924}
925
926pub fn verify_bytes(
927    algorithm: Algorithm,
928    data: &[u8],
929    key: &JWK,
930    signature: &[u8],
931) -> Result<(), Error> {
932    verify_bytes_warnable(algorithm, data, key, signature)?;
933    Ok(())
934}
935
936/// Recover a key from a signature and message, if the algorithm supports this.  (e.g.
937/// [ES256K-R](https://github.com/decentralized-identity/EcdsaSecp256k1RecoverySignature2020#es256k-r))
938pub fn recover(algorithm: Algorithm, data: &[u8], signature: &[u8]) -> Result<JWK, Error> {
939    match algorithm {
940        #[cfg(feature = "secp256k1")]
941        Algorithm::ES256KR => {
942            use k256::ecdsa::VerifyingKey;
943            if signature.len() != 65 {
944                Err(k256::ecdsa::Error::new())?;
945            }
946            let sig =
947                k256::ecdsa::Signature::try_from(&signature[..64]).map_err(ssi_jwk::Error::from)?;
948            let rec_id =
949                k256::ecdsa::RecoveryId::try_from(signature[64]).map_err(ssi_jwk::Error::from)?;
950            let hash = ssi_crypto::hashes::sha256::sha256(data);
951            let digest = k256::elliptic_curve::FieldBytes::<k256::Secp256k1>::from_slice(&hash);
952            let recovered_key = VerifyingKey::recover_from_prehash(digest, &sig, rec_id)
953                .map_err(ssi_jwk::Error::from)?;
954            use ssi_jwk::ECParams;
955            let jwk = JWK {
956                params: JWKParams::EC(ECParams::from(
957                    &k256::PublicKey::from_sec1_bytes(&recovered_key.to_sec1_bytes())
958                        .map_err(ssi_jwk::Error::from)?,
959                )),
960                public_key_use: None,
961                key_operations: None,
962                algorithm: None,
963                key_id: None,
964                x509_url: None,
965                x509_certificate_chain: None,
966                x509_thumbprint_sha1: None,
967                x509_thumbprint_sha256: None,
968            };
969            Ok(jwk)
970        }
971        #[cfg(feature = "secp256k1")]
972        Algorithm::ESKeccakKR => {
973            use k256::ecdsa::{signature::digest::Digest, VerifyingKey};
974            if signature.len() != 65 {
975                Err(k256::ecdsa::Error::new())?;
976            }
977            let sig =
978                k256::ecdsa::Signature::try_from(&signature[..64]).map_err(ssi_jwk::Error::from)?;
979            let rec_id =
980                k256::ecdsa::RecoveryId::try_from(signature[64]).map_err(ssi_jwk::Error::from)?;
981            let recovered_key = VerifyingKey::recover_from_digest(
982                sha3::Keccak256::new_with_prefix(data),
983                &sig,
984                rec_id,
985            )
986            .map_err(ssi_jwk::Error::from)?;
987            use ssi_jwk::ECParams;
988            let jwk = JWK::from(JWKParams::EC(ECParams::from(
989                &k256::PublicKey::from_sec1_bytes(&recovered_key.to_sec1_bytes())
990                    .map_err(ssi_jwk::Error::from)?,
991            )));
992            Ok(jwk)
993        }
994        _ => {
995            let _ = data;
996            let _ = signature;
997            Err(Error::UnsupportedAlgorithm(algorithm.to_string()))
998        }
999    }
1000}
1001
1002pub fn detached_sign_unencoded_payload(
1003    algorithm: Algorithm,
1004    payload: &[u8],
1005    key: &JWK,
1006) -> Result<String, Error> {
1007    let header = Header {
1008        algorithm,
1009        key_id: key.key_id.clone(),
1010        critical: Some(vec!["b64".to_string()]),
1011        base64urlencode_payload: Some(false),
1012        ..Default::default()
1013    };
1014    let header_b64 = base64_encode_json(&header)?;
1015    let signing_input = [header_b64.as_bytes(), b".", payload].concat();
1016    let sig_b64 = sign_bytes_b64(header.algorithm, &signing_input, key)?;
1017    let jws = header_b64 + ".." + &sig_b64;
1018    Ok(jws)
1019}
1020
1021pub fn prepare_detached_unencoded_payload(
1022    algorithm: Algorithm,
1023    payload: &[u8],
1024) -> Result<(Header, Vec<u8>), Error> {
1025    let header = Header {
1026        algorithm,
1027        critical: Some(vec!["b64".to_string()]),
1028        base64urlencode_payload: Some(false),
1029        ..Default::default()
1030    };
1031    let header_b64 = base64_encode_json(&header)?;
1032    let signing_input = [header_b64.as_bytes(), b".", payload].concat().to_vec();
1033    Ok((header, signing_input))
1034}
1035
1036pub fn complete_sign_unencoded_payload(header: &Header, sig_b64: &str) -> Result<String, Error> {
1037    let header_b64 = base64_encode_json(header)?;
1038    let jws = header_b64 + ".." + sig_b64;
1039    Ok(jws)
1040}
1041
1042pub fn encode_sign(algorithm: Algorithm, payload: &str, key: &JWK) -> Result<String, Error> {
1043    let header = Header {
1044        algorithm,
1045        key_id: key.key_id.clone(),
1046        ..Default::default()
1047    };
1048    encode_sign_custom_header(payload, key, &header)
1049}
1050
1051pub fn encode_sign_custom_header(
1052    payload: &str,
1053    key: &JWK,
1054    header: &Header,
1055) -> Result<String, Error> {
1056    let header_b64 = base64_encode_json(header)?;
1057    let payload_b64 = base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(payload);
1058    let signing_input = header_b64 + "." + &payload_b64;
1059    let sig_b64 = sign_bytes_b64(header.algorithm, signing_input.as_bytes(), key)?;
1060    let jws = [signing_input, sig_b64].join(".");
1061    Ok(jws)
1062}
1063
1064pub fn encode_unsigned(payload: &str) -> Result<String, Error> {
1065    let header = Header {
1066        algorithm: Algorithm::None,
1067        ..Default::default()
1068    };
1069    let header_b64 = base64_encode_json(&header)?;
1070    let payload_b64 = base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(payload);
1071    Ok(header_b64 + "." + &payload_b64 + ".")
1072}
1073
1074pub fn split_jws(jws: &str) -> Result<(&str, &str, &str), Error> {
1075    let mut parts = jws.splitn(3, '.');
1076    Ok(
1077        match (parts.next(), parts.next(), parts.next(), parts.next()) {
1078            (Some(a), Some(b), Some(c), None) => (a, b, c),
1079            _ => return Err(Error::InvalidJws),
1080        },
1081    )
1082}
1083
1084pub fn split_detached_jws(jws: &str) -> Result<(&str, &str), Error> {
1085    let (header_b64, omitted_payload, signature_b64) = split_jws(jws)?;
1086    if !omitted_payload.is_empty() {
1087        return Err(Error::InvalidJws);
1088    }
1089    Ok((header_b64, signature_b64))
1090}
1091
1092/// Decode JWS parts (JOSE header, payload, and signature) into useful values.
1093/// The payload argument is bytes since it may be unencoded if the b64:false header parameter is used; otherwise it must be a base64url-encoded string. Header and signature are always expected to be base64url-encoded.
1094/// "crit" (critical) header parameters are checked and disallowed if unrecognized/unsupported.
1095pub fn decode_jws_parts(
1096    header_b64: &str,
1097    payload_enc: &[u8],
1098    signature_b64: &str,
1099) -> Result<DecodedJws<'static>, Error> {
1100    let signature = base64::prelude::BASE64_URL_SAFE_NO_PAD.decode(signature_b64)?;
1101    let header = Header::decode(header_b64.as_bytes())?;
1102    let payload = if header.base64urlencode_payload.unwrap_or(true) {
1103        base64::prelude::BASE64_URL_SAFE_NO_PAD.decode(payload_enc)?
1104    } else {
1105        payload_enc.to_vec()
1106    };
1107    for name in header.critical.iter().flatten() {
1108        match name.as_str() {
1109            "alg" | "jku" | "jwk" | "kid" | "x5u" | "x5c" | "x5t" | "x5t#S256" | "typ" | "cty"
1110            | "crit" => return Err(Error::InvalidCriticalHeader),
1111            "b64" => {}
1112            _ => return Err(Error::UnknownCriticalHeader),
1113        }
1114    }
1115    let signing_input = [header_b64.as_bytes(), b".", payload_enc].concat();
1116    Ok(DecodedJws::new(
1117        DecodedSigningBytes::new(Cow::Owned(signing_input), header, payload),
1118        signature.into(),
1119    ))
1120}
1121
1122/// Verify a JWS with detached payload. Returns the JWS header on success.
1123pub fn detached_verify(jws: &str, payload_enc: &[u8], key: &JWK) -> Result<Header, Error> {
1124    let (header_b64, signature_b64) = split_detached_jws(jws)?;
1125    let (jws, signing_bytes) =
1126        decode_jws_parts(header_b64, payload_enc, signature_b64)?.into_jws_and_signing_bytes();
1127    verify_bytes(
1128        jws.header.algorithm,
1129        &signing_bytes,
1130        key,
1131        jws.signature.as_bytes(),
1132    )?;
1133    Ok(jws.header)
1134}
1135
1136/// Recover a JWK from a JWS and payload, if the algorithm supports that (such as [ES256K-R](https://github.com/decentralized-identity/EcdsaSecp256k1RecoverySignature2020#es256k-r)).
1137pub fn detached_recover(jws: &str, payload_enc: &[u8]) -> Result<(Header, JWK), Error> {
1138    let (header_b64, signature_b64) = split_detached_jws(jws)?;
1139    let (jws, signing_bytes) =
1140        decode_jws_parts(header_b64, payload_enc, signature_b64)?.into_jws_and_signing_bytes();
1141    let key = recover(
1142        jws.header.algorithm,
1143        &signing_bytes,
1144        jws.signature.as_bytes(),
1145    )?;
1146    Ok((jws.header, key))
1147}
1148
1149pub fn detached_recover_legacy_keccak_es256kr(
1150    jws: &str,
1151    payload_enc: &[u8],
1152) -> Result<(Header, JWK), Error> {
1153    let (header_b64, signature_b64) = split_detached_jws(jws)?;
1154    let (mut jws, signing_bytes) =
1155        decode_jws_parts(header_b64, payload_enc, signature_b64)?.into_jws_and_signing_bytes();
1156    // Allow ESKeccakK-R misimplementation of ES256K-R, for legacy reasons.
1157    if jws.header.algorithm != Algorithm::ES256KR {
1158        return Err(Error::AlgorithmMismatch);
1159    }
1160    jws.header.algorithm = Algorithm::ESKeccakKR;
1161    let key = recover(
1162        jws.header.algorithm,
1163        &signing_bytes,
1164        jws.signature.as_bytes(),
1165    )?;
1166    Ok((jws.header, key))
1167}
1168
1169pub fn decode_verify(jws: &str, key: &JWK) -> Result<(Header, Vec<u8>), Error> {
1170    let (header_b64, payload_enc, signature_b64) = split_jws(jws)?;
1171    let (jws, signing_bytes) = decode_jws_parts(header_b64, payload_enc.as_bytes(), signature_b64)?
1172        .into_jws_and_signing_bytes();
1173    verify_bytes(
1174        jws.header.algorithm,
1175        &signing_bytes,
1176        key,
1177        jws.signature.as_bytes(),
1178    )?;
1179    Ok((jws.header, jws.payload))
1180}
1181
1182pub fn decode_unverified(jws: &str) -> Result<(Header, Vec<u8>), Error> {
1183    let (header_b64, payload_enc, signature_b64) = split_jws(jws)?;
1184    let jws = decode_jws_parts(header_b64, payload_enc.as_bytes(), signature_b64)?.into_jws();
1185    Ok((jws.header, jws.payload))
1186}
1187
1188#[cfg(test)]
1189mod tests {
1190    #[allow(unused_imports)]
1191    use super::*;
1192
1193    #[test]
1194    #[cfg(feature = "rsa")]
1195    fn jws_encode() {
1196        // https://tools.ietf.org/html/rfc7515#appendix-A.2
1197        let payload =
1198            "{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n \"http://example.com/is_root\":true}";
1199
1200        use serde_json::json;
1201        // https://tools.ietf.org/html/rfc7515#page-41
1202        let key: JWK = serde_json::from_value(json!({"kty":"RSA",
1203         "n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ",
1204         "e":"AQAB",
1205         "d":"Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97IjlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYTCBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLhBOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ",
1206         "p":"4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPGBY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc", "q":"uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc",
1207         "dp":"BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3QCLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0",
1208         "dq":"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU",
1209         "qi":"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U"
1210        }))
1211        .unwrap();
1212
1213        // https://tools.ietf.org/html/rfc7515#page-43
1214        let jws = encode_sign(Algorithm::RS256, payload, &key).unwrap();
1215        assert_eq!(jws, "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw");
1216
1217        decode_verify(&jws, &key).unwrap();
1218    }
1219
1220    #[test]
1221    #[cfg(feature = "secp256k1")]
1222    fn secp256k1_sign_verify() {
1223        let key = JWK::generate_secp256k1();
1224        let data = b"asdf";
1225        let bad_data = b"no";
1226        let sig = sign_bytes(Algorithm::ES256K, data, &key).unwrap();
1227        verify_bytes(Algorithm::ES256K, data, &key, &sig).unwrap();
1228        verify_bytes(Algorithm::ES256K, bad_data, &key, &sig).unwrap_err();
1229
1230        // ES256K-R
1231        let key = JWK {
1232            algorithm: Some(Algorithm::ES256KR),
1233            ..key
1234        };
1235        verify_bytes(Algorithm::ES256KR, data, &key, &sig).unwrap_err();
1236        verify_bytes(Algorithm::ES256KR, bad_data, &key, &sig).unwrap_err();
1237
1238        // Test recovery
1239        let sig = sign_bytes(Algorithm::ES256KR, data, &key).unwrap();
1240        verify_bytes(Algorithm::ES256KR, data, &key, &sig).unwrap();
1241        verify_bytes(Algorithm::ES256KR, bad_data, &key, &sig).unwrap_err();
1242        let recovered_key = recover(Algorithm::ES256KR, data, &sig).unwrap();
1243        verify_bytes(Algorithm::ES256KR, data, &recovered_key, &sig).unwrap();
1244        let other_key = JWK::generate_secp256k1();
1245        verify_bytes(Algorithm::ES256KR, data, &other_key, &sig).unwrap_err();
1246    }
1247
1248    #[test]
1249    #[cfg(feature = "eip")]
1250    fn keccak_sign_verify() {
1251        let key = JWK::generate_secp256k1();
1252        let data = b"asdf";
1253        let bad_data = b"no";
1254        // ESKeccakK-R
1255        let key = JWK {
1256            algorithm: Some(Algorithm::ESKeccakKR),
1257            ..key
1258        };
1259
1260        let sig = sign_bytes(Algorithm::ES256KR, data, &key).unwrap();
1261        let other_key = JWK::generate_secp256k1();
1262        // TODO check the error type
1263        verify_bytes(Algorithm::ESKeccakKR, data, &key, &sig).unwrap_err();
1264        verify_bytes(Algorithm::ESKeccakKR, bad_data, &key, &sig).unwrap_err();
1265
1266        // Test recovery (ESKeccakK-R)
1267        let sig = sign_bytes(Algorithm::ESKeccakKR, data, &key).unwrap();
1268        verify_bytes(Algorithm::ESKeccakKR, data, &key, &sig).unwrap();
1269        verify_bytes(Algorithm::ESKeccakKR, bad_data, &key, &sig).unwrap_err();
1270        let recovered_key = recover(Algorithm::ESKeccakKR, data, &sig).unwrap();
1271        verify_bytes(Algorithm::ESKeccakKR, data, &recovered_key, &sig).unwrap();
1272        verify_bytes(Algorithm::ESKeccakKR, data, &other_key, &sig).unwrap_err();
1273    }
1274
1275    #[test]
1276    #[cfg(feature = "secp256r1")]
1277    fn p256_sign_verify() {
1278        let key = JWK::generate_p256();
1279        let data = b"asdf";
1280        let bad_data = b"no";
1281        let sig = sign_bytes(Algorithm::ES256, data, &key).unwrap();
1282        verify_bytes(Algorithm::ES256, data, &key, &sig).unwrap();
1283        verify_bytes(Algorithm::ES256, bad_data, &key, &sig).unwrap_err();
1284
1285        let key: JWK = serde_json::from_str(include_str!(
1286            "../../../../../tests/secp256r1-2021-03-18.json"
1287        ))
1288        .unwrap();
1289        let payload = "{\"iss\":\"did:example:foo\",\"vp\":{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"type\":\"VerifiablePresentation\"}}";
1290        let jws = encode_sign(Algorithm::ES256, payload, &key).unwrap();
1291        assert_eq!(jws, "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJkaWQ6ZXhhbXBsZTpmb28iLCJ2cCI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjoiVmVyaWZpYWJsZVByZXNlbnRhdGlvbiJ9fQ.rJzO6MmTNS8Tn-L3baIf9_2Jr9OoK8E06MxJtofz8xMUGSom6eRUmWGZ7oQVjgP3HogOD80miTvuvKTWa54Nvw");
1292        decode_verify(&jws, &key).unwrap();
1293    }
1294
1295    #[test]
1296    #[cfg(feature = "secp384r1")]
1297    fn p384_sign_verify() {
1298        let key = JWK::generate_p384();
1299        let data = b"asdf";
1300        let bad_data = b"no";
1301        let sig = sign_bytes(Algorithm::ES384, data, &key).unwrap();
1302        verify_bytes(Algorithm::ES384, data, &key, &sig).unwrap();
1303        verify_bytes(Algorithm::ES384, bad_data, &key, &sig).unwrap_err();
1304
1305        let key: JWK = serde_json::from_str(include_str!(
1306            "../../../../../tests/secp384r1-2022-05-10.json"
1307        ))
1308        .unwrap();
1309        let payload = "{\"iss\":\"did:example:foo\",\"vp\":{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"type\":\"VerifiablePresentation\"}}";
1310        let jws = encode_sign(Algorithm::ES384, payload, &key).unwrap();
1311        dbg!(&jws);
1312        decode_verify(&jws, &key).unwrap();
1313
1314        const JWS: &str = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJkaWQ6ZXhhbXBsZTpmb28iLCJ2cCI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjoiVmVyaWZpYWJsZVByZXNlbnRhdGlvbiJ9fQ.2vpBSFN7DxuS57epgq_e7-NyNiJ5eOOrExmi65C_wtZOC2-9i6fVvMnfUig7QmgiirznAg1wr_b7_kH-bbMCI5Pdf8pAnxQg3LL9I9OhzttyG06qAl9L7BE6aNS-aqnf";
1315        decode_verify(JWS, &key).unwrap();
1316    }
1317}