Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace ring by argonautica, rand, hmac and sha2 #84

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions .cirrus.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
stable_task:
container:
image: rust:latest
packages_script:
- apt-get update
- apt-get install -y clang libclang-dev
cargo_cache:
folder: $CARGO_HOME/registry
fingerprint_script: cargo update && cat Cargo.lock
Expand All @@ -18,6 +21,9 @@ stable_task:
nightly_task:
container:
image: rustlang/rust:nightly
packages_script:
- apt-get update
- apt-get install -y clang libclang-dev
cargo_cache:
folder: $CARGO_HOME/registry
fingerprint_script: cargo update && cat Cargo.lock
Expand All @@ -33,12 +39,6 @@ nightly_task:
test_script: cargo test -p "$CRATE"
before_cache_script: rm -rf $CARGO_HOME/registry/index

ring_task:
container:
image: rust:latest
ring_013_script: pushd tests/ring-0.13 && cargo build -v && popd
ring_014_script: pushd tests/ring-0.14 && cargo build -v && popd

release_task:
only_if: $CIRRUS_BRANCH =~ 'release.*'
container:
Expand All @@ -48,4 +48,7 @@ release_task:
doc_task:
container:
image: rustlang/rust:nightly
packages_script:
- apt-get update
- apt-get install -y clang libclang-dev
script: cargo doc --no-deps --document-private-items --all-features
1 change: 1 addition & 0 deletions Contributors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
HeroicKatora <[email protected]> (initial author)
ParisLiakos (Paris Liakos, gotham frontend)
asonix <[email protected]> (actix 1.0 update)
TheSpooler <[email protected]>
6 changes: 5 additions & 1 deletion oxide-auth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ license = "MIT OR Apache-2.0"
autoexamples = false

[dependencies]
argonautica = "0.2.0"
base64 = "0.11"
chrono = "0.4.2"
hmac = "0.7.1"
once_cell = "1.3.1"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
ring = ">=0.13,<0.15"
sha2 = "0.8.1"
rand = "0.7.3"
rmp-serde = "0.14"
url = "1.7"

Expand Down
14 changes: 6 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,7 @@ 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};

/// Proof Key for Code Exchange by OAuth Public Clients
///
Expand Down Expand Up @@ -166,13 +165,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() == verifier.as_bytes() { 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() == b64digest.as_bytes() { Ok(()) } else { Err(()) }
HeroicKatora marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions oxide-auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,19 @@
//! [`Scopes`]: endpoint/trait.Scopes.html
#![warn(missing_docs)]

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

pub mod code_grant;
pub mod endpoint;
Expand Down
80 changes: 49 additions & 31 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,22 @@ 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 {
fn generate(&mut self) -> String {
HeroicKatora marked this conversation as resolved.
Show resolved Hide resolved
let mut result = vec![0; self.len];
self.random.fill(result.as_mut_slice())
self.random.try_fill_bytes(result.as_mut_slice())
.expect("Failed to generate random token");
encode(&result)
}
Expand All @@ -80,7 +80,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,
key: Vec<u8>
}

/// The cryptographic suite ensuring integrity of tokens.
Expand Down Expand Up @@ -132,24 +132,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 { key: key.to_vec() },
HeroicKatora marked this conversation as resolved.
Show resolved Hide resolved
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(),
}
// XXX Why 64?
HeroicKatora marked this conversation as resolved.
Show resolved Hide resolved
let mut rand_bytes: [u8; 64] = [0;64];
thread_rng().fill_bytes(&mut rand_bytes);
Assertion { key: rand_bytes.to_vec() }
}

/// Get a reference to generator for the given tag.
Expand All @@ -160,14 +160,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 hmac = Hmac::<sha2::Sha256>::new_varkey(&self.key).unwrap();
HeroicKatora marked this conversation as resolved.
Show resolved Hide resolved
hmac.input(&assertion.0);
hmac.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 hmac = Hmac::<sha2::Sha256>::new_varkey(&self.key).unwrap();
hmac.input(data);
hmac.result()
}

fn counted_signature(&self, counter: u64, grant: &Grant)
Expand All @@ -176,14 +183,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 Expand Up @@ -232,21 +241,30 @@ impl TagGrant for RandomGenerator {
}
}

impl<'a> TagGrant for &'a RandomGenerator {
fn tag(&mut self, _: u64, _: &Grant) -> Result<String, ()> {
Ok(self.generate())
}
}
// impl<'a> TagGrant for &'a RandomGenerator {
// fn tag(&mut self, _: u64, _: &Grant) -> Result<String, ()> {
// // Ok(self.generate())
// Err(())
// }
// }

impl TagGrant for Rc<RandomGenerator> {
fn tag(&mut self, _: u64, _: &Grant) -> Result<String, ()> {
Ok(self.generate())
if let Some(rng) = Rc::get_mut(self) {
Ok(rng.generate())
} else {
Err(())
HeroicKatora marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

impl TagGrant for Arc<RandomGenerator> {
fn tag(&mut self, _: u64, _: &Grant) -> Result<String, ()> {
Ok(self.generate())
if let Some(rng) = Arc::get_mut(self) {
Ok(rng.generate())
} else {
Err(())
}
}
}

Expand Down
Loading