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
Private to public JWKS conversion
This commit is contained in:
@ -32,10 +32,12 @@ use crate::constraints::Constrainable;
|
||||
pub(crate) mod private_parameters;
|
||||
pub(crate) mod public_parameters;
|
||||
|
||||
use self::private_parameters::SymetricKeyError;
|
||||
pub use self::public_parameters::JsonWebKeyPublicParameters as JsonWebKeyParameters;
|
||||
|
||||
pub trait JwkKty {
|
||||
pub trait ParametersInfo {
|
||||
fn kty(&self) -> JsonWebKeyType;
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg];
|
||||
}
|
||||
|
||||
trait JwkEcCurve {
|
||||
@ -96,6 +98,24 @@ pub struct JsonWebKey<P> {
|
||||
pub type PublicJsonWebKey = JsonWebKey<self::public_parameters::JsonWebKeyPublicParameters>;
|
||||
pub type PrivateJsonWebKey = JsonWebKey<self::private_parameters::JsonWebKeyPrivateParameters>;
|
||||
|
||||
impl TryFrom<PrivateJsonWebKey> for PublicJsonWebKey {
|
||||
type Error = SymetricKeyError;
|
||||
|
||||
fn try_from(value: PrivateJsonWebKey) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
parameters: value.parameters.try_into()?,
|
||||
r#use: value.r#use,
|
||||
key_ops: value.key_ops,
|
||||
alg: value.alg,
|
||||
kid: value.kid,
|
||||
x5u: value.x5u,
|
||||
x5c: value.x5c,
|
||||
x5t: value.x5t,
|
||||
x5t_s256: value.x5t_s256,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> JsonWebKey<P> {
|
||||
#[must_use]
|
||||
pub const fn new(parameters: P) -> Self {
|
||||
@ -149,7 +169,7 @@ impl<P> JsonWebKey<P> {
|
||||
|
||||
impl<P> Constrainable for JsonWebKey<P>
|
||||
where
|
||||
P: JwkKty,
|
||||
P: ParametersInfo,
|
||||
{
|
||||
fn kid(&self) -> Option<&str> {
|
||||
self.kid.as_deref()
|
||||
@ -163,32 +183,7 @@ where
|
||||
if let Some(alg) = self.alg {
|
||||
Some(vec![alg])
|
||||
} else {
|
||||
match self.parameters.kty() {
|
||||
JsonWebKeyType::Rsa => Some(vec![
|
||||
JsonWebSignatureAlg::Rs256,
|
||||
JsonWebSignatureAlg::Rs384,
|
||||
JsonWebSignatureAlg::Rs512,
|
||||
JsonWebSignatureAlg::Ps256,
|
||||
JsonWebSignatureAlg::Ps384,
|
||||
JsonWebSignatureAlg::Ps512,
|
||||
]),
|
||||
JsonWebKeyType::Ec => {
|
||||
todo!()
|
||||
/*
|
||||
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]),
|
||||
}, */
|
||||
}
|
||||
JsonWebKeyType::Okp => Some(vec![JsonWebSignatureAlg::EdDsa]),
|
||||
JsonWebKeyType::Oct => Some(vec![
|
||||
JsonWebSignatureAlg::Hs256,
|
||||
JsonWebSignatureAlg::Hs384,
|
||||
JsonWebSignatureAlg::Hs512,
|
||||
]),
|
||||
}
|
||||
Some(self.parameters.possible_algs().to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,6 +201,17 @@ pub type PublicJsonWebKeySet = JsonWebKeySet<self::public_parameters::JsonWebKey
|
||||
pub type PrivateJsonWebKeySet =
|
||||
JsonWebKeySet<self::private_parameters::JsonWebKeyPrivateParameters>;
|
||||
|
||||
impl From<PrivateJsonWebKeySet> for PublicJsonWebKeySet {
|
||||
fn from(value: PrivateJsonWebKeySet) -> Self {
|
||||
let keys = value
|
||||
.keys
|
||||
.into_iter()
|
||||
.filter_map(|key: PrivateJsonWebKey| key.try_into().ok())
|
||||
.collect();
|
||||
Self { keys }
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> std::ops::Deref for JsonWebKeySet<P> {
|
||||
type Target = Vec<JsonWebKey<P>>;
|
||||
|
||||
@ -249,7 +255,7 @@ mod tests {
|
||||
]
|
||||
});
|
||||
|
||||
let jwks: JsonWebKeySet = serde_json::from_value(jwks).unwrap();
|
||||
let jwks: PublicJsonWebKeySet = serde_json::from_value(jwks).unwrap();
|
||||
// Both keys are RSA public keys
|
||||
for jwk in &jwks.keys {
|
||||
rsa::RsaPublicKey::try_from(jwk.parameters.clone()).unwrap();
|
||||
@ -383,7 +389,7 @@ mod tests {
|
||||
]
|
||||
});
|
||||
|
||||
let jwks: JsonWebKeySet = serde_json::from_value(jwks).unwrap();
|
||||
let jwks: PublicJsonWebKeySet = serde_json::from_value(jwks).unwrap();
|
||||
// The first 6 keys are RSA, 7th is P-256
|
||||
let mut keys = jwks.keys.into_iter();
|
||||
rsa::RsaPublicKey::try_from(keys.next().unwrap().parameters).unwrap();
|
||||
|
@ -12,7 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use mas_iana::jose::{JsonWebKeyEcEllipticCurve, JsonWebKeyOkpEllipticCurve, JsonWebKeyType};
|
||||
use mas_iana::jose::{
|
||||
JsonWebKeyEcEllipticCurve, JsonWebKeyOkpEllipticCurve, JsonWebKeyType, JsonWebSignatureAlg,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{
|
||||
@ -20,8 +22,9 @@ use serde_with::{
|
||||
formats::Unpadded,
|
||||
serde_as,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
use super::JwkKty;
|
||||
use super::{public_parameters::JsonWebKeyPublicParameters, ParametersInfo};
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
@ -40,7 +43,7 @@ pub enum JsonWebKeyPrivateParameters {
|
||||
Okp(OkpPrivateParameters),
|
||||
}
|
||||
|
||||
impl JwkKty for JsonWebKeyPrivateParameters {
|
||||
impl ParametersInfo for JsonWebKeyPrivateParameters {
|
||||
fn kty(&self) -> JsonWebKeyType {
|
||||
match self {
|
||||
Self::Oct(_) => JsonWebKeyType::Oct,
|
||||
@ -49,6 +52,32 @@ impl JwkKty for JsonWebKeyPrivateParameters {
|
||||
Self::Okp(_) => JsonWebKeyType::Okp,
|
||||
}
|
||||
}
|
||||
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
||||
match self {
|
||||
JsonWebKeyPrivateParameters::Oct(p) => p.possible_algs(),
|
||||
JsonWebKeyPrivateParameters::Rsa(p) => p.possible_algs(),
|
||||
JsonWebKeyPrivateParameters::Ec(p) => p.possible_algs(),
|
||||
JsonWebKeyPrivateParameters::Okp(p) => p.possible_algs(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("can't extract a public key out of a symetric key")]
|
||||
pub struct SymetricKeyError;
|
||||
|
||||
impl TryFrom<JsonWebKeyPrivateParameters> for JsonWebKeyPublicParameters {
|
||||
type Error = SymetricKeyError;
|
||||
|
||||
fn try_from(value: JsonWebKeyPrivateParameters) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
JsonWebKeyPrivateParameters::Oct(_) => Err(SymetricKeyError),
|
||||
JsonWebKeyPrivateParameters::Rsa(p) => Ok(JsonWebKeyPublicParameters::Rsa(p.into())),
|
||||
JsonWebKeyPrivateParameters::Ec(p) => Ok(JsonWebKeyPublicParameters::Ec(p.into())),
|
||||
JsonWebKeyPrivateParameters::Okp(p) => Ok(JsonWebKeyPublicParameters::Okp(p.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
@ -60,6 +89,20 @@ pub struct OctPrivateParameters {
|
||||
k: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ParametersInfo for OctPrivateParameters {
|
||||
fn kty(&self) -> JsonWebKeyType {
|
||||
JsonWebKeyType::Oct
|
||||
}
|
||||
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
||||
&[
|
||||
JsonWebSignatureAlg::Hs256,
|
||||
JsonWebSignatureAlg::Hs384,
|
||||
JsonWebSignatureAlg::Hs512,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct RsaPrivateParameters {
|
||||
@ -108,6 +151,29 @@ pub struct RsaPrivateParameters {
|
||||
oth: Option<Vec<RsaOtherPrimeInfo>>,
|
||||
}
|
||||
|
||||
impl ParametersInfo for RsaPrivateParameters {
|
||||
fn kty(&self) -> JsonWebKeyType {
|
||||
JsonWebKeyType::Rsa
|
||||
}
|
||||
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
||||
&[
|
||||
JsonWebSignatureAlg::Rs256,
|
||||
JsonWebSignatureAlg::Rs384,
|
||||
JsonWebSignatureAlg::Rs512,
|
||||
JsonWebSignatureAlg::Ps256,
|
||||
JsonWebSignatureAlg::Ps384,
|
||||
JsonWebSignatureAlg::Ps512,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RsaPrivateParameters> for super::public_parameters::RsaPublicParameters {
|
||||
fn from(params: RsaPrivateParameters) -> Self {
|
||||
Self::new(params.n, params.e)
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
struct RsaOtherPrimeInfo {
|
||||
@ -177,6 +243,27 @@ pub struct EcPrivateParameters {
|
||||
d: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ParametersInfo for EcPrivateParameters {
|
||||
fn kty(&self) -> JsonWebKeyType {
|
||||
JsonWebKeyType::Ec
|
||||
}
|
||||
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
||||
match self.crv {
|
||||
JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256],
|
||||
JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
|
||||
JsonWebKeyEcEllipticCurve::P521 => &[JsonWebSignatureAlg::Es512],
|
||||
JsonWebKeyEcEllipticCurve::Secp256K1 => &[JsonWebSignatureAlg::Es256K],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EcPrivateParameters> for super::public_parameters::EcPublicParameters {
|
||||
fn from(params: EcPrivateParameters) -> Self {
|
||||
Self::new(params.crv, params.x, params.y)
|
||||
}
|
||||
}
|
||||
|
||||
mod ec_impls {
|
||||
use digest::typenum::Unsigned;
|
||||
use ecdsa::EncodedPoint;
|
||||
@ -267,3 +354,19 @@ pub struct OkpPrivateParameters {
|
||||
#[serde_as(as = "Base64<UrlSafe, Unpadded>")]
|
||||
x: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ParametersInfo for OkpPrivateParameters {
|
||||
fn kty(&self) -> JsonWebKeyType {
|
||||
JsonWebKeyType::Okp
|
||||
}
|
||||
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
||||
&[JsonWebSignatureAlg::EdDsa]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OkpPrivateParameters> for super::public_parameters::OkpPublicParameters {
|
||||
fn from(params: OkpPrivateParameters) -> Self {
|
||||
Self::new(params.crv, params.x)
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use mas_iana::jose::{JsonWebKeyEcEllipticCurve, JsonWebKeyOkpEllipticCurve, JsonWebKeyType};
|
||||
use mas_iana::jose::{
|
||||
JsonWebKeyEcEllipticCurve, JsonWebKeyOkpEllipticCurve, JsonWebKeyType, JsonWebSignatureAlg,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{
|
||||
@ -21,7 +23,7 @@ use serde_with::{
|
||||
serde_as,
|
||||
};
|
||||
|
||||
use super::JwkKty;
|
||||
use super::ParametersInfo;
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
@ -37,7 +39,7 @@ pub enum JsonWebKeyPublicParameters {
|
||||
Okp(OkpPublicParameters),
|
||||
}
|
||||
|
||||
impl JwkKty for JsonWebKeyPublicParameters {
|
||||
impl ParametersInfo for JsonWebKeyPublicParameters {
|
||||
fn kty(&self) -> JsonWebKeyType {
|
||||
match self {
|
||||
Self::Rsa(_) => JsonWebKeyType::Rsa,
|
||||
@ -45,6 +47,14 @@ impl JwkKty for JsonWebKeyPublicParameters {
|
||||
Self::Okp(_) => JsonWebKeyType::Okp,
|
||||
}
|
||||
}
|
||||
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
||||
match self {
|
||||
JsonWebKeyPublicParameters::Rsa(p) => p.possible_algs(),
|
||||
JsonWebKeyPublicParameters::Ec(p) => p.possible_algs(),
|
||||
JsonWebKeyPublicParameters::Okp(p) => p.possible_algs(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
@ -59,6 +69,29 @@ pub struct RsaPublicParameters {
|
||||
e: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ParametersInfo for RsaPublicParameters {
|
||||
fn kty(&self) -> JsonWebKeyType {
|
||||
JsonWebKeyType::Rsa
|
||||
}
|
||||
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
||||
&[
|
||||
JsonWebSignatureAlg::Rs256,
|
||||
JsonWebSignatureAlg::Rs384,
|
||||
JsonWebSignatureAlg::Rs512,
|
||||
JsonWebSignatureAlg::Ps256,
|
||||
JsonWebSignatureAlg::Ps384,
|
||||
JsonWebSignatureAlg::Ps512,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl RsaPublicParameters {
|
||||
pub const fn new(n: Vec<u8>, e: Vec<u8>) -> Self {
|
||||
Self { n, e }
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct EcPublicParameters {
|
||||
@ -73,6 +106,31 @@ pub struct EcPublicParameters {
|
||||
y: Vec<u8>,
|
||||
}
|
||||
|
||||
impl EcPublicParameters {
|
||||
pub const fn new(crv: JsonWebKeyEcEllipticCurve, x: Vec<u8>, y: Vec<u8>) -> Self {
|
||||
Self { crv, x, y }
|
||||
}
|
||||
|
||||
pub const fn crv(&self) -> JsonWebKeyEcEllipticCurve {
|
||||
self.crv
|
||||
}
|
||||
}
|
||||
|
||||
impl ParametersInfo for EcPublicParameters {
|
||||
fn kty(&self) -> JsonWebKeyType {
|
||||
JsonWebKeyType::Ec
|
||||
}
|
||||
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
||||
match self.crv {
|
||||
JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256],
|
||||
JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
|
||||
JsonWebKeyEcEllipticCurve::P521 => &[JsonWebSignatureAlg::Es512],
|
||||
JsonWebKeyEcEllipticCurve::Secp256K1 => &[JsonWebSignatureAlg::Es256K],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct OkpPublicParameters {
|
||||
@ -83,8 +141,22 @@ pub struct OkpPublicParameters {
|
||||
x: Vec<u8>,
|
||||
}
|
||||
|
||||
impl EcPublicParameters {
|
||||
pub const fn crv(&self) -> JsonWebKeyEcEllipticCurve {
|
||||
impl ParametersInfo for OkpPublicParameters {
|
||||
fn kty(&self) -> JsonWebKeyType {
|
||||
JsonWebKeyType::Okp
|
||||
}
|
||||
|
||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
||||
&[JsonWebSignatureAlg::EdDsa]
|
||||
}
|
||||
}
|
||||
|
||||
impl OkpPublicParameters {
|
||||
pub const fn new(crv: JsonWebKeyOkpEllipticCurve, x: Vec<u8>) -> Self {
|
||||
Self { crv, x }
|
||||
}
|
||||
|
||||
pub const fn crv(&self) -> JsonWebKeyOkpEllipticCurve {
|
||||
self.crv
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,11 @@
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use mas_jose::{constraints::ConstraintSet, JsonWebKeySet, Jwt};
|
||||
use mas_jose::{
|
||||
constraints::ConstraintSet,
|
||||
jwk::{PrivateJsonWebKeySet, PublicJsonWebKeySet},
|
||||
Jwt,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
static HS256_JWT: &str = include_str!("./jwts/hs256.jwt");
|
||||
@ -34,10 +38,14 @@ static EDDSA_ED25519_JWT: &str = include_str!("./jwts/eddsa-ed25519.jwt");
|
||||
static EDDSA_ED448_JWT: &str = include_str!("./jwts/eddsa-ed448.jwt");
|
||||
static OCT_KEY: &[u8] = include_bytes!("./keys/oct.bin");
|
||||
|
||||
fn public_jwks() -> JsonWebKeySet {
|
||||
fn public_jwks() -> PublicJsonWebKeySet {
|
||||
serde_json::from_str(include_str!("./keys/jwks.pub.json")).unwrap()
|
||||
}
|
||||
|
||||
fn private_jwks() -> PrivateJsonWebKeySet {
|
||||
serde_json::from_str(include_str!("./keys/jwks.priv.json")).unwrap()
|
||||
}
|
||||
|
||||
fn oct_key() -> Vec<u8> {
|
||||
OCT_KEY.to_vec()
|
||||
}
|
||||
@ -105,3 +113,11 @@ asymetric_jwt_test!(test_es512, ES512_JWT, verify = false);
|
||||
asymetric_jwt_test!(test_es256k, ES256K_JWT);
|
||||
asymetric_jwt_test!(test_eddsa_ed25519, EDDSA_ED25519_JWT, verify = false);
|
||||
asymetric_jwt_test!(test_eddsa_ed448, EDDSA_ED448_JWT, verify = false);
|
||||
|
||||
#[test]
|
||||
fn test_private_to_public_jwks() {
|
||||
let priv_jwks = private_jwks();
|
||||
let pub_jwks = PublicJsonWebKeySet::from(priv_jwks);
|
||||
|
||||
assert_eq!(pub_jwks, public_jwks());
|
||||
}
|
||||
|
Reference in New Issue
Block a user