jws/
lib.rs

1//! This library provides JSON Web Signature encoding, decoding, signing and verification
2//! as described in [RFC 7515](https://tools.ietf.org/html/rfc7515).
3//!
4//! Currently, encoding and decoding is available only for the JWS Compact Serialization scheme in the
5//! [`compact`] module.
6//!
7//! Signing and verifying is done through the [`Signer`] and [`Verifier`] traits.
8//! The [`hmac`] module contains implementations for these traits that support the HMAC-SHA2 family of algorithms.
9//!
10//! # Example:
11//! ```
12//! use jws::{JsonObject, JsonValue};
13//! use jws::compact::{decode_verify, encode_sign};
14//! use jws::hmac::{Hs512Signer, HmacVerifier};
15//!
16//! fn encode_decode() -> jws::Result<()> {
17//!   // Add custom header parameters.
18//!   let mut header = JsonObject::new();
19//!   header.insert(String::from("typ"), JsonValue::from("text/plain"));
20//!
21//!   // Encode and sign the message.
22//!   let encoded = encode_sign(header, b"payload", &Hs512Signer::new(b"secretkey"))?;
23//!
24//!   // Decode and verify the message.
25//!   let decoded = decode_verify(encoded.data().as_bytes(), &HmacVerifier::new(b"secretkey"))?;
26//!
27//!   assert_eq!(decoded.payload, b"payload");
28//!   assert_eq!(decoded.header.get("typ").and_then(|x| x.as_str()), Some("text/plain"));
29//!
30//!   Ok(())
31//! }
32//!
33//! ```
34
35pub mod compact;
36pub mod hmac;
37mod error;
38mod header;
39mod combine;
40pub mod none;
41
42pub use crate::error::{Error, ErrorKind, Result};
43pub use crate::header::{get_header_param, get_required_header_param, parse_required_header_param};
44
45/// Re-exported [`serde_json::Value`].
46pub type JsonValue  = serde_json::Value;
47
48/// A JSON object.
49pub type JsonObject = std::collections::BTreeMap<String, JsonValue>;
50
51/// Create a JSON object.
52///
53/// This is similar to the `json` macro from serde,
54/// except that this macro always creates a JSON object, rather than a JSON value.
55///
56/// # Example
57/// ```
58/// # use jws::json_object;
59/// json_object!{
60///   "alg": "HS256",
61///   "typ": "jwt",
62/// };
63/// ```
64#[macro_export]
65macro_rules! json_object {
66	{} => { $crate::JsonObject::new() };
67
68	{ $( $name:tt : $value:expr, )+ } => {{
69		let mut object = $crate::JsonObject::new();
70		$(object.insert(String::from($name), $crate::JsonValue::from($value));)*
71		object
72	}};
73
74	{ $( $name:tt : $value:expr ),+ } => {{
75		let mut object = $crate::JsonObject::new();
76		$(object.insert(String::from($name), $crate::JsonValue::from($value));)*
77		object
78	}};
79}
80
81/// A verifier for JWS messages.
82pub trait Verifier: Sized {
83	/// Verify the signature of a JWS message.
84	///
85	/// This function needs access to the decoded message headers in order to determine which MAC algorithm to use.
86	/// It also needs access to the base64-url encoded parts to verify the signature.
87	///
88	/// If the signature is invalid, the function should return a [`Error::InvalidSignature`] error.
89	/// If the algorithm is not supported by the verifier, it should return a [`Error::UnsupportedMacAlgorithm`] error.
90	/// It may also report any of the other supported error variants.
91	///
92	/// # Args:
93	///   - protected_header:   The parsed protected header, if any.
94	///   - unprotected_header: The parsed unprotected header, if any.
95	///   - encoded_header:     The base64-url encoded protected header, needed to compute the MAC. If there is no protected header, this is an empty slice.
96	///   - encoded_payload:    The base64-url encoded payload, needed to compute the MAC.
97	///   - signature:          The signature associated with the message, should be tested against the computed MAC.
98	fn verify(
99		&self,
100		protected_header   : Option<&JsonObject>,
101		unprotected_header : Option<&JsonObject>,
102		encoded_header     : &[u8],
103		encoded_payload    : &[u8],
104		signature          : &[u8],
105	) -> Result<()>;
106
107	/// Create a new verifier that accepts a message if either this or the other verifier does.
108	fn or<Other: Verifier>(self, other: Other) -> combine::OrVerifier<Self, Other> {
109		combine::OrVerifier::new(self, other)
110	}
111
112	/// Create a new verifier that accepts a message if both this and the other verifier does.
113	fn and<Other: Verifier>(self, other: Other) -> combine::AndVerifier<Self, Other> {
114		combine::AndVerifier::new(self, other)
115	}
116}
117
118/// A signer for JWS messages.
119pub trait Signer {
120	/// Set the header parameters to indicate how the message should be verified.
121	///
122	/// This is the first step in the signing process, since the encoded headers will end up in the signature if they are added to the protected header.
123	fn set_header_params(&self, header: &mut JsonObject);
124
125	/// Compute the Message Authentication Code for the encoded protected header and encoded payload.
126	///
127	/// The returned MAC must be plain bytes, not hex or base64 encoded.
128	fn compute_mac(&self, encoded_protected_header: &[u8], encoded_payload: &[u8]) -> Result<Vec<u8>>;
129}