cargo fmt
This commit is contained in:
parent
b9a3e3086f
commit
06bebeaae3
12
src/lib.rs
12
src/lib.rs
|
@ -18,17 +18,17 @@ mod crypto;
|
|||
pub mod errors;
|
||||
mod header;
|
||||
mod keys;
|
||||
mod pem_decoder;
|
||||
mod serialization;
|
||||
mod validation;
|
||||
mod pem_decoder;
|
||||
|
||||
pub use algorithms::Algorithm;
|
||||
pub use crypto::{sign, verify};
|
||||
pub use header::Header;
|
||||
pub use keys::Key;
|
||||
pub use pem_decoder::PemEncodedKey;
|
||||
pub use serialization::TokenData;
|
||||
pub use validation::Validation;
|
||||
pub use pem_decoder::PemEncodedKey;
|
||||
|
||||
use serde::de::DeserializeOwned;
|
||||
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 ..-----`
|
||||
/// and end with a `-----END ..-----`
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// use jsonwebtoken::{decode_pem, sign, verify, Algorithm};
|
||||
///
|
||||
///
|
||||
/// let pem_content = "-----BEGIN PRIVATE KEY-----
|
||||
/// MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWTFfCGljY6aw3Hrt
|
||||
/// kHmPRiazukxPLb6ilpRAewjW8nihRANCAATDskChT+Altkm9X7MI69T3IUmrQU0L
|
||||
/// 950IxEzvw/x5BMEINRMrXLBJhqzO9Bm+d6JbqA21YQmd1Kt4RzLJR1W+
|
||||
/// -----END PRIVATE KEY-----";
|
||||
///
|
||||
///
|
||||
/// // First use decode_pem from jsonwebtoken
|
||||
/// let privkey_pem = decode_pem(pem_content).unwrap();
|
||||
/// // If it decodes Ok, then you can start using it with a given algorithm
|
||||
/// 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
|
||||
/// // The same code can be used for public keys too.
|
||||
/// let encrypted = sign("hello world", privkey, Algorithm::ES256).unwrap();
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
use crate::errors::{ErrorKind, Result};
|
||||
use crate::keys::Key;
|
||||
use crate::errors::{Result, ErrorKind};
|
||||
|
||||
extern crate pem;
|
||||
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
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum PemType {
|
||||
ECPublicKey,
|
||||
ECPrivateKey,
|
||||
RSAPublicKey,
|
||||
RSAPrivateKey,
|
||||
ECPublicKey,
|
||||
ECPrivateKey,
|
||||
RSAPublicKey,
|
||||
RSAPrivateKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum PemEncodedWith {
|
||||
PKCS1,
|
||||
PKCS8,
|
||||
PKCS1,
|
||||
PKCS8,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Classification {
|
||||
EC,
|
||||
RSA,
|
||||
EC,
|
||||
RSA,
|
||||
}
|
||||
|
||||
/// The return type of a successful PEM encoded key with `decode_pem`
|
||||
|
@ -41,106 +41,101 @@ enum Classification {
|
|||
/// Documentation about these formats is at
|
||||
/// PKCS#1: https://tools.ietf.org/html/rfc8017
|
||||
/// PKCS#8: https://tools.ietf.org/html/rfc5958
|
||||
#[derive(Debug)]
|
||||
pub struct PemEncodedKey {
|
||||
content: Vec<u8>,
|
||||
asn1: Vec<simple_asn1::ASN1Block>,
|
||||
pem_type: PemType,
|
||||
encoded_with: PemEncodedWith,
|
||||
content: Vec<u8>,
|
||||
asn1: Vec<simple_asn1::ASN1Block>,
|
||||
pem_type: PemType,
|
||||
encoded_with: PemEncodedWith,
|
||||
}
|
||||
|
||||
impl PemEncodedKey {
|
||||
/// Read the PEM file for later key use
|
||||
pub fn read(input: &str) -> Result<PemEncodedKey> {
|
||||
match pem::parse(input) {
|
||||
Ok(content) => {
|
||||
let pem_contents = content.contents;
|
||||
let asn1_content = match simple_asn1::from_der(pem_contents.as_slice()) {
|
||||
Ok(asn1) => asn1,
|
||||
Err(_) => return Err(ErrorKind::InvalidKeyFormat)?,
|
||||
};
|
||||
/// Read the PEM file for later key use
|
||||
pub fn read(input: &str) -> Result<PemEncodedKey> {
|
||||
match pem::parse(input) {
|
||||
Ok(content) => {
|
||||
let pem_contents = content.contents;
|
||||
let asn1_content = match simple_asn1::from_der(pem_contents.as_slice()) {
|
||||
Ok(asn1) => asn1,
|
||||
Err(_) => return Err(ErrorKind::InvalidKeyFormat)?,
|
||||
};
|
||||
|
||||
match content.tag.as_ref() {
|
||||
// This handles a PKCS#1 RSA Private key
|
||||
"RSA PRIVATE KEY" => Ok(PemEncodedKey {
|
||||
content: pem_contents,
|
||||
asn1: asn1_content,
|
||||
pem_type: PemType::RSAPrivateKey,
|
||||
encoded_with: PemEncodedWith::PKCS1,
|
||||
}),
|
||||
"RSA PUBLIC KEY" => Ok(PemEncodedKey {
|
||||
content: pem_contents,
|
||||
asn1: asn1_content,
|
||||
pem_type: PemType::RSAPublicKey,
|
||||
encoded_with: PemEncodedWith::PKCS1,
|
||||
}),
|
||||
match content.tag.as_ref() {
|
||||
// This handles a PKCS#1 RSA Private key
|
||||
"RSA PRIVATE KEY" => Ok(PemEncodedKey {
|
||||
content: pem_contents,
|
||||
asn1: asn1_content,
|
||||
pem_type: PemType::RSAPrivateKey,
|
||||
encoded_with: PemEncodedWith::PKCS1,
|
||||
}),
|
||||
"RSA PUBLIC KEY" => Ok(PemEncodedKey {
|
||||
content: pem_contents,
|
||||
asn1: asn1_content,
|
||||
pem_type: PemType::RSAPublicKey,
|
||||
encoded_with: PemEncodedWith::PKCS1,
|
||||
}),
|
||||
|
||||
// No "EC PRIVATE KEY"
|
||||
// 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"
|
||||
// No "EC PRIVATE KEY"
|
||||
// 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"
|
||||
|
||||
// This handles PKCS#8 private keys
|
||||
"PRIVATE KEY" => {
|
||||
match classify_pem(&asn1_content) {
|
||||
Some(Classification::EC) => Ok(PemEncodedKey {
|
||||
content: pem_contents,
|
||||
asn1: asn1_content,
|
||||
pem_type: PemType::ECPrivateKey,
|
||||
encoded_with: PemEncodedWith::PKCS8,
|
||||
}),
|
||||
Some(Classification::RSA) => Ok(PemEncodedKey {
|
||||
content: pem_contents,
|
||||
asn1: asn1_content,
|
||||
pem_type: PemType::RSAPrivateKey,
|
||||
encoded_with: PemEncodedWith::PKCS8,
|
||||
}),
|
||||
_ => return Err(ErrorKind::InvalidKeyFormat)?,
|
||||
// This handles PKCS#8 private keys
|
||||
"PRIVATE KEY" => match classify_pem(&asn1_content) {
|
||||
Some(Classification::EC) => Ok(PemEncodedKey {
|
||||
content: pem_contents,
|
||||
asn1: asn1_content,
|
||||
pem_type: PemType::ECPrivateKey,
|
||||
encoded_with: PemEncodedWith::PKCS8,
|
||||
}),
|
||||
Some(Classification::RSA) => Ok(PemEncodedKey {
|
||||
content: pem_contents,
|
||||
asn1: asn1_content,
|
||||
pem_type: PemType::RSAPrivateKey,
|
||||
encoded_with: PemEncodedWith::PKCS8,
|
||||
}),
|
||||
_ => 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)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)?,
|
||||
}
|
||||
},
|
||||
Err(_) => return Err(ErrorKind::InvalidKeyFormat)?,
|
||||
}
|
||||
}
|
||||
|
||||
/// This will do the initial parsing of a PEM file.
|
||||
/// Supported tagged pems include "RSA PRIVATE KEY", "RSA PUBLIC KEY",
|
||||
/// "PRIVATE KEY", "PUBLIC KEY"
|
||||
/// PEMs with multiple tagged portions are not supported
|
||||
pub fn as_key(&self) -> Result<Key<'_>> {
|
||||
match self.encoded_with {
|
||||
PemEncodedWith::PKCS1 => Ok(Key::Der(self.content.as_slice())),
|
||||
PemEncodedWith::PKCS8 => {
|
||||
match self.pem_type {
|
||||
PemType::RSAPrivateKey => 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::ECPublicKey => Ok(Key::Pkcs8(extract_first_bitstring(&self.asn1)?)),
|
||||
/// This will do the initial parsing of a PEM file.
|
||||
/// Supported tagged pems include "RSA PRIVATE KEY", "RSA PUBLIC KEY",
|
||||
/// "PRIVATE KEY", "PUBLIC KEY"
|
||||
/// PEMs with multiple tagged portions are not supported
|
||||
pub fn as_key(&self) -> Result<Key<'_>> {
|
||||
match self.encoded_with {
|
||||
PemEncodedWith::PKCS1 => Ok(Key::Der(self.content.as_slice())),
|
||||
PemEncodedWith::PKCS8 => match self.pem_type {
|
||||
PemType::RSAPrivateKey => 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::ECPublicKey => Ok(Key::Pkcs8(extract_first_bitstring(&self.asn1)?)),
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
// It will get confusing with certificates.
|
||||
fn extract_first_bitstring(asn1: &Vec<simple_asn1::ASN1Block>) -> Result<&[u8]> {
|
||||
for asn1_entry in asn1.iter() {
|
||||
match asn1_entry {
|
||||
simple_asn1::ASN1Block::Sequence(_, entries) => {
|
||||
if let Ok(result) = extract_first_bitstring(entries) {
|
||||
return Ok(result);
|
||||
for asn1_entry in asn1.iter() {
|
||||
match asn1_entry {
|
||||
simple_asn1::ASN1Block::Sequence(_, entries) => {
|
||||
if let Ok(result) = extract_first_bitstring(entries) {
|
||||
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> {
|
||||
// These should be constant but the macro requires
|
||||
// #![feature(const_vec_new)]
|
||||
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);
|
||||
// These should be constant but the macro requires
|
||||
// #![feature(const_vec_new)]
|
||||
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);
|
||||
|
||||
for asn1_entry in asn1.iter() {
|
||||
match asn1_entry {
|
||||
simple_asn1::ASN1Block::Sequence(_, entries) => {
|
||||
if let Some(classification) = classify_pem(entries) {
|
||||
return Some(classification);
|
||||
for asn1_entry in asn1.iter() {
|
||||
match asn1_entry {
|
||||
simple_asn1::ASN1Block::Sequence(_, entries) => {
|
||||
if let Some(classification) = classify_pem(entries) {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashSet;
|
||||
use chrono::Utc;
|
||||
use serde_json::map::Map;
|
||||
use serde_json::{from_value, Value};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::algorithms::Algorithm;
|
||||
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(aud) = claims.get("aud") {
|
||||
let provided_aud: HashSet<String> = from_value(aud.clone())?;
|
||||
if provided_aud.intersection(correct_aud).count() == 0 {
|
||||
let provided_aud: HashSet<String> = from_value(aud.clone())?;
|
||||
if provided_aud.intersection(correct_aud).count() == 0 {
|
||||
return Err(new_error(ErrorKind::InvalidAudience));
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue