cargo fmt

This commit is contained in:
Vincent Prouillet 2019-11-03 12:55:36 +00:00
parent b9a3e3086f
commit 06bebeaae3
3 changed files with 135 additions and 140 deletions

View File

@ -18,17 +18,17 @@ mod crypto;
pub mod errors; pub mod errors;
mod header; mod header;
mod keys; mod keys;
mod pem_decoder;
mod serialization; mod serialization;
mod validation; mod validation;
mod pem_decoder;
pub use algorithms::Algorithm; pub use algorithms::Algorithm;
pub use crypto::{sign, verify}; pub use crypto::{sign, verify};
pub use header::Header; pub use header::Header;
pub use keys::Key; pub use keys::Key;
pub use pem_decoder::PemEncodedKey;
pub use serialization::TokenData; pub use serialization::TokenData;
pub use validation::Validation; pub use validation::Validation;
pub use pem_decoder::PemEncodedKey;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::ser::Serialize; use serde::ser::Serialize;
@ -172,21 +172,21 @@ pub fn decode_header(token: &str) -> Result<Header> {
/// ///
/// This must be a tagged PEM encoded key, tags start with `-----BEGIN ..-----` /// This must be a tagged PEM encoded key, tags start with `-----BEGIN ..-----`
/// and end with a `-----END ..-----` /// and end with a `-----END ..-----`
/// ///
/// ```rust /// ```rust
/// use jsonwebtoken::{decode_pem, sign, verify, Algorithm}; /// use jsonwebtoken::{decode_pem, sign, verify, Algorithm};
/// ///
/// let pem_content = "-----BEGIN PRIVATE KEY----- /// let pem_content = "-----BEGIN PRIVATE KEY-----
/// MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWTFfCGljY6aw3Hrt /// MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWTFfCGljY6aw3Hrt
/// kHmPRiazukxPLb6ilpRAewjW8nihRANCAATDskChT+Altkm9X7MI69T3IUmrQU0L /// kHmPRiazukxPLb6ilpRAewjW8nihRANCAATDskChT+Altkm9X7MI69T3IUmrQU0L
/// 950IxEzvw/x5BMEINRMrXLBJhqzO9Bm+d6JbqA21YQmd1Kt4RzLJR1W+ /// 950IxEzvw/x5BMEINRMrXLBJhqzO9Bm+d6JbqA21YQmd1Kt4RzLJR1W+
/// -----END PRIVATE KEY-----"; /// -----END PRIVATE KEY-----";
/// ///
/// // First use decode_pem from jsonwebtoken /// // First use decode_pem from jsonwebtoken
/// let privkey_pem = decode_pem(pem_content).unwrap(); /// let privkey_pem = decode_pem(pem_content).unwrap();
/// // If it decodes Ok, then you can start using it with a given algorithm /// // If it decodes Ok, then you can start using it with a given algorithm
/// let privkey = privkey_pem.as_key().unwrap(); /// let privkey = privkey_pem.as_key().unwrap();
/// ///
/// // When using the as_key function, you do not need to wrap in Key::Der or Key::Pkcs8 /// // When using the as_key function, you do not need to wrap in Key::Der or Key::Pkcs8
/// // The same code can be used for public keys too. /// // The same code can be used for public keys too.
/// let encrypted = sign("hello world", privkey, Algorithm::ES256).unwrap(); /// let encrypted = sign("hello world", privkey, Algorithm::ES256).unwrap();

View File

@ -1,30 +1,30 @@
use crate::errors::{ErrorKind, Result};
use crate::keys::Key; use crate::keys::Key;
use crate::errors::{Result, ErrorKind};
extern crate pem; extern crate pem;
extern crate simple_asn1; extern crate simple_asn1;
use simple_asn1::{OID, BigUint}; use simple_asn1::{BigUint, OID};
/// Supported PEM files for EC and RSA Public and Private Keys /// Supported PEM files for EC and RSA Public and Private Keys
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum PemType { enum PemType {
ECPublicKey, ECPublicKey,
ECPrivateKey, ECPrivateKey,
RSAPublicKey, RSAPublicKey,
RSAPrivateKey, RSAPrivateKey,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum PemEncodedWith { enum PemEncodedWith {
PKCS1, PKCS1,
PKCS8, PKCS8,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum Classification { enum Classification {
EC, EC,
RSA, RSA,
} }
/// The return type of a successful PEM encoded key with `decode_pem` /// The return type of a successful PEM encoded key with `decode_pem`
@ -41,106 +41,101 @@ enum Classification {
/// Documentation about these formats is at /// Documentation about these formats is at
/// PKCS#1: https://tools.ietf.org/html/rfc8017 /// PKCS#1: https://tools.ietf.org/html/rfc8017
/// PKCS#8: https://tools.ietf.org/html/rfc5958 /// PKCS#8: https://tools.ietf.org/html/rfc5958
#[derive(Debug)]
pub struct PemEncodedKey { pub struct PemEncodedKey {
content: Vec<u8>, content: Vec<u8>,
asn1: Vec<simple_asn1::ASN1Block>, asn1: Vec<simple_asn1::ASN1Block>,
pem_type: PemType, pem_type: PemType,
encoded_with: PemEncodedWith, encoded_with: PemEncodedWith,
} }
impl PemEncodedKey { impl PemEncodedKey {
/// Read the PEM file for later key use /// Read the PEM file for later key use
pub fn read(input: &str) -> Result<PemEncodedKey> { pub fn read(input: &str) -> Result<PemEncodedKey> {
match pem::parse(input) { match pem::parse(input) {
Ok(content) => { Ok(content) => {
let pem_contents = content.contents; let pem_contents = content.contents;
let asn1_content = match simple_asn1::from_der(pem_contents.as_slice()) { let asn1_content = match simple_asn1::from_der(pem_contents.as_slice()) {
Ok(asn1) => asn1, Ok(asn1) => asn1,
Err(_) => return Err(ErrorKind::InvalidKeyFormat)?, Err(_) => return Err(ErrorKind::InvalidKeyFormat)?,
}; };
match content.tag.as_ref() { match content.tag.as_ref() {
// This handles a PKCS#1 RSA Private key // This handles a PKCS#1 RSA Private key
"RSA PRIVATE KEY" => Ok(PemEncodedKey { "RSA PRIVATE KEY" => Ok(PemEncodedKey {
content: pem_contents, content: pem_contents,
asn1: asn1_content, asn1: asn1_content,
pem_type: PemType::RSAPrivateKey, pem_type: PemType::RSAPrivateKey,
encoded_with: PemEncodedWith::PKCS1, encoded_with: PemEncodedWith::PKCS1,
}), }),
"RSA PUBLIC KEY" => Ok(PemEncodedKey { "RSA PUBLIC KEY" => Ok(PemEncodedKey {
content: pem_contents, content: pem_contents,
asn1: asn1_content, asn1: asn1_content,
pem_type: PemType::RSAPublicKey, pem_type: PemType::RSAPublicKey,
encoded_with: PemEncodedWith::PKCS1, encoded_with: PemEncodedWith::PKCS1,
}), }),
// No "EC PRIVATE KEY" // No "EC PRIVATE KEY"
// https://security.stackexchange.com/questions/84327/converting-ecc-private-key-to-pkcs1-format // https://security.stackexchange.com/questions/84327/converting-ecc-private-key-to-pkcs1-format
// "there is no such thing as a "PKCS#1 format" for elliptic curve (EC) keys" // "there is no such thing as a "PKCS#1 format" for elliptic curve (EC) keys"
// This handles PKCS#8 private keys // This handles PKCS#8 private keys
"PRIVATE KEY" => { "PRIVATE KEY" => match classify_pem(&asn1_content) {
match classify_pem(&asn1_content) { Some(Classification::EC) => Ok(PemEncodedKey {
Some(Classification::EC) => Ok(PemEncodedKey { content: pem_contents,
content: pem_contents, asn1: asn1_content,
asn1: asn1_content, pem_type: PemType::ECPrivateKey,
pem_type: PemType::ECPrivateKey, encoded_with: PemEncodedWith::PKCS8,
encoded_with: PemEncodedWith::PKCS8, }),
}), Some(Classification::RSA) => Ok(PemEncodedKey {
Some(Classification::RSA) => Ok(PemEncodedKey { content: pem_contents,
content: pem_contents, asn1: asn1_content,
asn1: asn1_content, pem_type: PemType::RSAPrivateKey,
pem_type: PemType::RSAPrivateKey, encoded_with: PemEncodedWith::PKCS8,
encoded_with: PemEncodedWith::PKCS8, }),
}), _ => return Err(ErrorKind::InvalidKeyFormat)?,
_ => return Err(ErrorKind::InvalidKeyFormat)?, },
// This handles PKCS#8 public keys
"PUBLIC KEY" => match classify_pem(&asn1_content) {
Some(Classification::EC) => Ok(PemEncodedKey {
content: pem_contents,
asn1: asn1_content,
pem_type: PemType::ECPublicKey,
encoded_with: PemEncodedWith::PKCS8,
}),
Some(Classification::RSA) => Ok(PemEncodedKey {
content: pem_contents,
asn1: asn1_content,
pem_type: PemType::RSAPublicKey,
encoded_with: PemEncodedWith::PKCS8,
}),
_ => return Err(ErrorKind::InvalidKeyFormat)?,
},
// Unknown type
_ => return Err(ErrorKind::InvalidKeyFormat)?,
}
} }
} Err(_) => return Err(ErrorKind::InvalidKeyFormat)?,
// This handles PKCS#8 public keys
"PUBLIC KEY" => {
match classify_pem(&asn1_content) {
Some(Classification::EC) => Ok(PemEncodedKey {
content: pem_contents,
asn1: asn1_content,
pem_type: PemType::ECPublicKey,
encoded_with: PemEncodedWith::PKCS8,
}),
Some(Classification::RSA) => Ok(PemEncodedKey {
content: pem_contents,
asn1: asn1_content,
pem_type: PemType::RSAPublicKey,
encoded_with: PemEncodedWith::PKCS8,
}),
_ => return Err(ErrorKind::InvalidKeyFormat)?,
}
}
// Unknown type
_ => return Err(ErrorKind::InvalidKeyFormat)?,
} }
},
Err(_) => return Err(ErrorKind::InvalidKeyFormat)?,
} }
}
/// This will do the initial parsing of a PEM file. /// This will do the initial parsing of a PEM file.
/// Supported tagged pems include "RSA PRIVATE KEY", "RSA PUBLIC KEY", /// Supported tagged pems include "RSA PRIVATE KEY", "RSA PUBLIC KEY",
/// "PRIVATE KEY", "PUBLIC KEY" /// "PRIVATE KEY", "PUBLIC KEY"
/// PEMs with multiple tagged portions are not supported /// PEMs with multiple tagged portions are not supported
pub fn as_key(&self) -> Result<Key<'_>> { pub fn as_key(&self) -> Result<Key<'_>> {
match self.encoded_with { match self.encoded_with {
PemEncodedWith::PKCS1 => Ok(Key::Der(self.content.as_slice())), PemEncodedWith::PKCS1 => Ok(Key::Der(self.content.as_slice())),
PemEncodedWith::PKCS8 => { PemEncodedWith::PKCS8 => match self.pem_type {
match self.pem_type { PemType::RSAPrivateKey => Ok(Key::Der(extract_first_bitstring(&self.asn1)?)),
PemType::RSAPrivateKey => Ok(Key::Der(extract_first_bitstring(&self.asn1)?)), PemType::RSAPublicKey => Ok(Key::Der(extract_first_bitstring(&self.asn1)?)),
PemType::RSAPublicKey => Ok(Key::Der(extract_first_bitstring(&self.asn1)?)), PemType::ECPrivateKey => Ok(Key::Pkcs8(self.content.as_slice())),
PemType::ECPrivateKey => Ok(Key::Pkcs8(self.content.as_slice())), PemType::ECPublicKey => Ok(Key::Pkcs8(extract_first_bitstring(&self.asn1)?)),
PemType::ECPublicKey => Ok(Key::Pkcs8(extract_first_bitstring(&self.asn1)?)), },
} }
},
} }
}
} }
// This really just finds and returns the first bitstring or octet string // This really just finds and returns the first bitstring or octet string
@ -149,47 +144,47 @@ impl PemEncodedKey {
// Though PKCS#11 keys shouldn't have anything else. // Though PKCS#11 keys shouldn't have anything else.
// It will get confusing with certificates. // It will get confusing with certificates.
fn extract_first_bitstring(asn1: &Vec<simple_asn1::ASN1Block>) -> Result<&[u8]> { fn extract_first_bitstring(asn1: &Vec<simple_asn1::ASN1Block>) -> Result<&[u8]> {
for asn1_entry in asn1.iter() { for asn1_entry in asn1.iter() {
match asn1_entry { match asn1_entry {
simple_asn1::ASN1Block::Sequence(_, entries) => { simple_asn1::ASN1Block::Sequence(_, entries) => {
if let Ok(result) = extract_first_bitstring(entries) { if let Ok(result) = extract_first_bitstring(entries) {
return Ok(result); return Ok(result);
}
}
simple_asn1::ASN1Block::BitString(_, _, value) => {
return Ok(value.as_ref());
}
simple_asn1::ASN1Block::OctetString(_, value) => {
return Ok(value.as_ref());
}
_ => (),
} }
}
simple_asn1::ASN1Block::BitString(_, _, value) => {
return Ok(value.as_ref());
}
simple_asn1::ASN1Block::OctetString(_, value) => {
return Ok(value.as_ref());
}
_ => ()
} }
} return Err(ErrorKind::InvalidEcdsaKey)?;
return Err(ErrorKind::InvalidEcdsaKey)?
} }
fn classify_pem(asn1: &Vec<simple_asn1::ASN1Block>) -> Option<Classification> { fn classify_pem(asn1: &Vec<simple_asn1::ASN1Block>) -> Option<Classification> {
// These should be constant but the macro requires // These should be constant but the macro requires
// #![feature(const_vec_new)] // #![feature(const_vec_new)]
let ec_public_key_oid = simple_asn1::oid!(1,2,840,10045,2,1); let ec_public_key_oid = simple_asn1::oid!(1, 2, 840, 10045, 2, 1);
let rsa_public_key_oid = simple_asn1::oid!(1,2,840,113549,1,1,1); let rsa_public_key_oid = simple_asn1::oid!(1, 2, 840, 113549, 1, 1, 1);
for asn1_entry in asn1.iter() { for asn1_entry in asn1.iter() {
match asn1_entry { match asn1_entry {
simple_asn1::ASN1Block::Sequence(_, entries) => { simple_asn1::ASN1Block::Sequence(_, entries) => {
if let Some(classification) = classify_pem(entries) { if let Some(classification) = classify_pem(entries) {
return Some(classification); return Some(classification);
}
}
simple_asn1::ASN1Block::ObjectIdentifier(_, oid) => {
if oid == ec_public_key_oid {
return Some(Classification::EC);
} else if oid == rsa_public_key_oid {
return Some(Classification::RSA);
}
}
_ => {}
} }
}
simple_asn1::ASN1Block::ObjectIdentifier(_, oid) => {
if oid == ec_public_key_oid {
return Some(Classification::EC);
} else if oid == rsa_public_key_oid {
return Some(Classification::RSA);
}
}
_ => {}
} }
}
None None
} }

View File

@ -1,7 +1,7 @@
use std::collections::HashSet;
use chrono::Utc; use chrono::Utc;
use serde_json::map::Map; use serde_json::map::Map;
use serde_json::{from_value, Value}; use serde_json::{from_value, Value};
use std::collections::HashSet;
use crate::algorithms::Algorithm; use crate::algorithms::Algorithm;
use crate::errors::{new_error, ErrorKind, Result}; use crate::errors::{new_error, ErrorKind, Result};
@ -141,8 +141,8 @@ pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()>
if let Some(ref correct_aud) = options.aud { if let Some(ref correct_aud) = options.aud {
if let Some(aud) = claims.get("aud") { if let Some(aud) = claims.get("aud") {
let provided_aud: HashSet<String> = from_value(aud.clone())?; let provided_aud: HashSet<String> = from_value(aud.clone())?;
if provided_aud.intersection(correct_aud).count() == 0 { if provided_aud.intersection(correct_aud).count() == 0 {
return Err(new_error(ErrorKind::InvalidAudience)); return Err(new_error(ErrorKind::InvalidAudience));
} }
} else { } else {