Enable remote OPRF seed support (#373)
This commit is contained in:
+12
-12
@@ -23,20 +23,20 @@ use crate::key_exchange::tripledh::DiffieHellman;
|
|||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde::Deserialize, serde::Serialize),
|
derive(serde::Deserialize, serde::Serialize),
|
||||||
serde(bound(
|
serde(bound(
|
||||||
deserialize = "S: serde::Deserialize<'de>",
|
deserialize = "SK: serde::Deserialize<'de>",
|
||||||
serialize = "S: serde::Serialize"
|
serialize = "SK: serde::Serialize"
|
||||||
))
|
))
|
||||||
)]
|
)]
|
||||||
#[derive_where(Clone)]
|
#[derive_where(Clone)]
|
||||||
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk, S)]
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk, SK)]
|
||||||
pub struct KeyPair<KG: KeGroup, S: Clone = PrivateKey<KG>> {
|
pub struct KeyPair<KG: KeGroup, SK: Clone = PrivateKey<KG>> {
|
||||||
pk: PublicKey<KG>,
|
pk: PublicKey<KG>,
|
||||||
sk: S,
|
sk: SK,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<KG: KeGroup, S: Clone> KeyPair<KG, S> {
|
impl<KG: KeGroup, SK: Clone> KeyPair<KG, SK> {
|
||||||
/// Creates a new [`KeyPair`] from the given keys.
|
/// Creates a new [`KeyPair`] from the given keys.
|
||||||
pub fn new(sk: S, pk: PublicKey<KG>) -> Self {
|
pub fn new(sk: SK, pk: PublicKey<KG>) -> Self {
|
||||||
Self { pk, sk }
|
Self { pk, sk }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ impl<KG: KeGroup, S: Clone> KeyPair<KG, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The private key component
|
/// The private key component
|
||||||
pub fn private(&self) -> &S {
|
pub fn private(&self) -> &SK {
|
||||||
&self.sk
|
&self.sk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,9 +171,9 @@ impl<'de, KG: KeGroup> serde::Deserialize<'de> for PrivateKey<KG> {
|
|||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl<KG: KeGroup> serde::Serialize for PrivateKey<KG> {
|
impl<KG: KeGroup> serde::Serialize for PrivateKey<KG> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<SK>(&self, serializer: SK) -> Result<SK::Ok, SK::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
SK: serde::Serializer,
|
||||||
{
|
{
|
||||||
KG::serialize_sk(self.0).serialize(serializer)
|
KG::serialize_sk(self.0).serialize(serializer)
|
||||||
}
|
}
|
||||||
@@ -217,9 +217,9 @@ impl<'de, KG: KeGroup> serde::Deserialize<'de> for PublicKey<KG> {
|
|||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl<KG: KeGroup> serde::Serialize for PublicKey<KG> {
|
impl<KG: KeGroup> serde::Serialize for PublicKey<KG> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<SK>(&self, serializer: SK) -> Result<SK::Ok, SK::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
SK: serde::Serializer,
|
||||||
{
|
{
|
||||||
KG::serialize_pk(self.0).serialize(serializer)
|
KG::serialize_pk(self.0).serialize(serializer)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1192,7 +1192,7 @@ pub use crate::messages::{
|
|||||||
pub use crate::opaque::{
|
pub use crate::opaque::{
|
||||||
ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult, ClientLoginStartResult,
|
ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult, ClientLoginStartResult,
|
||||||
ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationFinishResult,
|
ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationFinishResult,
|
||||||
ClientRegistrationStartResult, Identifiers, ServerLogin, ServerLoginFinishResult,
|
ClientRegistrationStartResult, Identifiers, KeyMaterialInfo, ServerLogin,
|
||||||
ServerLoginStartParameters, ServerLoginStartResult, ServerRegistration, ServerRegistrationLen,
|
ServerLoginFinishResult, ServerLoginStartParameters, ServerLoginStartResult,
|
||||||
ServerRegistrationStartResult, ServerSetup,
|
ServerRegistration, ServerRegistrationLen, ServerRegistrationStartResult, ServerSetup,
|
||||||
};
|
};
|
||||||
|
|||||||
+9
-9
@@ -115,21 +115,21 @@ pub struct CredentialRequest<CS: CipherSuite> {
|
|||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde::Deserialize, serde::Serialize),
|
derive(serde::Deserialize, serde::Serialize),
|
||||||
serde(bound(
|
serde(bound(
|
||||||
deserialize = "S: serde::Deserialize<'de>, <CS::KeyExchange as KeyExchange<OprfHash<CS>, \
|
deserialize = "SK: serde::Deserialize<'de>, <CS::KeyExchange as KeyExchange<OprfHash<CS>, \
|
||||||
CS::KeGroup>>::KE2Builder: serde::Deserialize<'de>",
|
CS::KeGroup>>::KE2Builder: serde::Deserialize<'de>",
|
||||||
serialize = "S: serde::Serialize, <CS::KeyExchange as KeyExchange<OprfHash<CS>, \
|
serialize = "SK: serde::Serialize, <CS::KeyExchange as KeyExchange<OprfHash<CS>, \
|
||||||
CS::KeGroup>>::KE2Builder: serde::Serialize"
|
CS::KeGroup>>::KE2Builder: serde::Serialize"
|
||||||
))
|
))
|
||||||
)]
|
)]
|
||||||
#[derive_where(Clone)]
|
#[derive_where(Clone)]
|
||||||
#[derive_where(
|
#[derive_where(
|
||||||
Debug, Eq, PartialEq;
|
Debug, Eq, PartialEq;
|
||||||
S,
|
SK,
|
||||||
voprf::EvaluationElement<CS::OprfCs>,
|
voprf::EvaluationElement<CS::OprfCs>,
|
||||||
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Builder,
|
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Builder,
|
||||||
)]
|
)]
|
||||||
pub struct ServerLoginBuilder<CS: CipherSuite, S: Clone> {
|
pub struct ServerLoginBuilder<CS: CipherSuite, SK: Clone> {
|
||||||
pub(crate) server_s_sk: S,
|
pub(crate) server_s_sk: SK,
|
||||||
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
|
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
|
||||||
pub(crate) masking_nonce: Zeroizing<GenericArray<u8, NonceLen>>,
|
pub(crate) masking_nonce: Zeroizing<GenericArray<u8, NonceLen>>,
|
||||||
pub(crate) masked_response: MaskedResponse<CS>,
|
pub(crate) masked_response: MaskedResponse<CS>,
|
||||||
@@ -138,7 +138,7 @@ pub struct ServerLoginBuilder<CS: CipherSuite, S: Clone> {
|
|||||||
pub(crate) ke2_builder: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Builder,
|
pub(crate) ke2_builder: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Builder,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS: CipherSuite, S: Clone> ServerLoginBuilder<CS, S> {
|
impl<CS: CipherSuite, SK: Clone> ServerLoginBuilder<CS, SK> {
|
||||||
/// The returned data here has to be processed and the result given as an
|
/// The returned data here has to be processed and the result given as an
|
||||||
/// input to [`ServerLoginBuilder::build()`]. To understand what kind of
|
/// input to [`ServerLoginBuilder::build()`]. To understand what kind of
|
||||||
/// output is expected here and how to process it, refer to the
|
/// output is expected here and how to process it, refer to the
|
||||||
@@ -150,7 +150,7 @@ impl<CS: CipherSuite, S: Clone> ServerLoginBuilder<CS, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The handle to the corresponding [`ServerSetup`]s private key.
|
/// The handle to the corresponding [`ServerSetup`]s private key.
|
||||||
pub fn private_key(&self) -> &S {
|
pub fn private_key(&self) -> &SK {
|
||||||
&self.server_s_sk
|
&self.server_s_sk
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,9 +325,9 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates a dummy instance used for faking a [CredentialResponse]
|
// Creates a dummy instance used for faking a [CredentialResponse]
|
||||||
pub(crate) fn dummy<R: RngCore + CryptoRng, S: Clone>(
|
pub(crate) fn dummy<R: RngCore + CryptoRng, SK: Clone, OS: Clone>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
server_setup: &ServerSetup<CS, S>,
|
server_setup: &ServerSetup<CS, SK, OS>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut masking_key = Output::<OprfHash<CS>>::default();
|
let mut masking_key = Output::<OprfHash<CS>>::default();
|
||||||
rng.fill_bytes(&mut masking_key);
|
rng.fill_bytes(&mut masking_key);
|
||||||
|
|||||||
+208
-69
@@ -11,7 +11,7 @@
|
|||||||
use core::ops::{Add, Deref};
|
use core::ops::{Add, Deref};
|
||||||
|
|
||||||
use derive_where::derive_where;
|
use derive_where::derive_where;
|
||||||
use digest::Output;
|
use digest::{Output, OutputSizeUser};
|
||||||
use generic_array::sequence::Concat;
|
use generic_array::sequence::Concat;
|
||||||
use generic_array::typenum::{Sum, Unsigned, U2};
|
use generic_array::typenum::{Sum, Unsigned, U2};
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
@@ -60,15 +60,19 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8; 20] = b"OPAQUE-DeriveKeyPair";
|
|||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde::Deserialize, serde::Serialize),
|
derive(serde::Deserialize, serde::Serialize),
|
||||||
serde(bound(
|
serde(bound(
|
||||||
deserialize = "S: serde::Deserialize<'de>",
|
deserialize = "SK: serde::Deserialize<'de>, OS: serde::Deserialize<'de>",
|
||||||
serialize = "S: serde::Serialize"
|
serialize = "SK: serde::Serialize, OS: serde::Serialize"
|
||||||
))
|
))
|
||||||
)]
|
)]
|
||||||
#[derive_where(Clone)]
|
#[derive_where(Clone)]
|
||||||
#[derive_where(Debug, Eq, PartialEq; <CS::KeGroup as KeGroup>::Pk, <CS::KeGroup as KeGroup>::Sk, S)]
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::KeGroup as KeGroup>::Pk, <CS::KeGroup as KeGroup>::Sk, SK, OS)]
|
||||||
pub struct ServerSetup<CS: CipherSuite, S: Clone = PrivateKey<<CS as CipherSuite>::KeGroup>> {
|
pub struct ServerSetup<
|
||||||
oprf_seed: Zeroizing<Output<OprfHash<CS>>>,
|
CS: CipherSuite,
|
||||||
keypair: KeyPair<CS::KeGroup, S>,
|
SK: Clone = PrivateKey<<CS as CipherSuite>::KeGroup>,
|
||||||
|
OS: Clone = Zeroizing<Output<OprfHash<CS>>>,
|
||||||
|
> {
|
||||||
|
oprf_seed: OS,
|
||||||
|
keypair: KeyPair<CS::KeGroup, SK>,
|
||||||
pub(crate) fake_keypair: KeyPair<CS::KeGroup>,
|
pub(crate) fake_keypair: KeyPair<CS::KeGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,10 +166,85 @@ impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<CS::KeGroup>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Length of [`ServerSetup`] in bytes for serialization.
|
/// Length of [`ServerSetup`] in bytes for serialization.
|
||||||
pub type ServerSetupLen<CS: CipherSuite, S: PrivateKeySerialization<CS::KeGroup>> =
|
pub type ServerSetupLen<
|
||||||
Sum<Sum<OutputSize<OprfHash<CS>>, S::Len>, <CS::KeGroup as KeGroup>::SkLen>;
|
CS: CipherSuite,
|
||||||
|
SK: PrivateKeySerialization<CS::KeGroup>,
|
||||||
|
OS: OprfSeedSerialization<OprfHash<CS>, SK::Error>,
|
||||||
|
> = Sum<Sum<OS::Len, SK::Len>, <CS::KeGroup as KeGroup>::SkLen>;
|
||||||
|
|
||||||
impl<CS: CipherSuite, S: Clone> ServerSetup<CS, S> {
|
impl<CS: CipherSuite, SK: Clone, OS: Clone> ServerSetup<CS, SK, OS> {
|
||||||
|
/// Create [`ServerSetup`] with the given keypair and OPRF seed.
|
||||||
|
///
|
||||||
|
/// This function should not be used to restore a previously-existing
|
||||||
|
/// instance of [`ServerSetup`]. Instead, use [`ServerSetup::serialize`] and
|
||||||
|
/// [`ServerSetup::deserialize`] for this purpose.
|
||||||
|
pub fn new_with_key_pair_and_seed<R: CryptoRng + RngCore>(
|
||||||
|
rng: &mut R,
|
||||||
|
keypair: KeyPair<CS::KeGroup, SK>,
|
||||||
|
oprf_seed: OS,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
oprf_seed,
|
||||||
|
keypair,
|
||||||
|
fake_keypair: KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(rng),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The information required to generate the key material for
|
||||||
|
/// [`ServerRegistration::start_with_key_material()`] and
|
||||||
|
/// [`ServerLogin::builder_with_key_material()`].
|
||||||
|
pub fn key_material_info<'ci>(
|
||||||
|
&self,
|
||||||
|
credential_identifier: &'ci [u8],
|
||||||
|
) -> KeyMaterialInfo<'ci, OS> {
|
||||||
|
KeyMaterialInfo {
|
||||||
|
ikm: self.oprf_seed.clone(),
|
||||||
|
info: [credential_identifier, STR_OPRF_KEY],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialization into bytes
|
||||||
|
pub fn serialize(&self) -> GenericArray<u8, ServerSetupLen<CS, SK, OS>>
|
||||||
|
where
|
||||||
|
SK: PrivateKeySerialization<CS::KeGroup>,
|
||||||
|
OS: OprfSeedSerialization<OprfHash<CS>, SK::Error>,
|
||||||
|
// ServerSetup: Hash + KeSk + KeSk
|
||||||
|
OS::Len: Add<SK::Len>,
|
||||||
|
Sum<OS::Len, SK::Len>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::SkLen>,
|
||||||
|
ServerSetupLen<CS, SK, OS>: ArrayLength<u8>,
|
||||||
|
{
|
||||||
|
self.oprf_seed
|
||||||
|
.serialize()
|
||||||
|
.concat(SK::serialize_key_pair(&self.keypair))
|
||||||
|
.concat(self.fake_keypair.private().serialize())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialization from bytes
|
||||||
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError<SK::Error>>
|
||||||
|
where
|
||||||
|
SK: PrivateKeySerialization<CS::KeGroup>,
|
||||||
|
OS: OprfSeedSerialization<OprfHash<CS>, SK::Error>,
|
||||||
|
{
|
||||||
|
let seed_len = OS::Len::USIZE;
|
||||||
|
let key_len = <CS::KeGroup as KeGroup>::SkLen::USIZE;
|
||||||
|
let checked_slice = check_slice_size(input, seed_len + key_len + key_len, "server_setup")
|
||||||
|
.map_err(ProtocolError::into_custom)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
oprf_seed: OS::deserialize(&checked_slice[..seed_len])?,
|
||||||
|
keypair: SK::deserialize_key_pair(&checked_slice[seed_len..seed_len + key_len])?,
|
||||||
|
fake_keypair: PrivateKey::deserialize_key_pair(&checked_slice[seed_len + key_len..])
|
||||||
|
.map_err(ProtocolError::into_custom)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the keypair
|
||||||
|
pub fn keypair(&self) -> &KeyPair<CS::KeGroup, SK> {
|
||||||
|
&self.keypair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<CS: CipherSuite, SK: Clone> ServerSetup<CS, SK> {
|
||||||
/// Create [`ServerSetup`] with the given keypair
|
/// Create [`ServerSetup`] with the given keypair
|
||||||
///
|
///
|
||||||
/// This function should not be used to restore a previously-existing
|
/// This function should not be used to restore a previously-existing
|
||||||
@@ -173,7 +252,7 @@ impl<CS: CipherSuite, S: Clone> ServerSetup<CS, S> {
|
|||||||
/// [`ServerSetup::deserialize`] for this purpose.
|
/// [`ServerSetup::deserialize`] for this purpose.
|
||||||
pub fn new_with_key_pair<R: CryptoRng + RngCore>(
|
pub fn new_with_key_pair<R: CryptoRng + RngCore>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
keypair: KeyPair<CS::KeGroup, S>,
|
keypair: KeyPair<CS::KeGroup, SK>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut oprf_seed = GenericArray::default();
|
let mut oprf_seed = GenericArray::default();
|
||||||
rng.fill_bytes(&mut oprf_seed);
|
rng.fill_bytes(&mut oprf_seed);
|
||||||
@@ -184,46 +263,48 @@ impl<CS: CipherSuite, S: Clone> ServerSetup<CS, S> {
|
|||||||
fake_keypair: KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(rng),
|
fake_keypair: KeyPair::<CS::KeGroup>::generate_random::<CS::OprfCs, _>(rng),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait to facilitate
|
||||||
|
/// [`ServerSetup::de/serialize`](crate::ServerSetup::serialize).
|
||||||
|
pub trait OprfSeedSerialization<H, E>: Sized {
|
||||||
|
/// Serialization size in bytes.
|
||||||
|
type Len: ArrayLength<u8>;
|
||||||
|
|
||||||
/// Serialization into bytes
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> GenericArray<u8, ServerSetupLen<CS, S>>
|
fn serialize(&self) -> GenericArray<u8, Self::Len>;
|
||||||
where
|
|
||||||
S: PrivateKeySerialization<CS::KeGroup>,
|
|
||||||
// ServerSetup: Hash + KeSk + KeSk
|
|
||||||
OutputSize<OprfHash<CS>>: Add<S::Len>,
|
|
||||||
Sum<OutputSize<OprfHash<CS>>, S::Len>:
|
|
||||||
ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::SkLen>,
|
|
||||||
ServerSetupLen<CS, S>: ArrayLength<u8>,
|
|
||||||
{
|
|
||||||
self.oprf_seed
|
|
||||||
.deref()
|
|
||||||
.clone()
|
|
||||||
.concat(S::serialize_key_pair(&self.keypair))
|
|
||||||
.concat(self.fake_keypair.private().serialize())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deserialization from bytes
|
/// Deserialization from bytes
|
||||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError<S::Error>>
|
fn deserialize(input: &[u8]) -> Result<Self, ProtocolError<E>>;
|
||||||
where
|
}
|
||||||
S: PrivateKeySerialization<CS::KeGroup>,
|
|
||||||
{
|
impl<H: OutputSizeUser, E> OprfSeedSerialization<H, E> for Zeroizing<Output<H>> {
|
||||||
let seed_len = OutputSize::<OprfHash<CS>>::USIZE;
|
type Len = H::OutputSize;
|
||||||
let key_len = <CS::KeGroup as KeGroup>::SkLen::USIZE;
|
|
||||||
let checked_slice = check_slice_size(input, seed_len + key_len + key_len, "server_setup")
|
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||||
|
self.deref().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(input: &[u8]) -> Result<Self, ProtocolError<E>> {
|
||||||
|
check_slice_size(input, H::OutputSize::USIZE, "oprf_seed")
|
||||||
.map_err(ProtocolError::into_custom)?;
|
.map_err(ProtocolError::into_custom)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Zeroizing::new(GenericArray::clone_from_slice(input)))
|
||||||
oprf_seed: Zeroizing::new(GenericArray::clone_from_slice(&checked_slice[..seed_len])),
|
|
||||||
keypair: S::deserialize_key_pair(&checked_slice[seed_len..seed_len + key_len])?,
|
|
||||||
fake_keypair: PrivateKey::deserialize_key_pair(&checked_slice[seed_len + key_len..])
|
|
||||||
.map_err(ProtocolError::into_custom)?,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the keypair
|
/// The information required to generate the key material for
|
||||||
pub fn keypair(&self) -> &KeyPair<CS::KeGroup, S> {
|
/// [`ServerRegistration::start_with_key_material()`] and
|
||||||
&self.keypair
|
/// [`ServerLogin::builder_with_key_material()`].
|
||||||
}
|
///
|
||||||
|
/// Use an HKDF, with the input key material [`ikm`](Self::ikm), expand
|
||||||
|
/// operation with [`info`](Self::info) with an output length
|
||||||
|
/// of [`CS::OprfCs::ScalarLen`](Group::ScalarLen).
|
||||||
|
pub struct KeyMaterialInfo<'ci, OS: Clone> {
|
||||||
|
/// Input key material for the HKDF.
|
||||||
|
pub ikm: OS,
|
||||||
|
/// Info for the HKDF expand operation.
|
||||||
|
pub info: [&'ci [u8]; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registration
|
// Registration
|
||||||
@@ -370,14 +451,16 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
|
|||||||
Ok(Self(RegistrationUpload::deserialize(input)?))
|
Ok(Self(RegistrationUpload::deserialize(input)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// From the client's "blinded" password, returns a response to be sent back
|
/// Create a [`RegistrationResponse`] with a remote OPRF seed. To generate
|
||||||
/// to the client, as well as a [`ServerRegistration`]
|
/// the `key_material` see [`ServerSetup::key_material_info()`].
|
||||||
pub fn start<S: Clone>(
|
///
|
||||||
server_setup: &ServerSetup<CS, S>,
|
/// See [`ServerRegistration::start()`] for the regular path.
|
||||||
|
pub fn start_with_key_material<SK: Clone, OS: Clone>(
|
||||||
|
server_setup: &ServerSetup<CS, SK, OS>,
|
||||||
|
key_material: GenericArray<u8, <OprfGroup<CS> as Group>::ScalarLen>,
|
||||||
message: RegistrationRequest<CS>,
|
message: RegistrationRequest<CS>,
|
||||||
credential_identifier: &[u8],
|
|
||||||
) -> Result<ServerRegistrationStartResult<CS>, ProtocolError> {
|
) -> Result<ServerRegistrationStartResult<CS>, ProtocolError> {
|
||||||
let oprf_key = oprf_key_from_seed::<CS>(&server_setup.oprf_seed, credential_identifier)?;
|
let oprf_key = oprf_key_from_key_material::<CS>(key_material)?;
|
||||||
|
|
||||||
let server = voprf::OprfServer::new_with_key(&oprf_key)?;
|
let server = voprf::OprfServer::new_with_key(&oprf_key)?;
|
||||||
let evaluation_element = server.blind_evaluate(&message.blinded_element);
|
let evaluation_element = server.blind_evaluate(&message.blinded_element);
|
||||||
@@ -385,13 +468,29 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
|
|||||||
Ok(ServerRegistrationStartResult {
|
Ok(ServerRegistrationStartResult {
|
||||||
message: RegistrationResponse {
|
message: RegistrationResponse {
|
||||||
evaluation_element,
|
evaluation_element,
|
||||||
server_s_pk: server_setup.keypair.public().clone(),
|
server_s_pk: server_setup.keypair().public().clone(),
|
||||||
},
|
},
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
oprf_key,
|
oprf_key,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// From the client's "blinded" password, returns a response to be sent back
|
||||||
|
/// to the client, as well as a [`ServerRegistration`]
|
||||||
|
pub fn start<SK: Clone>(
|
||||||
|
server_setup: &ServerSetup<CS, SK>,
|
||||||
|
message: RegistrationRequest<CS>,
|
||||||
|
credential_identifier: &[u8],
|
||||||
|
) -> Result<ServerRegistrationStartResult<CS>, ProtocolError> {
|
||||||
|
let KeyMaterialInfo {
|
||||||
|
ikm: oprf_seed,
|
||||||
|
info,
|
||||||
|
} = server_setup.key_material_info(credential_identifier);
|
||||||
|
let key_material = oprf_key_material::<CS>(&oprf_seed, &info)?;
|
||||||
|
|
||||||
|
Self::start_with_key_material(server_setup, key_material, message)
|
||||||
|
}
|
||||||
|
|
||||||
/// From the client's cryptographic identifiers, fully populates and returns
|
/// From the client's cryptographic identifiers, fully populates and returns
|
||||||
/// a [`ServerRegistration`]
|
/// a [`ServerRegistration`]
|
||||||
pub fn finish(message: RegistrationUpload<CS>) -> Self {
|
pub fn finish(message: RegistrationUpload<CS>) -> Self {
|
||||||
@@ -399,9 +498,9 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates a dummy instance used for faking a [CredentialResponse]
|
// Creates a dummy instance used for faking a [CredentialResponse]
|
||||||
pub(crate) fn dummy<R: RngCore + CryptoRng, S: Clone>(
|
pub(crate) fn dummy<R: RngCore + CryptoRng, SK: Clone, S: Clone>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
server_setup: &ServerSetup<CS, S>,
|
server_setup: &ServerSetup<CS, SK, S>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(RegistrationUpload::dummy(rng, server_setup))
|
Self(RegistrationUpload::dummy(rng, server_setup))
|
||||||
}
|
}
|
||||||
@@ -598,20 +697,23 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a [`ServerLoginBuilder`] to use with a remote private key.
|
/// Create a [`ServerLoginBuilder`] with a remote OPRF seed and private key.
|
||||||
|
/// To generate the `key_material` see
|
||||||
|
/// [`ServerSetup::key_material_info()`].
|
||||||
///
|
///
|
||||||
/// See [`ServerLogin::start()`] for the regular path.
|
/// See [`ServerLogin::start()`] for the regular path. Or
|
||||||
pub fn builder<R: RngCore + CryptoRng, S: Clone>(
|
/// [`ServerLogin::builder()`] with just a remote private key.
|
||||||
|
pub fn builder_with_key_material<R: RngCore + CryptoRng, SK: Clone, OS: Clone>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
server_setup: &ServerSetup<CS, S>,
|
server_setup: &ServerSetup<CS, SK, OS>,
|
||||||
|
key_material: GenericArray<u8, <OprfGroup<CS> as Group>::ScalarLen>,
|
||||||
password_file: Option<ServerRegistration<CS>>,
|
password_file: Option<ServerRegistration<CS>>,
|
||||||
credential_request: CredentialRequest<CS>,
|
credential_request: CredentialRequest<CS>,
|
||||||
credential_identifier: &[u8],
|
|
||||||
ServerLoginStartParameters {
|
ServerLoginStartParameters {
|
||||||
context,
|
context,
|
||||||
identifiers,
|
identifiers,
|
||||||
}: ServerLoginStartParameters,
|
}: ServerLoginStartParameters,
|
||||||
) -> Result<ServerLoginBuilder<CS, S>, ProtocolError>
|
) -> Result<ServerLoginBuilder<CS, SK>, ProtocolError>
|
||||||
where
|
where
|
||||||
// MaskedResponse: (Nonce + Hash) + KePk
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
@@ -652,7 +754,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
|||||||
let credential_request_bytes =
|
let credential_request_bytes =
|
||||||
CredentialRequest::<CS>::serialize_iter(&blinded_element, &ke1_message);
|
CredentialRequest::<CS>::serialize_iter(&blinded_element, &ke1_message);
|
||||||
|
|
||||||
let oprf_key = oprf_key_from_seed::<CS>(&server_setup.oprf_seed, credential_identifier)?;
|
let oprf_key = oprf_key_from_key_material::<CS>(key_material)?;
|
||||||
let server = voprf::OprfServer::new_with_key(&oprf_key).map_err(ProtocolError::from)?;
|
let server = voprf::OprfServer::new_with_key(&oprf_key).map_err(ProtocolError::from)?;
|
||||||
let evaluation_element = server.blind_evaluate(&credential_request.blinded_element);
|
let evaluation_element = server.blind_evaluate(&credential_request.blinded_element);
|
||||||
|
|
||||||
@@ -682,8 +784,42 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn build<S: Clone>(
|
/// Create a [`ServerLoginBuilder`] to use with a remote private key.
|
||||||
builder: ServerLoginBuilder<CS, S>,
|
///
|
||||||
|
/// See [`ServerLogin::start()`] for the regular path.
|
||||||
|
pub fn builder<R: RngCore + CryptoRng, SK: Clone>(
|
||||||
|
rng: &mut R,
|
||||||
|
server_setup: &ServerSetup<CS, SK>,
|
||||||
|
password_file: Option<ServerRegistration<CS>>,
|
||||||
|
credential_request: CredentialRequest<CS>,
|
||||||
|
credential_identifier: &[u8],
|
||||||
|
params: ServerLoginStartParameters,
|
||||||
|
) -> Result<ServerLoginBuilder<CS, SK>, ProtocolError>
|
||||||
|
where
|
||||||
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
|
Sum<NonceLen, OutputSize<OprfHash<CS>>>:
|
||||||
|
ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||||
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||||
|
{
|
||||||
|
let KeyMaterialInfo {
|
||||||
|
ikm: oprf_seed,
|
||||||
|
info,
|
||||||
|
} = server_setup.key_material_info(credential_identifier);
|
||||||
|
let key_material = oprf_key_material::<CS>(&oprf_seed, &info)?;
|
||||||
|
|
||||||
|
Self::builder_with_key_material(
|
||||||
|
rng,
|
||||||
|
server_setup,
|
||||||
|
key_material,
|
||||||
|
password_file,
|
||||||
|
credential_request,
|
||||||
|
params,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build<SK: Clone>(
|
||||||
|
builder: ServerLoginBuilder<CS, SK>,
|
||||||
input: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2BuilderInput,
|
input: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2BuilderInput,
|
||||||
) -> Result<ServerLoginStartResult<CS>, ProtocolError> {
|
) -> Result<ServerLoginStartResult<CS>, ProtocolError> {
|
||||||
let result = CS::KeyExchange::build_ke2(builder.ke2_builder.clone(), input)?;
|
let result = CS::KeyExchange::build_ke2(builder.ke2_builder.clone(), input)?;
|
||||||
@@ -966,23 +1102,26 @@ fn get_password_derived_key<CS: CipherSuite>(
|
|||||||
Ok(hkdf.finalize())
|
Ok(hkdf.finalize())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn oprf_key_from_seed<CS: CipherSuite>(
|
fn oprf_key_material<CS: CipherSuite>(
|
||||||
oprf_seed: &Output<OprfHash<CS>>,
|
oprf_seed: &Output<OprfHash<CS>>,
|
||||||
credential_identifier: &[u8],
|
info: &[&[u8]],
|
||||||
) -> Result<GenericArray<u8, <OprfGroup<CS> as Group>::ScalarLen>, ProtocolError> {
|
) -> Result<GenericArray<u8, <OprfGroup<CS> as Group>::ScalarLen>, InternalError> {
|
||||||
let mut ikm = GenericArray::<_, <OprfGroup<CS> as Group>::ScalarLen>::default();
|
let mut ikm = GenericArray::<_, <OprfGroup<CS> as Group>::ScalarLen>::default();
|
||||||
Hkdf::<OprfHash<CS>>::from_prk(oprf_seed)
|
Hkdf::<OprfHash<CS>>::from_prk(oprf_seed)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|hkdf| {
|
.and_then(|hkdf| hkdf.expand_multi_info(info, &mut ikm).ok())
|
||||||
hkdf.expand_multi_info(&[credential_identifier, STR_OPRF_KEY], &mut ikm)
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
.ok_or(InternalError::HkdfError)?;
|
.ok_or(InternalError::HkdfError)?;
|
||||||
|
|
||||||
|
Ok(ikm)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oprf_key_from_key_material<CS: CipherSuite>(
|
||||||
|
input: GenericArray<u8, <OprfGroup<CS> as Group>::ScalarLen>,
|
||||||
|
) -> Result<GenericArray<u8, <OprfGroup<CS> as Group>::ScalarLen>, InternalError> {
|
||||||
Ok(OprfGroup::<CS>::serialize_scalar(voprf::derive_key::<
|
Ok(OprfGroup::<CS>::serialize_scalar(voprf::derive_key::<
|
||||||
CS::OprfCs,
|
CS::OprfCs,
|
||||||
>(
|
>(
|
||||||
ikm.as_slice(),
|
input.as_slice(),
|
||||||
&GenericArray::from(*STR_OPAQUE_DERIVE_KEY_PAIR),
|
&GenericArray::from(*STR_OPAQUE_DERIVE_KEY_PAIR),
|
||||||
voprf::Mode::Oprf,
|
voprf::Mode::Oprf,
|
||||||
)?))
|
)?))
|
||||||
|
|||||||
+89
-12
@@ -17,6 +17,7 @@ use cryptoki::mechanism::Mechanism;
|
|||||||
use cryptoki::object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle};
|
use cryptoki::object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle};
|
||||||
use cryptoki::session::{Session, UserType};
|
use cryptoki::session::{Session, UserType};
|
||||||
use cryptoki::types::AuthPin;
|
use cryptoki::types::AuthPin;
|
||||||
|
use digest::OutputSizeUser;
|
||||||
use elliptic_curve::group::Curve;
|
use elliptic_curve::group::Curve;
|
||||||
use elliptic_curve::pkcs8::der::asn1::{OctetString, OctetStringRef};
|
use elliptic_curve::pkcs8::der::asn1::{OctetString, OctetStringRef};
|
||||||
use elliptic_curve::pkcs8::der::{Decode, Encode};
|
use elliptic_curve::pkcs8::der::{Decode, Encode};
|
||||||
@@ -24,7 +25,7 @@ use elliptic_curve::pkcs8::{AssociatedOid, ObjectIdentifier};
|
|||||||
use elliptic_curve::point::{AffineCoordinates, DecompressPoint};
|
use elliptic_curve::point::{AffineCoordinates, DecompressPoint};
|
||||||
use elliptic_curve::sec1::{ModulusSize, Tag, ToEncodedPoint};
|
use elliptic_curve::sec1::{ModulusSize, Tag, ToEncodedPoint};
|
||||||
use elliptic_curve::{AffinePoint, CurveArithmetic, FieldBytesSize, Group, ProjectivePoint};
|
use elliptic_curve::{AffinePoint, CurveArithmetic, FieldBytesSize, Group, ProjectivePoint};
|
||||||
use generic_array::typenum::Sum;
|
use generic_array::typenum::{Sum, Unsigned};
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use p256::NistP256;
|
use p256::NistP256;
|
||||||
use p384::NistP384;
|
use p384::NistP384;
|
||||||
@@ -32,7 +33,7 @@ use p521::NistP521;
|
|||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
|
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
|
||||||
|
|
||||||
use crate::ciphersuite::OprfHash;
|
use crate::ciphersuite::{OprfGroup, OprfHash};
|
||||||
use crate::envelope::NonceLen;
|
use crate::envelope::NonceLen;
|
||||||
use crate::hash::OutputSize;
|
use crate::hash::OutputSize;
|
||||||
use crate::key_exchange::group::KeGroup;
|
use crate::key_exchange::group::KeGroup;
|
||||||
@@ -60,7 +61,11 @@ fn p256() {
|
|||||||
type Ksf = Identity;
|
type Ksf = Identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
test::<Suite>(Mechanism::EccKeyPairGen, NistP256::OID);
|
test::<Suite>(
|
||||||
|
Mechanism::EccKeyPairGen,
|
||||||
|
NistP256::OID,
|
||||||
|
Mechanism::Sha256Hmac,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -74,7 +79,11 @@ fn p384() {
|
|||||||
type Ksf = Identity;
|
type Ksf = Identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
test::<Suite>(Mechanism::EccKeyPairGen, NistP384::OID);
|
test::<Suite>(
|
||||||
|
Mechanism::EccKeyPairGen,
|
||||||
|
NistP384::OID,
|
||||||
|
Mechanism::Sha384Hmac,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -88,7 +97,11 @@ fn p521() {
|
|||||||
type Ksf = Identity;
|
type Ksf = Identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
test::<Suite>(Mechanism::EccKeyPairGen, NistP521::OID);
|
test::<Suite>(
|
||||||
|
Mechanism::EccKeyPairGen,
|
||||||
|
NistP521::OID,
|
||||||
|
Mechanism::Sha512Hmac,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -108,6 +121,7 @@ fn curve25519() {
|
|||||||
// implementation. See https://github.com/softhsm/SoftHSMv2/issues/647.
|
// implementation. See https://github.com/softhsm/SoftHSMv2/issues/647.
|
||||||
Mechanism::EccEdwardsKeyPairGen,
|
Mechanism::EccEdwardsKeyPairGen,
|
||||||
ObjectIdentifier::new("1.3.101.110").unwrap(),
|
ObjectIdentifier::new("1.3.101.110").unwrap(),
|
||||||
|
Mechanism::Sha512Hmac,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,8 +136,11 @@ trait Pkcs11DiffieHellman<KG: KeGroup> {
|
|||||||
) -> GenericArray<u8, KG::PkLen>;
|
) -> GenericArray<u8, KG::PkLen>;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test<CS: CipherSuite<KeyExchange = TripleDh>>(mechanism: Mechanism, oid: ObjectIdentifier)
|
fn test<CS: CipherSuite<KeyExchange = TripleDh>>(
|
||||||
where
|
dh_mechanism: Mechanism,
|
||||||
|
oid: ObjectIdentifier,
|
||||||
|
hmac_mechanism: Mechanism,
|
||||||
|
) where
|
||||||
RemoteKey: Pkcs11DiffieHellman<CS::KeGroup>,
|
RemoteKey: Pkcs11DiffieHellman<CS::KeGroup>,
|
||||||
<CS::KeGroup as KeGroup>::Sk: DiffieHellman<CS::KeGroup>,
|
<CS::KeGroup as KeGroup>::Sk: DiffieHellman<CS::KeGroup>,
|
||||||
// MaskedResponse: (Nonce + Hash) + KePk
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
@@ -147,10 +164,11 @@ where
|
|||||||
Sum<NonceLen, <CS::KeGroup as KeGroup>::PkLen>: ArrayLength<u8> + Add<OutputSize<OprfHash<CS>>>,
|
Sum<NonceLen, <CS::KeGroup as KeGroup>::PkLen>: ArrayLength<u8> + Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<Sum<NonceLen, <CS::KeGroup as KeGroup>::PkLen>, OutputSize<OprfHash<CS>>>: ArrayLength<u8>,
|
Sum<Sum<NonceLen, <CS::KeGroup as KeGroup>::PkLen>, OutputSize<OprfHash<CS>>>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
let (remote_key, pk) = pkcs11_generate_key_pair(mechanism, oid);
|
let (remote_key, pk) = pkcs11_generate_key_pair(dh_mechanism, oid);
|
||||||
|
|
||||||
let keypair = KeyPair::new(RemoteKey(remote_key), pk);
|
let keypair = KeyPair::new(RemoteKey(remote_key), pk);
|
||||||
let server_setup = ServerSetup::new_with_key_pair(&mut OsRng, keypair);
|
let oprf_seed = pkcs11_generate_oprf_seed(<OprfHash<CS> as OutputSizeUser>::OutputSize::U64);
|
||||||
|
let server_setup = ServerSetup::new_with_key_pair_and_seed(&mut OsRng, keypair, oprf_seed);
|
||||||
|
|
||||||
const PASSWORD: &str = "password";
|
const PASSWORD: &str = "password";
|
||||||
|
|
||||||
@@ -158,7 +176,13 @@ where
|
|||||||
message,
|
message,
|
||||||
state: client,
|
state: client,
|
||||||
} = ClientRegistration::<CS>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
} = ClientRegistration::<CS>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
||||||
let message = ServerRegistration::start(&server_setup, message, &[])
|
let key_material_info = server_setup.key_material_info(&[]);
|
||||||
|
let key_material = pkcs11_hkdf::<CS>(
|
||||||
|
key_material_info.ikm,
|
||||||
|
hmac_mechanism,
|
||||||
|
Vec::from_iter(key_material_info.info.into_iter().flatten().copied()),
|
||||||
|
);
|
||||||
|
let message = ServerRegistration::start_with_key_material(&server_setup, key_material, message)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.message;
|
.message;
|
||||||
let message = client
|
let message = client
|
||||||
@@ -176,12 +200,18 @@ where
|
|||||||
message,
|
message,
|
||||||
state: client,
|
state: client,
|
||||||
} = ClientLogin::<CS>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
} = ClientLogin::<CS>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
||||||
let builder = ServerLogin::builder(
|
let key_material_info = server_setup.key_material_info(&[]);
|
||||||
|
let key_material = pkcs11_hkdf::<CS>(
|
||||||
|
key_material_info.ikm,
|
||||||
|
hmac_mechanism,
|
||||||
|
Vec::from_iter(key_material_info.info.into_iter().flatten().copied()),
|
||||||
|
);
|
||||||
|
let builder = ServerLogin::builder_with_key_material(
|
||||||
&mut OsRng,
|
&mut OsRng,
|
||||||
&server_setup,
|
&server_setup,
|
||||||
|
key_material,
|
||||||
Some(file),
|
Some(file),
|
||||||
message,
|
message,
|
||||||
&[],
|
|
||||||
ServerLoginStartParameters::default(),
|
ServerLoginStartParameters::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -265,6 +295,53 @@ fn pkcs11_generate_key_pair<KG: KeGroup>(
|
|||||||
(remote_key, pk)
|
(remote_key, pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pkcs11_generate_oprf_seed(length: u64) -> ObjectHandle {
|
||||||
|
SESSION
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.generate_key(
|
||||||
|
&Mechanism::GenericSecretKeyGen,
|
||||||
|
&[Attribute::Token(false), Attribute::ValueLen(length.into())],
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SoftHSM, nor any other popular HSM at the time of writing, supports HKDF. So
|
||||||
|
// we instead implement HKDF by hand on top of the HSMs HMAC, which is supported
|
||||||
|
// by almost all HSMs and still protects the OPRF seed.
|
||||||
|
fn pkcs11_hkdf<CS: CipherSuite>(
|
||||||
|
hmac: ObjectHandle,
|
||||||
|
mechanism: Mechanism,
|
||||||
|
info: Vec<u8>,
|
||||||
|
) -> GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen> {
|
||||||
|
let mut okm = GenericArray::default();
|
||||||
|
let mut prev: Option<Vec<u8>> = None;
|
||||||
|
let chunk_len = <OprfHash<CS> as OutputSizeUser>::OutputSize::USIZE;
|
||||||
|
|
||||||
|
if okm.len() > chunk_len * 255 {
|
||||||
|
panic!("invalid length");
|
||||||
|
}
|
||||||
|
|
||||||
|
let session = SESSION.lock().unwrap();
|
||||||
|
|
||||||
|
for (block_n, block) in (0..).zip(okm.chunks_mut(chunk_len)) {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
|
||||||
|
if let Some(ref prev) = prev {
|
||||||
|
data.extend(prev.as_slice())
|
||||||
|
};
|
||||||
|
|
||||||
|
data.extend(&info);
|
||||||
|
data.extend(&[block_n + 1]);
|
||||||
|
|
||||||
|
let output = session.sign(&mechanism, hmac, &data).unwrap();
|
||||||
|
block.copy_from_slice(&output[..block.len()]);
|
||||||
|
prev = Some(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
okm
|
||||||
|
}
|
||||||
|
|
||||||
impl Pkcs11DiffieHellman<NistP256> for RemoteKey {
|
impl Pkcs11DiffieHellman<NistP256> for RemoteKey {
|
||||||
fn pkcs11_diffie_hellman(
|
fn pkcs11_diffie_hellman(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
Reference in New Issue
Block a user