diff --git a/src/lib.rs b/src/lib.rs index 6785890..5a81b2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,4 +215,4 @@ pub fn encode_ec_public_pem(x_coordinate: &[u8]) -> Result { /// TODO pub fn encode_ec_public_der(x_coordinate: &[u8]) -> Result> { pem_encoder::encode_ec_public_der(x_coordinate) -} \ No newline at end of file +} diff --git a/src/pem_encoder.rs b/src/pem_encoder.rs index 0149259..101cef7 100644 --- a/src/pem_encoder.rs +++ b/src/pem_encoder.rs @@ -1,6 +1,6 @@ use crate::errors::{ErrorKind, Result}; -use simple_asn1::{ASN1Block, BigUint, BigInt, OID}; -use pem::{Pem}; +use pem::Pem; +use simple_asn1::{ASN1Block, BigInt, BigUint, OID}; extern crate base64; extern crate pem; @@ -35,10 +35,7 @@ pub fn encode_rsa_public_pkcs8_der(modulus: &[u8], exponent: &[u8]) -> Result Result { - Ok(pem::encode(&Pem { - contents: encode_ec_public_der(x)?, - tag: "PUBLIC KEY".to_string(), - })) + Ok(pem::encode(&Pem { contents: encode_ec_public_der(x)?, tag: "PUBLIC KEY".to_string() })) } pub fn encode_ec_public_der(x: &[u8]) -> Result> { @@ -60,12 +57,12 @@ fn encode_rsa_public_pksc8_asn1(modulus: &[u8], exponent: &[u8]) -> Result ASN1Block { ], ) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::decode_pem; + use crate::keys::Key; + use ring::{signature, signature::KeyPair}; + + #[test] + fn public_key_encoding_pkcs1() { + let privkey_pem = + decode_pem(include_str!("../tests/rsa/private_rsa_key_pkcs8.pem")).unwrap(); + let privkey = privkey_pem.as_key().unwrap(); + let ring_key = signature::RsaKeyPair::from_der(match privkey { + Key::Der(bytes) => bytes, + _ => panic!("Unexpected"), + }) + .unwrap(); + let mut modulus = vec![0]; + modulus.extend(ring_key.public_key().modulus().big_endian_without_leading_zero()); + let exponent = ring_key.public_key().exponent(); + + let public_key_pkcs1_pem = encode_rsa_public_pkcs1_pem( + modulus.as_ref(), + exponent.big_endian_without_leading_zero(), + ) + .unwrap(); + assert_eq!( + include_str!("../tests/rsa/public_rsa_key_pkcs1.pem").trim(), + public_key_pkcs1_pem.replace('\r', "").trim() + ); + + let public_key_pkcs1_der = encode_rsa_public_pkcs1_der( + modulus.as_ref(), + exponent.big_endian_without_leading_zero(), + ) + .unwrap(); + assert_eq!( + include_bytes!("../tests/rsa/public_rsa_key.der").to_vec(), + public_key_pkcs1_der + ); + } + + #[test] + fn public_key_encoding_pkcs8() { + let privkey_pem = + decode_pem(include_str!("../tests/rsa/private_rsa_key_pkcs8.pem")).unwrap(); + let privkey = privkey_pem.as_key().unwrap(); + let ring_key = signature::RsaKeyPair::from_der(match privkey { + Key::Der(bytes) => bytes, + _ => panic!("Unexpected"), + }) + .unwrap(); + let mut modulus = vec![0]; + modulus.extend(ring_key.public_key().modulus().big_endian_without_leading_zero()); + let exponent = ring_key.public_key().exponent(); + + let public_key_pkcs8 = encode_rsa_public_pkcs8_pem( + modulus.as_ref(), + exponent.big_endian_without_leading_zero(), + ) + .unwrap(); + assert_eq!( + include_str!("../tests/rsa/public_rsa_key_pkcs8.pem").trim(), + public_key_pkcs8.replace('\r', "").trim() + ); + } + + #[test] + fn public_key_encoding() { + let privkey_pem = decode_pem(include_str!("../tests/ec/private_ecdsa_key.pem")).unwrap(); + let privkey = privkey_pem.as_key().unwrap(); + let alg = &signature::ECDSA_P256_SHA256_FIXED_SIGNING; + let ring_key = signature::EcdsaKeyPair::from_pkcs8( + alg, + match privkey { + Key::Pkcs8(bytes) => bytes, + _ => panic!("Unexpected"), + }, + ) + .unwrap(); + + let public_key_pem = encode_ec_public_pem(ring_key.public_key().as_ref()).unwrap(); + assert_eq!( + include_str!("../tests/ec/public_ecdsa_key.pem").trim(), + public_key_pem.replace('\r', "").trim() + ); + + let public_key_der = encode_ec_public_der(ring_key.public_key().as_ref()).unwrap(); + // The stored ".pk8" key is just the x coordinate of the EC key + // It's not truly a pkcs8 formatted DER + // To get around that, a prepended binary specifies the EC key, EC name, + // and X coordinate length. The length is unlikely to change.. in the + // event that it does, look at the pem file (convert base64 to hex) and find + // where 0x03, 0x42 don't match up. 0x42 is the length. + let mut stored_pk8_der = vec![ + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, + 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, + ]; + stored_pk8_der.extend(include_bytes!("../tests/ec/public_ecdsa_key.pk8").to_vec()); + assert_eq!(stored_pk8_der, public_key_der); + } +} diff --git a/tests/ec/mod.rs b/tests/ec/mod.rs index d4fb16d..cc3321e 100644 --- a/tests/ec/mod.rs +++ b/tests/ec/mod.rs @@ -1,7 +1,6 @@ use chrono::Utc; -use jsonwebtoken::{decode, decode_pem, encode_ec_public_pem, encode_ec_public_der, encode, sign, verify, Algorithm, Header, Key, Validation}; +use jsonwebtoken::{decode, decode_pem, encode, sign, verify, Algorithm, Header, Key, Validation}; use serde::{Deserialize, Serialize}; -use ring::{signature, signature::KeyPair}; #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] pub struct Claims { @@ -46,30 +45,3 @@ fn round_trip_claim() { assert_eq!(my_claims, token_data.claims); assert!(token_data.header.kid.is_none()); } - -#[test] -fn public_key_encoding() { - let privkey_pem = decode_pem(include_str!("private_ecdsa_key.pem")).unwrap(); - let privkey = privkey_pem.as_key().unwrap(); - let alg = &signature::ECDSA_P256_SHA256_FIXED_SIGNING; - let ring_key = signature::EcdsaKeyPair::from_pkcs8(alg, match privkey { - Key::Pkcs8(bytes) => bytes, - _ => panic!("Unexpected") - }).unwrap(); - - let public_key_pem = encode_ec_public_pem(ring_key.public_key().as_ref()).unwrap(); - assert_eq!(include_str!("public_ecdsa_key.pem").trim(), public_key_pem.replace('\r', "").trim()); - - let public_key_der = encode_ec_public_der(ring_key.public_key().as_ref()).unwrap(); - // The stored ".pk8" key is just the x coordinate of the EC key - // It's not truly a pkcs8 formatted DER - // To get around that, a prepended binary specifies the EC key, EC name, - // and X coordinate length. The length is unlikely to change.. in the - // event that it does, look at the pem file (convert base64 to hex) and find - // where 0x03, 0x42 don't match up. 0x42 is the length. - let mut stored_pk8_der = vec![0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, - 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, - 0x07, 0x03, 0x42, 0x00]; - stored_pk8_der.extend(include_bytes!("public_ecdsa_key.pk8").to_vec()); - assert_eq!(stored_pk8_der, public_key_der); -} \ No newline at end of file diff --git a/tests/rsa/mod.rs b/tests/rsa/mod.rs index c1c3962..8fde515 100644 --- a/tests/rsa/mod.rs +++ b/tests/rsa/mod.rs @@ -1,7 +1,6 @@ use chrono::Utc; -use jsonwebtoken::{decode, decode_pem, encode_rsa_public_pkcs1_pem, encode_rsa_public_pkcs1_der, encode_rsa_public_pkcs8_pem, encode, sign, verify, Algorithm, Header, Key, Validation}; +use jsonwebtoken::{decode, decode_pem, encode, sign, verify, Algorithm, Header, Key, Validation}; use serde::{Deserialize, Serialize}; -use ring::{signature, signature::KeyPair}; const RSA_ALGORITHMS: &[Algorithm] = &[ Algorithm::RS256, @@ -130,47 +129,3 @@ fn fails_with_non_pkcs8_key_format() { let privkey = include_bytes!("private_rsa_key.der"); let _encrypted = sign("hello world", Key::Der(&privkey[..]), Algorithm::ES256).unwrap(); } - -#[test] -fn public_key_encoding_pkcs1() { - let privkey_pem = decode_pem(include_str!("private_rsa_key_pkcs8.pem")).unwrap(); - let privkey = privkey_pem.as_key().unwrap(); - let ring_key = signature::RsaKeyPair::from_der(match privkey { - Key::Der(bytes) => bytes, - _ => panic!("Unexpected") - }).unwrap(); - let mut modulus = vec!(0); - modulus.extend(ring_key.public_key().modulus().big_endian_without_leading_zero()); - let exponent = ring_key.public_key().exponent(); - - let public_key_pkcs1_pem = encode_rsa_public_pkcs1_pem( - modulus.as_ref(), - exponent.big_endian_without_leading_zero() - ).unwrap(); - assert_eq!(include_str!("public_rsa_key_pkcs1.pem").trim(), public_key_pkcs1_pem.replace('\r', "").trim()); - - let public_key_pkcs1_der = encode_rsa_public_pkcs1_der( - modulus.as_ref(), - exponent.big_endian_without_leading_zero() - ).unwrap(); - assert_eq!(include_bytes!("public_rsa_key.der").to_vec(), public_key_pkcs1_der); -} - -#[test] -fn public_key_encoding_pkcs8() { - let privkey_pem = decode_pem(include_str!("private_rsa_key_pkcs8.pem")).unwrap(); - let privkey = privkey_pem.as_key().unwrap(); - let ring_key = signature::RsaKeyPair::from_der(match privkey { - Key::Der(bytes) => bytes, - _ => panic!("Unexpected") - }).unwrap(); - let mut modulus = vec!(0); - modulus.extend(ring_key.public_key().modulus().big_endian_without_leading_zero()); - let exponent = ring_key.public_key().exponent(); - - let public_key_pkcs8 = encode_rsa_public_pkcs8_pem( - modulus.as_ref(), - exponent.big_endian_without_leading_zero() - ).unwrap(); - assert_eq!(include_str!("public_rsa_key_pkcs8.pem").trim(), public_key_pkcs8.replace('\r', "").trim()); -} \ No newline at end of file