Skip to content

Commit 5260d7c

Browse files
committed
feat: add Jwk::from_decoding_key
Allow for constructing a Jwk from a decoding key. This allows it to be created from a DER encoded file, for example. This patch refactors some Jwk internals to reduce code duplication.
1 parent 53a3fc2 commit 5260d7c

1 file changed

Lines changed: 211 additions & 74 deletions

File tree

src/jwk.rs

Lines changed: 211 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
1010

1111
use crate::serialization::b64_encode;
1212
use crate::{
13-
Algorithm, EncodingKey,
13+
Algorithm, EncodingKey, DecodingKey,
14+
decoding::DecodingKeyKind,
1415
errors::{self, Error, ErrorKind},
1516
};
1617

@@ -19,12 +20,6 @@ use aws_lc_rs::{digest, signature as aws_sig};
1920
#[cfg(feature = "aws_lc_rs")]
2021
use aws_sig::KeyPair;
2122
#[cfg(feature = "rust_crypto")]
22-
use p256::{ecdsa::SigningKey as P256SigningKey, pkcs8::DecodePrivateKey};
23-
#[cfg(feature = "rust_crypto")]
24-
use p384::ecdsa::SigningKey as P384SigningKey;
25-
#[cfg(feature = "rust_crypto")]
26-
use rsa::{RsaPrivateKey, pkcs1::DecodeRsaPrivateKey, traits::PublicKeyParts};
27-
#[cfg(feature = "rust_crypto")]
2823
use sha2::{Digest, Sha256, Sha384, Sha512};
2924

3025
/// The intended usage of the public `KeyType`. This enum is serialized `untagged`
@@ -234,6 +229,25 @@ impl FromStr for KeyAlgorithm {
234229
}
235230
}
236231

232+
impl From<Algorithm> for KeyAlgorithm {
233+
fn from(algorithm: Algorithm) -> Self {
234+
match algorithm {
235+
Algorithm::HS256 => KeyAlgorithm::HS256,
236+
Algorithm::HS384 => KeyAlgorithm::HS384,
237+
Algorithm::HS512 => KeyAlgorithm::HS512,
238+
Algorithm::ES256 => KeyAlgorithm::ES256,
239+
Algorithm::ES384 => KeyAlgorithm::ES384,
240+
Algorithm::RS256 => KeyAlgorithm::RS256,
241+
Algorithm::RS384 => KeyAlgorithm::RS384,
242+
Algorithm::RS512 => KeyAlgorithm::RS512,
243+
Algorithm::PS256 => KeyAlgorithm::PS256,
244+
Algorithm::PS384 => KeyAlgorithm::PS384,
245+
Algorithm::PS512 => KeyAlgorithm::PS512,
246+
Algorithm::EdDSA => KeyAlgorithm::EdDSA,
247+
}
248+
}
249+
}
250+
237251
impl fmt::Display for KeyAlgorithm {
238252
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
239253
write!(f, "{:?}", self)
@@ -440,80 +454,141 @@ pub struct Jwk {
440454
}
441455

442456
#[cfg(feature = "aws_lc_rs")]
443-
fn extract_rsa_public_key_components(key_content: &[u8]) -> errors::Result<(Vec<u8>, Vec<u8>)> {
444-
let key_pair = aws_sig::RsaKeyPair::from_der(key_content)
445-
.map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?;
446-
let public = key_pair.public_key();
447-
let components = aws_sig::RsaPublicKeyComponents::<Vec<u8>>::from(public);
448-
Ok((components.n, components.e))
457+
mod rsa_pubkey_components {
458+
use super::*;
459+
460+
pub fn from_private_key(key_content: &[u8]) -> errors::Result<(Vec<u8>, Vec<u8>)> {
461+
let key_pair = aws_sig::RsaKeyPair::from_der(key_content)
462+
.map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?;
463+
let public = key_pair.public_key();
464+
let components = aws_sig::RsaPublicKeyComponents::<Vec<u8>>::from(public);
465+
Ok((components.n, components.e))
466+
}
467+
468+
pub fn from_public_key(key_content: &[u8]) -> errors::Result<(Vec<u8>, Vec<u8>)> {
469+
let public = aws_lc_rs::rsa::PublicKey::from_der(key_content)
470+
.map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?;
471+
472+
let components = aws_sig::RsaPublicKeyComponents::<Vec<u8>>::from(&public);
473+
Ok((components.n, components.e))
474+
}
449475
}
450476

451477
#[cfg(feature = "rust_crypto")]
452-
fn extract_rsa_public_key_components(key_content: &[u8]) -> errors::Result<(Vec<u8>, Vec<u8>)> {
453-
let private_key = RsaPrivateKey::from_pkcs1_der(key_content)
454-
.map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?;
455-
let public_key = private_key.to_public_key();
456-
Ok((public_key.n().to_bytes_be(), public_key.e().to_bytes_be()))
478+
mod rsa_pubkey_components {
479+
use super::*;
480+
use rsa::{RsaPrivateKey, RsaPublicKey, pkcs1::DecodeRsaPrivateKey, traits::PublicKeyParts};
481+
482+
pub fn from_private_key(key_content: &[u8]) -> errors::Result<(Vec<u8>, Vec<u8>)> {
483+
let private_key = RsaPrivateKey::from_pkcs1_der(key_content)
484+
.map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?;
485+
let public_key = private_key.to_public_key();
486+
Ok((public_key.n().to_bytes_be(), public_key.e().to_bytes_be()))
487+
}
488+
489+
pub fn from_public_key(key_content: &[u8]) -> errors::Result<(Vec<u8>, Vec<u8>)> {
490+
use rsa::pkcs1::DecodeRsaPublicKey;
491+
492+
let public_key = RsaPublicKey::from_pkcs1_der(key_content)
493+
.map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?;
494+
Ok((public_key.n().to_bytes_be(), public_key.e().to_bytes_be()))
495+
}
457496
}
458497

459-
#[cfg(feature = "aws_lc_rs")]
460-
fn extract_ec_public_key_coordinates(
461-
key_content: &[u8],
462-
alg: Algorithm,
498+
fn ec_components_from_public_key(
499+
pub_bytes: &[u8],
463500
) -> errors::Result<(EllipticCurve, Vec<u8>, Vec<u8>)> {
464-
use aws_lc_rs::signature::{
465-
ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED_SIGNING, EcdsaKeyPair,
466-
};
467-
468-
let (signing_alg, curve, pub_elem_bytes) = match alg {
469-
Algorithm::ES256 => (&ECDSA_P256_SHA256_FIXED_SIGNING, EllipticCurve::P256, 32),
470-
Algorithm::ES384 => (&ECDSA_P384_SHA384_FIXED_SIGNING, EllipticCurve::P384, 48),
501+
let (curve, pub_elem_bytes) = match pub_bytes.len() {
502+
65 => (EllipticCurve::P256, 32),
503+
97 => (EllipticCurve::P384, 48),
471504
_ => return Err(ErrorKind::InvalidEcdsaKey.into()),
472505
};
473506

474-
let key_pair = EcdsaKeyPair::from_pkcs8(signing_alg, key_content)
475-
.map_err(|_| ErrorKind::InvalidEcdsaKey)?;
476-
477-
let pub_bytes = key_pair.public_key().as_ref();
478507
if pub_bytes[0] != 4 {
479508
return Err(ErrorKind::InvalidEcdsaKey.into());
480509
}
481510

482511
let (x, y) = pub_bytes[1..].split_at(pub_elem_bytes);
483512
Ok((curve, x.to_vec(), y.to_vec()))
484513
}
514+
#[cfg(feature = "aws_lc_rs")]
515+
mod ec_pubkey_components {
516+
use super::*;
517+
518+
pub fn from_private_key(
519+
key_content: &[u8],
520+
alg: Algorithm,
521+
) -> errors::Result<(EllipticCurve, Vec<u8>, Vec<u8>)> {
522+
use aws_lc_rs::signature::{
523+
ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED_SIGNING, EcdsaKeyPair,
524+
};
525+
526+
let (signing_alg, curve, pub_elem_bytes) = match alg {
527+
Algorithm::ES256 => (&ECDSA_P256_SHA256_FIXED_SIGNING, EllipticCurve::P256, 32),
528+
Algorithm::ES384 => (&ECDSA_P384_SHA384_FIXED_SIGNING, EllipticCurve::P384, 48),
529+
_ => return Err(ErrorKind::InvalidEcdsaKey.into()),
530+
};
531+
532+
let key_pair = EcdsaKeyPair::from_pkcs8(signing_alg, key_content)
533+
.map_err(|_| ErrorKind::InvalidEcdsaKey)?;
534+
535+
let pub_bytes = key_pair.public_key().as_ref();
536+
if pub_bytes[0] != 4 {
537+
return Err(ErrorKind::InvalidEcdsaKey.into());
538+
}
539+
540+
let (x, y) = pub_bytes[1..].split_at(pub_elem_bytes);
541+
Ok((curve, x.to_vec(), y.to_vec()))
542+
}
543+
544+
pub fn from_public_key(
545+
pub_bytes: &[u8],
546+
) -> errors::Result<(EllipticCurve, Vec<u8>, Vec<u8>)> {
547+
ec_components_from_public_key(pub_bytes)
548+
}
549+
}
485550

486551
#[cfg(feature = "rust_crypto")]
487-
fn extract_ec_public_key_coordinates(
488-
key_content: &[u8],
489-
alg: Algorithm,
490-
) -> errors::Result<(EllipticCurve, Vec<u8>, Vec<u8>)> {
491-
match alg {
492-
Algorithm::ES256 => {
493-
let signing_key = P256SigningKey::from_pkcs8_der(key_content)
494-
.map_err(|_| ErrorKind::InvalidEcdsaKey)?;
495-
let public_key = signing_key.verifying_key();
496-
let encoded = public_key.to_encoded_point(false);
497-
match encoded.coordinates() {
498-
p256::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => {
499-
Ok((EllipticCurve::P256, x.to_vec(), y.to_vec()))
552+
mod ec_pubkey_components {
553+
use super::*;
554+
use p256::{ecdsa::SigningKey as P256SigningKey, pkcs8::DecodePrivateKey};
555+
use p384::ecdsa::SigningKey as P384SigningKey;
556+
557+
pub fn from_private_key(
558+
key_content: &[u8],
559+
alg: Algorithm,
560+
) -> errors::Result<(EllipticCurve, Vec<u8>, Vec<u8>)> {
561+
match alg {
562+
Algorithm::ES256 => {
563+
let signing_key = P256SigningKey::from_pkcs8_der(key_content)
564+
.map_err(|_| ErrorKind::InvalidEcdsaKey)?;
565+
let public_key = signing_key.verifying_key();
566+
let encoded = public_key.to_encoded_point(false);
567+
match encoded.coordinates() {
568+
p256::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => {
569+
Ok((EllipticCurve::P256, x.to_vec(), y.to_vec()))
570+
}
571+
_ => Err(ErrorKind::InvalidEcdsaKey.into()),
500572
}
501-
_ => Err(ErrorKind::InvalidEcdsaKey.into()),
502573
}
503-
}
504-
Algorithm::ES384 => {
505-
let signing_key = P384SigningKey::from_pkcs8_der(key_content)
506-
.map_err(|_| ErrorKind::InvalidEcdsaKey)?;
507-
let public_key = signing_key.verifying_key();
508-
let encoded = public_key.to_encoded_point(false);
509-
match encoded.coordinates() {
510-
p384::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => {
511-
Ok((EllipticCurve::P384, x.to_vec(), y.to_vec()))
574+
Algorithm::ES384 => {
575+
let signing_key = P384SigningKey::from_pkcs8_der(key_content)
576+
.map_err(|_| ErrorKind::InvalidEcdsaKey)?;
577+
let public_key = signing_key.verifying_key();
578+
let encoded = public_key.to_encoded_point(false);
579+
match encoded.coordinates() {
580+
p384::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => {
581+
Ok((EllipticCurve::P384, x.to_vec(), y.to_vec()))
582+
}
583+
_ => Err(ErrorKind::InvalidEcdsaKey.into()),
512584
}
513-
_ => Err(ErrorKind::InvalidEcdsaKey.into()),
514585
}
586+
_ => Err(ErrorKind::InvalidEcdsaKey.into()),
515587
}
516-
_ => Err(ErrorKind::InvalidEcdsaKey.into()),
588+
}
589+
590+
pub fn from_public_key(pub_bytes: &[u8]) -> errors::Result<(EllipticCurve, Vec<u8>, Vec<u8>)> {
591+
ec_components_from_public_key(pub_bytes)
517592
}
518593
}
519594

@@ -547,20 +622,7 @@ impl Jwk {
547622
pub fn from_encoding_key(key: &EncodingKey, alg: Algorithm) -> crate::errors::Result<Self> {
548623
Ok(Self {
549624
common: CommonParameters {
550-
key_algorithm: Some(match alg {
551-
Algorithm::HS256 => KeyAlgorithm::HS256,
552-
Algorithm::HS384 => KeyAlgorithm::HS384,
553-
Algorithm::HS512 => KeyAlgorithm::HS512,
554-
Algorithm::ES256 => KeyAlgorithm::ES256,
555-
Algorithm::ES384 => KeyAlgorithm::ES384,
556-
Algorithm::RS256 => KeyAlgorithm::RS256,
557-
Algorithm::RS384 => KeyAlgorithm::RS384,
558-
Algorithm::RS512 => KeyAlgorithm::RS512,
559-
Algorithm::PS256 => KeyAlgorithm::PS256,
560-
Algorithm::PS384 => KeyAlgorithm::PS384,
561-
Algorithm::PS512 => KeyAlgorithm::PS512,
562-
Algorithm::EdDSA => KeyAlgorithm::EdDSA,
563-
}),
625+
key_algorithm: Some(alg.into()),
564626
..Default::default()
565627
},
566628
algorithm: match key.family {
@@ -571,15 +633,15 @@ impl Jwk {
571633
})
572634
}
573635
crate::algorithms::AlgorithmFamily::Rsa => {
574-
let (n, e) = extract_rsa_public_key_components(&key.content)?;
636+
let (n, e) = rsa_pubkey_components::from_private_key(&key.content)?;
575637
AlgorithmParameters::RSA(RSAKeyParameters {
576638
key_type: RSAKeyType::RSA,
577639
n: b64_encode(n),
578640
e: b64_encode(e),
579641
})
580642
}
581643
crate::algorithms::AlgorithmFamily::Ec => {
582-
let (curve, x, y) = extract_ec_public_key_coordinates(&key.content, alg)?;
644+
let (curve, x, y) = ec_pubkey_components::from_private_key(&key.content, alg)?;
583645
AlgorithmParameters::EllipticCurve(EllipticCurveKeyParameters {
584646
key_type: EllipticCurveKeyType::EC,
585647
curve,
@@ -592,6 +654,62 @@ impl Jwk {
592654
}
593655
},
594656
})
657+
658+
}
659+
660+
pub fn from_decoding_key(key: &DecodingKey, alg: Option<Algorithm>) -> crate::errors::Result<Self> {
661+
Ok(Self {
662+
common: CommonParameters {
663+
key_algorithm: alg.map(|a| a.into()),
664+
..Default::default()
665+
},
666+
algorithm: match key.family {
667+
crate::algorithms::AlgorithmFamily::Hmac => {
668+
let secret = match &key.kind {
669+
DecodingKeyKind::SecretOrDer(secret) => secret,
670+
_ => return Err(ErrorKind::InvalidKeyFormat.into()),
671+
};
672+
673+
AlgorithmParameters::OctetKey(OctetKeyParameters {
674+
key_type: OctetKeyType::Octet,
675+
value: b64_encode(secret),
676+
})
677+
}
678+
crate::algorithms::AlgorithmFamily::Rsa => {
679+
let (n, e) = match &key.kind {
680+
DecodingKeyKind::RsaModulusExponent { n, e } => (b64_encode(n), b64_encode(e)),
681+
DecodingKeyKind::SecretOrDer(der) => {
682+
let (n, e) = rsa_pubkey_components::from_public_key(der)?;
683+
(b64_encode(n), b64_encode(e))
684+
}
685+
};
686+
687+
AlgorithmParameters::RSA(RSAKeyParameters {
688+
key_type: RSAKeyType::RSA,
689+
n,
690+
e,
691+
})
692+
}
693+
crate::algorithms::AlgorithmFamily::Ec => {
694+
let (curve, x, y) = match &key.kind {
695+
DecodingKeyKind::SecretOrDer(pub_bytes) => {
696+
ec_pubkey_components::from_public_key(pub_bytes)?
697+
}
698+
_ => return Err(ErrorKind::InvalidKeyFormat.into()),
699+
};
700+
701+
AlgorithmParameters::EllipticCurve(EllipticCurveKeyParameters {
702+
key_type: EllipticCurveKeyType::EC,
703+
curve,
704+
x: b64_encode(x),
705+
y: b64_encode(y),
706+
})
707+
},
708+
crate::algorithms::AlgorithmFamily::Ed => {
709+
unimplemented!();
710+
}
711+
},
712+
})
595713
}
596714

597715
/// Compute the thumbprint of the JWK.
@@ -669,6 +787,7 @@ mod tests {
669787
AlgorithmParameters, Jwk, JwkSet, KeyAlgorithm, OctetKeyType, RSAKeyParameters,
670788
ThumbprintHash,
671789
};
790+
use crate::{EncodingKey, DecodingKey};
672791
use crate::serialization::b64_encode;
673792

674793
#[test]
@@ -724,4 +843,22 @@ mod tests {
724843
.thumbprint(ThumbprintHash::SHA256);
725844
assert_eq!(tp.as_str(), "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs");
726845
}
846+
847+
#[test]
848+
fn check_jwk_from_decoding_key_rsa() {
849+
let enc_key = EncodingKey::from_rsa_pem(include_bytes!("../tests/rsa/private_rsa_key_pkcs8.pem")).unwrap();
850+
let dec_key = DecodingKey::from_rsa_pem(include_bytes!("../tests/rsa/public_rsa_key_pkcs8.pem")).unwrap();
851+
let expected_jwk = Jwk::from_encoding_key(&enc_key, Algorithm::RS256).unwrap();
852+
let jwk = Jwk::from_decoding_key(&dec_key, Some(Algorithm::RS256)).unwrap();
853+
assert_eq!(jwk, expected_jwk);
854+
}
855+
856+
#[test]
857+
fn check_jwk_from_decoding_key_ec() {
858+
let enc_key = EncodingKey::from_ec_pem(include_bytes!("../tests/ecdsa/private_ecdsa_key.pem")).unwrap();
859+
let dec_key = DecodingKey::from_ec_pem(include_bytes!("../tests/ecdsa/public_ecdsa_key.pem")).unwrap();
860+
let expected_jwk = Jwk::from_encoding_key(&enc_key, Algorithm::ES256).unwrap();
861+
let jwk = Jwk::from_decoding_key(&dec_key, Some(Algorithm::ES256)).unwrap();
862+
assert_eq!(jwk, expected_jwk);
863+
}
727864
}

0 commit comments

Comments
 (0)