diff --git a/crates/jose/src/jwk/mod.rs b/crates/jose/src/jwk/mod.rs
index 7baf4769..aacd6155 100644
--- a/crates/jose/src/jwk/mod.rs
+++ b/crates/jose/src/jwk/mod.rs
@@ -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
{
pub type PublicJsonWebKey = JsonWebKey;
pub type PrivateJsonWebKey = JsonWebKey;
+impl TryFrom for PublicJsonWebKey {
+ type Error = SymetricKeyError;
+
+ fn try_from(value: PrivateJsonWebKey) -> Result {
+ 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 JsonWebKey
{
#[must_use]
pub const fn new(parameters: P) -> Self {
@@ -149,7 +169,7 @@ impl
JsonWebKey
{
impl
Constrainable for JsonWebKey
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;
+impl From 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 std::ops::Deref for JsonWebKeySet
{
type Target = Vec>;
@@ -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();
diff --git a/crates/jose/src/jwk/private_parameters.rs b/crates/jose/src/jwk/private_parameters.rs
index 78a20cd3..6b9f1ea1 100644
--- a/crates/jose/src/jwk/private_parameters.rs
+++ b/crates/jose/src/jwk/private_parameters.rs
@@ -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 for JsonWebKeyPublicParameters {
+ type Error = SymetricKeyError;
+
+ fn try_from(value: JsonWebKeyPrivateParameters) -> Result {
+ 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,
}
+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>,
}
+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 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,
}
+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 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")]
x: Vec,
}
+
+impl ParametersInfo for OkpPrivateParameters {
+ fn kty(&self) -> JsonWebKeyType {
+ JsonWebKeyType::Okp
+ }
+
+ fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
+ &[JsonWebSignatureAlg::EdDsa]
+ }
+}
+
+impl From for super::public_parameters::OkpPublicParameters {
+ fn from(params: OkpPrivateParameters) -> Self {
+ Self::new(params.crv, params.x)
+ }
+}
diff --git a/crates/jose/src/jwk/public_parameters.rs b/crates/jose/src/jwk/public_parameters.rs
index 2fe00dc4..2366a334 100644
--- a/crates/jose/src/jwk/public_parameters.rs
+++ b/crates/jose/src/jwk/public_parameters.rs
@@ -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,
}
+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, e: Vec) -> 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,
}
+impl EcPublicParameters {
+ pub const fn new(crv: JsonWebKeyEcEllipticCurve, x: Vec, y: Vec) -> 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,
}
-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) -> Self {
+ Self { crv, x }
+ }
+
+ pub const fn crv(&self) -> JsonWebKeyOkpEllipticCurve {
self.crv
}
}
diff --git a/crates/jose/tests/jws.rs b/crates/jose/tests/jws.rs
index 6cabfb67..82078e41 100644
--- a/crates/jose/tests/jws.rs
+++ b/crates/jose/tests/jws.rs
@@ -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 {
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());
+}