mas_jose/jwk/
public_parameters.rs

1// Copyright 2024 New Vector Ltd.
2// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only
5// Please see LICENSE 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};
12
13use super::ParametersInfo;
14use crate::base64::Base64UrlNoPad;
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
17#[serde(tag = "kty")]
18pub enum JsonWebKeyPublicParameters {
19    #[serde(rename = "RSA")]
20    Rsa(RsaPublicParameters),
21
22    #[serde(rename = "EC")]
23    Ec(EcPublicParameters),
24
25    #[serde(rename = "OKP")]
26    Okp(OkpPublicParameters),
27}
28
29impl JsonWebKeyPublicParameters {
30    #[must_use]
31    pub const fn rsa(&self) -> Option<&RsaPublicParameters> {
32        match self {
33            Self::Rsa(params) => Some(params),
34            _ => None,
35        }
36    }
37
38    #[must_use]
39    pub const fn ec(&self) -> Option<&EcPublicParameters> {
40        match self {
41            Self::Ec(params) => Some(params),
42            _ => None,
43        }
44    }
45
46    #[must_use]
47    pub const fn okp(&self) -> Option<&OkpPublicParameters> {
48        match self {
49            Self::Okp(params) => Some(params),
50            _ => None,
51        }
52    }
53}
54
55impl ParametersInfo for JsonWebKeyPublicParameters {
56    fn kty(&self) -> JsonWebKeyType {
57        match self {
58            Self::Rsa(_) => JsonWebKeyType::Rsa,
59            Self::Ec(_) => JsonWebKeyType::Ec,
60            Self::Okp(_) => JsonWebKeyType::Okp,
61        }
62    }
63
64    fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
65        match self {
66            JsonWebKeyPublicParameters::Rsa(p) => p.possible_algs(),
67            JsonWebKeyPublicParameters::Ec(p) => p.possible_algs(),
68            JsonWebKeyPublicParameters::Okp(p) => p.possible_algs(),
69        }
70    }
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
74pub struct RsaPublicParameters {
75    #[schemars(with = "String")]
76    n: Base64UrlNoPad,
77
78    #[schemars(with = "String")]
79    e: Base64UrlNoPad,
80}
81
82impl ParametersInfo for RsaPublicParameters {
83    fn kty(&self) -> JsonWebKeyType {
84        JsonWebKeyType::Rsa
85    }
86
87    fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
88        &[
89            JsonWebSignatureAlg::Rs256,
90            JsonWebSignatureAlg::Rs384,
91            JsonWebSignatureAlg::Rs512,
92            JsonWebSignatureAlg::Ps256,
93            JsonWebSignatureAlg::Ps384,
94            JsonWebSignatureAlg::Ps512,
95        ]
96    }
97}
98
99impl RsaPublicParameters {
100    pub const fn new(n: Base64UrlNoPad, e: Base64UrlNoPad) -> Self {
101        Self { n, e }
102    }
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
106pub struct EcPublicParameters {
107    pub(crate) crv: JsonWebKeyEcEllipticCurve,
108
109    #[schemars(with = "String")]
110    x: Base64UrlNoPad,
111
112    #[schemars(with = "String")]
113    y: Base64UrlNoPad,
114}
115
116impl EcPublicParameters {
117    pub const fn new(crv: JsonWebKeyEcEllipticCurve, x: Base64UrlNoPad, y: Base64UrlNoPad) -> Self {
118        Self { crv, x, y }
119    }
120}
121
122impl ParametersInfo for EcPublicParameters {
123    fn kty(&self) -> JsonWebKeyType {
124        JsonWebKeyType::Ec
125    }
126
127    fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
128        match &self.crv {
129            JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256],
130            JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
131            JsonWebKeyEcEllipticCurve::P521 => &[JsonWebSignatureAlg::Es512],
132            JsonWebKeyEcEllipticCurve::Secp256K1 => &[JsonWebSignatureAlg::Es256K],
133            _ => &[],
134        }
135    }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
139pub struct OkpPublicParameters {
140    crv: JsonWebKeyOkpEllipticCurve,
141
142    #[schemars(with = "String")]
143    x: Base64UrlNoPad,
144}
145
146impl ParametersInfo for OkpPublicParameters {
147    fn kty(&self) -> JsonWebKeyType {
148        JsonWebKeyType::Okp
149    }
150
151    fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
152        &[JsonWebSignatureAlg::EdDsa]
153    }
154}
155
156impl OkpPublicParameters {
157    pub const fn new(crv: JsonWebKeyOkpEllipticCurve, x: Base64UrlNoPad) -> Self {
158        Self { crv, x }
159    }
160}
161
162mod rsa_impls {
163    use rsa::{BigUint, RsaPublicKey, traits::PublicKeyParts};
164
165    use super::{JsonWebKeyPublicParameters, RsaPublicParameters};
166    use crate::base64::Base64UrlNoPad;
167
168    impl From<RsaPublicKey> for JsonWebKeyPublicParameters {
169        fn from(key: RsaPublicKey) -> Self {
170            Self::from(&key)
171        }
172    }
173
174    impl From<&RsaPublicKey> for JsonWebKeyPublicParameters {
175        fn from(key: &RsaPublicKey) -> Self {
176            Self::Rsa(key.into())
177        }
178    }
179
180    impl From<RsaPublicKey> for RsaPublicParameters {
181        fn from(key: RsaPublicKey) -> Self {
182            Self::from(&key)
183        }
184    }
185
186    impl From<&RsaPublicKey> for RsaPublicParameters {
187        fn from(key: &RsaPublicKey) -> Self {
188            Self {
189                n: Base64UrlNoPad::new(key.n().to_bytes_be()),
190                e: Base64UrlNoPad::new(key.e().to_bytes_be()),
191            }
192        }
193    }
194
195    impl TryFrom<RsaPublicParameters> for RsaPublicKey {
196        type Error = rsa::errors::Error;
197        fn try_from(value: RsaPublicParameters) -> Result<Self, Self::Error> {
198            (&value).try_into()
199        }
200    }
201
202    impl TryFrom<&RsaPublicParameters> for RsaPublicKey {
203        type Error = rsa::errors::Error;
204        fn try_from(value: &RsaPublicParameters) -> Result<Self, Self::Error> {
205            let n = BigUint::from_bytes_be(value.n.as_bytes());
206            let e = BigUint::from_bytes_be(value.e.as_bytes());
207            let key = RsaPublicKey::new(n, e)?;
208            Ok(key)
209        }
210    }
211}
212
213mod ec_impls {
214    use digest::typenum::Unsigned;
215    use ecdsa::EncodedPoint;
216    use elliptic_curve::{
217        AffinePoint, FieldBytes, PublicKey,
218        sec1::{Coordinates, FromEncodedPoint, ModulusSize, ToEncodedPoint},
219    };
220
221    use super::{super::JwkEcCurve, EcPublicParameters, JsonWebKeyPublicParameters};
222    use crate::base64::Base64UrlNoPad;
223
224    impl<C> TryFrom<&EcPublicParameters> for PublicKey<C>
225    where
226        C: elliptic_curve::CurveArithmetic,
227        AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
228        C::FieldBytesSize: ModulusSize + Unsigned,
229    {
230        type Error = elliptic_curve::Error;
231        fn try_from(value: &EcPublicParameters) -> Result<Self, Self::Error> {
232            let x = value
233                .x
234                .as_bytes()
235                .get(..C::FieldBytesSize::USIZE)
236                .ok_or(elliptic_curve::Error)?;
237            let y = value
238                .y
239                .as_bytes()
240                .get(..C::FieldBytesSize::USIZE)
241                .ok_or(elliptic_curve::Error)?;
242
243            let x = FieldBytes::<C>::from_slice(x);
244            let y = FieldBytes::<C>::from_slice(y);
245            let pubkey = EncodedPoint::<C>::from_affine_coordinates(x, y, false);
246            let pubkey: Option<_> = PublicKey::from_encoded_point(&pubkey).into();
247            pubkey.ok_or(elliptic_curve::Error)
248        }
249    }
250
251    impl<C> From<PublicKey<C>> for JsonWebKeyPublicParameters
252    where
253        C: elliptic_curve::CurveArithmetic + JwkEcCurve,
254        AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
255        C::FieldBytesSize: ModulusSize,
256    {
257        fn from(key: PublicKey<C>) -> Self {
258            (&key).into()
259        }
260    }
261
262    impl<C> From<&PublicKey<C>> for JsonWebKeyPublicParameters
263    where
264        C: elliptic_curve::CurveArithmetic + JwkEcCurve,
265        AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
266        C::FieldBytesSize: ModulusSize,
267    {
268        fn from(key: &PublicKey<C>) -> Self {
269            Self::Ec(key.into())
270        }
271    }
272
273    impl<C> From<PublicKey<C>> for EcPublicParameters
274    where
275        C: elliptic_curve::CurveArithmetic + JwkEcCurve,
276        AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
277        C::FieldBytesSize: ModulusSize,
278    {
279        fn from(key: PublicKey<C>) -> Self {
280            (&key).into()
281        }
282    }
283
284    impl<C> From<&PublicKey<C>> for EcPublicParameters
285    where
286        C: elliptic_curve::CurveArithmetic + JwkEcCurve,
287        AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
288        C::FieldBytesSize: ModulusSize,
289    {
290        fn from(key: &PublicKey<C>) -> Self {
291            let point = key.to_encoded_point(false);
292            let Coordinates::Uncompressed { x, y } = point.coordinates() else {
293                unreachable!()
294            };
295            EcPublicParameters {
296                crv: C::CRV,
297                x: Base64UrlNoPad::new(x.to_vec()),
298                y: Base64UrlNoPad::new(y.to_vec()),
299            }
300        }
301    }
302}