// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::{der, PR_FALSE}; use crate::err::{secstatus_to_res, Error, IntoResult}; use crate::init; use crate::p11::PK11ObjectType::PK11_TypePrivKey; use crate::p11::PK11_ExportDERPrivateKeyInfo; use crate::p11::PK11_GenerateKeyPair; use crate::p11::PK11_ImportDERPrivateKeyInfoAndReturnKey; use crate::p11::PK11_PubDeriveWithKDF; use crate::p11::PK11_ReadRawAttribute; use crate::p11::PK11_ImportPublicKey; use crate::p11::SECKEY_DecodeDERSubjectPublicKeyInfo; use crate::p11::Slot; use crate::p11::KU_ALL; use crate::util::SECItemMut; use crate::PrivateKey; use crate::PublicKey; use crate::SECItem; use crate::SECItemBorrowed; use pkcs11_bindings::CKA_VALUE; use pkcs11_bindings::CKM_EC_EDWARDS_KEY_PAIR_GEN; use pkcs11_bindings::CKM_EC_KEY_PAIR_GEN; use pkcs11_bindings::CKM_EC_MONTGOMERY_KEY_PAIR_GEN; use pkcs11_bindings::CK_FALSE; use std::ptr; // // Constants // #[derive(Clone, Debug, Eq, PartialEq)] pub enum EcCurve { P256, P384, P521, X25519, Ed25519, } pub type EcdhPublicKey = PublicKey; pub type EcdhPrivateKey = PrivateKey; pub struct EcdhKeypair { pub public: EcdhPublicKey, pub private: EcdhPrivateKey, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct Ecdh(EcCurve); impl Ecdh { pub fn new(&self, curve: EcCurve) -> Self { Self(curve) } pub fn generate_keypair(&self, curve: EcCurve) -> Result { return ecdh_keygen(curve); } } // Object identifiers in DER tag-length-value form pub const OID_EC_PUBLIC_KEY_BYTES: &[u8] = &[ /* RFC 5480 (id-ecPublicKey) */ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, ]; pub const OID_SECP256R1_BYTES: &[u8] = &[ /* RFC 5480 (secp256r1) */ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, ]; pub const OID_SECP384R1_BYTES: &[u8] = &[ /* RFC 5480 (secp384r1) */ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x34, ]; pub const OID_SECP521R1_BYTES: &[u8] = &[ /* RFC 5480 (secp521r1) */ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x35, ]; pub const OID_ED25519_BYTES: &[u8] = &[/* RFC 8410 (id-ed25519) */ 0x2b, 0x65, 0x70]; pub const OID_RS256_BYTES: &[u8] = &[ /* RFC 4055 (sha256WithRSAEncryption) */ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, ]; pub const OID_X25519_BYTES: &[u8] = &[ /* https://tools.ietf.org/html/draft-josefsson-pkix-newcurves-01 * 1.3.6.1.4.1.11591.15.1 */ 0x2b, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01, ]; pub fn object_id(val: &[u8]) -> Result, Error> { let mut out = Vec::with_capacity(der::MAX_TAG_AND_LENGTH_BYTES + val.len()); der::write_tag_and_length(&mut out, der::TAG_OBJECT_ID, val.len())?; out.extend_from_slice(val); Ok(out) } fn ec_curve_to_oid(alg: &EcCurve) -> Result, Error> { match alg { EcCurve::X25519 => Ok(OID_X25519_BYTES.to_vec()), EcCurve::Ed25519 => Ok(OID_ED25519_BYTES.to_vec()), EcCurve::P256 => Ok(OID_SECP256R1_BYTES.to_vec()), EcCurve::P384 => Ok(OID_SECP384R1_BYTES.to_vec()), EcCurve::P521 => Ok(OID_SECP521R1_BYTES.to_vec()), } } fn ec_curve_to_ckm(alg: &EcCurve) -> pkcs11_bindings::CK_MECHANISM_TYPE { match alg { EcCurve::P256 | EcCurve::P384 | EcCurve::P521 => CKM_EC_KEY_PAIR_GEN.into(), EcCurve::Ed25519 => CKM_EC_EDWARDS_KEY_PAIR_GEN.into(), EcCurve::X25519 => CKM_EC_MONTGOMERY_KEY_PAIR_GEN.into(), } } // // Curve functions // pub fn ecdh_keygen(curve: EcCurve) -> Result { init(); // Get the OID for the Curve let curve_oid = ec_curve_to_oid(&curve)?; let oid_bytes = object_id(&curve_oid)?; let mut oid = SECItemBorrowed::wrap(&oid_bytes); let oid_ptr: *mut SECItem = oid.as_mut(); // Get the Mechanism based on the Curve and its use let ckm = ec_curve_to_ckm(&curve); // Get the PKCS11 slot let slot = Slot::internal()?; // Create a pointer for the public key let mut pk_ptr = ptr::null_mut(); // https://github.com/mozilla/nss-gk-api/issues/1 unsafe { let sk = PK11_GenerateKeyPair( *slot, ckm, oid_ptr.cast(), &mut pk_ptr, CK_FALSE.into(), CK_FALSE.into(), ptr::null_mut(), ) .into_result()?; let pk = EcdhPublicKey::from_ptr(pk_ptr)?; let kp = EcdhKeypair { public: pk, private: sk, }; Ok(kp) } } pub fn export_ec_private_key_pkcs8(key: PrivateKey) -> Result, Error> { init(); unsafe { let sk: crate::ScopedSECItem = PK11_ExportDERPrivateKeyInfo(*key, ptr::null_mut()) .into_result() .unwrap(); return Ok(sk.into_vec()); } } pub fn import_ec_public_key_from_spki(spki: &[u8]) -> Result { init(); let mut spki_item = SECItemBorrowed::wrap(&spki); let spki_item_ptr = spki_item.as_mut(); let slot = Slot::internal()?; unsafe { let spki = SECKEY_DecodeDERSubjectPublicKeyInfo(spki_item_ptr) .into_result() .unwrap(); let pk: PublicKey = crate::p11::SECKEY_ExtractPublicKey(spki.as_mut().unwrap()) .into_result() .unwrap(); let handle = PK11_ImportPublicKey(*slot, *pk, PR_FALSE); if handle == pkcs11_bindings::CK_INVALID_HANDLE { return Err(Error::InvalidInput) } Ok(pk) } } pub fn import_ec_private_key_pkcs8(pki: &[u8]) -> Result { init(); // Get the PKCS11 slot let slot = Slot::internal()?; let mut der_pki = SECItemBorrowed::wrap(&pki); let der_pki_ptr: *mut SECItem = der_pki.as_mut(); // Create a pointer for the private key let mut pk_ptr = ptr::null_mut(); unsafe { secstatus_to_res(PK11_ImportDERPrivateKeyInfoAndReturnKey( *slot, der_pki_ptr, ptr::null_mut(), ptr::null_mut(), 0, 0, KU_ALL, &mut pk_ptr, ptr::null_mut(), )) .expect("PKCS8 encoded key import has failed"); let sk = EcdhPrivateKey::from_ptr(pk_ptr)?; Ok(sk) } } pub fn export_ec_private_key_from_raw(key: PrivateKey) -> Result, Error> { init(); let mut key_item = SECItemMut::make_empty(); unsafe { PK11_ReadRawAttribute(PK11_TypePrivKey, key.cast(), CKA_VALUE, key_item.as_mut()) }; Ok(key_item.as_slice().to_owned()) } pub fn ecdh(sk: PrivateKey, pk: PublicKey) -> Result, Error> { init(); let sym_key = unsafe { PK11_PubDeriveWithKDF( sk.cast(), pk.cast(), 0, ptr::null_mut(), ptr::null_mut(), pkcs11_bindings::CKM_ECDH1_DERIVE, pkcs11_bindings::CKM_SHA512_HMAC, pkcs11_bindings::CKA_SIGN, 0, pkcs11_bindings::CKD_NULL, ptr::null_mut(), ptr::null_mut(), ) .into_result()? }; let key = sym_key.key_data().unwrap(); Ok(key.to_vec()) } pub fn convert_to_public(sk: PrivateKey) -> Result { init(); unsafe { let pk = crate::p11::SECKEY_ConvertToPublicKey(*sk).into_result()?; Ok(pk) } } pub fn sign( private_key: PrivateKey, data: &[u8], mechanism: std::os::raw::c_ulong, ) -> Result, Error> { init(); let data_signature = vec![0u8; 0x40]; let mut data_to_sign = SECItemBorrowed::wrap(&data); let mut signature = SECItemBorrowed::wrap(&data_signature); unsafe { secstatus_to_res(crate::p11::PK11_SignWithMechanism( private_key.as_mut().unwrap(), mechanism, std::ptr::null_mut(), signature.as_mut(), data_to_sign.as_mut(), )) .expect("Signature has failed"); let signature = signature.as_slice().to_vec(); Ok(signature) } } pub fn sign_ecdsa(private_key: PrivateKey, data: &[u8]) -> Result, Error> { sign(private_key, data, crate::p11::CKM_ECDSA.into()) } pub fn sign_eddsa(private_key: PrivateKey, data: &[u8]) -> Result, Error> { sign(private_key, data, crate::p11::CKM_EDDSA.into()) } pub fn verify( public_key: PublicKey, data: &[u8], signature: &[u8], mechanism: std::os::raw::c_ulong, ) -> Result { init(); unsafe { let mut data_to_sign = SECItemBorrowed::wrap(&data); let mut signature = SECItemBorrowed::wrap(&signature); let rv = crate::p11::PK11_VerifyWithMechanism( public_key.as_mut().unwrap(), mechanism.into(), std::ptr::null_mut(), signature.as_mut(), data_to_sign.as_mut(), std::ptr::null_mut(), ); match rv { 0 => Ok(true), _ => Ok(false), } } } pub fn verify_ecdsa(public_key: PublicKey, data: &[u8], signature: &[u8]) -> Result { verify(public_key, data, signature, crate::p11::CKM_ECDSA.into()) } pub fn verify_eddsa(public_key: PublicKey, data: &[u8], signature: &[u8]) -> Result { verify(public_key, data, signature, crate::p11::CKM_EDDSA.into()) }