Skip to content

Commit

Permalink
Merge pull request #85 from thespooler/unring-partial
Browse files Browse the repository at this point in the history
Remove ring from pkce and generator
  • Loading branch information
HeroicKatora authored Apr 13, 2020
2 parents d9b7dc3 + 1d03a47 commit 3685e1a
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 32 deletions.
4 changes: 4 additions & 0 deletions oxide-auth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ autoexamples = false
[dependencies]
base64 = "0.11"
chrono = "0.4.2"
hmac = "0.7.1"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
sha2 = "0.8.1"
subtle = "2.2.2"
rand = "0.7.3"
ring = ">=0.13,<0.15"
rmp-serde = "0.14"
url = "1.7"
Expand Down
15 changes: 7 additions & 8 deletions oxide-auth/src/code_grant/extensions/pkce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::borrow::Cow;
use primitives::grant::{GrantExtension, Value};

use base64;
use ring::digest::{SHA256, digest};
use ring::constant_time::verify_slices_are_equal;
use sha2::{Digest, Sha256};
use subtle::ConstantTimeEq;

/// Proof Key for Code Exchange by OAuth Public Clients
///
Expand Down Expand Up @@ -166,13 +166,12 @@ impl Method {
fn verify(&self, verifier: &str) -> Result<(), ()> {
match self {
Method::Plain(encoded) =>
verify_slices_are_equal(encoded.as_bytes(), verifier.as_bytes())
.map_err(|_| ()),
if encoded.as_bytes().ct_eq(verifier.as_bytes()).into() { Ok(()) } else { Err(()) },
Method::Sha256(encoded) => {
let digest = digest(&SHA256, verifier.as_bytes());
let b64digest = b64encode(digest.as_ref());
verify_slices_are_equal(encoded.as_bytes(), b64digest.as_bytes())
.map_err(|_| ())
let mut hasher = Sha256::new();
hasher.input(verifier.as_bytes());
let b64digest = b64encode(&hasher.result());
if encoded.as_bytes().ct_eq(b64digest.as_bytes()).into() { Ok(()) } else { Err(()) }
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion oxide-auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,17 @@

extern crate base64;
extern crate chrono;
extern crate url;
extern crate hmac;
extern crate rand;
extern crate ring;
extern crate rmp_serde;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate sha2;
extern crate subtle;
extern crate url;

pub mod code_grant;
pub mod endpoint;
Expand Down
56 changes: 33 additions & 23 deletions oxide-auth/src/primitives/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//! - `Assertion` cryptographically verifies the integrity of a token, trading security without
//! persistent storage for the loss of revocability. It is thus unfit for some backends, which
//! is not currently expressed in the type system or with traits.
use super::grant::{Value, Extensions, Grant};
use super::{Url, Time};
use super::scope::Scope;
Expand All @@ -18,9 +19,8 @@ use std::rc::Rc;
use std::sync::Arc;

use base64::{encode, decode};
use ring::digest::SHA256;
use ring::rand::{SystemRandom, SecureRandom};
use ring::hmac::SigningKey;
use hmac::{crypto_mac::MacResult, Mac, Hmac};
use rand::{rngs::OsRng, RngCore, thread_rng};
use rmp_serde;

/// Generic token for a specific grant.
Expand Down Expand Up @@ -49,22 +49,23 @@ pub trait TagGrant {
/// Each byte is chosen randomly from the basic `rand::thread_rng`. This generator will always
/// succeed.
pub struct RandomGenerator {
random: SystemRandom,
random: OsRng,
len: usize
}

impl RandomGenerator {
/// Generates tokens with a specific byte length.
pub fn new(length: usize) -> RandomGenerator {
RandomGenerator {
random: SystemRandom::new(),
random: OsRng {},
len: length
}
}

fn generate(&self) -> String {
let mut result = vec![0; self.len];
self.random.fill(result.as_mut_slice())
let mut rnd = self.random.clone();
rnd.try_fill_bytes(result.as_mut_slice())
.expect("Failed to generate random token");
encode(&result)
}
Expand All @@ -80,7 +81,7 @@ impl RandomGenerator {
/// signing the same grant for different uses, i.e. separating authorization from bearer grants and
/// refresh tokens.
pub struct Assertion {
secret: SigningKey,
hasher: Hmac::<sha2::Sha256>
}

/// The cryptographic suite ensuring integrity of tokens.
Expand Down Expand Up @@ -132,24 +133,24 @@ impl Assertion {
/// padding or shortening of the supplied key material may be applied in the form dictated by
/// the signature type. See the respective standards.
///
/// If future suites are added where this is not possible, his function may panic when supplied
/// If future suites are added where this is not possible, this function may panic when supplied
/// with an incorrect key length.
///
/// Currently, the implementation lacks the ability to really make use of another hasing mechanism than
/// hmac + sha256.
pub fn new(kind: AssertionKind, key: &[u8]) -> Self {
let key = match kind {
AssertionKind::HmacSha256 => SigningKey::new(&SHA256, key),
match kind {
AssertionKind::HmacSha256 => Assertion { hasher: Hmac::<sha2::Sha256>::new_varkey(key).unwrap() },
AssertionKind::__NonExhaustive => unreachable!(),
};

Assertion {
secret: key,
}
}

/// Construct an assertion instance whose tokens are only valid for the program execution.
pub fn ephemeral() -> Self {
Assertion {
secret: SigningKey::generate(&SHA256, &SystemRandom::new()).unwrap(),
}
// TODO Extract KeySize from currently selected hasher
let mut rand_bytes: [u8; 32] = [0;32];
thread_rng().fill_bytes(&mut rand_bytes);
Assertion { hasher: Hmac::<sha2::Sha256>::new_varkey(&rand_bytes).unwrap() }
}

/// Get a reference to generator for the given tag.
Expand All @@ -160,14 +161,21 @@ impl Assertion {
fn extract<'a>(&self, token: &'a str) -> Result<(Grant, String), ()> {
let decoded = decode(token).map_err(|_| ())?;
let assertion: AssertGrant = rmp_serde::from_slice(&decoded).map_err(|_| ())?;
ring::hmac::verify_with_own_key(&self.secret, &assertion.0, &assertion.1).map_err(|_| ())?;

let mut hasher = self.hasher.clone();
hasher.input(&assertion.0);
hasher.verify(assertion.1.as_slice()).map_err(|_| ())?;

let (_, serde_grant, tag): (u64, SerdeAssertionGrant, String)
= rmp_serde::from_slice(&assertion.0).map_err(|_| ())?;

Ok((serde_grant.grant(), tag))
}

fn signature(&self, data: &[u8]) -> ring::hmac::Signature {
ring::hmac::sign(&self.secret, data)
fn signature(&self, data: &[u8]) -> MacResult<<hmac::Hmac<sha2::Sha256> as Mac>::OutputSize> {
let mut hasher = self.hasher.clone();
hasher.input(data);
hasher.result()
}

fn counted_signature(&self, counter: u64, grant: &Grant)
Expand All @@ -176,14 +184,16 @@ impl Assertion {
let serde_grant = SerdeAssertionGrant::try_from(grant)?;
let tosign = rmp_serde::to_vec(&(serde_grant, counter)).unwrap();
let signature = self.signature(&tosign);
Ok(base64::encode(&signature))
Ok(base64::encode(&signature.code()))
}

fn generate_tagged(&self, counter: u64, grant: &Grant, tag: &str) -> Result<String, ()> {
let serde_grant = SerdeAssertionGrant::try_from(grant)?;
let tosign = rmp_serde::to_vec(&(counter, serde_grant, tag)).unwrap();
let signature = self.signature(&tosign);
Ok(encode(&rmp_serde::to_vec(&AssertGrant(tosign, signature.as_ref().to_vec())).unwrap()))
let signature = self.signature(&tosign);
let assert = AssertGrant(tosign, signature.code().to_vec());

Ok(encode(&rmp_serde::to_vec(&assert).unwrap()))
}
}

Expand Down

0 comments on commit 3685e1a

Please sign in to comment.