#![cfg(all(feature = "signature", ecc, ecc_sign, ecc_verify, ecc_import, ecc_export, ecc_curve_ids, random))]
use core::ffi::c_void;
use core::mem::size_of;
use signature::{Error, Keypair, SignatureEncoding, SignerMut, Verifier};
use crate::ecc::ECC;
use crate::random::RNG;
use crate::sys;
fn der_to_rs<const SIG_SIZE: usize, const FIELD_SIZE: usize>(
der: &[u8],
) -> Result<[u8; SIG_SIZE], Error> {
debug_assert_eq!(SIG_SIZE, 2 * FIELD_SIZE);
let mut r_buf = [0u8; FIELD_SIZE];
let mut s_buf = [0u8; FIELD_SIZE];
let mut r_len = FIELD_SIZE as u32;
let mut s_len = FIELD_SIZE as u32;
let rc = unsafe {
sys::wc_ecc_sig_to_rs(
der.as_ptr(), der.len() as u32,
r_buf.as_mut_ptr(), &mut r_len,
s_buf.as_mut_ptr(), &mut s_len,
)
};
if rc != 0 {
return Err(Error::new());
}
let r_len = r_len as usize;
let s_len = s_len as usize;
if r_len > FIELD_SIZE || s_len > FIELD_SIZE {
return Err(Error::new());
}
let mut out = [0u8; SIG_SIZE];
out[FIELD_SIZE - r_len..FIELD_SIZE].copy_from_slice(&r_buf[..r_len]);
out[SIG_SIZE - s_len..SIG_SIZE].copy_from_slice(&s_buf[..s_len]);
Ok(out)
}
fn rs_to_der<const FIELD_SIZE: usize>(
rs: &[u8],
der_out: &mut [u8],
) -> Result<usize, Error> {
if rs.len() != 2 * FIELD_SIZE {
return Err(Error::new());
}
let (r, s) = rs.split_at(FIELD_SIZE);
let mut der_len = der_out.len() as u32;
let rc = unsafe {
sys::wc_ecc_rs_raw_to_sig(
r.as_ptr(), FIELD_SIZE as u32,
s.as_ptr(), FIELD_SIZE as u32,
der_out.as_mut_ptr(), &mut der_len,
)
};
if rc != 0 {
return Err(Error::new());
}
Ok(der_len as usize)
}
macro_rules! define_ecdsa_curve {
(
$(#[$meta:meta])*
($signing_key:ident, $verifying_key:ident, $signature:ident),
field_size = $field_size:literal,
sig_size = $sig_size:literal,
x963_size = $x963_size:literal,
der_max = $der_max:literal,
curve_id = $curve_id:expr,
hash_type = $hash_type:expr,
hash_cfg = $hash_cfg:meta $(,)?
) => {
$(#[$meta])*
#[cfg($hash_cfg)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct $signature([u8; $sig_size]);
#[cfg($hash_cfg)]
impl $signature {
pub const BYTE_SIZE: usize = $sig_size;
pub const fn from_bytes(bytes: [u8; $sig_size]) -> Self {
Self(bytes)
}
pub const fn to_bytes(&self) -> [u8; $sig_size] {
self.0
}
}
#[cfg($hash_cfg)]
impl AsRef<[u8]> for $signature {
fn as_ref(&self) -> &[u8] { &self.0 }
}
#[cfg($hash_cfg)]
impl TryFrom<&[u8]> for $signature {
type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Self, Error> {
let arr: [u8; $sig_size] = bytes.try_into().map_err(|_| Error::new())?;
Ok(Self(arr))
}
}
#[cfg($hash_cfg)]
impl From<$signature> for [u8; $sig_size] {
fn from(sig: $signature) -> Self { sig.0 }
}
#[cfg($hash_cfg)]
impl SignatureEncoding for $signature {
type Repr = [u8; $sig_size];
}
$(#[$meta])*
#[cfg($hash_cfg)]
pub struct $signing_key {
inner: ECC,
rng: RNG,
pub_bytes: [u8; $x963_size],
}
#[cfg($hash_cfg)]
impl $signing_key {
pub const PUB_KEY_SIZE: usize = $x963_size;
pub const SCALAR_SIZE: usize = $field_size;
pub fn generate(mut rng: RNG) -> Result<Self, i32> {
let ecc = ECC::generate_ex(
$field_size as i32,
&mut rng,
$curve_id,
None, None,
)?;
Self::from_ecc(ecc, rng)
}
pub fn import_unsigned(
qx: &[u8; $field_size],
qy: &[u8; $field_size],
d: &[u8; $field_size],
rng: RNG,
) -> Result<Self, i32> {
let ecc = ECC::import_unsigned(qx, qy, d, $curve_id, None, None)?;
Self::from_ecc(ecc, rng)
}
pub fn import_x963(
public_x963: &[u8; $x963_size],
d: &[u8; $field_size],
rng: RNG,
) -> Result<Self, i32> {
let ecc = ECC::import_private_key_ex(
d, public_x963, $curve_id, None, None,
)?;
Self::from_ecc(ecc, rng)
}
pub fn as_ecc(&self) -> &ECC { &self.inner }
pub fn into_parts(self) -> (ECC, RNG) {
(self.inner, self.rng)
}
fn from_ecc(mut ecc: ECC, rng: RNG) -> Result<Self, i32> {
let mut pub_bytes = [0u8; $x963_size];
let written = ecc.export_x963(&mut pub_bytes)?;
if written != $x963_size {
return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG);
}
Ok(Self { inner: ecc, rng, pub_bytes })
}
}
#[cfg($hash_cfg)]
impl Keypair for $signing_key {
type VerifyingKey = $verifying_key;
fn verifying_key(&self) -> $verifying_key {
$verifying_key { pub_bytes: self.pub_bytes }
}
}
#[cfg($hash_cfg)]
impl SignerMut<$signature> for $signing_key {
fn try_sign(&mut self, msg: &[u8]) -> Result<$signature, Error> {
let mut der = [0u8; $der_max];
let mut der_len: u32 = der.len() as u32;
let msg_len: u32 = msg.len().try_into().map_err(|_| Error::new())?;
let rc = unsafe {
sys::wc_SignatureGenerate(
$hash_type,
sys::wc_SignatureType_WC_SIGNATURE_TYPE_ECC,
msg.as_ptr(), msg_len,
der.as_mut_ptr(), &mut der_len,
self.inner.wc_ecc_key as *mut c_void,
size_of::<sys::ecc_key>() as u32,
self.rng.wc_rng,
)
};
if rc != 0 {
return Err(Error::new());
}
let rs = der_to_rs::<$sig_size, $field_size>(&der[..der_len as usize])?;
Ok($signature(rs))
}
}
$(#[$meta])*
#[cfg($hash_cfg)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct $verifying_key {
pub_bytes: [u8; $x963_size],
}
#[cfg($hash_cfg)]
impl $verifying_key {
pub const BYTE_SIZE: usize = $x963_size;
pub const fn from_bytes(bytes: [u8; $x963_size]) -> Self {
Self { pub_bytes: bytes }
}
pub const fn to_bytes(&self) -> [u8; $x963_size] {
self.pub_bytes
}
}
#[cfg($hash_cfg)]
impl AsRef<[u8]> for $verifying_key {
fn as_ref(&self) -> &[u8] { &self.pub_bytes }
}
#[cfg($hash_cfg)]
impl TryFrom<&[u8]> for $verifying_key {
type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Self, Error> {
let arr: [u8; $x963_size] =
bytes.try_into().map_err(|_| Error::new())?;
Ok(Self { pub_bytes: arr })
}
}
#[cfg($hash_cfg)]
impl Verifier<$signature> for $verifying_key {
fn verify(&self, msg: &[u8], sig: &$signature) -> Result<(), Error> {
let mut der = [0u8; $der_max];
let der_len = rs_to_der::<$field_size>(&sig.0, &mut der)?;
let key = ECC::import_x963_ex(&self.pub_bytes, $curve_id, None, None)
.map_err(|_| Error::new())?;
let msg_len: u32 = msg.len().try_into().map_err(|_| Error::new())?;
let rc = unsafe {
sys::wc_SignatureVerify(
$hash_type,
sys::wc_SignatureType_WC_SIGNATURE_TYPE_ECC,
msg.as_ptr(), msg_len,
der.as_ptr(), der_len as u32,
key.wc_ecc_key as *mut c_void,
size_of::<sys::ecc_key>() as u32,
)
};
if rc != 0 {
return Err(Error::new());
}
Ok(())
}
}
};
}
define_ecdsa_curve! {
(P256SigningKey, P256VerifyingKey, P256Signature),
field_size = 32,
sig_size = 64,
x963_size = 65,
der_max = 72,
curve_id = sys::ecc_curve_ids_ECC_SECP256R1,
hash_type = sys::wc_HashType_WC_HASH_TYPE_SHA256,
hash_cfg = sha256,
}
define_ecdsa_curve! {
(P384SigningKey, P384VerifyingKey, P384Signature),
field_size = 48,
sig_size = 96,
x963_size = 97,
der_max = 104,
curve_id = sys::ecc_curve_ids_ECC_SECP384R1,
hash_type = sys::wc_HashType_WC_HASH_TYPE_SHA384,
hash_cfg = sha384,
}
define_ecdsa_curve! {
(P521SigningKey, P521VerifyingKey, P521Signature),
field_size = 66,
sig_size = 132,
x963_size = 133,
der_max = 141,
curve_id = sys::ecc_curve_ids_ECC_SECP521R1,
hash_type = sys::wc_HashType_WC_HASH_TYPE_SHA512,
hash_cfg = sha512,
}