Skip to content

Commit 4d94ed5

Browse files
committed
feat(jose-jws): make generic over claims
1. Allow custom types to be used for `Protected` and `Unprotected` 2. Prepare to support JWT claims 3. Implement `Deref` and `DerefMut` for `Protected`
1 parent 0a9a98a commit 4d94ed5

5 files changed

Lines changed: 86 additions & 38 deletions

File tree

jose-jws/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ let jws_json = serde_json::json!({
5454
]
5555
});
5656

57-
let Jws::General(jws) = serde_json::from_value(jws_json).unwrap() else {
57+
let Jws::General(jws) = serde_json::from_value::<Jws>(jws_json).unwrap() else {
5858
panic!("couldn't deserialize JWS");
5959
};
6060

jose-jws/src/compact.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,32 @@ use jose_b64::stream::Error;
99

1010
use crate::{Flattened, General, Jws, Signature};
1111

12-
impl FromStr for Jws {
12+
impl<U, P> FromStr for Jws<U, P>
13+
where
14+
P: serde::de::DeserializeOwned,
15+
{
1316
type Err = Error<serde_json::Error>;
1417

1518
fn from_str(s: &str) -> Result<Self, Self::Err> {
1619
Ok(Flattened::from_str(s)?.into())
1720
}
1821
}
1922

20-
impl FromStr for General {
23+
impl<U, P> FromStr for General<U, P>
24+
where
25+
P: serde::de::DeserializeOwned,
26+
{
2127
type Err = Error<serde_json::Error>;
2228

2329
fn from_str(s: &str) -> Result<Self, Self::Err> {
2430
Ok(Flattened::from_str(s)?.into())
2531
}
2632
}
2733

28-
impl FromStr for Flattened {
34+
impl<U, P> FromStr for Flattened<U, P>
35+
where
36+
P: serde::de::DeserializeOwned,
37+
{
2938
type Err = Error<serde_json::Error>;
3039

3140
fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -54,7 +63,7 @@ impl FromStr for Flattened {
5463
}
5564
}
5665

57-
impl Display for Flattened {
66+
impl<U, P> Display for Flattened<U, P> {
5867
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
5968
let mut prot = alloc::string::String::new();
6069
if let Some(x) = self.signature.protected.as_ref() {

jose-jws/src/crypto/mod.rs

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,38 @@ pub trait Signer: Update {
1515
#[allow(missing_docs)]
1616
type FinishError: From<Self::Error>;
1717

18+
/// The unprotected header type
19+
type Unprotected;
20+
21+
/// The protected header type
22+
type Protected;
23+
1824
/// Finish processing payload and create the signature.
19-
fn finish(self, rng: impl 'static + RngCore) -> Result<Signature, Self::FinishError>;
25+
fn finish(
26+
self,
27+
rng: impl 'static + RngCore,
28+
) -> Result<Signature<Self::Unprotected, Self::Protected>, Self::FinishError>;
2029
}
2130

2231
/// A signature creation key
23-
pub trait SigningKey<'a> {
32+
pub trait SigningKey<'a, U = Unprotected, P = Protected<U>> {
2433
#[allow(missing_docs)]
2534
type StartError: From<<Self::Signer as Update>::Error>;
2635

36+
/// The unprotected header type
37+
type Unprotected;
38+
39+
/// The protected header type
40+
type Protected;
41+
2742
/// The state object used during signing.
28-
type Signer: Signer;
43+
type Signer: Signer<Unprotected = Self::Unprotected, Protected = Self::Protected>;
2944

3045
/// Begin the signature creation process.
3146
fn sign(
3247
&'a self,
33-
prot: Option<Protected>,
34-
head: Option<Unprotected>,
48+
prot: Option<Self::Protected>,
49+
head: Option<Self::Unprotected>,
3550
) -> Result<Self::Signer, Self::StartError>;
3651
}
3752

@@ -98,26 +113,31 @@ where
98113
}
99114
}
100115

101-
impl<'a, T: VerifyingKey<'a, &'a Signature>> VerifyingKey<'a, &'a Flattened> for T
116+
impl<'a, T, U, P> VerifyingKey<'a, &'a Flattened<U, P>> for T
102117
where
118+
T: VerifyingKey<'a, &'a Signature<U, P>>,
103119
<T::Verifier as Verifier<'a>>::FinishError: Default,
104120
{
105121
type StartError = T::StartError;
106122
type Verifier = Vec<T::Verifier>;
107123

108-
fn verify(&'a self, flattened: &'a Flattened) -> Result<Self::Verifier, Self::StartError> {
124+
fn verify(
125+
&'a self,
126+
flattened: &'a Flattened<U, P>,
127+
) -> Result<Self::Verifier, Self::StartError> {
109128
Ok(vec![self.verify(&flattened.signature)?])
110129
}
111130
}
112131

113-
impl<'a, T: VerifyingKey<'a, &'a Signature>> VerifyingKey<'a, &'a General> for T
132+
impl<'a, T, U, P> VerifyingKey<'a, &'a General<U, P>> for T
114133
where
134+
T: VerifyingKey<'a, &'a Signature<U, P>>,
115135
<T::Verifier as Verifier<'a>>::FinishError: Default,
116136
{
117137
type StartError = T::StartError;
118138
type Verifier = Vec<T::Verifier>;
119139

120-
fn verify(&'a self, general: &'a General) -> Result<Self::Verifier, Self::StartError> {
140+
fn verify(&'a self, general: &'a General<U, P>) -> Result<Self::Verifier, Self::StartError> {
121141
general
122142
.signatures
123143
.iter()
@@ -126,17 +146,17 @@ where
126146
}
127147
}
128148

129-
impl<'a, T, V, E> VerifyingKey<'a, &'a Jws> for T
149+
impl<'a, T, V, E, U, P> VerifyingKey<'a, &'a Jws<U, P>> for T
130150
where
131-
T: VerifyingKey<'a, &'a Flattened, Verifier = V, StartError = E>,
132-
T: VerifyingKey<'a, &'a General, Verifier = V, StartError = E>,
151+
T: VerifyingKey<'a, &'a Flattened<U, P>, Verifier = V, StartError = E>,
152+
T: VerifyingKey<'a, &'a General<U, P>, Verifier = V, StartError = E>,
133153
E: From<V::Error>,
134154
V: Verifier<'a>,
135155
{
136156
type StartError = E;
137157
type Verifier = V;
138158

139-
fn verify(&'a self, jws: &'a Jws) -> Result<Self::Verifier, Self::StartError> {
159+
fn verify(&'a self, jws: &'a Jws<U, P>) -> Result<Self::Verifier, Self::StartError> {
140160
match jws {
141161
Jws::General(general) => self.verify(general),
142162
Jws::Flattened(flattened) => self.verify(flattened),

jose-jws/src/head.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use alloc::vec::Vec;
55
use alloc::{boxed::Box, string::String};
6+
use core::ops::{Deref, DerefMut};
67

78
use jose_b64::base64ct::Base64;
89
use jose_b64::serde::Bytes;
@@ -22,7 +23,7 @@ fn b64_serialize(value: &bool) -> bool {
2223

2324
/// The JWS Protected Header
2425
#[derive(Clone, Debug, Serialize, Deserialize)]
25-
pub struct Protected {
26+
pub struct Protected<U = Unprotected> {
2627
/// RFC 7517 Section 4.1.11
2728
#[serde(skip_serializing_if = "Option::is_none", default)]
2829
pub crit: Option<Vec<String>>,
@@ -37,20 +38,34 @@ pub struct Protected {
3738

3839
/// Other values that may appear in the protected header.
3940
#[serde(flatten)]
40-
pub oth: Unprotected,
41+
pub oth: U,
4142
}
4243

43-
impl Default for Protected {
44+
impl<U: Default> Default for Protected<U> {
4445
fn default() -> Self {
4546
Self {
4647
crit: None,
4748
nonce: None,
4849
b64: true,
49-
oth: Unprotected::default(),
50+
oth: U::default(),
5051
}
5152
}
5253
}
5354

55+
impl<U> Deref for Protected<U> {
56+
type Target = U;
57+
58+
fn deref(&self) -> &Self::Target {
59+
&self.oth
60+
}
61+
}
62+
63+
impl<U> DerefMut for Protected<U> {
64+
fn deref_mut(&mut self) -> &mut Self::Target {
65+
&mut self.oth
66+
}
67+
}
68+
5469
/// The JWS Unprotected Header
5570
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
5671
pub struct Unprotected {

jose-jws/src/lib.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,24 @@ use serde::{Deserialize, Serialize};
3737
#[derive(Clone, Debug, Serialize, Deserialize)]
3838
#[non_exhaustive]
3939
#[allow(clippy::large_enum_variant)]
40+
#[serde(bound(deserialize = "U: Deserialize<'de>, P: serde::de::DeserializeOwned"))]
4041
#[serde(untagged)]
41-
pub enum Jws {
42+
pub enum Jws<U = Unprotected, P = Protected<U>> {
4243
/// General Serialization. This is
43-
General(General),
44+
General(General<U, P>),
4445

4546
/// Flattened Serialization
46-
Flattened(Flattened),
47+
Flattened(Flattened<U, P>),
4748
}
4849

49-
impl From<General> for Jws {
50-
fn from(value: General) -> Self {
50+
impl<U, P> From<General<U, P>> for Jws<U, P> {
51+
fn from(value: General<U, P>) -> Self {
5152
Jws::General(value)
5253
}
5354
}
5455

55-
impl From<Flattened> for Jws {
56-
fn from(value: Flattened) -> Self {
56+
impl<U, P> From<Flattened<U, P>> for Jws<U, P> {
57+
fn from(value: Flattened<U, P>) -> Self {
5758
Jws::Flattened(value)
5859
}
5960
}
@@ -77,16 +78,17 @@ impl From<Flattened> for Jws {
7778
/// }
7879
/// ```
7980
#[derive(Clone, Debug, Serialize, Deserialize)]
80-
pub struct General {
81+
#[serde(bound(deserialize = "U: Deserialize<'de>, P: serde::de::DeserializeOwned"))]
82+
pub struct General<U = Unprotected, P = Protected<U>> {
8183
/// The payload of the signature.
8284
pub payload: Option<Bytes>,
8385

8486
/// The signatures over the payload.
85-
pub signatures: Vec<Signature>,
87+
pub signatures: Vec<Signature<U, P>>,
8688
}
8789

88-
impl From<Flattened> for General {
89-
fn from(value: Flattened) -> Self {
90+
impl<U, P> From<Flattened<U, P>> for General<U, P> {
91+
fn from(value: Flattened<U, P>) -> Self {
9092
Self {
9193
payload: value.payload,
9294
signatures: vec![value.signature],
@@ -108,23 +110,25 @@ impl From<Flattened> for General {
108110
/// }
109111
/// ```
110112
#[derive(Clone, Debug, Serialize, Deserialize)]
111-
pub struct Flattened {
113+
#[serde(bound(deserialize = "U: Deserialize<'de>, P: serde::de::DeserializeOwned"))]
114+
pub struct Flattened<U = Unprotected, P = Protected<U>> {
112115
/// The payload of the signature.
113116
pub payload: Option<Bytes>,
114117

115118
/// The signature over the payload.
116119
#[serde(flatten)]
117-
pub signature: Signature,
120+
pub signature: Signature<U, P>,
118121
}
119122

120123
/// A Signature
121124
#[derive(Clone, Debug, Serialize, Deserialize)]
122-
pub struct Signature {
125+
#[serde(bound(deserialize = "U: Deserialize<'de>, P: serde::de::DeserializeOwned"))]
126+
pub struct Signature<U = Unprotected, P = Protected<U>> {
123127
/// The JWS Unprotected Header
124-
pub header: Option<Unprotected>,
128+
pub header: Option<U>,
125129

126130
/// The JWS Protected Header
127-
pub protected: Option<Json<Protected>>,
131+
pub protected: Option<Json<P>>,
128132

129133
/// The Signature Bytes
130134
pub signature: Bytes,

0 commit comments

Comments
 (0)