use crate::attribute::Attribute;
use crate::ec::get_ec_point_from_obj;
use crate::error::Result;
use crate::kasn1::DerEncBigUint;
use crate::mechanism::*;
use crate::misc::zeromem;
use crate::object::Object;
use crate::ossl::common::*;
use crate::pkcs11::*;
use ossl::pkey::{EccData, EvpPkey, PkeyData};
use ossl::signature::{OsslSignature, SigAlg, SigOp};
use ossl::OsslSecret;
pub fn ecc_object_to_pkey(
key: &Object,
class: CK_OBJECT_CLASS,
) -> Result<EvpPkey> {
let kclass = key.get_attr_as_ulong(CKA_CLASS)?;
if kclass != class {
return Err(CKR_KEY_TYPE_INCONSISTENT)?;
}
match kclass {
CKO_PUBLIC_KEY => Ok(EvpPkey::import(
osslctx(),
get_evp_pkey_type_from_obj(key)?,
PkeyData::Ecc(EccData {
pubkey: Some(get_ec_point_from_obj(key)?),
prikey: None,
}),
)?),
CKO_PRIVATE_KEY => Ok(EvpPkey::import(
osslctx(),
get_evp_pkey_type_from_obj(key)?,
PkeyData::Ecc(EccData {
pubkey: None,
prikey: Some(OsslSecret::from_vec(
key.get_attr_as_bytes(CKA_VALUE)?.clone(),
)),
}),
)?),
_ => Err(CKR_KEY_TYPE_INCONSISTENT)?,
}
}
#[derive(asn1::Asn1Read, asn1::Asn1Write)]
struct EcdsaSignature<'a> {
r: DerEncBigUint<'a>,
s: DerEncBigUint<'a>,
}
fn slice_to_sig_half(hin: &[u8], hout: &mut [u8]) -> Result<()> {
let mut len = hin.len();
if len > hout.len() {
for i in 0..hin.len() {
if hin[i] != 0 {
break;
}
len -= 1;
}
if len == 0 || len > hout.len() {
return Err(CKR_GENERAL_ERROR)?;
}
}
let ipad = hin.len() - len;
let opad = hout.len() - len;
if opad > 0 {
hout[0..opad].fill(0);
}
hout[opad..].copy_from_slice(&hin[ipad..]);
Ok(())
}
fn ossl_to_pkcs11_signature(
ossl_sign: &Vec<u8>,
signature: &mut [u8],
) -> Result<()> {
let sig = match asn1::parse_single::<EcdsaSignature>(ossl_sign.as_slice()) {
Ok(a) => a,
Err(_) => return Err(CKR_GENERAL_ERROR)?,
};
let bn_len = signature.len() / 2;
slice_to_sig_half(sig.r.as_bytes(), &mut signature[..bn_len])?;
slice_to_sig_half(sig.s.as_bytes(), &mut signature[bn_len..])
}
fn pkcs11_to_ossl_signature(signature: &[u8]) -> Result<Vec<u8>> {
let bn_len = signature.len() / 2;
let sig = EcdsaSignature {
r: DerEncBigUint::new(&signature[..bn_len])?,
s: DerEncBigUint::new(&signature[bn_len..])?,
};
let ossl_sign = match asn1::write_single(&sig) {
Ok(b) => b,
Err(_) => return Err(CKR_GENERAL_ERROR)?,
};
Ok(ossl_sign)
}
pub fn ecdsa_type_to_ossl_alg(mech: CK_MECHANISM_TYPE) -> Result<SigAlg> {
Ok(match mech {
CKM_ECDSA => SigAlg::Ecdsa,
#[cfg(not(feature = "no_sha1"))]
CKM_ECDSA_SHA1 => SigAlg::EcdsaSha1,
CKM_ECDSA_SHA224 => SigAlg::EcdsaSha2_224,
CKM_ECDSA_SHA256 => SigAlg::EcdsaSha2_256,
CKM_ECDSA_SHA384 => SigAlg::EcdsaSha2_384,
CKM_ECDSA_SHA512 => SigAlg::EcdsaSha2_512,
CKM_ECDSA_SHA3_224 => SigAlg::EcdsaSha3_224,
CKM_ECDSA_SHA3_256 => SigAlg::EcdsaSha3_256,
CKM_ECDSA_SHA3_384 => SigAlg::EcdsaSha3_384,
CKM_ECDSA_SHA3_512 => SigAlg::EcdsaSha3_512,
_ => return Err(CKR_MECHANISM_INVALID)?,
})
}
#[derive(Debug)]
pub struct EcdsaOperation {
mech: CK_MECHANISM_TYPE,
output_len: usize,
finalized: bool,
in_use: bool,
sigctx: OsslSignature,
}
impl EcdsaOperation {
fn new_op(
flag: CK_FLAGS,
mech: &CK_MECHANISM,
key: &Object,
signature: Option<Vec<u8>>,
) -> Result<EcdsaOperation> {
let (op, mut pkey) = match flag {
CKF_SIGN => (SigOp::Sign, privkey_from_object(key)?),
CKF_VERIFY => (SigOp::Verify, pubkey_from_object(key)?),
_ => return Err(CKR_GENERAL_ERROR)?,
};
let output_len = 2 * ((pkey.get_bits()? + 7) / 8);
let mut sigctx = OsslSignature::new(
osslctx(),
op,
ecdsa_type_to_ossl_alg(mech.mechanism)?,
&mut pkey,
None,
)?;
if let Some(s) = &signature {
if s.len() != output_len {
return Err(CKR_SIGNATURE_LEN_RANGE)?;
}
let mut sig = pkcs11_to_ossl_signature(s)?;
sigctx.set_signature(sig.as_slice())?;
zeromem(sig.as_mut_slice());
}
Ok(EcdsaOperation {
mech: mech.mechanism,
output_len: output_len,
finalized: false,
in_use: false,
sigctx: sigctx,
})
}
pub fn sign_new(
mech: &CK_MECHANISM,
key: &Object,
_: &CK_MECHANISM_INFO,
) -> Result<EcdsaOperation> {
Self::new_op(CKF_SIGN, mech, key, None)
}
pub fn verify_new(
mech: &CK_MECHANISM,
key: &Object,
_: &CK_MECHANISM_INFO,
) -> Result<EcdsaOperation> {
Self::new_op(CKF_VERIFY, mech, key, None)
}
pub fn verify_signature_new(
mech: &CK_MECHANISM,
key: &Object,
_: &CK_MECHANISM_INFO,
signature: &[u8],
) -> Result<EcdsaOperation> {
Self::new_op(CKF_VERIFY, mech, key, Some(signature.to_vec()))
}
pub fn generate_keypair(
pubkey: &mut Object,
privkey: &mut Object,
) -> Result<()> {
let pkey =
EvpPkey::generate(osslctx(), get_evp_pkey_type_from_obj(pubkey)?)?;
let mut ecc = match pkey.export()? {
PkeyData::Ecc(e) => e,
_ => return Err(CKR_GENERAL_ERROR)?,
};
if let Some(key) = ecc.pubkey.take() {
let point_encoded = match asn1::write_single(&key.as_slice()) {
Ok(b) => b,
Err(_) => return Err(CKR_GENERAL_ERROR)?,
};
pubkey
.set_attr(Attribute::from_bytes(CKA_EC_POINT, point_encoded))?;
} else {
return Err(CKR_DEVICE_ERROR)?;
}
if let Some(key) = ecc.prikey.take() {
privkey.set_attr(Attribute::from_bytes(CKA_VALUE, key.to_vec()))?;
} else {
return Err(CKR_DEVICE_ERROR)?;
}
Ok(())
}
}
impl MechOperation for EcdsaOperation {
fn mechanism(&self) -> Result<CK_MECHANISM_TYPE> {
Ok(self.mech)
}
fn finalized(&self) -> bool {
self.finalized
}
}
impl Sign for EcdsaOperation {
fn sign(&mut self, data: &[u8], signature: &mut [u8]) -> Result<()> {
if self.in_use {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
if self.finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
if self.mech == CKM_ECDSA {
self.finalized = true;
if signature.len() != self.output_len {
return Err(CKR_SIGNATURE_LEN_RANGE)?;
}
let mut sig = vec![0u8; self.sigctx.sign(data, None)?];
let len = self.sigctx.sign(data, Some(sig.as_mut_slice()))?;
sig.resize(len, 0);
let ret = ossl_to_pkcs11_signature(&sig, signature);
zeromem(sig.as_mut_slice());
return ret;
}
self.sign_update(data)?;
self.sign_final(signature)
}
fn sign_update(&mut self, data: &[u8]) -> Result<()> {
if self.mech == CKM_ECDSA {
self.finalized = true;
}
if self.finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
self.in_use = true;
Ok(self.sigctx.update(data)?)
}
fn sign_final(&mut self, signature: &mut [u8]) -> Result<()> {
if !self.in_use {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
if self.finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
self.finalized = true;
let mut sig = vec![0u8; signature.len() + 10];
let len = self.sigctx.sign_final(sig.as_mut_slice())?;
if len > sig.len() {
return Err(CKR_DEVICE_ERROR)?;
}
sig.resize(len, 0);
let ret = ossl_to_pkcs11_signature(&sig, signature);
zeromem(sig.as_mut_slice());
ret
}
fn signature_len(&self) -> Result<usize> {
Ok(self.output_len)
}
}
impl EcdsaOperation {
fn verify_internal(
&mut self,
data: &[u8],
signature: Option<&[u8]>,
) -> Result<()> {
if self.in_use {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
if self.finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
if self.mech == CKM_ECDSA {
self.finalized = true;
if let Some(s) = &signature {
if s.len() != self.output_len {
return Err(CKR_SIGNATURE_LEN_RANGE)?;
}
let mut sig = pkcs11_to_ossl_signature(s)?;
let ret = self.sigctx.verify(data, Some(sig.as_slice()));
zeromem(sig.as_mut_slice());
return Ok(ret?);
} else {
return Ok(self.sigctx.verify(data, None)?);
}
}
self.verify_int_update(data)?;
self.verify_int_final(signature)
}
fn verify_int_update(&mut self, data: &[u8]) -> Result<()> {
if self.mech == CKM_ECDSA {
self.finalized = true;
}
if self.finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
self.in_use = true;
Ok(self.sigctx.update(data)?)
}
fn verify_int_final(&mut self, signature: Option<&[u8]>) -> Result<()> {
if !self.in_use {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
if self.finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
self.finalized = true;
if let Some(s) = &signature {
if s.len() != self.output_len {
return Err(CKR_SIGNATURE_LEN_RANGE)?;
}
let mut sig = pkcs11_to_ossl_signature(s)?;
let ret = self.sigctx.verify_final(Some(sig.as_slice()));
zeromem(sig.as_mut_slice());
Ok(ret?)
} else {
Ok(self.sigctx.verify_final(None)?)
}
}
}
impl Verify for EcdsaOperation {
fn verify(&mut self, data: &[u8], signature: &[u8]) -> Result<()> {
self.verify_internal(data, Some(signature))
}
fn verify_update(&mut self, data: &[u8]) -> Result<()> {
self.verify_int_update(data)
}
fn verify_final(&mut self, signature: &[u8]) -> Result<()> {
self.verify_int_final(Some(signature))
}
fn signature_len(&self) -> Result<usize> {
Ok(self.output_len)
}
}
impl VerifySignature for EcdsaOperation {
fn verify(&mut self, data: &[u8]) -> Result<()> {
self.verify_internal(data, None)
}
fn verify_update(&mut self, data: &[u8]) -> Result<()> {
self.verify_int_update(data)
}
fn verify_final(&mut self) -> Result<()> {
self.verify_int_final(None)
}
}