Skip to main content

mas_jose/jwk/
private_parameters.rs

1// Copyright 2025, 2026 Element Creations Ltd.
2// Copyright 2024, 2025 New Vector Ltd.
3// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
4//
5// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
6// Please see LICENSE files in the repository root for full details.
7
8use mas_iana::jose::{
9    JsonWebKeyEcEllipticCurve, JsonWebKeyOkpEllipticCurve, JsonWebKeyType, JsonWebSignatureAlg,
10};
11use schemars::JsonSchema;
12use serde::{Deserialize, Serialize};
13use thiserror::Error;
14
15use super::{ParametersInfo, public_parameters::JsonWebKeyPublicParameters};
16use crate::base64::Base64UrlNoPad;
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
19#[serde(tag = "kty")]
20pub enum JsonWebKeyPrivateParameters {
21    #[serde(rename = "oct")]
22    Oct(OctPrivateParameters),
23
24    #[serde(rename = "RSA")]
25    Rsa(RsaPrivateParameters),
26
27    #[serde(rename = "EC")]
28    Ec(EcPrivateParameters),
29
30    #[serde(rename = "OKP")]
31    Okp(OkpPrivateParameters),
32}
33
34impl JsonWebKeyPrivateParameters {
35    #[must_use]
36    pub const fn oct(&self) -> Option<&OctPrivateParameters> {
37        match self {
38            Self::Oct(params) => Some(params),
39            _ => None,
40        }
41    }
42
43    #[must_use]
44    pub const fn rsa(&self) -> Option<&RsaPrivateParameters> {
45        match self {
46            Self::Rsa(params) => Some(params),
47            _ => None,
48        }
49    }
50
51    #[must_use]
52    pub const fn ec(&self) -> Option<&EcPrivateParameters> {
53        match self {
54            Self::Ec(params) => Some(params),
55            _ => None,
56        }
57    }
58
59    #[must_use]
60    pub const fn okp(&self) -> Option<&OkpPrivateParameters> {
61        match self {
62            Self::Okp(params) => Some(params),
63            _ => None,
64        }
65    }
66}
67
68impl ParametersInfo for JsonWebKeyPrivateParameters {
69    fn kty(&self) -> JsonWebKeyType {
70        match self {
71            Self::Oct(_) => JsonWebKeyType::Oct,
72            Self::Rsa(_) => JsonWebKeyType::Rsa,
73            Self::Ec(_) => JsonWebKeyType::Ec,
74            Self::Okp(_) => JsonWebKeyType::Okp,
75        }
76    }
77
78    fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
79        match self {
80            JsonWebKeyPrivateParameters::Oct(p) => p.possible_algs(),
81            JsonWebKeyPrivateParameters::Rsa(p) => p.possible_algs(),
82            JsonWebKeyPrivateParameters::Ec(p) => p.possible_algs(),
83            JsonWebKeyPrivateParameters::Okp(p) => p.possible_algs(),
84        }
85    }
86}
87
88#[derive(Debug, Error)]
89#[error("can't extract a public key out of a symetric key")]
90pub struct SymetricKeyError;
91
92impl TryFrom<JsonWebKeyPrivateParameters> for JsonWebKeyPublicParameters {
93    type Error = SymetricKeyError;
94
95    fn try_from(value: JsonWebKeyPrivateParameters) -> Result<Self, Self::Error> {
96        match value {
97            JsonWebKeyPrivateParameters::Oct(_) => Err(SymetricKeyError),
98            JsonWebKeyPrivateParameters::Rsa(p) => Ok(JsonWebKeyPublicParameters::Rsa(p.into())),
99            JsonWebKeyPrivateParameters::Ec(p) => Ok(JsonWebKeyPublicParameters::Ec(p.into())),
100            JsonWebKeyPrivateParameters::Okp(p) => Ok(JsonWebKeyPublicParameters::Okp(p.into())),
101        }
102    }
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
106pub struct OctPrivateParameters {
107    /// Key Value
108    #[schemars(with = "String")]
109    k: Base64UrlNoPad,
110}
111
112impl ParametersInfo for OctPrivateParameters {
113    fn kty(&self) -> JsonWebKeyType {
114        JsonWebKeyType::Oct
115    }
116
117    fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
118        &[
119            JsonWebSignatureAlg::Hs256,
120            JsonWebSignatureAlg::Hs384,
121            JsonWebSignatureAlg::Hs512,
122        ]
123    }
124}
125
126#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
127pub struct RsaPrivateParameters {
128    /// Modulus
129    #[schemars(with = "String")]
130    n: Base64UrlNoPad,
131
132    /// Exponent
133    #[schemars(with = "String")]
134    e: Base64UrlNoPad,
135
136    /// Private Exponent
137    #[schemars(with = "String")]
138    d: Base64UrlNoPad,
139
140    /// First Prime Factor
141    #[schemars(with = "String")]
142    p: Base64UrlNoPad,
143
144    /// Second Prime Factor
145    #[schemars(with = "String")]
146    q: Base64UrlNoPad,
147
148    /// First Factor CRT Exponent
149    #[schemars(with = "String")]
150    dp: Base64UrlNoPad,
151
152    /// Second Factor CRT Exponent
153    #[schemars(with = "String")]
154    dq: Base64UrlNoPad,
155
156    /// First CRT Coefficient
157    #[schemars(with = "String")]
158    qi: Base64UrlNoPad,
159
160    /// Other Primes Info
161    #[serde(skip_serializing_if = "Option::is_none")]
162    oth: Option<Vec<RsaOtherPrimeInfo>>,
163}
164
165impl ParametersInfo for RsaPrivateParameters {
166    fn kty(&self) -> JsonWebKeyType {
167        JsonWebKeyType::Rsa
168    }
169
170    fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
171        &[
172            JsonWebSignatureAlg::Rs256,
173            JsonWebSignatureAlg::Rs384,
174            JsonWebSignatureAlg::Rs512,
175            JsonWebSignatureAlg::Ps256,
176            JsonWebSignatureAlg::Ps384,
177            JsonWebSignatureAlg::Ps512,
178        ]
179    }
180}
181
182impl From<RsaPrivateParameters> for super::public_parameters::RsaPublicParameters {
183    fn from(params: RsaPrivateParameters) -> Self {
184        Self::new(params.n, params.e)
185    }
186}
187
188#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
189struct RsaOtherPrimeInfo {
190    /// Prime Factor
191    #[schemars(with = "String")]
192    r: Base64UrlNoPad,
193
194    /// Factor CRT Exponent
195    #[schemars(with = "String")]
196    d: Base64UrlNoPad,
197
198    /// Factor CRT Coefficient
199    #[schemars(with = "String")]
200    t: Base64UrlNoPad,
201}
202
203mod rsa_impls {
204    use rsa::{BoxedUint, RsaPrivateKey};
205
206    use super::RsaPrivateParameters;
207
208    impl TryFrom<RsaPrivateParameters> for RsaPrivateKey {
209        type Error = rsa::errors::Error;
210        fn try_from(value: RsaPrivateParameters) -> Result<Self, Self::Error> {
211            Self::try_from(&value)
212        }
213    }
214
215    impl TryFrom<&RsaPrivateParameters> for RsaPrivateKey {
216        type Error = rsa::errors::Error;
217
218        fn try_from(value: &RsaPrivateParameters) -> Result<Self, Self::Error> {
219            let n = BoxedUint::from_be_slice_vartime(value.n.as_bytes());
220            let e = BoxedUint::from_be_slice_vartime(value.e.as_bytes());
221            let d = BoxedUint::from_be_slice_vartime(value.d.as_bytes());
222
223            let primes = [&value.p, &value.q]
224                .into_iter()
225                .chain(value.oth.iter().flatten().map(|o| &o.r))
226                .map(|i| BoxedUint::from_be_slice_vartime(i.as_bytes()))
227                .collect();
228
229            let key = RsaPrivateKey::from_components(n, e, d, primes)?;
230
231            key.validate()?;
232
233            Ok(key)
234        }
235    }
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
239pub struct EcPrivateParameters {
240    pub(crate) crv: JsonWebKeyEcEllipticCurve,
241
242    #[schemars(with = "String")]
243    x: Base64UrlNoPad,
244
245    #[schemars(with = "String")]
246    y: Base64UrlNoPad,
247
248    #[schemars(with = "String")]
249    d: Base64UrlNoPad,
250}
251
252impl ParametersInfo for EcPrivateParameters {
253    fn kty(&self) -> JsonWebKeyType {
254        JsonWebKeyType::Ec
255    }
256
257    fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
258        match self.crv {
259            JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256],
260            JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
261            JsonWebKeyEcEllipticCurve::P521 => &[JsonWebSignatureAlg::Es512],
262            JsonWebKeyEcEllipticCurve::Secp256K1 => &[JsonWebSignatureAlg::Es256K],
263            _ => &[],
264        }
265    }
266}
267
268impl From<EcPrivateParameters> for super::public_parameters::EcPublicParameters {
269    fn from(params: EcPrivateParameters) -> Self {
270        Self::new(params.crv, params.x, params.y)
271    }
272}
273
274mod ec_impls {
275    use elliptic_curve::{
276        AffinePoint, Curve, SecretKey,
277        sec1::{Coordinates, FromSec1Point, ModulusSize, ToSec1Point},
278    };
279
280    use super::{super::JwkEcCurve, EcPrivateParameters};
281    use crate::base64::Base64UrlNoPad;
282
283    impl<C> TryFrom<EcPrivateParameters> for SecretKey<C>
284    where
285        C: Curve,
286    {
287        type Error = elliptic_curve::Error;
288        fn try_from(value: EcPrivateParameters) -> Result<Self, Self::Error> {
289            Self::try_from(&value)
290        }
291    }
292
293    impl<C> TryFrom<&EcPrivateParameters> for SecretKey<C>
294    where
295        C: Curve,
296    {
297        type Error = elliptic_curve::Error;
298
299        fn try_from(value: &EcPrivateParameters) -> Result<Self, Self::Error> {
300            SecretKey::from_slice(value.d.as_bytes())
301        }
302    }
303
304    impl<C> From<SecretKey<C>> for EcPrivateParameters
305    where
306        C: elliptic_curve::CurveArithmetic + JwkEcCurve,
307        AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
308        C::FieldBytesSize: ModulusSize,
309    {
310        fn from(key: SecretKey<C>) -> Self {
311            (&key).into()
312        }
313    }
314
315    impl<C> From<&SecretKey<C>> for EcPrivateParameters
316    where
317        C: elliptic_curve::CurveArithmetic + JwkEcCurve,
318        AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
319        C::FieldBytesSize: ModulusSize,
320    {
321        fn from(key: &SecretKey<C>) -> Self {
322            let point = key.public_key().to_sec1_point(false);
323            let Coordinates::Uncompressed { x, y } = point.coordinates() else {
324                unreachable!()
325            };
326            let d = key.to_bytes();
327            EcPrivateParameters {
328                crv: C::CRV,
329                x: Base64UrlNoPad::new(x.to_vec()),
330                y: Base64UrlNoPad::new(y.to_vec()),
331                d: Base64UrlNoPad::new(d.to_vec()),
332            }
333        }
334    }
335}
336
337#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
338pub struct OkpPrivateParameters {
339    crv: JsonWebKeyOkpEllipticCurve,
340
341    #[schemars(with = "String")]
342    x: Base64UrlNoPad,
343}
344
345impl ParametersInfo for OkpPrivateParameters {
346    fn kty(&self) -> JsonWebKeyType {
347        JsonWebKeyType::Okp
348    }
349
350    fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
351        &[JsonWebSignatureAlg::EdDsa]
352    }
353}
354
355impl From<OkpPrivateParameters> for super::public_parameters::OkpPublicParameters {
356    fn from(params: OkpPrivateParameters) -> Self {
357        Self::new(params.crv, params.x)
358    }
359}