1use std::collections::HashSet;
17
18use crate::check_256bit_len;
19use crate::openssl_ec_priv_key_to_jwk;
20use crate::public_key_from_jwk_es256;
21use crate::CryptoError;
22use crate::EcPrivate;
23use crate::FormatError;
24use base64::engine::general_purpose::URL_SAFE_NO_PAD;
25use base64::Engine;
26use bherror::traits::ForeignError;
27use openssl::bn::BigNum;
28use openssl::ec::EcKey;
29use openssl::pkey::Private;
30use secrecy::ExposeSecret;
31use secrecy::SecretString;
32use serde::Deserializer;
33use serde::Serializer;
34use serde::{Deserialize, Serialize};
35use serde_json::{Map, Value};
36
37pub type JwkPublic = Map<String, Value>;
43
44#[derive(Serialize, Deserialize)]
50pub struct EcJwkPrivate {
51 #[serde(flatten)]
55 pub jwk_public: JwkPublic,
56 #[serde(
61 rename = "d",
62 serialize_with = "serialize_secret_string",
63 deserialize_with = "deserialize_secret_string"
64 )]
65 pub private_key_part: SecretString,
66}
67
68fn serialize_secret_string<S>(secret: &SecretString, serializer: S) -> Result<S::Ok, S::Error>
69where
70 S: Serializer,
71{
72 serializer.serialize_str(secret.expose_secret())
73}
74
75fn deserialize_secret_string<'de, D>(deserializer: D) -> Result<SecretString, D::Error>
76where
77 D: Deserializer<'de>,
78{
79 let s = String::deserialize(deserializer)?;
80 Ok(SecretString::from(s))
81}
82
83impl EcJwkPrivate {
84 pub fn from_openssl(private_key: &EcPrivate) -> bherror::Result<Self, CryptoError> {
87 openssl_ec_priv_key_to_jwk(private_key, None)
88 }
89
90 pub fn to_openssl(&self) -> bherror::Result<EcKey<Private>, FormatError> {
92 let d = URL_SAFE_NO_PAD
93 .decode(self.private_key_part.expose_secret())
94 .foreign_err(|| {
95 FormatError::JwkParsingFailed("decoding private key part failed".to_string())
96 })?;
97 let d = BigNum::from_slice(check_256bit_len(&d)?).foreign_err(|| {
98 FormatError::JwkParsingFailed("Failed to construct BigNum".to_string())
99 })?;
100
101 let public_key = public_key_from_jwk_es256(&self.jwk_public)?;
102
103 EcPrivate::from_private_components(public_key.group(), d.as_ref(), public_key.public_key())
104 .foreign_err(|| {
105 FormatError::JwkParsingFailed("private key construction failed".to_string())
106 })
107 }
108}
109
110#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
128#[serde(try_from = "JwkSetUnverified")]
129pub struct JwkSet {
130 pub keys: Vec<JwkPublic>,
134}
135
136impl JwkSet {
137 pub fn empty() -> Self {
139 JwkSet { keys: vec![] }
140 }
141}
142
143#[derive(Deserialize, Debug)]
150struct JwkSetUnverified {
151 keys: Vec<JwkPublic>,
153}
154
155impl TryFrom<JwkSetUnverified> for JwkSet {
156 type Error = &'static str;
157
158 fn try_from(value: JwkSetUnverified) -> std::result::Result<Self, Self::Error> {
159 let keys = value.keys;
160 let jwk_with_kid_cnt = keys.iter().filter(|jwk| jwk.contains_key("kid")).count();
161
162 if jwk_with_kid_cnt == 0 {
163 return Ok(JwkSet { keys });
164 }
165 if jwk_with_kid_cnt != keys.len() {
166 return Err("Some of the provided JWKs contain kid parameter values and some don't");
167 }
168
169 let mut uniq = HashSet::new();
170 for key in keys.iter() {
171 if !uniq.insert(
172 key.get("kid")
173 .unwrap() .as_str()
175 .ok_or("JWK contains a `kid` parameter that is not a string")?,
176 ) {
177 return Err("Provided JWKs contain duplicate kid parameter values");
178 }
179 }
180
181 Ok(JwkSet { keys })
182 }
183}
184
185#[cfg(test)]
186pub(crate) mod tests {
187 use serde_json::json;
188
189 use crate::JwkSet;
190
191 #[test]
193 fn jwk_set_example_serialization() {
194 let jwk_set = json!({"keys":
195 [
196 {"kty":"EC",
197 "crv":"P-256",
198 "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
199 "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
200 "use":"enc",
201 "kid":"1"},
202
203 {"kty":"RSA",
204 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx
205 4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs
206 tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2
207 QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI
208 SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb
209 w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
210 "e":"AQAB",
211 "alg":"RS256",
212 "kid":"2011-04-29"}
213 ]
214 });
215
216 let deserialized = serde_json::from_str::<JwkSet>(jwk_set.to_string().as_str()).unwrap();
217 let serialized = serde_json::to_string(&deserialized).unwrap();
218
219 let keys = deserialized.keys;
220 assert_eq!(
221 keys.first().unwrap().get("kid").unwrap().as_str().unwrap(),
222 "1"
223 );
224 assert_eq!(
225 keys.get(1).unwrap().get("kid").unwrap().as_str().unwrap(),
226 "2011-04-29"
227 );
228 assert_eq!(serialized, jwk_set.to_string().as_str());
229 }
230
231 #[test]
232 fn invalid_jwk_set_duplicate_kid() {
233 let jwk_set = json!({"keys":
234 [
235 { "kid": "1" },
236 { "kid": "1" }
237 ]
238 });
239
240 let error = serde_json::from_str::<JwkSet>(jwk_set.to_string().as_str());
241
242 assert_eq!(
243 error.unwrap_err().to_string(),
244 "Provided JWKs contain duplicate kid parameter values"
245 );
246 }
247
248 #[test]
249 fn jwk_without_kid() {
250 let jwk_set = json!({"keys":
251 [
252 { "key": "1" },
253 { "key": "1" }
254 ]
255 });
256
257 let keys = serde_json::from_str::<JwkSet>(jwk_set.to_string().as_str())
258 .unwrap()
259 .keys;
260
261 assert_eq!(
262 keys.first().unwrap().get("key").unwrap().as_str().unwrap(),
263 "1"
264 );
265 assert_eq!(
266 keys.get(1).unwrap().get("key").unwrap().as_str().unwrap(),
267 "1"
268 );
269 }
270
271 #[test]
272 fn invalid_jwk_set_some_jwks_without_kid() {
273 let jwk_set = json!({"keys":
274 [
275 { "kid": "1" },
276 { "key": "1" }
277 ]
278 });
279
280 let error = serde_json::from_str::<JwkSet>(jwk_set.to_string().as_str());
281
282 assert_eq!(
283 error.unwrap_err().to_string(),
284 "Some of the provided JWKs contain kid parameter values and some don't"
285 );
286 }
287}