extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use core::cell::UnsafeCell;
use core::ffi::c_int;
use core::marker::PhantomData;
use generic_array::GenericArray;
use crate::error::WolfCryptError;
use wolfcrypt_rs::{
WC_RNG, wc_InitRng, wc_FreeRng,
wc_ecc_key,
wc_ecc_key_new, wc_ecc_key_free,
wc_ecc_make_key_ex, wc_ecc_set_rng,
wc_ecc_import_private_key_ex, wc_ecc_import_x963, wc_ecc_export_x963,
wc_ecc_sign_hash, wc_ecc_verify_hash,
wc_ecc_sig_to_rs, wc_ecc_rs_raw_to_sig,
ECC_SECP256R1,
};
#[cfg(wolfssl_ecc_p384)]
use wolfcrypt_rs::ECC_SECP384R1;
#[cfg(all(wolfssl_ecc_p521, wolfssl_sha512))]
use wolfcrypt_rs::ECC_SECP521R1;
mod sealed {
pub trait Sealed {}
}
pub trait EcdsaCurve: sealed::Sealed + 'static {
const CURVE_ID: c_int;
const FIELD_SIZE: usize;
const SIG_SIZE: usize;
const UNCOMPRESSED_POINT_SIZE: usize;
const HASH_LEN: usize;
type SigSize: generic_array::ArrayLength<u8>;
fn hash_message(msg: &[u8]) -> Result<Vec<u8>, WolfCryptError>;
}
pub struct P256;
impl sealed::Sealed for P256 {}
impl EcdsaCurve for P256 {
const CURVE_ID: c_int = ECC_SECP256R1;
const FIELD_SIZE: usize = 32;
const SIG_SIZE: usize = 64;
const UNCOMPRESSED_POINT_SIZE: usize = 65;
const HASH_LEN: usize = 32;
type SigSize = typenum::U64;
fn hash_message(msg: &[u8]) -> Result<Vec<u8>, WolfCryptError> {
let mut hash = vec![0u8; 32];
let rc = unsafe {
wolfcrypt_rs::wc_Sha256Hash(msg.as_ptr(), msg.len() as u32, hash.as_mut_ptr())
};
if rc != 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_Sha256Hash" });
}
Ok(hash)
}
}
#[cfg(wolfssl_ecc_p384)]
pub struct P384;
#[cfg(wolfssl_ecc_p384)]
impl sealed::Sealed for P384 {}
#[cfg(wolfssl_ecc_p384)]
impl EcdsaCurve for P384 {
const CURVE_ID: c_int = ECC_SECP384R1;
const FIELD_SIZE: usize = 48;
const SIG_SIZE: usize = 96;
const UNCOMPRESSED_POINT_SIZE: usize = 97;
const HASH_LEN: usize = 48;
type SigSize = typenum::U96;
fn hash_message(msg: &[u8]) -> Result<Vec<u8>, WolfCryptError> {
let mut hash = vec![0u8; 48];
let rc = unsafe {
wolfcrypt_rs::wc_Sha384Hash(msg.as_ptr(), msg.len() as u32, hash.as_mut_ptr())
};
if rc != 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_Sha384Hash" });
}
Ok(hash)
}
}
#[cfg(all(wolfssl_ecc_p521, wolfssl_sha512))]
pub struct P521;
#[cfg(all(wolfssl_ecc_p521, wolfssl_sha512))]
impl sealed::Sealed for P521 {}
#[cfg(all(wolfssl_ecc_p521, wolfssl_sha512))]
impl EcdsaCurve for P521 {
const CURVE_ID: c_int = ECC_SECP521R1;
const FIELD_SIZE: usize = 66;
const SIG_SIZE: usize = 132;
const UNCOMPRESSED_POINT_SIZE: usize = 133;
const HASH_LEN: usize = 64;
type SigSize = typenum::U132;
fn hash_message(msg: &[u8]) -> Result<Vec<u8>, WolfCryptError> {
let mut hash = vec![0u8; 64];
let rc = unsafe {
wolfcrypt_rs::wc_Sha512Hash(msg.as_ptr(), msg.len() as u32, hash.as_mut_ptr())
};
if rc != 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_Sha512Hash" });
}
Ok(hash)
}
}
pub struct EcdsaSignature<C: EcdsaCurve> {
bytes: GenericArray<u8, C::SigSize>,
_curve: PhantomData<C>,
}
impl<C: EcdsaCurve> EcdsaSignature<C> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, WolfCryptError> {
if bytes.len() != C::SIG_SIZE {
return Err(WolfCryptError::INVALID_INPUT);
}
Ok(Self {
bytes: GenericArray::clone_from_slice(bytes),
_curve: PhantomData,
})
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn r_bytes(&self) -> &[u8] {
&self.bytes[..C::FIELD_SIZE]
}
pub fn s_bytes(&self) -> &[u8] {
&self.bytes[C::FIELD_SIZE..]
}
}
impl<C: EcdsaCurve> Clone for EcdsaSignature<C> {
fn clone(&self) -> Self {
Self { bytes: self.bytes.clone(), _curve: PhantomData }
}
}
impl<C: EcdsaCurve> PartialEq for EcdsaSignature<C> {
fn eq(&self, other: &Self) -> bool {
self.bytes == other.bytes
}
}
impl<C: EcdsaCurve> Eq for EcdsaSignature<C> {}
impl<C: EcdsaCurve> core::fmt::Debug for EcdsaSignature<C> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("EcdsaSignature")
.field("len", &self.bytes.len())
.finish()
}
}
impl<C: EcdsaCurve> signature_trait::SignatureEncoding for EcdsaSignature<C> {
type Repr = Vec<u8>;
}
impl<C: EcdsaCurve> TryFrom<&[u8]> for EcdsaSignature<C> {
type Error = signature_trait::Error;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
Self::from_bytes(bytes).map_err(|_| signature_trait::Error::new())
}
}
impl<C: EcdsaCurve> From<EcdsaSignature<C>> for Vec<u8> {
fn from(sig: EcdsaSignature<C>) -> Vec<u8> {
sig.bytes.to_vec()
}
}
impl<C: EcdsaCurve> AsRef<[u8]> for EcdsaSignature<C> {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
fn der_to_fixed_rs<C: EcdsaCurve>(
der: &[u8],
der_len: u32,
) -> Result<GenericArray<u8, C::SigSize>, WolfCryptError> {
let mut r = vec![0u8; C::FIELD_SIZE];
let mut s = vec![0u8; C::FIELD_SIZE];
let mut r_len = C::FIELD_SIZE as u32;
let mut s_len = C::FIELD_SIZE as u32;
let rc = unsafe {
wc_ecc_sig_to_rs(
der.as_ptr(), der_len,
r.as_mut_ptr(), &mut r_len,
s.as_mut_ptr(), &mut s_len,
)
};
if rc != 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ecc_sig_to_rs" });
}
if r_len as usize > C::FIELD_SIZE || s_len as usize > C::FIELD_SIZE {
return Err(WolfCryptError::INVALID_INPUT);
}
let mut combined = GenericArray::<u8, C::SigSize>::default();
let r_pad = C::FIELD_SIZE - r_len as usize;
combined[r_pad..C::FIELD_SIZE].copy_from_slice(&r[..r_len as usize]);
let s_pad = C::FIELD_SIZE - s_len as usize;
combined[C::FIELD_SIZE + s_pad..].copy_from_slice(&s[..s_len as usize]);
Ok(combined)
}
pub struct EcdsaSigningKey<C: EcdsaCurve> {
key: UnsafeCell<*mut wc_ecc_key>,
_curve: PhantomData<C>,
}
unsafe impl<C: EcdsaCurve> Send for EcdsaSigningKey<C> {}
impl<C: EcdsaCurve> Drop for EcdsaSigningKey<C> {
fn drop(&mut self) {
let key = *self.key.get_mut();
if !key.is_null() {
unsafe { wc_ecc_key_free(key) };
}
}
}
impl<C: EcdsaCurve> EcdsaSigningKey<C> {
pub fn generate() -> Result<Self, WolfCryptError> {
let key = unsafe { wc_ecc_key_new(core::ptr::null_mut()) };
if key.is_null() {
return Err(WolfCryptError::ALLOC_FAILED);
}
let mut rng = WC_RNG::zeroed();
let rc = unsafe { wc_InitRng(&mut rng) };
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_InitRng" });
}
let rc = unsafe {
wc_ecc_make_key_ex(&mut rng, C::FIELD_SIZE as c_int, key, C::CURVE_ID)
};
unsafe { wc_FreeRng(&mut rng) };
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ecc_make_key_ex" });
}
Ok(Self { key: UnsafeCell::new(key), _curve: PhantomData })
}
pub fn from_private_key_and_public_point(
priv_bytes: &[u8],
pub_bytes: &[u8],
) -> Result<Self, WolfCryptError> {
if pub_bytes.len() != C::UNCOMPRESSED_POINT_SIZE || pub_bytes[0] != 0x04 {
return Err(WolfCryptError::INVALID_INPUT);
}
let key = unsafe { wc_ecc_key_new(core::ptr::null_mut()) };
if key.is_null() {
return Err(WolfCryptError::ALLOC_FAILED);
}
let rc = unsafe {
wc_ecc_import_private_key_ex(
priv_bytes.as_ptr(), priv_bytes.len() as u32,
pub_bytes.as_ptr(), pub_bytes.len() as u32,
key, C::CURVE_ID,
)
};
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ecc_import_private_key_ex" });
}
Ok(Self { key: UnsafeCell::new(key), _curve: PhantomData })
}
pub fn from_private_key_bytes(priv_bytes: &[u8]) -> Result<Self, WolfCryptError> {
let key = unsafe { wc_ecc_key_new(core::ptr::null_mut()) };
if key.is_null() {
return Err(WolfCryptError::ALLOC_FAILED);
}
let rc = unsafe {
wc_ecc_import_private_key_ex(
priv_bytes.as_ptr(), priv_bytes.len() as u32,
core::ptr::null(), 0,
key, C::CURVE_ID,
)
};
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ecc_import_private_key_ex" });
}
Ok(Self { key: UnsafeCell::new(key), _curve: PhantomData })
}
pub fn verifying_key(&self) -> Result<EcdsaVerifyingKey<C>, WolfCryptError> {
let key = unsafe { *self.key.get() };
let mut buf = vec![0u8; C::UNCOMPRESSED_POINT_SIZE];
let mut sz = buf.len() as u32;
let rc = unsafe { wc_ecc_export_x963(key, buf.as_mut_ptr(), &mut sz) };
if rc != 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ecc_export_x963" });
}
buf.truncate(sz as usize);
EcdsaVerifyingKey::from_uncompressed_point(&buf)
}
pub fn sign_prehash(&self, hash: &[u8]) -> Result<EcdsaSignature<C>, WolfCryptError> {
if hash.len() != C::HASH_LEN {
return Err(WolfCryptError::INVALID_INPUT);
}
let key = unsafe { *self.key.get() };
let mut der = vec![0u8; C::FIELD_SIZE * 2 + 16];
let mut der_len = der.len() as u32;
let mut rng = WC_RNG::zeroed();
let rc = unsafe { wc_InitRng(&mut rng) };
if rc != 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_InitRng (sign)" });
}
let rc = unsafe { wc_ecc_set_rng(key, &mut rng) };
if rc != 0 {
unsafe { wc_FreeRng(&mut rng) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ecc_set_rng" });
}
let rc = unsafe {
wc_ecc_sign_hash(
hash.as_ptr(), hash.len() as u32,
der.as_mut_ptr(), &mut der_len,
&mut rng,
key,
)
};
unsafe { wc_FreeRng(&mut rng) };
if rc != 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ecc_sign_hash" });
}
let combined = der_to_fixed_rs::<C>(&der, der_len)?;
Ok(EcdsaSignature { bytes: combined, _curve: PhantomData })
}
}
impl<C: EcdsaCurve> signature_trait::Signer<EcdsaSignature<C>> for EcdsaSigningKey<C> {
fn try_sign(&self, msg: &[u8]) -> Result<EcdsaSignature<C>, signature_trait::Error> {
let hash = C::hash_message(msg).map_err(|_| signature_trait::Error::new())?;
self.sign_prehash(&hash).map_err(|_| signature_trait::Error::new())
}
}
pub struct EcdsaVerifyingKey<C: EcdsaCurve> {
key: UnsafeCell<*mut wc_ecc_key>,
pub_bytes: Vec<u8>,
_curve: PhantomData<C>,
}
unsafe impl<C: EcdsaCurve> Send for EcdsaVerifyingKey<C> {}
impl<C: EcdsaCurve> Drop for EcdsaVerifyingKey<C> {
fn drop(&mut self) {
let key = *self.key.get_mut();
if !key.is_null() {
unsafe { wc_ecc_key_free(key) };
}
}
}
impl<C: EcdsaCurve> EcdsaVerifyingKey<C> {
pub fn from_uncompressed_point(bytes: &[u8]) -> Result<Self, WolfCryptError> {
if bytes.len() != C::UNCOMPRESSED_POINT_SIZE || bytes[0] != 0x04 {
return Err(WolfCryptError::INVALID_INPUT);
}
let key = unsafe { wc_ecc_key_new(core::ptr::null_mut()) };
if key.is_null() {
return Err(WolfCryptError::ALLOC_FAILED);
}
let rc = unsafe {
wc_ecc_import_x963(bytes.as_ptr(), bytes.len() as u32, key)
};
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ecc_import_x963" });
}
Ok(Self {
key: UnsafeCell::new(key),
pub_bytes: bytes.to_vec(),
_curve: PhantomData,
})
}
pub fn as_bytes(&self) -> &[u8] {
&self.pub_bytes
}
}
impl<C: EcdsaCurve> signature_trait::Verifier<EcdsaSignature<C>> for EcdsaVerifyingKey<C> {
fn verify(
&self,
msg: &[u8],
signature: &EcdsaSignature<C>,
) -> Result<(), signature_trait::Error> {
let hash = C::hash_message(msg).map_err(|_| signature_trait::Error::new())?;
let key = unsafe { *self.key.get() };
let r = signature.r_bytes();
let s = signature.s_bytes();
let mut der = vec![0u8; C::FIELD_SIZE * 2 + 16];
let mut der_len = der.len() as u32;
let rc = unsafe {
wc_ecc_rs_raw_to_sig(
r.as_ptr(), r.len() as u32,
s.as_ptr(), s.len() as u32,
der.as_mut_ptr(), &mut der_len,
)
};
if rc != 0 {
return Err(signature_trait::Error::new());
}
let mut res: c_int = 0;
let rc = unsafe {
wc_ecc_verify_hash(
der.as_ptr(), der_len,
hash.as_ptr(), hash.len() as u32,
&mut res, key,
)
};
if rc != 0 || res != 1 {
return Err(signature_trait::Error::new());
}
Ok(())
}
}
pub type P256SigningKey = EcdsaSigningKey<P256>;
pub type P256VerifyingKey = EcdsaVerifyingKey<P256>;
pub type P256Signature = EcdsaSignature<P256>;
#[cfg(wolfssl_ecc_p384)]
pub type P384SigningKey = EcdsaSigningKey<P384>;
#[cfg(wolfssl_ecc_p384)]
pub type P384VerifyingKey = EcdsaVerifyingKey<P384>;
#[cfg(wolfssl_ecc_p384)]
pub type P384Signature = EcdsaSignature<P384>;
#[cfg(all(wolfssl_ecc_p521, wolfssl_sha512))]
pub type P521SigningKey = EcdsaSigningKey<P521>;
#[cfg(all(wolfssl_ecc_p521, wolfssl_sha512))]
pub type P521VerifyingKey = EcdsaVerifyingKey<P521>;
#[cfg(all(wolfssl_ecc_p521, wolfssl_sha512))]
pub type P521Signature = EcdsaSignature<P521>;