1use std::ops::Deref;
5use std::str::FromStr;
6
7use identity_core::common::Url;
8
9use crate::error::Error;
10use crate::error::Result;
11use crate::jwk::Jwk;
12use crate::jwk::JwkOperation;
13use crate::jwk::JwkParams;
14use crate::jwk::JwkParamsAkp;
15use crate::jwk::JwkParamsEc;
16use crate::jwk::JwkParamsOct;
17use crate::jwk::JwkParamsOkp;
18use crate::jwk::JwkParamsRsa;
19use crate::jwk::JwkType;
20use crate::jwk::JwkUse;
21use crate::jws::JwsAlgorithm;
22
23#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
25#[serde(transparent)]
26pub struct PostQuantumJwk(Jwk);
27
28impl PostQuantumJwk {
29 pub fn new(paramsakp: JwkParamsAkp) -> Self {
31 Self(Jwk {
32 kty: JwkType::Akp,
33 use_: None,
34 key_ops: None,
35 alg: None,
36 kid: None,
37 x5u: None,
38 x5c: None,
39 x5t: None,
40 x5t_s256: None,
41 params: JwkParams::Akp(paramsakp),
42 })
43 }
44
45 pub fn from_kty(kty: impl Into<JwkType>) -> Result<Self> {
47 let kty: JwkType = kty.into();
48 if kty != JwkType::Akp {
49 return Err(Error::KeyError("PostQuantumJwk can only be created with JwkType::Akp"));
50 }
51
52 Ok(Self(Jwk {
53 kty,
54 use_: None,
55 key_ops: None,
56 alg: None,
57 kid: None,
58 x5u: None,
59 x5c: None,
60 x5t: None,
61 x5t_s256: None,
62 params: JwkParams::new(kty),
63 }))
64 }
65
66 pub fn from_params(params: impl Into<JwkParams>) -> Result<Self> {
68 let params: JwkParams = params.into();
69
70 if params.kty() != JwkType::Akp {
71 return Err(Error::KeyError(
72 "PostQuantumJwk can only be created from a JwkParamsAkp",
73 ));
74 }
75
76 Ok(Self(Jwk {
77 kty: params.kty(),
78 use_: None,
79 key_ops: None,
80 alg: None,
81 kid: None,
82 x5u: None,
83 x5c: None,
84 x5t: None,
85 x5t_s256: None,
86 params,
87 }))
88 }
89
90 pub fn set_use(&mut self, value: impl Into<JwkUse>) {
92 self.0.set_use(value)
93 }
94
95 pub fn set_key_ops(&mut self, value: impl IntoIterator<Item = impl Into<JwkOperation>>) {
97 self.0.set_key_ops(value);
98 }
99
100 pub fn set_alg(&mut self, value: impl Into<String>) -> Result<()> {
102 let alg = JwsAlgorithm::from_str(&value.into()).map_err(|_| Error::InvalidParam("Invalid JWS algorithm"))?;
103 if !is_post_quantum(&alg) {
104 return Err(Error::InvalidParam(
105 "PostQuantumJwk can only be created with a post-quantum JWS algorithm",
106 ));
107 }
108 self.0.set_alg(alg.to_string());
109 Ok(())
110 }
111
112 pub fn set_kid(&mut self, value: impl Into<String>) {
114 self.0.set_kid(value);
115 }
116
117 pub fn set_x5u(&mut self, value: impl Into<Url>) {
119 self.0.set_x5u(value);
120 }
121
122 pub fn set_x5c(&mut self, value: impl IntoIterator<Item = impl Into<String>>) {
124 self.0.set_x5c(value);
125 }
126
127 pub fn set_x5t(&mut self, value: impl Into<String>) {
129 self.0.set_x5t(value);
130 }
131
132 pub fn set_x5t_s256(&mut self, value: impl Into<String>) {
135 self.0.set_x5t_s256(value);
136 }
137
138 pub fn set_params(&mut self, params: impl Into<JwkParams>) -> Result<()> {
140 let params: JwkParams = params.into();
141 if params.kty() != JwkType::Akp {
142 return Err(Error::InvalidParam("`params` type does not match `Akp`"));
143 }
144 self.0.set_params_unchecked(params);
145 Ok(())
146 }
147
148 pub fn akp_params(&self) -> &JwkParamsAkp {
150 self
151 .0
152 .try_akp_params()
153 .expect("PostQuantumJwk must have JwkParamsAkp as params")
154 }
155
156 pub fn akp_params_mut(&mut self) -> &mut JwkParamsAkp {
158 self
159 .0
160 .try_akp_params_mut()
161 .expect("PostQuantumJwk must have JwkParamsAkp as params")
162 }
163
164 #[inline(always)]
166 pub fn strip_private(&mut self) {
167 self.0.params_mut().strip_private();
168 }
169
170 pub fn into_public(mut self) -> Option<Self> {
172 self.0.params.strip_private();
173 Some(self)
174 }
175}
176
177impl Deref for PostQuantumJwk {
178 type Target = Jwk;
179
180 fn deref(&self) -> &Self::Target {
181 &self.0
182 }
183}
184
185impl TryFrom<Jwk> for PostQuantumJwk {
186 type Error = Error;
187
188 fn try_from(value: Jwk) -> Result<Self> {
189 let alg = JwsAlgorithm::from_str(value.alg().ok_or(Error::KeyError("Missing JWK algorithm"))?)?;
190 if value.kty != JwkType::Akp && !is_post_quantum(&alg) {
191 return Err(Error::KeyError(
192 "PostQuantumJwk can only be created from a post quantum Jwk",
193 ));
194 }
195
196 Ok(Self(value))
197 }
198}
199
200impl AsRef<Jwk> for PostQuantumJwk {
201 fn as_ref(&self) -> &Jwk {
202 &self.0
203 }
204}
205
206impl From<PostQuantumJwk> for Jwk {
207 fn from(value: PostQuantumJwk) -> Self {
208 value.0
209 }
210}
211
212#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
215#[serde(transparent)]
216pub struct TraditionalJwk(Jwk);
217
218impl TraditionalJwk {
219 pub fn new(kty: JwkParamsOkp) -> Self {
221 Self(Jwk {
222 kty: JwkType::Okp,
223 use_: None,
224 key_ops: None,
225 alg: None,
226 kid: None,
227 x5u: None,
228 x5c: None,
229 x5t: None,
230 x5t_s256: None,
231 params: JwkParams::Okp(kty),
232 })
233 }
234
235 pub fn from_kty(kty: JwkType) -> Result<Self> {
237 if kty == JwkType::Akp {
238 return Err(Error::KeyError(
239 "TraditionalJwk can only be created with different from JwkType::Akp",
240 ));
241 }
242
243 Ok(Self(Jwk {
244 kty,
245 use_: None,
246 key_ops: None,
247 alg: None,
248 kid: None,
249 x5u: None,
250 x5c: None,
251 x5t: None,
252 x5t_s256: None,
253 params: JwkParams::new(kty),
254 }))
255 }
256
257 pub fn from_params(params: impl Into<JwkParams>) -> Result<Self> {
259 let params: JwkParams = params.into();
260
261 if params.kty() == JwkType::Akp {
262 return Err(Error::KeyError(
263 "TraditionalJwk can only be created with different from JwkType::Akp",
264 ));
265 }
266
267 Ok(Self(Jwk {
268 kty: params.kty(),
269 use_: None,
270 key_ops: None,
271 alg: None,
272 kid: None,
273 x5u: None,
274 x5c: None,
275 x5t: None,
276 x5t_s256: None,
277 params,
278 }))
279 }
280
281 pub fn set_use(&mut self, value: impl Into<JwkUse>) {
283 self.0.set_use(value)
284 }
285
286 pub fn set_key_ops(&mut self, value: impl IntoIterator<Item = impl Into<JwkOperation>>) {
288 self.0.set_key_ops(value);
289 }
290
291 pub fn set_alg(&mut self, value: impl Into<String>) -> Result<()> {
293 let alg = JwsAlgorithm::from_str(&value.into()).map_err(|_| Error::InvalidParam("Invalid JWS algorithm"))?;
294 if is_post_quantum(&alg) {
295 return Err(Error::InvalidParam(
296 "TraditionalJwk can only be created with a traditional JWS algorithm",
297 ));
298 }
299 self.0.set_alg(alg.to_string());
300 Ok(())
301 }
302
303 pub fn set_kid(&mut self, value: impl Into<String>) {
305 self.0.set_kid(value);
306 }
307
308 pub fn set_x5u(&mut self, value: impl Into<Url>) {
310 self.0.set_x5u(value);
311 }
312
313 pub fn set_x5c(&mut self, value: impl IntoIterator<Item = impl Into<String>>) {
315 self.0.set_x5c(value);
316 }
317
318 pub fn set_x5t(&mut self, value: impl Into<String>) {
320 self.0.set_x5t(value);
321 }
322
323 pub fn set_x5t_s256(&mut self, value: impl Into<String>) {
326 self.0.set_x5t_s256(value);
327 }
328
329 pub fn set_params(&mut self, params: impl Into<JwkParams>) -> Result<()> {
335 self.0.set_params(params)
336 }
337
338 pub fn set_params_unchecked(&mut self, value: impl Into<JwkParams>) {
342 self.0.set_params_unchecked(value)
343 }
344
345 pub fn try_ec_params_mut(&mut self) -> Result<&mut JwkParamsEc> {
347 self.0.try_ec_params_mut()
348 }
349
350 pub fn try_rsa_params_mut(&mut self) -> Result<&mut JwkParamsRsa> {
352 self.0.try_rsa_params_mut()
353 }
354
355 pub fn try_oct_params_mut(&mut self) -> Result<&mut JwkParamsOct> {
357 self.0.try_oct_params_mut()
358 }
359
360 pub fn try_okp_params_mut(&mut self) -> Result<&mut JwkParamsOkp> {
362 self.0.try_okp_params_mut()
363 }
364
365 #[inline(always)]
368 pub fn strip_private(&mut self) {
369 self.0.params_mut().strip_private();
370 }
371
372 pub fn into_public(mut self) -> Option<Self> {
375 if matches!(&self.params, JwkParams::Oct(_)) {
376 None
377 } else {
378 self.0.params.strip_private();
379 Some(self)
380 }
381 }
382}
383
384impl Deref for TraditionalJwk {
385 type Target = Jwk;
386
387 fn deref(&self) -> &Self::Target {
388 &self.0
389 }
390}
391
392impl TryFrom<Jwk> for TraditionalJwk {
393 type Error = Error;
394
395 fn try_from(value: Jwk) -> Result<Self> {
396 let alg = JwsAlgorithm::from_str(value.alg().ok_or(Error::KeyError("Missing JWK algorithm"))?)?;
397 if value.kty == JwkType::Akp && is_post_quantum(&alg) {
398 return Err(Error::KeyError(
399 "TraditionalJwk can only be created from a traditional Jwk",
400 ));
401 }
402 Ok(Self(value))
403 }
404}
405
406impl AsRef<Jwk> for TraditionalJwk {
407 fn as_ref(&self) -> &Jwk {
408 &self.0
409 }
410}
411
412impl From<TraditionalJwk> for Jwk {
413 fn from(value: TraditionalJwk) -> Self {
414 value.0
415 }
416}
417
418fn is_post_quantum(alg: &JwsAlgorithm) -> bool {
419 matches!(
420 alg,
421 JwsAlgorithm::FALCON1024
422 | JwsAlgorithm::FALCON512
423 | JwsAlgorithm::ML_DSA_44
424 | JwsAlgorithm::ML_DSA_65
425 | JwsAlgorithm::ML_DSA_87
426 | JwsAlgorithm::SLH_DSA_SHA2_128s
427 | JwsAlgorithm::SLH_DSA_SHAKE_128s
428 | JwsAlgorithm::SLH_DSA_SHA2_128f
429 | JwsAlgorithm::SLH_DSA_SHAKE_128f
430 | JwsAlgorithm::SLH_DSA_SHA2_192s
431 | JwsAlgorithm::SLH_DSA_SHAKE_192s
432 | JwsAlgorithm::SLH_DSA_SHA2_192f
433 | JwsAlgorithm::SLH_DSA_SHAKE_192f
434 | JwsAlgorithm::SLH_DSA_SHA2_256s
435 | JwsAlgorithm::SLH_DSA_SHAKE_256s
436 | JwsAlgorithm::SLH_DSA_SHA2_256f
437 | JwsAlgorithm::SLH_DSA_SHAKE_256f
438 )
439}