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}