Skip to content

Commit

Permalink
provide a cryptoki-backed CSPRNG
Browse files Browse the repository at this point in the history
Signed-off-by: Arthur Gautier <[email protected]>
  • Loading branch information
baloo committed Nov 26, 2023
1 parent ccba914 commit b00e7c5
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 0 deletions.
8 changes: 8 additions & 0 deletions cryptoki-rustcrypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use cryptoki::{
};

pub mod ecdsa;
pub mod rng;
pub mod rsa;
pub mod x509;

Expand All @@ -21,6 +22,7 @@ pub trait SessionLike {
attributes: &[AttributeType],
) -> Result<Vec<Attribute>>;
fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result<Vec<u8>>;
fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()>;
}

impl SessionLike for Session {
Expand All @@ -40,6 +42,9 @@ impl SessionLike for Session {
fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result<Vec<u8>> {
Session::sign(self, mechanism, key, data)
}
fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()> {
Session::generate_random_slice(self, random_data)
}
}

impl<'s> SessionLike for &'s Session {
Expand All @@ -59,4 +64,7 @@ impl<'s> SessionLike for &'s Session {
fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result<Vec<u8>> {
Session::sign(self, mechanism, key, data)
}
fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()> {
Session::generate_random_slice(self, random_data)
}
}
50 changes: 50 additions & 0 deletions cryptoki-rustcrypto/src/rng.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2023 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

use signature::rand_core::{CryptoRng, Error as RndError, RngCore};
use thiserror::Error;

use crate::SessionLike;

#[derive(Debug, Error)]
pub enum Error {}

/// [`Rng`] is a PKCS#11-backed CSPRNG.
pub struct Rng<S: SessionLike>(S);

// TODO(baloo): check for CKF_RNG bit flag (CK_TOKEN_INFO struct -> flags)
impl<S: SessionLike> Rng<S> {
pub fn new(session: S) -> Result<Self, Error> {
Ok(Self(session))
}
}

macro_rules! impl_next_uint {
($self:ident, $u:ty) => {{
let mut buf = <$u>::MIN.to_be_bytes();
$self.fill_bytes(&mut buf[..]);

<$u>::from_be_bytes(buf)
}};
}

impl<S: SessionLike> RngCore for Rng<S> {
fn next_u32(&mut self) -> u32 {
impl_next_uint!(self, u32)
}

fn next_u64(&mut self) -> u64 {
impl_next_uint!(self, u64)
}

fn fill_bytes(&mut self, dest: &mut [u8]) {
self.try_fill_bytes(dest)
.expect("Cryptoki provider failed to generate random");
}

fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), RndError> {
self.0.generate_random_slice(dest).map_err(RndError::new)
}
}

impl<S: SessionLike> CryptoRng for Rng<S> {}
57 changes: 57 additions & 0 deletions cryptoki-rustcrypto/tests/rng.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2023 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

mod common;

use crate::common::USER_PIN;
use common::init_pins;
use cryptoki::{session::UserType, types::AuthPin};
use cryptoki_rustcrypto::rng::Rng;
use serial_test::serial;
use signature::rand_core::{CryptoRngCore, RngCore};
use testresult::TestResult;

// This test is meant to ensure we provide [`rand_core::CryptoRngCore`].
// This is the trait consumers will use throughout the RustCrypto ecosystem
// to express interest in a CSPRNG.
#[test]
#[serial]
fn ensure_crypto_rng_core() -> TestResult {
fn just_making_sure<R: CryptoRngCore>(_r: &mut R) {
// Hi! just making sure you provide a CSPRNG.
}
let (pkcs11, slot) = init_pins();

// open a session
let session = pkcs11.open_rw_session(slot)?;

// log in the session
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;

let mut rng = Rng::new(session).unwrap();
just_making_sure(&mut rng);

Ok(())
}

#[test]
#[serial]
fn generate_random() -> TestResult {
let (pkcs11, slot) = init_pins();

// open a session
let session = pkcs11.open_rw_session(slot)?;

// log in the session
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;

let mut rng = Rng::new(session).unwrap();
rng.next_u32();
rng.next_u64();

let mut buf = vec![0; 123];
rng.fill_bytes(&mut buf);
rng.try_fill_bytes(&mut buf).unwrap();

Ok(())
}

0 comments on commit b00e7c5

Please sign in to comment.