identity_jose/jws/
algorithm.rs

1// Copyright 2020-2025 IOTA Stiftung, Fondazione LINKS
2// SPDX-License-Identifier: Apache-2.0
3
4use core::fmt::Display;
5use core::fmt::Formatter;
6use core::fmt::Result;
7use std::str::FromStr;
8
9/// Supported algorithms for the JSON Web Signatures `alg` claim.
10///
11/// [More Info](https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms)
12#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize, serde::Serialize)]
13#[cfg_attr(not(feature = "custom_alg"), derive(Copy))]
14#[allow(non_camel_case_types)]
15pub enum JwsAlgorithm {
16  /// HMAC using SHA-256
17  HS256,
18  /// HMAC using SHA-384
19  HS384,
20  /// HMAC using SHA-512
21  HS512,
22  /// RSASSA-PKCS1-v1_5 using SHA-256
23  RS256,
24  /// RSASSA-PKCS1-v1_5 using SHA-384
25  RS384,
26  /// RSASSA-PKCS1-v1_5 using SHA-512
27  RS512,
28  /// RSASSA-PSS using SHA-256 and MGF1 with SHA-256
29  PS256,
30  /// RSASSA-PSS using SHA-384 and MGF1 with SHA-384
31  PS384,
32  /// RSASSA-PSS using SHA-512 and MGF1 with SHA-512
33  PS512,
34  /// ECDSA using P-256 and SHA-256
35  ES256,
36  /// ECDSA using P-384 and SHA-384
37  ES384,
38  /// ECDSA using P-521 and SHA-512
39  ES512,
40  /// ECDSA using secp256k1 curve and SHA-256
41  ES256K,
42  /// No digital signature or MAC performed
43  #[serde(rename = "none")]
44  NONE,
45  /// EdDSA signature algorithms
46  EdDSA,
47  /// JSON Web Signature Algorithm for ML-DSA-44
48  /// [More Info](https://datatracker.ietf.org/doc/html/draft-ietf-cose-dilithium#name-the-ml-dsa-algorithm-family)
49  #[serde(rename = "ML-DSA-44")]
50  ML_DSA_44,
51  /// JSON Web Signature Algorithm for ML-DSA-44
52  /// [More Info](https://datatracker.ietf.org/doc/html/draft-ietf-cose-dilithium#name-the-ml-dsa-algorithm-family)
53  #[serde(rename = "ML-DSA-65")]
54  ML_DSA_65,
55  /// JSON Web Signature Algorithm for ML-DSA-44
56  /// [More Info](https://datatracker.ietf.org/doc/html/draft-ietf-cose-dilithium#name-the-ml-dsa-algorithm-family)
57  #[serde(rename = "ML-DSA-87")]
58  ML_DSA_87,
59  /// JSON Web Signature Algorithm for SLH-DSA-SHA2-128s
60  /// [More Info](https://datatracker.ietf.org/doc/html/draft-ietf-cose-sphincs-plus#name-the-slh-dsa-algorithm-famil)
61  #[serde(rename = "SLH-DSA-SHA2-128s")]
62  SLH_DSA_SHA2_128s,
63  /// JSON Web Signature Algorithm for SLH-DSA-SHAKE-128s
64  /// [More Info](https://datatracker.ietf.org/doc/html/draft-ietf-cose-sphincs-plus#name-the-slh-dsa-algorithm-famil)
65  #[serde(rename = "SLH-DSA-SHAKE-128s")]
66  SLH_DSA_SHAKE_128s,
67  /// JSON Web Signature Algorithm for SLH-DSA-SHA2-128f
68  /// [More Info](https://datatracker.ietf.org/doc/html/draft-ietf-cose-sphincs-plus#name-the-slh-dsa-algorithm-famil)
69  #[serde(rename = "SLH-DSA-SHA2-128f")]
70  SLH_DSA_SHA2_128f,
71  ///SLH_DSA_SHAKE_128f
72  #[serde(rename = "SLH-DSA-SHAKE-128f")]
73  SLH_DSA_SHAKE_128f,
74  ///SLH_DSA_SHA2_192s
75  #[serde(rename = "SLH-DSA-SHA2-192s")]
76  SLH_DSA_SHA2_192s,
77  ///SLH_DSA_SHAKE_192s
78  #[serde(rename = "SLH-DSA-SHAKE-192s")]
79  SLH_DSA_SHAKE_192s,
80  ///SLH-DSA-SHA2-192f
81  #[serde(rename = "SLH-DSA-SHA2-192f")]
82  SLH_DSA_SHA2_192f,
83  ///SLH-DSA-SHAKE-192f
84  #[serde(rename = "SLH-DSA-SHAKE-192f")]
85  SLH_DSA_SHAKE_192f,
86  ///SLH-DSA-SHA2-256s
87  #[serde(rename = "SLH-DSA-SHA2-256s")]
88  SLH_DSA_SHA2_256s,
89  ///SLH-DSA-SHA2-256s
90  #[serde(rename = "SLH-DSA-SHAKE-256s")]
91  SLH_DSA_SHAKE_256s,
92  ///SLH-DSA-SHA2-256f
93  #[serde(rename = "SLH-DSA-SHA2-256f")]
94  SLH_DSA_SHA2_256f,
95  ///SLH-DSA-SHAKE-256f
96  #[serde(rename = "SLH-DSA-SHAKE-256f")]
97  SLH_DSA_SHAKE_256f,
98  ///FALCON512
99  FALCON512,
100  ///FALCON1024
101  FALCON1024,
102  ///id-MLDSA44-Ed25519
103  #[serde(rename = "id-MLDSA44-Ed25519")]
104  IdMldsa44Ed25519,
105  ///id-MLDSA65-Ed25519
106  #[serde(rename = "id-MLDSA65-Ed25519")]
107  IdMldsa65Ed25519,
108  /// Custom algorithm
109  #[cfg(feature = "custom_alg")]
110  #[serde(untagged)]
111  Custom(String),
112}
113
114impl JwsAlgorithm {
115  /// A slice of all supported [`JwsAlgorithm`]s.
116  ///
117  /// Not available when feature `custom_alg` is enabled
118  /// as it is not possible to enumerate all variants when
119  /// supporting arbitrary `alg` values.
120  #[cfg(not(feature = "custom_alg"))]
121  pub const ALL: &'static [Self] = &[
122    Self::HS256,
123    Self::HS384,
124    Self::HS512,
125    Self::RS256,
126    Self::RS384,
127    Self::RS512,
128    Self::PS256,
129    Self::PS384,
130    Self::PS512,
131    Self::ES256,
132    Self::ES384,
133    Self::ES512,
134    Self::ES256K,
135    Self::NONE,
136    Self::EdDSA,
137    Self::ML_DSA_44,
138    Self::ML_DSA_65,
139    Self::ML_DSA_87,
140    Self::SLH_DSA_SHA2_128s,
141    Self::SLH_DSA_SHAKE_128s,
142    Self::SLH_DSA_SHA2_128f,
143    Self::SLH_DSA_SHAKE_128f,
144    Self::SLH_DSA_SHA2_192s,
145    Self::SLH_DSA_SHAKE_192s,
146    Self::SLH_DSA_SHA2_192f,
147    Self::SLH_DSA_SHAKE_192f,
148    Self::SLH_DSA_SHA2_256s,
149    Self::SLH_DSA_SHAKE_256s,
150    Self::SLH_DSA_SHA2_256f,
151    Self::SLH_DSA_SHAKE_256f,
152    Self::FALCON512,
153    Self::FALCON1024,
154    Self::IdMldsa44Ed25519,
155    Self::IdMldsa65Ed25519,
156  ];
157
158  /// Returns the JWS algorithm as a `str` slice.
159  #[cfg(not(feature = "custom_alg"))]
160  pub const fn name(self) -> &'static str {
161    match self {
162      Self::HS256 => "HS256",
163      Self::HS384 => "HS384",
164      Self::HS512 => "HS512",
165      Self::RS256 => "RS256",
166      Self::RS384 => "RS384",
167      Self::RS512 => "RS512",
168      Self::PS256 => "PS256",
169      Self::PS384 => "PS384",
170      Self::PS512 => "PS512",
171      Self::ES256 => "ES256",
172      Self::ES384 => "ES384",
173      Self::ES512 => "ES512",
174      Self::ES256K => "ES256K",
175      Self::NONE => "none",
176      Self::EdDSA => "EdDSA",
177      Self::ML_DSA_44 => "ML-DSA-44",
178      Self::ML_DSA_65 => "ML-DSA-65",
179      Self::ML_DSA_87 => "ML-DSA-87",
180      Self::SLH_DSA_SHA2_128s => "SLH-DSA-SHA2-128s",
181      Self::SLH_DSA_SHAKE_128s => "SLH-DSA-SHAKE-128s",
182      Self::SLH_DSA_SHA2_128f => "SLH-DSA-SHA2-128f",
183      Self::SLH_DSA_SHAKE_128f => "SLH-DSA-SHAKE-128f",
184      Self::SLH_DSA_SHA2_192s => "SLH-DSA-SHA2-192s",
185      Self::SLH_DSA_SHAKE_192s => "SLH-DSA-SHAKE-192s",
186      Self::SLH_DSA_SHA2_192f => "SLH-DSA-SHA2-192f",
187      Self::SLH_DSA_SHAKE_192f => "SLH-DSA-SHAKE-192f",
188      Self::SLH_DSA_SHA2_256s => "SLH-DSA-SHA2-256s",
189      Self::SLH_DSA_SHAKE_256s => "SLH-DSA-SHAKE-256s",
190      Self::SLH_DSA_SHA2_256f => "SLH-DSA-SHA2-256f",
191      Self::SLH_DSA_SHAKE_256f => "SLH-DSA-SHAKE-256f",
192      Self::FALCON512 => "FALCON512",
193      Self::FALCON1024 => "FALCON1024",
194      Self::IdMldsa44Ed25519 => "id-MLDSA44-Ed25519",
195      Self::IdMldsa65Ed25519 => "id-MLDSA65-Ed25519",
196    }
197  }
198
199  /// Returns the JWS algorithm as a `str` slice.
200  #[cfg(feature = "custom_alg")]
201  pub fn name(&self) -> String {
202    match self {
203      Self::HS256 => "HS256".to_string(),
204      Self::HS384 => "HS384".to_string(),
205      Self::HS512 => "HS512".to_string(),
206      Self::RS256 => "RS256".to_string(),
207      Self::RS384 => "RS384".to_string(),
208      Self::RS512 => "RS512".to_string(),
209      Self::PS256 => "PS256".to_string(),
210      Self::PS384 => "PS384".to_string(),
211      Self::PS512 => "PS512".to_string(),
212      Self::ES256 => "ES256".to_string(),
213      Self::ES384 => "ES384".to_string(),
214      Self::ES512 => "ES512".to_string(),
215      Self::ES256K => "ES256K".to_string(),
216      Self::NONE => "none".to_string(),
217      Self::EdDSA => "EdDSA".to_string(),
218      Self::ML_DSA_44 => "ML-DSA-44".to_string(),
219      Self::ML_DSA_65 => "ML-DSA-65".to_string(),
220      Self::ML_DSA_87 => "ML-DSA-87".to_string(),
221      Self::SLH_DSA_SHA2_128s => "SLH-DSA-SHA2-128s".to_string(),
222      Self::SLH_DSA_SHAKE_128s => "SLH-DSA-SHAKE-128s".to_string(),
223      Self::SLH_DSA_SHA2_128f => "SLH-DSA-SHA2-128f".to_string(),
224      Self::SLH_DSA_SHAKE_128f => "SLH-DSA-SHAKE-128f".to_string(),
225      Self::SLH_DSA_SHA2_192s => "SLH-DSA-SHA2-192s".to_string(),
226      Self::SLH_DSA_SHAKE_192s => "SLH-DSA-SHAKE-192s".to_string(),
227      Self::SLH_DSA_SHA2_192f => "SLH-DSA-SHA2-192f".to_string(),
228      Self::SLH_DSA_SHAKE_192f => "SLH-DSA-SHAKE-192f".to_string(),
229      Self::SLH_DSA_SHA2_256s => "SLH-DSA-SHA2-256s".to_string(),
230      Self::SLH_DSA_SHAKE_256s => "SLH-DSA-SHAKE-256s".to_string(),
231      Self::SLH_DSA_SHA2_256f => "SLH-DSA-SHA2-256f".to_string(),
232      Self::SLH_DSA_SHAKE_256f => "SLH-DSA-SHAKE-256f".to_string(),
233      Self::FALCON512 => "FALCON512".to_string(),
234      Self::FALCON1024 => "FALCON1024".to_string(),
235      Self::IdMldsa44Ed25519 => "id-MLDSA44-Ed25519".to_string(),
236      Self::IdMldsa65Ed25519 => "id-MLDSA65-Ed25519".to_string(),
237      Self::Custom(name) => name.clone(),
238    }
239  }
240}
241
242impl FromStr for JwsAlgorithm {
243  type Err = crate::error::Error;
244
245  fn from_str(string: &str) -> std::result::Result<Self, Self::Err> {
246    match string {
247      "HS256" => Ok(Self::HS256),
248      "HS384" => Ok(Self::HS384),
249      "HS512" => Ok(Self::HS512),
250      "RS256" => Ok(Self::RS256),
251      "RS384" => Ok(Self::RS384),
252      "RS512" => Ok(Self::RS512),
253      "PS256" => Ok(Self::PS256),
254      "PS384" => Ok(Self::PS384),
255      "PS512" => Ok(Self::PS512),
256      "ES256" => Ok(Self::ES256),
257      "ES384" => Ok(Self::ES384),
258      "ES512" => Ok(Self::ES512),
259      "ES256K" => Ok(Self::ES256K),
260      "none" => Ok(Self::NONE),
261      "EdDSA" => Ok(Self::EdDSA),
262      "ML-DSA-44" => Ok(Self::ML_DSA_44),
263      "ML-DSA-65" => Ok(Self::ML_DSA_65),
264      "ML-DSA-87" => Ok(Self::ML_DSA_87),
265      "SLH-DSA-SHA2-128s" => Ok(Self::SLH_DSA_SHA2_128s),
266      "SLH-DSA-SHAKE-128s" => Ok(Self::SLH_DSA_SHAKE_128s),
267      "SLH-DSA-SHA2-128f" => Ok(Self::SLH_DSA_SHA2_128f),
268      "SLH-DSA-SHAKE-128f" => Ok(Self::SLH_DSA_SHAKE_128f),
269      "SLH-DSA-SHA2-192s" => Ok(Self::SLH_DSA_SHA2_192s),
270      "SLH-DSA-SHAKE-192s" => Ok(Self::SLH_DSA_SHAKE_192s),
271      "SLH-DSA-SHA2-192f" => Ok(Self::SLH_DSA_SHA2_192f),
272      "SLH-DSA-SHAKE-192f" => Ok(Self::SLH_DSA_SHAKE_192f),
273      "SLH-DSA-SHA2-256s" => Ok(Self::SLH_DSA_SHA2_256s),
274      "SLH-DSA-SHAKE-256s" => Ok(Self::SLH_DSA_SHAKE_256s),
275      "SLH-DSA-SHA2-256f" => Ok(Self::SLH_DSA_SHA2_256f),
276      "SLH-DSA-SHAKE-256f" => Ok(Self::SLH_DSA_SHAKE_256f),
277      "FALCON512" => Ok(Self::FALCON512),
278      "FALCON1024" => Ok(Self::FALCON1024),
279      "id-MLDSA44-Ed25519" => Ok(Self::IdMldsa44Ed25519),
280      "id-MLDSA65-Ed25519" => Ok(Self::IdMldsa65Ed25519),
281      #[cfg(feature = "custom_alg")]
282      value => Ok(Self::Custom(value.to_string())),
283      #[cfg(not(feature = "custom_alg"))]
284      _ => Err(crate::error::Error::JwsAlgorithmParsingError),
285    }
286  }
287}
288
289#[cfg(not(feature = "custom_alg"))]
290impl Display for JwsAlgorithm {
291  fn fmt(&self, f: &mut Formatter<'_>) -> Result {
292    f.write_str(self.name())
293  }
294}
295
296#[cfg(feature = "custom_alg")]
297impl Display for JwsAlgorithm {
298  fn fmt(&self, f: &mut Formatter<'_>) -> Result {
299    f.write_str(&(*self).name())
300  }
301}