You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Prepare the private JWK
This commit is contained in:
@ -14,13 +14,10 @@
|
||||
|
||||
//! Ref: <https://www.rfc-editor.org/rfc/rfc7517.html>
|
||||
|
||||
use anyhow::bail;
|
||||
use mas_iana::jose::{
|
||||
JsonWebKeyEcEllipticCurve, JsonWebKeyOkpEllipticCurve, JsonWebKeyOperation, JsonWebKeyType,
|
||||
JsonWebKeyUse, JsonWebSignatureAlg,
|
||||
JsonWebKeyEcEllipticCurve, JsonWebKeyOperation, JsonWebKeyType, JsonWebKeyUse,
|
||||
JsonWebSignatureAlg,
|
||||
};
|
||||
use p256::NistP256;
|
||||
use rsa::{BigUint, PublicKeyParts};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{
|
||||
@ -32,6 +29,27 @@ use url::Url;
|
||||
|
||||
use crate::constraints::Constrainable;
|
||||
|
||||
pub(crate) mod private_parameters;
|
||||
pub(crate) mod public_parameters;
|
||||
|
||||
pub use self::public_parameters::JsonWebKeyPublicParameters as JsonWebKeyParameters;
|
||||
|
||||
trait JwkEcCurve {
|
||||
const CRV: JsonWebKeyEcEllipticCurve;
|
||||
}
|
||||
|
||||
impl JwkEcCurve for p256::NistP256 {
|
||||
const CRV: JsonWebKeyEcEllipticCurve = JsonWebKeyEcEllipticCurve::P256;
|
||||
}
|
||||
|
||||
impl JwkEcCurve for p384::NistP384 {
|
||||
const CRV: JsonWebKeyEcEllipticCurve = JsonWebKeyEcEllipticCurve::P384;
|
||||
}
|
||||
|
||||
impl JwkEcCurve for k256::Secp256k1 {
|
||||
const CRV: JsonWebKeyEcEllipticCurve = JsonWebKeyEcEllipticCurve::Secp256K1;
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
@ -139,7 +157,7 @@ impl Constrainable for JsonWebKey {
|
||||
if let Some(alg) = self.alg {
|
||||
Some(vec![alg])
|
||||
} else {
|
||||
match self.parameters {
|
||||
match &self.parameters {
|
||||
JsonWebKeyParameters::Rsa { .. } => Some(vec![
|
||||
JsonWebSignatureAlg::Rs256,
|
||||
JsonWebSignatureAlg::Rs384,
|
||||
@ -148,22 +166,12 @@ impl Constrainable for JsonWebKey {
|
||||
JsonWebSignatureAlg::Ps384,
|
||||
JsonWebSignatureAlg::Ps512,
|
||||
]),
|
||||
JsonWebKeyParameters::Ec {
|
||||
crv: JsonWebKeyEcEllipticCurve::P256,
|
||||
..
|
||||
} => Some(vec![JsonWebSignatureAlg::Es256]),
|
||||
JsonWebKeyParameters::Ec {
|
||||
crv: JsonWebKeyEcEllipticCurve::P384,
|
||||
..
|
||||
} => Some(vec![JsonWebSignatureAlg::Es384]),
|
||||
JsonWebKeyParameters::Ec {
|
||||
crv: JsonWebKeyEcEllipticCurve::P521,
|
||||
..
|
||||
} => Some(vec![JsonWebSignatureAlg::Es512]),
|
||||
JsonWebKeyParameters::Ec {
|
||||
crv: JsonWebKeyEcEllipticCurve::Secp256K1,
|
||||
..
|
||||
} => Some(vec![JsonWebSignatureAlg::Es256K]),
|
||||
JsonWebKeyParameters::Ec(params) => match params.crv() {
|
||||
JsonWebKeyEcEllipticCurve::P256 => Some(vec![JsonWebSignatureAlg::Es256]),
|
||||
JsonWebKeyEcEllipticCurve::P384 => Some(vec![JsonWebSignatureAlg::Es384]),
|
||||
JsonWebKeyEcEllipticCurve::P521 => Some(vec![JsonWebSignatureAlg::Es512]),
|
||||
JsonWebKeyEcEllipticCurve::Secp256K1 => Some(vec![JsonWebSignatureAlg::Es256K]),
|
||||
},
|
||||
JsonWebKeyParameters::Okp { .. } => Some(vec![JsonWebSignatureAlg::EdDsa]),
|
||||
}
|
||||
}
|
||||
@ -194,100 +202,6 @@ impl JsonWebKeySet {
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(tag = "kty")]
|
||||
pub enum JsonWebKeyParameters {
|
||||
#[serde(rename = "RSA")]
|
||||
Rsa {
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
n: Vec<u8>,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
e: Vec<u8>,
|
||||
},
|
||||
#[serde(rename = "EC")]
|
||||
Ec {
|
||||
crv: JsonWebKeyEcEllipticCurve,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
x: Vec<u8>,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
y: Vec<u8>,
|
||||
},
|
||||
#[serde(rename = "OKP")]
|
||||
Okp {
|
||||
crv: JsonWebKeyOkpEllipticCurve,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
x: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
impl TryFrom<JsonWebKeyParameters> for ecdsa::VerifyingKey<NistP256> {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(params: JsonWebKeyParameters) -> Result<Self, Self::Error> {
|
||||
let (x, y): ([u8; 32], [u8; 32]) = match params {
|
||||
JsonWebKeyParameters::Ec {
|
||||
x,
|
||||
y,
|
||||
crv: JsonWebKeyEcEllipticCurve::P256,
|
||||
} => (
|
||||
x.try_into()
|
||||
.map_err(|_| anyhow::anyhow!("invalid curve parameter x"))?,
|
||||
y.try_into()
|
||||
.map_err(|_| anyhow::anyhow!("invalid curve parameter y"))?,
|
||||
),
|
||||
_ => bail!("Wrong key type"),
|
||||
};
|
||||
|
||||
let point = sec1::EncodedPoint::from_affine_coordinates(&x.into(), &y.into(), false);
|
||||
let key = ecdsa::VerifyingKey::from_encoded_point(&point)?;
|
||||
Ok(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ecdsa::VerifyingKey<NistP256>> for JsonWebKeyParameters {
|
||||
fn from(key: ecdsa::VerifyingKey<NistP256>) -> Self {
|
||||
let points = key.to_encoded_point(false);
|
||||
JsonWebKeyParameters::Ec {
|
||||
x: points.x().unwrap().to_vec(),
|
||||
y: points.y().unwrap().to_vec(),
|
||||
crv: JsonWebKeyEcEllipticCurve::P256,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<JsonWebKeyParameters> for rsa::RsaPublicKey {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(params: JsonWebKeyParameters) -> Result<Self, Self::Error> {
|
||||
let (n, e) = match ¶ms {
|
||||
JsonWebKeyParameters::Rsa { n, e } => (n, e),
|
||||
_ => bail!("Wrong key type"),
|
||||
};
|
||||
let n = BigUint::from_bytes_be(n);
|
||||
let e = BigUint::from_bytes_be(e);
|
||||
Ok(rsa::RsaPublicKey::new(n, e)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rsa::RsaPublicKey> for JsonWebKeyParameters {
|
||||
fn from(key: rsa::RsaPublicKey) -> Self {
|
||||
JsonWebKeyParameters::Rsa {
|
||||
n: key.n().to_bytes_be(),
|
||||
e: key.e().to_bytes_be(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
257
crates/jose/src/jwk/private_parameters.rs
Normal file
257
crates/jose/src/jwk/private_parameters.rs
Normal file
@ -0,0 +1,257 @@
|
||||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use mas_iana::jose::{JsonWebKeyEcEllipticCurve, JsonWebKeyOkpEllipticCurve};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{
|
||||
base64::{Base64, UrlSafe},
|
||||
formats::Unpadded,
|
||||
serde_as,
|
||||
};
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(tag = "kty")]
|
||||
pub enum JsonWebKeyPrivateParameters {
|
||||
#[serde(rename = "oct")]
|
||||
Oct(OctPrivateParameters),
|
||||
|
||||
#[serde(rename = "RSA")]
|
||||
Rsa(RsaPrivateParameters),
|
||||
|
||||
#[serde(rename = "EC")]
|
||||
Ec(EcPrivateParameters),
|
||||
|
||||
#[serde(rename = "OKP")]
|
||||
Okp(OkpPrivateParameters),
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct OctPrivateParameters {
|
||||
/// Key Value
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
k: Vec<u8>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct RsaPrivateParameters {
|
||||
/// Modulus
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
n: Vec<u8>,
|
||||
|
||||
/// Exponent
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
e: Vec<u8>,
|
||||
|
||||
/// Private Exponent
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
d: Vec<u8>,
|
||||
|
||||
/// First Prime Factor
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
p: Vec<u8>,
|
||||
|
||||
/// Second Prime Factor
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
q: Vec<u8>,
|
||||
|
||||
/// First Factor CRT Exponent
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
dp: Vec<u8>,
|
||||
|
||||
/// Second Factor CRT Exponent
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
dq: Vec<u8>,
|
||||
|
||||
/// First CRT Coefficient
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
qi: Vec<u8>,
|
||||
|
||||
/// Other Primes Info
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
oth: Option<Vec<RsaOtherPrimeInfo>>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
struct RsaOtherPrimeInfo {
|
||||
/// Prime Factor
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
r: Vec<u8>,
|
||||
|
||||
/// Factor CRT Exponent
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
d: Vec<u8>,
|
||||
|
||||
/// Factor CRT Coefficient
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
t: Vec<u8>,
|
||||
}
|
||||
|
||||
mod rsa_impls {
|
||||
use rsa::{BigUint, RsaPrivateKey};
|
||||
|
||||
use super::RsaPrivateParameters;
|
||||
|
||||
impl TryInto<RsaPrivateKey> for RsaPrivateParameters {
|
||||
type Error = rsa::errors::Error;
|
||||
fn try_into(self) -> Result<RsaPrivateKey, Self::Error> {
|
||||
(&self).try_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<RsaPrivateKey> for &RsaPrivateParameters {
|
||||
type Error = rsa::errors::Error;
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
fn try_into(self) -> Result<RsaPrivateKey, Self::Error> {
|
||||
let n = BigUint::from_bytes_be(&self.n);
|
||||
let e = BigUint::from_bytes_be(&self.e);
|
||||
let d = BigUint::from_bytes_be(&self.d);
|
||||
|
||||
let primes = [&self.p, &self.q]
|
||||
.into_iter()
|
||||
.chain(self.oth.iter().flatten().map(|o| &o.r))
|
||||
.map(|i| BigUint::from_bytes_be(i))
|
||||
.collect();
|
||||
|
||||
RsaPrivateKey::from_components(n, e, d, primes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct EcPrivateParameters {
|
||||
crv: JsonWebKeyEcEllipticCurve,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
x: Vec<u8>,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
y: Vec<u8>,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
d: Vec<u8>,
|
||||
}
|
||||
|
||||
mod ec_impls {
|
||||
use digest::typenum::Unsigned;
|
||||
use ecdsa::EncodedPoint;
|
||||
use elliptic_curve::{
|
||||
sec1::{Coordinates, FromEncodedPoint, ModulusSize, ToEncodedPoint, ValidatePublicKey},
|
||||
AffinePoint, Curve, FieldBytes, FieldSize, SecretKey,
|
||||
};
|
||||
|
||||
use super::{super::JwkEcCurve, EcPrivateParameters};
|
||||
|
||||
impl<C> TryInto<SecretKey<C>> for EcPrivateParameters
|
||||
where
|
||||
C: Curve + ValidatePublicKey,
|
||||
FieldSize<C>: ModulusSize,
|
||||
{
|
||||
type Error = elliptic_curve::Error;
|
||||
fn try_into(self) -> Result<SecretKey<C>, Self::Error> {
|
||||
(&self).try_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> TryInto<SecretKey<C>> for &EcPrivateParameters
|
||||
where
|
||||
C: Curve + ValidatePublicKey,
|
||||
FieldSize<C>: ModulusSize,
|
||||
{
|
||||
type Error = elliptic_curve::Error;
|
||||
|
||||
fn try_into(self) -> Result<SecretKey<C>, Self::Error> {
|
||||
let x = self
|
||||
.x
|
||||
.get(..FieldSize::<C>::USIZE)
|
||||
.ok_or(elliptic_curve::Error)?;
|
||||
let y = self
|
||||
.x
|
||||
.get(..FieldSize::<C>::USIZE)
|
||||
.ok_or(elliptic_curve::Error)?;
|
||||
|
||||
let x = FieldBytes::<C>::from_slice(x);
|
||||
let y = FieldBytes::<C>::from_slice(y);
|
||||
let pubkey = EncodedPoint::<C>::from_affine_coordinates(x, y, false);
|
||||
let privkey = SecretKey::from_be_bytes(&self.d)?;
|
||||
C::validate_public_key(&privkey, &pubkey)?;
|
||||
Ok(privkey)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> From<SecretKey<C>> for EcPrivateParameters
|
||||
where
|
||||
C: Curve + elliptic_curve::ProjectiveArithmetic + JwkEcCurve,
|
||||
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
|
||||
FieldSize<C>: ModulusSize,
|
||||
{
|
||||
fn from(key: SecretKey<C>) -> Self {
|
||||
(&key).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> From<&SecretKey<C>> for EcPrivateParameters
|
||||
where
|
||||
C: Curve + elliptic_curve::ProjectiveArithmetic + JwkEcCurve,
|
||||
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
|
||||
FieldSize<C>: ModulusSize,
|
||||
{
|
||||
fn from(key: &SecretKey<C>) -> Self {
|
||||
let point = key.public_key().to_encoded_point(false);
|
||||
let (x, y) = match point.coordinates() {
|
||||
Coordinates::Uncompressed { x, y } => (x, y),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let d = key.to_be_bytes();
|
||||
EcPrivateParameters {
|
||||
crv: C::CRV,
|
||||
x: x.to_vec(),
|
||||
y: y.to_vec(),
|
||||
d: d.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct OkpPrivateParameters {
|
||||
crv: JsonWebKeyOkpEllipticCurve,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
x: Vec<u8>,
|
||||
}
|
||||
|
253
crates/jose/src/jwk/public_parameters.rs
Normal file
253
crates/jose/src/jwk/public_parameters.rs
Normal file
@ -0,0 +1,253 @@
|
||||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use mas_iana::jose::{JsonWebKeyEcEllipticCurve, JsonWebKeyOkpEllipticCurve};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{
|
||||
base64::{Base64, UrlSafe},
|
||||
formats::Unpadded,
|
||||
serde_as,
|
||||
};
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(tag = "kty")]
|
||||
pub enum JsonWebKeyPublicParameters {
|
||||
#[serde(rename = "RSA")]
|
||||
Rsa(RsaPublicParameters),
|
||||
|
||||
#[serde(rename = "EC")]
|
||||
Ec(EcPublicParameters),
|
||||
|
||||
#[serde(rename = "OKP")]
|
||||
Okp(OkpPublicParameters),
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct RsaPublicParameters {
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
n: Vec<u8>,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
e: Vec<u8>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct EcPublicParameters {
|
||||
pub(crate) crv: JsonWebKeyEcEllipticCurve,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
x: Vec<u8>,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
y: Vec<u8>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct OkpPublicParameters {
|
||||
crv: JsonWebKeyOkpEllipticCurve,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
x: Vec<u8>,
|
||||
}
|
||||
|
||||
impl EcPublicParameters {
|
||||
pub const fn crv(&self) -> JsonWebKeyEcEllipticCurve {
|
||||
self.crv
|
||||
}
|
||||
}
|
||||
|
||||
mod rsa_impls {
|
||||
use rsa::{BigUint, RsaPublicKey};
|
||||
|
||||
use super::RsaPublicParameters;
|
||||
|
||||
impl TryFrom<RsaPublicParameters> for RsaPublicKey {
|
||||
type Error = rsa::errors::Error;
|
||||
fn try_from(value: RsaPublicParameters) -> Result<Self, Self::Error> {
|
||||
(&value).try_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&RsaPublicParameters> for RsaPublicKey {
|
||||
type Error = rsa::errors::Error;
|
||||
fn try_from(value: &RsaPublicParameters) -> Result<Self, Self::Error> {
|
||||
let n = BigUint::from_bytes_be(&value.n);
|
||||
let e = BigUint::from_bytes_be(&value.e);
|
||||
let key = RsaPublicKey::new(n, e)?;
|
||||
Ok(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod ec_impls {
|
||||
use digest::typenum::Unsigned;
|
||||
use ecdsa::{EncodedPoint, PrimeCurve, VerifyingKey};
|
||||
use elliptic_curve::{
|
||||
sec1::{Coordinates, FromEncodedPoint, ModulusSize, ToEncodedPoint},
|
||||
AffinePoint, Curve, FieldBytes, FieldSize, ProjectiveArithmetic, PublicKey,
|
||||
};
|
||||
|
||||
use super::{super::JwkEcCurve, EcPublicParameters};
|
||||
|
||||
impl<C> TryFrom<EcPublicParameters> for VerifyingKey<C>
|
||||
where
|
||||
C: PrimeCurve + ProjectiveArithmetic + JwkEcCurve,
|
||||
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
|
||||
FieldSize<C>: ModulusSize,
|
||||
{
|
||||
type Error = ecdsa::Error;
|
||||
fn try_from(value: EcPublicParameters) -> Result<Self, Self::Error> {
|
||||
(&value).try_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> TryFrom<&EcPublicParameters> for VerifyingKey<C>
|
||||
where
|
||||
C: PrimeCurve + ProjectiveArithmetic + JwkEcCurve,
|
||||
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
|
||||
FieldSize<C>: ModulusSize,
|
||||
{
|
||||
type Error = ecdsa::Error;
|
||||
|
||||
fn try_from(value: &EcPublicParameters) -> Result<Self, Self::Error> {
|
||||
if value.crv() != C::CRV {
|
||||
return Err(Self::Error::default());
|
||||
}
|
||||
|
||||
let x = value
|
||||
.x
|
||||
.get(..FieldSize::<C>::USIZE)
|
||||
.ok_or_else(Self::Error::default)?;
|
||||
let y = value
|
||||
.x
|
||||
.get(..FieldSize::<C>::USIZE)
|
||||
.ok_or_else(Self::Error::default)?;
|
||||
|
||||
let x = FieldBytes::<C>::from_slice(x);
|
||||
let y = FieldBytes::<C>::from_slice(y);
|
||||
let pubkey = EncodedPoint::<C>::from_affine_coordinates(x, y, false);
|
||||
let pubkey = VerifyingKey::from_encoded_point(&pubkey)?;
|
||||
Ok(pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> From<PublicKey<C>> for EcPublicParameters
|
||||
where
|
||||
C: Curve + elliptic_curve::ProjectiveArithmetic + JwkEcCurve,
|
||||
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
|
||||
FieldSize<C>: ModulusSize,
|
||||
{
|
||||
fn from(key: PublicKey<C>) -> Self {
|
||||
(&key).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> From<&PublicKey<C>> for EcPublicParameters
|
||||
where
|
||||
C: Curve + elliptic_curve::ProjectiveArithmetic + JwkEcCurve,
|
||||
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
|
||||
FieldSize<C>: ModulusSize,
|
||||
{
|
||||
fn from(key: &PublicKey<C>) -> Self {
|
||||
let point = key.to_encoded_point(false);
|
||||
let (x, y) = match point.coordinates() {
|
||||
Coordinates::Uncompressed { x, y } => (x, y),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
EcPublicParameters {
|
||||
crv: C::CRV,
|
||||
x: x.to_vec(),
|
||||
y: y.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Some legacy implementations to remove
|
||||
mod legacy {
|
||||
use anyhow::bail;
|
||||
use mas_iana::jose::JsonWebKeyEcEllipticCurve;
|
||||
use p256::NistP256;
|
||||
use rsa::{BigUint, PublicKeyParts};
|
||||
|
||||
use super::{EcPublicParameters, JsonWebKeyPublicParameters, RsaPublicParameters};
|
||||
|
||||
impl TryFrom<JsonWebKeyPublicParameters> for ecdsa::VerifyingKey<NistP256> {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(params: JsonWebKeyPublicParameters) -> Result<Self, Self::Error> {
|
||||
let (x, y): ([u8; 32], [u8; 32]) = match params {
|
||||
JsonWebKeyPublicParameters::Ec(EcPublicParameters {
|
||||
x,
|
||||
y,
|
||||
crv: JsonWebKeyEcEllipticCurve::P256,
|
||||
}) => (
|
||||
x.try_into()
|
||||
.map_err(|_| anyhow::anyhow!("invalid curve parameter x"))?,
|
||||
y.try_into()
|
||||
.map_err(|_| anyhow::anyhow!("invalid curve parameter y"))?,
|
||||
),
|
||||
_ => bail!("Wrong key type"),
|
||||
};
|
||||
|
||||
let point = sec1::EncodedPoint::from_affine_coordinates(&x.into(), &y.into(), false);
|
||||
let key = ecdsa::VerifyingKey::from_encoded_point(&point)?;
|
||||
Ok(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ecdsa::VerifyingKey<NistP256>> for JsonWebKeyPublicParameters {
|
||||
fn from(key: ecdsa::VerifyingKey<NistP256>) -> Self {
|
||||
let points = key.to_encoded_point(false);
|
||||
JsonWebKeyPublicParameters::Ec(EcPublicParameters {
|
||||
x: points.x().unwrap().to_vec(),
|
||||
y: points.y().unwrap().to_vec(),
|
||||
crv: JsonWebKeyEcEllipticCurve::P256,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<JsonWebKeyPublicParameters> for rsa::RsaPublicKey {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(params: JsonWebKeyPublicParameters) -> Result<Self, Self::Error> {
|
||||
let (n, e) = match ¶ms {
|
||||
JsonWebKeyPublicParameters::Rsa(RsaPublicParameters { n, e }) => (n, e),
|
||||
_ => bail!("Wrong key type"),
|
||||
};
|
||||
let n = BigUint::from_bytes_be(n);
|
||||
let e = BigUint::from_bytes_be(e);
|
||||
Ok(rsa::RsaPublicKey::new(n, e)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rsa::RsaPublicKey> for JsonWebKeyPublicParameters {
|
||||
fn from(key: rsa::RsaPublicKey) -> Self {
|
||||
JsonWebKeyPublicParameters::Rsa(RsaPublicParameters {
|
||||
n: key.n().to_bytes_be(),
|
||||
e: key.e().to_bytes_be(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -13,12 +13,11 @@
|
||||
// limitations under the License.
|
||||
|
||||
use mas_iana::jose::{JsonWebKeyEcEllipticCurve, JsonWebSignatureAlg};
|
||||
use rsa::BigUint;
|
||||
use sha2::{Sha256, Sha384, Sha512};
|
||||
use signature::Signature;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::jwk::JsonWebKeyParameters;
|
||||
use crate::jwk::{public_parameters::EcPublicParameters, JsonWebKeyParameters};
|
||||
|
||||
pub enum Verifier {
|
||||
Hs256 {
|
||||
@ -104,135 +103,91 @@ impl Verifier {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn for_jwk_and_alg(
|
||||
key: &JsonWebKeyParameters,
|
||||
alg: JsonWebSignatureAlg,
|
||||
) -> Result<Self, VerifierFromJwkError> {
|
||||
match (key, alg) {
|
||||
(JsonWebKeyParameters::Rsa { n, e }, JsonWebSignatureAlg::Rs256) => {
|
||||
let n = BigUint::from_bytes_be(n);
|
||||
let e = BigUint::from_bytes_be(e);
|
||||
let key = rsa::RsaPublicKey::new(n, e)?;
|
||||
(JsonWebKeyParameters::Rsa(params), JsonWebSignatureAlg::Rs256) => {
|
||||
let key = rsa::RsaPublicKey::try_from(params)?;
|
||||
Ok(Self::Rs256 { key: key.into() })
|
||||
}
|
||||
|
||||
(JsonWebKeyParameters::Rsa { n, e }, JsonWebSignatureAlg::Rs384) => {
|
||||
let n = BigUint::from_bytes_be(n);
|
||||
let e = BigUint::from_bytes_be(e);
|
||||
let key = rsa::RsaPublicKey::new(n, e)?;
|
||||
(JsonWebKeyParameters::Rsa(params), JsonWebSignatureAlg::Rs384) => {
|
||||
let key = rsa::RsaPublicKey::try_from(params)?;
|
||||
Ok(Self::Rs384 { key: key.into() })
|
||||
}
|
||||
|
||||
(JsonWebKeyParameters::Rsa { n, e }, JsonWebSignatureAlg::Rs512) => {
|
||||
let n = BigUint::from_bytes_be(n);
|
||||
let e = BigUint::from_bytes_be(e);
|
||||
let key = rsa::RsaPublicKey::new(n, e)?;
|
||||
(JsonWebKeyParameters::Rsa(params), JsonWebSignatureAlg::Rs512) => {
|
||||
let key = rsa::RsaPublicKey::try_from(params)?;
|
||||
Ok(Self::Rs512 { key: key.into() })
|
||||
}
|
||||
|
||||
(JsonWebKeyParameters::Rsa { n, e }, JsonWebSignatureAlg::Ps256) => {
|
||||
let n = BigUint::from_bytes_be(n);
|
||||
let e = BigUint::from_bytes_be(e);
|
||||
let key = rsa::RsaPublicKey::new(n, e)?;
|
||||
(JsonWebKeyParameters::Rsa(params), JsonWebSignatureAlg::Ps256) => {
|
||||
let key = rsa::RsaPublicKey::try_from(params)?;
|
||||
Ok(Self::Ps256 { key: key.into() })
|
||||
}
|
||||
|
||||
(JsonWebKeyParameters::Rsa { n, e }, JsonWebSignatureAlg::Ps384) => {
|
||||
let n = BigUint::from_bytes_be(n);
|
||||
let e = BigUint::from_bytes_be(e);
|
||||
let key = rsa::RsaPublicKey::new(n, e)?;
|
||||
(JsonWebKeyParameters::Rsa(params), JsonWebSignatureAlg::Ps384) => {
|
||||
let key = rsa::RsaPublicKey::try_from(params)?;
|
||||
Ok(Self::Ps384 { key: key.into() })
|
||||
}
|
||||
|
||||
(JsonWebKeyParameters::Rsa { n, e }, JsonWebSignatureAlg::Ps512) => {
|
||||
let n = BigUint::from_bytes_be(n);
|
||||
let e = BigUint::from_bytes_be(e);
|
||||
let key = rsa::RsaPublicKey::new(n, e)?;
|
||||
(JsonWebKeyParameters::Rsa(params), JsonWebSignatureAlg::Ps512) => {
|
||||
let key = rsa::RsaPublicKey::try_from(params)?;
|
||||
Ok(Self::Ps512 { key: key.into() })
|
||||
}
|
||||
|
||||
(
|
||||
JsonWebKeyParameters::Ec {
|
||||
crv: JsonWebKeyEcEllipticCurve::P256,
|
||||
x,
|
||||
y,
|
||||
},
|
||||
JsonWebKeyParameters::Ec(
|
||||
params @ EcPublicParameters {
|
||||
crv: JsonWebKeyEcEllipticCurve::P256,
|
||||
..
|
||||
},
|
||||
),
|
||||
JsonWebSignatureAlg::Es256,
|
||||
) => {
|
||||
let x: &[u8; 32] = x
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| VerifierFromJwkError::InvalidCurveParameterX)?;
|
||||
let y: &[u8; 32] = y
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| VerifierFromJwkError::InvalidCurveParameterY)?;
|
||||
|
||||
let point = sec1::EncodedPoint::from_affine_coordinates(x.into(), y.into(), false);
|
||||
let key = ecdsa::VerifyingKey::from_encoded_point(&point)?;
|
||||
|
||||
let key = ecdsa::VerifyingKey::try_from(params)?;
|
||||
Ok(Self::Es256 { key })
|
||||
}
|
||||
|
||||
(
|
||||
JsonWebKeyParameters::Ec {
|
||||
crv: JsonWebKeyEcEllipticCurve::P384,
|
||||
x,
|
||||
y,
|
||||
},
|
||||
JsonWebKeyParameters::Ec(
|
||||
params @ EcPublicParameters {
|
||||
crv: JsonWebKeyEcEllipticCurve::P384,
|
||||
..
|
||||
},
|
||||
),
|
||||
JsonWebSignatureAlg::Es384,
|
||||
) => {
|
||||
let x: &[u8; 48] = x
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| VerifierFromJwkError::InvalidCurveParameterX)?;
|
||||
let y: &[u8; 48] = y
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| VerifierFromJwkError::InvalidCurveParameterY)?;
|
||||
|
||||
let point = sec1::EncodedPoint::from_affine_coordinates(x.into(), y.into(), false);
|
||||
let key = ecdsa::VerifyingKey::from_encoded_point(&point)?;
|
||||
|
||||
let key = ecdsa::VerifyingKey::try_from(params)?;
|
||||
Ok(Self::Es384 { key })
|
||||
}
|
||||
|
||||
(
|
||||
JsonWebKeyParameters::Ec {
|
||||
JsonWebKeyParameters::Ec(EcPublicParameters {
|
||||
crv: JsonWebKeyEcEllipticCurve::P521,
|
||||
x: _,
|
||||
y: _,
|
||||
},
|
||||
..
|
||||
}),
|
||||
JsonWebSignatureAlg::Es512,
|
||||
) => Err(VerifierFromJwkError::UnsupportedAlgorithm {
|
||||
algorithm: JsonWebSignatureAlg::Es512,
|
||||
}),
|
||||
|
||||
(
|
||||
JsonWebKeyParameters::Ec {
|
||||
crv: JsonWebKeyEcEllipticCurve::Secp256K1,
|
||||
x,
|
||||
y,
|
||||
},
|
||||
JsonWebKeyParameters::Ec(
|
||||
params @ EcPublicParameters {
|
||||
crv: JsonWebKeyEcEllipticCurve::Secp256K1,
|
||||
..
|
||||
},
|
||||
),
|
||||
JsonWebSignatureAlg::Es256K,
|
||||
) => {
|
||||
let x: &[u8; 32] = x
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| VerifierFromJwkError::InvalidCurveParameterX)?;
|
||||
let y: &[u8; 32] = y
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| VerifierFromJwkError::InvalidCurveParameterY)?;
|
||||
|
||||
let point = sec1::EncodedPoint::from_affine_coordinates(x.into(), y.into(), false);
|
||||
let key = ecdsa::VerifyingKey::from_encoded_point(&point)?;
|
||||
|
||||
let key = ecdsa::VerifyingKey::try_from(params)?;
|
||||
Ok(Self::Es256K { key })
|
||||
}
|
||||
|
||||
(JsonWebKeyParameters::Okp { crv: _, x: _ }, JsonWebSignatureAlg::EdDsa) => {
|
||||
(JsonWebKeyParameters::Okp(_params), JsonWebSignatureAlg::EdDsa) => {
|
||||
Err(VerifierFromJwkError::UnsupportedAlgorithm {
|
||||
algorithm: JsonWebSignatureAlg::EdDsa,
|
||||
})
|
||||
|
Reference in New Issue
Block a user