use rand_core::RngCore;
use trussed_core::{
api::{reply, request},
types::{Bytes, KeyId, KeySerialization, SerializedKey, Signature, SignatureSerialization},
Error,
};
use crate::key;
use crate::service::MechanismImpl;
use crate::store::Keystore;
#[inline(never)]
fn load_public_key(
keystore: &mut impl Keystore,
key_id: &KeyId,
) -> Result<salty::PublicKey, Error> {
let public_bytes: [u8; 32] = keystore
.load_key(key::Secrecy::Public, Some(key::Kind::Ed255), key_id)?
.material
.as_slice()
.try_into()
.map_err(|_| Error::InternalError)?;
let public_key =
salty::signature::PublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?;
Ok(public_key)
}
#[inline(never)]
fn load_keypair(keystore: &mut impl Keystore, key_id: &KeyId) -> Result<salty::Keypair, Error> {
let seed: [u8; 32] = keystore
.load_key(key::Secrecy::Secret, Some(key::Kind::Ed255), key_id)?
.material
.as_slice()
.try_into()
.map_err(|_| Error::InternalError)?;
let keypair = salty::signature::Keypair::from(&seed);
Ok(keypair)
}
impl MechanismImpl for super::Ed255 {
#[inline(never)]
fn derive_key(
&self,
keystore: &mut impl Keystore,
request: &request::DeriveKey,
) -> Result<reply::DeriveKey, Error> {
let base_id = &request.base_key;
let keypair = load_keypair(keystore, base_id)?;
let public_id = keystore.store_key(
request.attributes.persistence,
key::Secrecy::Public,
key::Kind::Ed255,
keypair.public.as_bytes(),
)?;
Ok(reply::DeriveKey { key: public_id })
}
#[inline(never)]
fn deserialize_key(
&self,
keystore: &mut impl Keystore,
request: &request::DeserializeKey,
) -> Result<reply::DeserializeKey, Error> {
if request.format != KeySerialization::Raw {
return Err(Error::InternalError);
}
if request.serialized_key.len() != 32 {
return Err(Error::InvalidSerializedKey);
}
let serialized_key: [u8; 32] = request.serialized_key[..32].try_into().unwrap();
let public_key = salty::signature::PublicKey::try_from(&serialized_key)
.map_err(|_| Error::InvalidSerializedKey)?;
let public_id = keystore.store_key(
request.attributes.persistence,
key::Secrecy::Public,
key::Kind::Ed255,
public_key.as_bytes(),
)?;
Ok(reply::DeserializeKey { key: public_id })
}
#[inline(never)]
fn generate_key(
&self,
keystore: &mut impl Keystore,
request: &request::GenerateKey,
) -> Result<reply::GenerateKey, Error> {
let mut seed = [0u8; 32];
keystore.rng().fill_bytes(&mut seed);
let key_id = keystore.store_key(
request.attributes.persistence,
key::Secrecy::Secret,
key::Info::from(key::Kind::Ed255).with_local_flag(),
&seed,
)?;
Ok(reply::GenerateKey { key: key_id })
}
#[inline(never)]
fn serialize_key(
&self,
keystore: &mut impl Keystore,
request: &request::SerializeKey,
) -> Result<reply::SerializeKey, Error> {
let key_id = request.key;
let public_key = load_public_key(keystore, &key_id)?;
let serialized_key = match request.format {
KeySerialization::Cose => {
let cose_pk = cosey::Ed25519PublicKey {
x: Bytes::from(public_key.as_bytes()),
};
crate::cbor_serialize_bytes(&cose_pk).map_err(|_| Error::CborError)?
}
KeySerialization::Raw => {
let mut serialized_key = SerializedKey::new();
serialized_key
.extend_from_slice(public_key.as_bytes())
.map_err(|_| Error::InternalError)?;
serialized_key
}
_ => {
return Err(Error::InternalError);
}
};
Ok(reply::SerializeKey { serialized_key })
}
#[inline(never)]
fn exists(
&self,
keystore: &mut impl Keystore,
request: &request::Exists,
) -> Result<reply::Exists, Error> {
let key_id = request.key;
let exists = keystore.exists_key(key::Secrecy::Secret, Some(key::Kind::Ed255), &key_id);
Ok(reply::Exists { exists })
}
#[inline(never)]
fn sign(
&self,
keystore: &mut impl Keystore,
request: &request::Sign,
) -> Result<reply::Sign, Error> {
let key_id = request.key;
let keypair = load_keypair(keystore, &key_id)?;
let native_signature = keypair.sign(&request.message);
let our_signature = Signature::from(&native_signature.to_bytes());
Ok(reply::Sign {
signature: our_signature,
})
}
#[inline(never)]
fn verify(
&self,
keystore: &mut impl Keystore,
request: &request::Verify,
) -> Result<reply::Verify, Error> {
if let SignatureSerialization::Raw = request.format {
} else {
return Err(Error::InvalidSerializationFormat);
}
if request.signature.len() != salty::constants::SIGNATURE_SERIALIZED_LENGTH {
return Err(Error::WrongSignatureLength);
}
let key_id = request.key;
let public_key = load_public_key(keystore, &key_id)?;
let mut signature_array = [0u8; salty::constants::SIGNATURE_SERIALIZED_LENGTH];
signature_array.copy_from_slice(request.signature.as_ref());
let salty_signature = salty::signature::Signature::from(&signature_array);
Ok(reply::Verify {
valid: public_key
.verify(&request.message, &salty_signature)
.is_ok(),
})
}
fn unsafe_inject_key(
&self,
keystore: &mut impl Keystore,
request: &request::UnsafeInjectKey,
) -> Result<reply::UnsafeInjectKey, Error> {
if request.format != KeySerialization::Raw {
return Err(Error::InvalidSerializationFormat);
}
if request.raw_key.len() != salty::constants::SECRETKEY_SERIALIZED_LENGTH {
return Err(Error::InvalidSerializedKey);
}
let info = key::Info {
flags: key::Flags::SENSITIVE,
kind: key::Kind::Ed255,
};
keystore
.store_key(
request.attributes.persistence,
key::Secrecy::Secret,
info,
&request.raw_key,
)
.map(|key| reply::UnsafeInjectKey { key })
}
}