Skip to main content

mas_jose/jwk/
private_parameters.rs

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