You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +03:00
Some cleanups
This commit is contained in:
@ -355,7 +355,7 @@ async fn authorization_code_grant(
|
|||||||
|
|
||||||
let header = JsonWebSignatureHeader::new(alg)
|
let header = JsonWebSignatureHeader::new(alg)
|
||||||
.with_kid(key.kid().context("key has no `kid` for some reason")?);
|
.with_kid(key.kid().context("key has no `kid` for some reason")?);
|
||||||
let signer = key.params().signer_for_alg(alg)?;
|
let signer = key.params().signing_key_for_alg(alg)?;
|
||||||
let id_token = Jwt::sign(header, claims, &signer)?;
|
let id_token = Jwt::sign(header, claims, &signer)?;
|
||||||
|
|
||||||
Some(id_token.as_str().to_owned())
|
Some(id_token.as_str().to_owned())
|
||||||
|
@ -82,7 +82,7 @@ pub async fn get(
|
|||||||
|
|
||||||
let header = JsonWebSignatureHeader::new(alg)
|
let header = JsonWebSignatureHeader::new(alg)
|
||||||
.with_kid(key.kid().context("key has no `kid` for some reason")?);
|
.with_kid(key.kid().context("key has no `kid` for some reason")?);
|
||||||
let signer = key.params().signer_for_alg(alg)?;
|
let signer = key.params().signing_key_for_alg(alg)?;
|
||||||
|
|
||||||
let user_info = SignedUserInfo {
|
let user_info = SignedUserInfo {
|
||||||
iss: url_builder.oidc_issuer().to_string(),
|
iss: url_builder.oidc_issuer().to_string(),
|
||||||
|
@ -76,11 +76,15 @@ pub enum ConstraintDecision {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Constrainable {
|
pub trait Constrainable {
|
||||||
/// List of available algorithms for this key
|
fn alg(&self) -> Option<JsonWebSignatureAlg> {
|
||||||
fn algs(&self) -> Option<Vec<JsonWebSignatureAlg>> {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List of available algorithms for this key
|
||||||
|
fn algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
|
||||||
/// Key ID (`kid`) of this key
|
/// Key ID (`kid`) of this key
|
||||||
fn kid(&self) -> Option<&str> {
|
fn kid(&self) -> Option<&str> {
|
||||||
None
|
None
|
||||||
@ -99,25 +103,36 @@ impl<'a> Constraint<'a> {
|
|||||||
fn decide<T: Constrainable>(&self, constrainable: &T) -> ConstraintDecision {
|
fn decide<T: Constrainable>(&self, constrainable: &T) -> ConstraintDecision {
|
||||||
match self {
|
match self {
|
||||||
Constraint::Alg { constraint_alg } => {
|
Constraint::Alg { constraint_alg } => {
|
||||||
if let Some(algs) = constrainable.algs() {
|
// If the constrainable has one specific alg defined, use that
|
||||||
if algs.contains(constraint_alg) {
|
if let Some(alg) = constrainable.alg() {
|
||||||
|
if alg == *constraint_alg {
|
||||||
ConstraintDecision::Positive
|
ConstraintDecision::Positive
|
||||||
} else {
|
} else {
|
||||||
ConstraintDecision::Negative
|
ConstraintDecision::Negative
|
||||||
}
|
}
|
||||||
} else {
|
// If not, check that the requested alg is valid for this
|
||||||
|
// constrainable
|
||||||
|
} else if constrainable.algs().contains(constraint_alg) {
|
||||||
ConstraintDecision::Neutral
|
ConstraintDecision::Neutral
|
||||||
|
} else {
|
||||||
|
ConstraintDecision::Negative
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Constraint::Algs { constraint_algs } => {
|
Constraint::Algs { constraint_algs } => {
|
||||||
if let Some(algs) = constrainable.algs() {
|
if let Some(alg) = constrainable.alg() {
|
||||||
if algs.iter().any(|alg| constraint_algs.contains(alg)) {
|
if constraint_algs.contains(&alg) {
|
||||||
ConstraintDecision::Positive
|
ConstraintDecision::Positive
|
||||||
} else {
|
} else {
|
||||||
ConstraintDecision::Negative
|
ConstraintDecision::Negative
|
||||||
}
|
}
|
||||||
} else {
|
} else if constrainable
|
||||||
|
.algs()
|
||||||
|
.iter()
|
||||||
|
.any(|alg| constraint_algs.contains(alg))
|
||||||
|
{
|
||||||
ConstraintDecision::Neutral
|
ConstraintDecision::Neutral
|
||||||
|
} else {
|
||||||
|
ConstraintDecision::Negative
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Constraint::Kid { constraint_kid } => {
|
Constraint::Kid { constraint_kid } => {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
use super::signature::Signature;
|
use super::signature::Signature;
|
||||||
|
|
||||||
pub trait RsaHashIdentifier {
|
pub(crate) trait RsaHashIdentifier {
|
||||||
const HASH: rsa::Hash;
|
const HASH: rsa::Hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ use serde_with::{
|
|||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::constraints::Constrainable;
|
use crate::constraints::{Constrainable, Constraint, ConstraintSet};
|
||||||
|
|
||||||
pub(crate) mod private_parameters;
|
pub(crate) mod private_parameters;
|
||||||
pub(crate) mod public_parameters;
|
pub(crate) mod public_parameters;
|
||||||
@ -39,9 +39,11 @@ pub use self::{
|
|||||||
|
|
||||||
pub trait ParametersInfo {
|
pub trait ParametersInfo {
|
||||||
fn kty(&self) -> JsonWebKeyType;
|
fn kty(&self) -> JsonWebKeyType;
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg];
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An utilitary trait to figure out the [`JsonWebKeyEcEllipticCurve`] value for
|
||||||
|
/// elliptic curves
|
||||||
trait JwkEcCurve {
|
trait JwkEcCurve {
|
||||||
const CRV: JsonWebKeyEcEllipticCurve;
|
const CRV: JsonWebKeyEcEllipticCurve;
|
||||||
}
|
}
|
||||||
@ -239,12 +241,12 @@ where
|
|||||||
self.parameters.kty()
|
self.parameters.kty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn algs(&self) -> Option<Vec<JsonWebSignatureAlg>> {
|
fn algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
if let Some(alg) = self.alg {
|
self.parameters.possible_algs()
|
||||||
Some(vec![alg])
|
}
|
||||||
} else {
|
|
||||||
Some(self.parameters.possible_algs().to_vec())
|
fn alg(&self) -> Option<JsonWebSignatureAlg> {
|
||||||
}
|
self.alg
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_(&self) -> Option<JsonWebKeyUse> {
|
fn use_(&self) -> Option<JsonWebKeyUse> {
|
||||||
@ -293,6 +295,55 @@ impl<P> JsonWebKeySet<P> {
|
|||||||
pub fn new(keys: Vec<JsonWebKey<P>>) -> Self {
|
pub fn new(keys: Vec<JsonWebKey<P>>) -> Self {
|
||||||
Self { keys }
|
Self { keys }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the best key given the constraints
|
||||||
|
#[must_use]
|
||||||
|
pub fn find_key(&self, constraints: &ConstraintSet) -> Option<&JsonWebKey<P>>
|
||||||
|
where
|
||||||
|
P: ParametersInfo,
|
||||||
|
{
|
||||||
|
constraints.filter(&self.keys).pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find the list of keys which match the given constraints
|
||||||
|
#[must_use]
|
||||||
|
pub fn find_keys(&self, constraints: &ConstraintSet) -> Vec<&JsonWebKey<P>>
|
||||||
|
where
|
||||||
|
P: ParametersInfo,
|
||||||
|
{
|
||||||
|
constraints.filter(&self.keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find a key for the given algorithm. Returns `None` if no suitable key
|
||||||
|
/// was found.
|
||||||
|
#[must_use]
|
||||||
|
pub fn signing_key_for_algorithm(&self, alg: JsonWebSignatureAlg) -> Option<&JsonWebKey<P>>
|
||||||
|
where
|
||||||
|
P: ParametersInfo,
|
||||||
|
{
|
||||||
|
let constraints = ConstraintSet::new([
|
||||||
|
Constraint::alg(alg),
|
||||||
|
Constraint::use_(mas_iana::jose::JsonWebKeyUse::Sig),
|
||||||
|
]);
|
||||||
|
self.find_key(&constraints)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a list of available signing algorithms for this [`Keystore`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn available_signing_algorithms(&self) -> Vec<JsonWebSignatureAlg>
|
||||||
|
where
|
||||||
|
P: ParametersInfo,
|
||||||
|
{
|
||||||
|
let mut algs: Vec<_> = self
|
||||||
|
.keys
|
||||||
|
.iter()
|
||||||
|
.flat_map(|key| key.params().possible_algs())
|
||||||
|
.copied()
|
||||||
|
.collect();
|
||||||
|
algs.sort();
|
||||||
|
algs.dedup();
|
||||||
|
algs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P> FromIterator<JsonWebKey<P>> for JsonWebKeySet<P> {
|
impl<P> FromIterator<JsonWebKey<P>> for JsonWebKeySet<P> {
|
||||||
|
@ -87,7 +87,7 @@ impl ParametersInfo for JsonWebKeyPrivateParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
match self {
|
match self {
|
||||||
JsonWebKeyPrivateParameters::Oct(p) => p.possible_algs(),
|
JsonWebKeyPrivateParameters::Oct(p) => p.possible_algs(),
|
||||||
JsonWebKeyPrivateParameters::Rsa(p) => p.possible_algs(),
|
JsonWebKeyPrivateParameters::Rsa(p) => p.possible_algs(),
|
||||||
@ -128,7 +128,7 @@ impl ParametersInfo for OctPrivateParameters {
|
|||||||
JsonWebKeyType::Oct
|
JsonWebKeyType::Oct
|
||||||
}
|
}
|
||||||
|
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
&[
|
&[
|
||||||
JsonWebSignatureAlg::Hs256,
|
JsonWebSignatureAlg::Hs256,
|
||||||
JsonWebSignatureAlg::Hs384,
|
JsonWebSignatureAlg::Hs384,
|
||||||
@ -190,7 +190,7 @@ impl ParametersInfo for RsaPrivateParameters {
|
|||||||
JsonWebKeyType::Rsa
|
JsonWebKeyType::Rsa
|
||||||
}
|
}
|
||||||
|
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
&[
|
&[
|
||||||
JsonWebSignatureAlg::Rs256,
|
JsonWebSignatureAlg::Rs256,
|
||||||
JsonWebSignatureAlg::Rs384,
|
JsonWebSignatureAlg::Rs384,
|
||||||
@ -330,7 +330,7 @@ impl ParametersInfo for EcPrivateParameters {
|
|||||||
JsonWebKeyType::Ec
|
JsonWebKeyType::Ec
|
||||||
}
|
}
|
||||||
|
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
match self.crv {
|
match self.crv {
|
||||||
JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256],
|
JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256],
|
||||||
JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
|
JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
|
||||||
@ -471,7 +471,7 @@ impl ParametersInfo for OkpPrivateParameters {
|
|||||||
JsonWebKeyType::Okp
|
JsonWebKeyType::Okp
|
||||||
}
|
}
|
||||||
|
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
&[JsonWebSignatureAlg::EdDsa]
|
&[JsonWebSignatureAlg::EdDsa]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ impl ParametersInfo for JsonWebKeyPublicParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
match self {
|
match self {
|
||||||
JsonWebKeyPublicParameters::Rsa(p) => p.possible_algs(),
|
JsonWebKeyPublicParameters::Rsa(p) => p.possible_algs(),
|
||||||
JsonWebKeyPublicParameters::Ec(p) => p.possible_algs(),
|
JsonWebKeyPublicParameters::Ec(p) => p.possible_algs(),
|
||||||
@ -100,7 +100,7 @@ impl ParametersInfo for RsaPublicParameters {
|
|||||||
JsonWebKeyType::Rsa
|
JsonWebKeyType::Rsa
|
||||||
}
|
}
|
||||||
|
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
&[
|
&[
|
||||||
JsonWebSignatureAlg::Rs256,
|
JsonWebSignatureAlg::Rs256,
|
||||||
JsonWebSignatureAlg::Rs384,
|
JsonWebSignatureAlg::Rs384,
|
||||||
@ -147,7 +147,7 @@ impl ParametersInfo for EcPublicParameters {
|
|||||||
JsonWebKeyType::Ec
|
JsonWebKeyType::Ec
|
||||||
}
|
}
|
||||||
|
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
match self.crv {
|
match self.crv {
|
||||||
JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256],
|
JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256],
|
||||||
JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
|
JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
|
||||||
@ -172,7 +172,7 @@ impl ParametersInfo for OkpPublicParameters {
|
|||||||
JsonWebKeyType::Okp
|
JsonWebKeyType::Okp
|
||||||
}
|
}
|
||||||
|
|
||||||
fn possible_algs(&self) -> &'static [JsonWebSignatureAlg] {
|
fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
|
||||||
&[JsonWebSignatureAlg::EdDsa]
|
&[JsonWebSignatureAlg::EdDsa]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,12 @@
|
|||||||
)]
|
)]
|
||||||
#![warn(clippy::pedantic)]
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use der::{zeroize::Zeroizing, Decode};
|
use der::{zeroize::Zeroizing, Decode};
|
||||||
use mas_iana::jose::{JsonWebKeyType, JsonWebSignatureAlg};
|
use mas_iana::jose::{JsonWebKeyType, JsonWebSignatureAlg};
|
||||||
pub use mas_jose::jwk::{JsonWebKey, JsonWebKeySet};
|
pub use mas_jose::jwk::{JsonWebKey, JsonWebKeySet};
|
||||||
use mas_jose::{
|
use mas_jose::{
|
||||||
constraints::{Constraint, ConstraintSet},
|
|
||||||
jwa::{AsymmetricSigningKey, AsymmetricVerifyingKey},
|
jwa::{AsymmetricSigningKey, AsymmetricVerifyingKey},
|
||||||
jwk::{JsonWebKeyPublicParameters, ParametersInfo, PublicJsonWebKeySet},
|
jwk::{JsonWebKeyPublicParameters, ParametersInfo, PublicJsonWebKeySet},
|
||||||
};
|
};
|
||||||
@ -395,7 +394,7 @@ impl PrivateKey {
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the key is not suited for the selected algorithm
|
/// Returns an error if the key is not suited for the selected algorithm
|
||||||
pub fn verifier_for_alg(
|
pub fn verifying_key_for_alg(
|
||||||
&self,
|
&self,
|
||||||
alg: JsonWebSignatureAlg,
|
alg: JsonWebSignatureAlg,
|
||||||
) -> Result<AsymmetricVerifyingKey, WrongAlgorithmError> {
|
) -> Result<AsymmetricVerifyingKey, WrongAlgorithmError> {
|
||||||
@ -437,7 +436,7 @@ impl PrivateKey {
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the key is not suited for the selected algorithm
|
/// Returns an error if the key is not suited for the selected algorithm
|
||||||
pub fn signer_for_alg(
|
pub fn signing_key_for_alg(
|
||||||
&self,
|
&self,
|
||||||
alg: JsonWebSignatureAlg,
|
alg: JsonWebSignatureAlg,
|
||||||
) -> Result<AsymmetricSigningKey, WrongAlgorithmError> {
|
) -> Result<AsymmetricSigningKey, WrongAlgorithmError> {
|
||||||
@ -593,44 +592,12 @@ impl Keystore {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Find the best key given the constraints
|
impl Deref for Keystore {
|
||||||
#[must_use]
|
type Target = JsonWebKeySet<PrivateKey>;
|
||||||
pub fn find_key(&self, constraints: &ConstraintSet) -> Option<&JsonWebKey<PrivateKey>> {
|
|
||||||
constraints.filter(self.keys.iter()).pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find the list of keys which match the givent constraints
|
fn deref(&self) -> &Self::Target {
|
||||||
#[must_use]
|
&self.keys
|
||||||
pub fn find_keys(&self, constraints: &ConstraintSet) -> Vec<&JsonWebKey<PrivateKey>> {
|
|
||||||
constraints.filter(self.keys.iter())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find a key for the given algorithm. Returns `None` if no suitable key
|
|
||||||
/// was found.
|
|
||||||
#[must_use]
|
|
||||||
pub fn signing_key_for_algorithm(
|
|
||||||
&self,
|
|
||||||
alg: JsonWebSignatureAlg,
|
|
||||||
) -> Option<&JsonWebKey<PrivateKey>> {
|
|
||||||
let constraints = ConstraintSet::new([
|
|
||||||
Constraint::alg(alg),
|
|
||||||
Constraint::use_(mas_iana::jose::JsonWebKeyUse::Sig),
|
|
||||||
]);
|
|
||||||
self.find_key(&constraints)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a list of available signing algorithms for this [`Keystore`]
|
|
||||||
#[must_use]
|
|
||||||
pub fn available_signing_algorithms(&self) -> Vec<JsonWebSignatureAlg> {
|
|
||||||
let mut algs: Vec<_> = self
|
|
||||||
.keys
|
|
||||||
.iter()
|
|
||||||
.flat_map(|key| key.params().possible_algs())
|
|
||||||
.copied()
|
|
||||||
.collect();
|
|
||||||
algs.sort();
|
|
||||||
algs.dedup();
|
|
||||||
algs
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,18 @@ macro_rules! plain_test {
|
|||||||
let bytes = include_bytes!(concat!("./keys/", $path));
|
let bytes = include_bytes!(concat!("./keys/", $path));
|
||||||
let key = PrivateKey::load(bytes).unwrap();
|
let key = PrivateKey::load(bytes).unwrap();
|
||||||
assert!(matches!(key, PrivateKey::$kind(_)), "wrong key type");
|
assert!(matches!(key, PrivateKey::$kind(_)), "wrong key type");
|
||||||
|
|
||||||
|
let algs = key.possible_algs();
|
||||||
|
assert_ne!(algs.len(), 0);
|
||||||
|
|
||||||
|
for &alg in algs {
|
||||||
|
let header = JsonWebSignatureHeader::new(alg);
|
||||||
|
let payload = "hello";
|
||||||
|
let signer = key.signing_key_for_alg(alg).unwrap();
|
||||||
|
let jwt = Jwt::sign(header, payload, &signer).unwrap();
|
||||||
|
let verifier = key.verifying_key_for_alg(alg).unwrap();
|
||||||
|
jwt.verify(&verifier).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -45,9 +57,9 @@ macro_rules! enc_test {
|
|||||||
for &alg in algs {
|
for &alg in algs {
|
||||||
let header = JsonWebSignatureHeader::new(alg);
|
let header = JsonWebSignatureHeader::new(alg);
|
||||||
let payload = "hello";
|
let payload = "hello";
|
||||||
let signer = key.signer_for_alg(alg).unwrap();
|
let signer = key.signing_key_for_alg(alg).unwrap();
|
||||||
let jwt = Jwt::sign(header, payload, &signer).unwrap();
|
let jwt = Jwt::sign(header, payload, &signer).unwrap();
|
||||||
let verifier = key.verifier_for_alg(alg).unwrap();
|
let verifier = key.verifying_key_for_alg(alg).unwrap();
|
||||||
jwt.verify(&verifier).unwrap();
|
jwt.verify(&verifier).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user