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