Merge branch 'update-dependency-and-edition' into 'master'
Update dependencies, edition, remove OpenSSL, and release 0.4.3 Closes #4 See merge request lumi/sasl-rs!5
This commit is contained in:
commit
16a84f2d09
12 changed files with 99 additions and 98 deletions
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "sasl"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
authors = ["lumi <lumi@pew.im>"]
|
||||
description = "A crate for SASL authentication. Currently only does the client side."
|
||||
homepage = "https://gitlab.com/lumi/sasl-rs"
|
||||
|
|
@ -9,17 +9,19 @@ documentation = "https://docs.rs/sasl"
|
|||
readme = "README.md"
|
||||
keywords = ["sasl", "authentication"]
|
||||
license = "LGPL-3.0+"
|
||||
edition = "2018"
|
||||
|
||||
[badges]
|
||||
gitlab = { repository = "lumi/sasl-rs" }
|
||||
|
||||
[features]
|
||||
default = ["scram"]
|
||||
scram = ["openssl"]
|
||||
scram = []
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.9.1"
|
||||
|
||||
[dependencies.openssl]
|
||||
version = "0.10.7"
|
||||
optional = true
|
||||
base64 = "0.10"
|
||||
rand_os = "0.1"
|
||||
sha-1 = "0.8"
|
||||
sha2 = "0.8"
|
||||
hmac = "0.7"
|
||||
pbkdf2 = { version = "0.3", default-features = false }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Provides the SASL "ANONYMOUS" mechanism.
|
||||
|
||||
use client::Mechanism;
|
||||
use common::{Credentials, Secret};
|
||||
use crate::client::Mechanism;
|
||||
use crate::common::{Credentials, Secret};
|
||||
|
||||
/// A struct for the SASL ANONYMOUS mechanism.
|
||||
pub struct Anonymous;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Provides the SASL "PLAIN" mechanism.
|
||||
|
||||
use client::Mechanism;
|
||||
use common::{Credentials, Identity, Password, Secret};
|
||||
use crate::client::Mechanism;
|
||||
use crate::common::{Credentials, Identity, Password, Secret};
|
||||
|
||||
/// A struct for the SASL PLAIN mechanism.
|
||||
pub struct Plain {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
use base64;
|
||||
|
||||
use client::Mechanism;
|
||||
use common::scram::{generate_nonce, ScramProvider};
|
||||
use common::{parse_frame, xor, ChannelBinding, Credentials, Identity, Password, Secret};
|
||||
use crate::client::Mechanism;
|
||||
use crate::common::scram::{generate_nonce, ScramProvider};
|
||||
use crate::common::{parse_frame, xor, ChannelBinding, Credentials, Identity, Password, Secret};
|
||||
|
||||
use error::Error;
|
||||
use crate::error::Error;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
|
@ -137,8 +137,8 @@ impl<S: ScramProvider> Mechanism for Scram<S> {
|
|||
client_final_message_bare.extend(b",r=");
|
||||
client_final_message_bare.extend(server_nonce.bytes());
|
||||
let salted_password = S::derive(&self.password, &salt, iterations)?;
|
||||
let client_key = S::hmac(b"Client Key", &salted_password);
|
||||
let server_key = S::hmac(b"Server Key", &salted_password);
|
||||
let client_key = S::hmac(b"Client Key", &salted_password)?;
|
||||
let server_key = S::hmac(b"Server Key", &salted_password)?;
|
||||
let mut auth_message = Vec::new();
|
||||
auth_message.extend(initial_message);
|
||||
auth_message.push(b',');
|
||||
|
|
@ -146,9 +146,9 @@ impl<S: ScramProvider> Mechanism for Scram<S> {
|
|||
auth_message.push(b',');
|
||||
auth_message.extend(&client_final_message_bare);
|
||||
let stored_key = S::hash(&client_key);
|
||||
let client_signature = S::hmac(&auth_message, &stored_key);
|
||||
let client_signature = S::hmac(&auth_message, &stored_key)?;
|
||||
let client_proof = xor(&client_key, &client_signature);
|
||||
let server_signature = S::hmac(&auth_message, &server_key);
|
||||
let server_signature = S::hmac(&auth_message, &server_key)?;
|
||||
let mut client_final_message = Vec::new();
|
||||
client_final_message.extend(&client_final_message_bare);
|
||||
client_final_message.extend(b",p=");
|
||||
|
|
@ -189,9 +189,9 @@ impl<S: ScramProvider> Mechanism for Scram<S> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use client::mechanisms::Scram;
|
||||
use client::Mechanism;
|
||||
use common::scram::{Sha1, Sha256};
|
||||
use crate::client::mechanisms::Scram;
|
||||
use crate::client::Mechanism;
|
||||
use crate::common::scram::{Sha1, Sha256};
|
||||
|
||||
#[test]
|
||||
fn scram_sha1_works() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use common::Credentials;
|
||||
use crate::common::Credentials;
|
||||
|
||||
/// A trait which defines SASL mechanisms.
|
||||
pub trait Mechanism {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
use openssl::error::ErrorStack;
|
||||
use openssl::hash::hash;
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::pkcs5::pbkdf2_hmac;
|
||||
use openssl::pkey::PKey;
|
||||
use openssl::rand::rand_bytes;
|
||||
use openssl::sign::Signer;
|
||||
use hmac::{Hmac, Mac};
|
||||
use pbkdf2::pbkdf2;
|
||||
use rand_os::{
|
||||
rand_core::{Error as RngError, RngCore},
|
||||
OsRng,
|
||||
};
|
||||
use sha1::{Digest, Sha1 as Sha1_hash};
|
||||
use sha2::Sha256 as Sha256_hash;
|
||||
|
||||
use common::Password;
|
||||
use crate::common::Password;
|
||||
|
||||
use secret;
|
||||
use crate::secret;
|
||||
|
||||
use base64;
|
||||
|
||||
/// Generate a nonce for SCRAM authentication.
|
||||
pub fn generate_nonce() -> Result<String, ErrorStack> {
|
||||
let mut data = vec![0; 32];
|
||||
rand_bytes(&mut data)?;
|
||||
pub fn generate_nonce() -> Result<String, RngError> {
|
||||
let mut data = [0u8; 32];
|
||||
let mut rng = OsRng::new()?;
|
||||
rng.fill_bytes(&mut data);
|
||||
Ok(base64::encode(&data))
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +33,7 @@ pub trait ScramProvider {
|
|||
fn hash(data: &[u8]) -> Vec<u8>;
|
||||
|
||||
/// A function which performs an HMAC using the hash function.
|
||||
fn hmac(data: &[u8], key: &[u8]) -> Vec<u8>;
|
||||
fn hmac(data: &[u8], key: &[u8]) -> Result<Vec<u8>, String>;
|
||||
|
||||
/// A function which does PBKDF2 key derivation using the hash function.
|
||||
fn derive(data: &Password, salt: &[u8], iterations: usize) -> Result<Vec<u8>, String>;
|
||||
|
|
@ -41,7 +43,6 @@ pub trait ScramProvider {
|
|||
pub struct Sha1;
|
||||
|
||||
impl ScramProvider for Sha1 {
|
||||
// TODO: look at all these unwraps
|
||||
type Secret = secret::Pbkdf2Sha1;
|
||||
|
||||
fn name() -> &'static str {
|
||||
|
|
@ -49,28 +50,30 @@ impl ScramProvider for Sha1 {
|
|||
}
|
||||
|
||||
fn hash(data: &[u8]) -> Vec<u8> {
|
||||
hash(MessageDigest::sha1(), data).unwrap().to_vec()
|
||||
let hash = Sha1_hash::digest(data);
|
||||
let mut vec = Vec::with_capacity(Sha1_hash::output_size());
|
||||
vec.extend_from_slice(hash.as_slice());
|
||||
vec
|
||||
}
|
||||
|
||||
fn hmac(data: &[u8], key: &[u8]) -> Vec<u8> {
|
||||
let pkey = PKey::hmac(key).unwrap();
|
||||
let mut signer = Signer::new(MessageDigest::sha1(), &pkey).unwrap();
|
||||
signer.update(data).unwrap();
|
||||
signer.sign_to_vec().unwrap()
|
||||
fn hmac(data: &[u8], key: &[u8]) -> Result<Vec<u8>, String> {
|
||||
type HmacSha1 = Hmac<Sha1_hash>;
|
||||
let mut mac = match HmacSha1::new_varkey(key) {
|
||||
Ok(mac) => mac,
|
||||
Err(err) => return Err(format!("{}", err)),
|
||||
};
|
||||
mac.input(data);
|
||||
let result = mac.result();
|
||||
let mut vec = Vec::with_capacity(Sha1_hash::output_size());
|
||||
vec.extend_from_slice(result.code().as_slice());
|
||||
Ok(vec)
|
||||
}
|
||||
|
||||
fn derive(password: &Password, salt: &[u8], iterations: usize) -> Result<Vec<u8>, String> {
|
||||
match *password {
|
||||
Password::Plain(ref plain) => {
|
||||
let mut result = vec![0; 20];
|
||||
pbkdf2_hmac(
|
||||
plain.as_bytes(),
|
||||
salt,
|
||||
iterations,
|
||||
MessageDigest::sha1(),
|
||||
&mut result,
|
||||
)
|
||||
.unwrap();
|
||||
pbkdf2::<Hmac<Sha1_hash>>(plain.as_bytes(), salt, iterations, &mut result);
|
||||
Ok(result)
|
||||
}
|
||||
Password::Pbkdf2 {
|
||||
|
|
@ -104,7 +107,6 @@ impl ScramProvider for Sha1 {
|
|||
pub struct Sha256;
|
||||
|
||||
impl ScramProvider for Sha256 {
|
||||
// TODO: look at all these unwraps
|
||||
type Secret = secret::Pbkdf2Sha256;
|
||||
|
||||
fn name() -> &'static str {
|
||||
|
|
@ -112,28 +114,30 @@ impl ScramProvider for Sha256 {
|
|||
}
|
||||
|
||||
fn hash(data: &[u8]) -> Vec<u8> {
|
||||
hash(MessageDigest::sha256(), data).unwrap().to_vec()
|
||||
let hash = Sha256_hash::digest(data);
|
||||
let mut vec = Vec::with_capacity(Sha256_hash::output_size());
|
||||
vec.extend_from_slice(hash.as_slice());
|
||||
vec
|
||||
}
|
||||
|
||||
fn hmac(data: &[u8], key: &[u8]) -> Vec<u8> {
|
||||
let pkey = PKey::hmac(key).unwrap();
|
||||
let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap();
|
||||
signer.update(data).unwrap();
|
||||
signer.sign_to_vec().unwrap()
|
||||
fn hmac(data: &[u8], key: &[u8]) -> Result<Vec<u8>, String> {
|
||||
type HmacSha256 = Hmac<Sha256_hash>;
|
||||
let mut mac = match HmacSha256::new_varkey(key) {
|
||||
Ok(mac) => mac,
|
||||
Err(err) => return Err(format!("{}", err)),
|
||||
};
|
||||
mac.input(data);
|
||||
let result = mac.result();
|
||||
let mut vec = Vec::with_capacity(Sha256_hash::output_size());
|
||||
vec.extend_from_slice(result.code().as_slice());
|
||||
Ok(vec)
|
||||
}
|
||||
|
||||
fn derive(password: &Password, salt: &[u8], iterations: usize) -> Result<Vec<u8>, String> {
|
||||
match *password {
|
||||
Password::Plain(ref plain) => {
|
||||
let mut result = vec![0; 32];
|
||||
pbkdf2_hmac(
|
||||
plain.as_bytes(),
|
||||
salt,
|
||||
iterations,
|
||||
MessageDigest::sha256(),
|
||||
&mut result,
|
||||
)
|
||||
.unwrap();
|
||||
pbkdf2::<Hmac<Sha256_hash>>(plain.as_bytes(), salt, iterations, &mut result);
|
||||
Ok(result)
|
||||
}
|
||||
Password::Pbkdf2 {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
#[cfg(feature = "scram")]
|
||||
use openssl::error::ErrorStack;
|
||||
use rand_os::rand_core::Error as RngError;
|
||||
|
||||
/// A wrapper enum for things that could go wrong in this crate.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
#[cfg(feature = "scram")]
|
||||
/// An error in OpenSSL.
|
||||
OpenSslErrorStack(ErrorStack),
|
||||
/// An error while initializing the Rng.
|
||||
RngError(RngError),
|
||||
/// An error in a SASL mechanism.
|
||||
SaslError(String),
|
||||
}
|
||||
|
||||
#[cfg(feature = "scram")]
|
||||
impl From<ErrorStack> for Error {
|
||||
fn from(err: ErrorStack) -> Error {
|
||||
Error::OpenSslErrorStack(err)
|
||||
impl From<RngError> for Error {
|
||||
fn from(err: RngError) -> Error {
|
||||
Error::RngError(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,11 +163,6 @@
|
|||
//! sasl = "*"
|
||||
//! ```
|
||||
|
||||
extern crate base64;
|
||||
|
||||
#[cfg(feature = "scram")]
|
||||
extern crate openssl;
|
||||
|
||||
mod error;
|
||||
|
||||
pub mod client;
|
||||
|
|
@ -176,4 +171,4 @@ pub mod server;
|
|||
pub mod common;
|
||||
pub mod secret;
|
||||
|
||||
pub use error::Error;
|
||||
pub use crate::error::Error;
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ pub struct Pbkdf2Sha1 {
|
|||
}
|
||||
|
||||
impl Pbkdf2Sha1 {
|
||||
#[cfg(feature = "openssl")]
|
||||
#[cfg(feature = "scram")]
|
||||
pub fn derive(password: &str, salt: &[u8], iterations: usize) -> Result<Pbkdf2Sha1, String> {
|
||||
use common::scram::{ScramProvider, Sha1};
|
||||
use common::Password;
|
||||
use crate::common::scram::{ScramProvider, Sha1};
|
||||
use crate::common::Password;
|
||||
let digest = Sha1::derive(&Password::Plain(password.to_owned()), salt, iterations)?;
|
||||
Ok(Pbkdf2Sha1 {
|
||||
salt: salt.to_vec(),
|
||||
|
|
@ -54,10 +54,10 @@ pub struct Pbkdf2Sha256 {
|
|||
}
|
||||
|
||||
impl Pbkdf2Sha256 {
|
||||
#[cfg(feature = "openssl")]
|
||||
#[cfg(feature = "scram")]
|
||||
pub fn derive(password: &str, salt: &[u8], iterations: usize) -> Result<Pbkdf2Sha256, String> {
|
||||
use common::scram::{ScramProvider, Sha256};
|
||||
use common::Password;
|
||||
use crate::common::scram::{ScramProvider, Sha256};
|
||||
use crate::common::Password;
|
||||
let digest = Sha256::derive(&Password::Plain(password.to_owned()), salt, iterations)?;
|
||||
Ok(Pbkdf2Sha256 {
|
||||
salt: salt.to_vec(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use common::Identity;
|
||||
use secret;
|
||||
use server::{Mechanism, Response, Validator};
|
||||
use crate::common::Identity;
|
||||
use crate::secret;
|
||||
use crate::server::{Mechanism, Response, Validator};
|
||||
|
||||
pub struct Plain<V: Validator<secret::Plain>> {
|
||||
validator: V,
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ use std::marker::PhantomData;
|
|||
|
||||
use base64;
|
||||
|
||||
use common::scram::{generate_nonce, ScramProvider};
|
||||
use common::{parse_frame, xor, ChannelBinding, Identity};
|
||||
use secret;
|
||||
use secret::Pbkdf2Secret;
|
||||
use server::{Mechanism, Provider, Response};
|
||||
use crate::common::scram::{generate_nonce, ScramProvider};
|
||||
use crate::common::{parse_frame, xor, ChannelBinding, Identity};
|
||||
use crate::secret;
|
||||
use crate::secret::Pbkdf2Secret;
|
||||
use crate::server::{Mechanism, Provider, Response};
|
||||
|
||||
enum ScramState {
|
||||
Init,
|
||||
|
|
@ -150,8 +150,8 @@ where
|
|||
client_final_message_bare.extend(base64::encode(&cb_data).bytes());
|
||||
client_final_message_bare.extend(b",r=");
|
||||
client_final_message_bare.extend(server_nonce.bytes());
|
||||
let client_key = S::hmac(b"Client Key", &salted_password);
|
||||
let server_key = S::hmac(b"Server Key", &salted_password);
|
||||
let client_key = S::hmac(b"Client Key", &salted_password)?;
|
||||
let server_key = S::hmac(b"Server Key", &salted_password)?;
|
||||
let mut auth_message = Vec::new();
|
||||
auth_message.extend(initial_client_message);
|
||||
auth_message.extend(b",");
|
||||
|
|
@ -159,7 +159,7 @@ where
|
|||
auth_message.extend(b",");
|
||||
auth_message.extend(client_final_message_bare.clone());
|
||||
let stored_key = S::hash(&client_key);
|
||||
let client_signature = S::hmac(&auth_message, &stored_key);
|
||||
let client_signature = S::hmac(&auth_message, &stored_key)?;
|
||||
let client_proof = xor(&client_key, &client_signature);
|
||||
let sent_proof = frame.get("p").ok_or_else(|| "no proof".to_owned())?;
|
||||
let sent_proof =
|
||||
|
|
@ -167,7 +167,7 @@ where
|
|||
if client_proof != sent_proof {
|
||||
return Err("authentication failed".to_owned());
|
||||
}
|
||||
let server_signature = S::hmac(&auth_message, &server_key);
|
||||
let server_signature = S::hmac(&auth_message, &server_key)?;
|
||||
let mut buf = Vec::new();
|
||||
buf.extend(b"v=");
|
||||
buf.extend(base64::encode(&server_signature).bytes());
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use common::Identity;
|
||||
use secret::Secret;
|
||||
use crate::common::Identity;
|
||||
use crate::secret::Secret;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_validator_using_provider {
|
||||
|
|
|
|||
Loading…
Reference in a new issue