use crate::internal_alloc::Vec;
use noxtls_core::{Error, Result};
use noxtls_crypto::{
rsaes_oaep_sha256_decrypt, rsaes_pkcs1_v15_decrypt, rsassa_pss_sha256_sign, rsassa_sha256_sign,
x25519_shared_secret, RsaPrivateKey, X25519PrivateKey, X25519PublicKey,
};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ExternalKeyHandle {
id: Vec<u8>,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum KeySignAlgorithm {
RsaPkcs1Sha256,
RsaPssSha256,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum KeyDecryptAlgorithm {
RsaPkcs1v15,
RsaOaepSha256,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum KeyDeriveAlgorithm {
X25519,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct KeySignRequest<'a> {
pub handle: &'a ExternalKeyHandle,
pub algorithm: KeySignAlgorithm,
pub message: &'a [u8],
pub salt: Option<&'a [u8]>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct KeyDecryptRequest<'a> {
pub handle: &'a ExternalKeyHandle,
pub algorithm: KeyDecryptAlgorithm,
pub ciphertext: &'a [u8],
pub label: Option<&'a [u8]>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct KeyDeriveRequest<'a> {
pub handle: &'a ExternalKeyHandle,
pub algorithm: KeyDeriveAlgorithm,
pub peer_public_key: &'a [u8],
}
pub trait ExternalKeyProvider {
fn sign(&self, request: &KeySignRequest<'_>) -> Result<Vec<u8>>;
fn decrypt(&self, request: &KeyDecryptRequest<'_>) -> Result<Vec<u8>>;
fn derive_shared_secret(&self, request: &KeyDeriveRequest<'_>) -> Result<Vec<u8>>;
}
#[derive(Debug, Clone, Default)]
pub struct SoftwareKeyProvider {
rsa_signing_keys: Vec<(ExternalKeyHandle, RsaPrivateKey)>,
rsa_decrypt_keys: Vec<(ExternalKeyHandle, RsaPrivateKey)>,
x25519_keys: Vec<(ExternalKeyHandle, X25519PrivateKey)>,
}
impl ExternalKeyHandle {
pub fn new(id: &[u8]) -> Result<Self> {
if id.is_empty() {
return Err(Error::InvalidLength(
"external key handle must not be empty",
));
}
Ok(Self { id: id.to_vec() })
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.id
}
}
impl SoftwareKeyProvider {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn register_rsa_signing_key(
&mut self,
handle: ExternalKeyHandle,
key: RsaPrivateKey,
) -> Result<()> {
if self
.rsa_signing_keys
.iter()
.any(|(existing, _)| existing == &handle)
{
return Err(Error::StateError(
"rsa signing key handle is already registered",
));
}
self.rsa_signing_keys.push((handle, key));
Ok(())
}
pub fn register_rsa_decryption_key(
&mut self,
handle: ExternalKeyHandle,
key: RsaPrivateKey,
) -> Result<()> {
if self
.rsa_decrypt_keys
.iter()
.any(|(existing, _)| existing == &handle)
{
return Err(Error::StateError(
"rsa decryption key handle is already registered",
));
}
self.rsa_decrypt_keys.push((handle, key));
Ok(())
}
pub fn register_x25519_key(
&mut self,
handle: ExternalKeyHandle,
key: X25519PrivateKey,
) -> Result<()> {
if self
.x25519_keys
.iter()
.any(|(existing, _)| existing == &handle)
{
return Err(Error::StateError("x25519 key handle is already registered"));
}
self.x25519_keys.push((handle, key));
Ok(())
}
fn rsa_signing_key(&self, handle: &ExternalKeyHandle) -> Result<&RsaPrivateKey> {
self.rsa_signing_keys
.iter()
.find_map(|(existing, key)| (existing == handle).then_some(key))
.ok_or(Error::StateError("unknown rsa signing key handle"))
}
fn rsa_decryption_key(&self, handle: &ExternalKeyHandle) -> Result<&RsaPrivateKey> {
self.rsa_decrypt_keys
.iter()
.find_map(|(existing, key)| (existing == handle).then_some(key))
.ok_or(Error::StateError("unknown rsa decryption key handle"))
}
fn x25519_private_key(&self, handle: &ExternalKeyHandle) -> Result<X25519PrivateKey> {
self.x25519_keys
.iter()
.find_map(|(existing, key)| (existing == handle).then_some(key.clone()))
.ok_or(Error::StateError("unknown x25519 key handle"))
}
}
impl ExternalKeyProvider for SoftwareKeyProvider {
fn sign(&self, request: &KeySignRequest<'_>) -> Result<Vec<u8>> {
let key = self.rsa_signing_key(request.handle)?;
match request.algorithm {
KeySignAlgorithm::RsaPkcs1Sha256 => rsassa_sha256_sign(key, request.message),
KeySignAlgorithm::RsaPssSha256 => {
let salt = request.salt.ok_or(Error::InvalidLength(
"rsa-pss-sha256 signing requires a salt",
))?;
rsassa_pss_sha256_sign(key, request.message, salt)
}
}
}
fn decrypt(&self, request: &KeyDecryptRequest<'_>) -> Result<Vec<u8>> {
let key = self.rsa_decryption_key(request.handle)?;
let plaintext = match request.algorithm {
KeyDecryptAlgorithm::RsaPkcs1v15 => rsaes_pkcs1_v15_decrypt(key, request.ciphertext),
KeyDecryptAlgorithm::RsaOaepSha256 => {
let label = request.label.unwrap_or(&[]);
rsaes_oaep_sha256_decrypt(key, request.ciphertext, label)
}
};
plaintext.map_err(|_| Error::CryptoFailure("key provider decryption failed"))
}
fn derive_shared_secret(&self, request: &KeyDeriveRequest<'_>) -> Result<Vec<u8>> {
match request.algorithm {
KeyDeriveAlgorithm::X25519 => {
let private_key = self.x25519_private_key(request.handle)?;
let peer_bytes: [u8; 32] = request
.peer_public_key
.try_into()
.map_err(|_| Error::InvalidLength("x25519 peer public key must be 32 bytes"))?;
let peer_public = X25519PublicKey::from_bytes(peer_bytes);
let shared = x25519_shared_secret(private_key, peer_public)?;
Ok(shared.to_vec())
}
}
}
}