Source code

Revision control

Copy as Markdown

Other Tools

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ptr;
use pkcs11_bindings::{
CK_FALSE, CKA_VALUE, CKM_EC_EDWARDS_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN,
CKM_EC_MONTGOMERY_KEY_PAIR_GEN,
};
// use std::ptr::null;
// use std::ptr::null_mut;
use crate::{
PrivateKey, PublicKey, SECItem, SECItemBorrowed, der,
err::{Error, IntoResult as _, secstatus_to_res},
init,
p11::{
KU_ALL, PK11_ExportDERPrivateKeyInfo, PK11_GenerateKeyPair,
PK11_ImportDERPrivateKeyInfoAndReturnKey, PK11_ImportPublicKey, PK11_PubDeriveWithKDF,
PK11_ReadRawAttribute, PK11ObjectType::PK11_TypePrivKey,
SECKEY_DecodeDERSubjectPublicKeyInfo, Slot,
},
ssl::PRBool,
util::SECItemMut,
};
//
// 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 {
#[must_use]
pub const fn new(curve: EcCurve) -> Self {
Self(curve)
}
pub fn generate_keypair(curve: &EcCurve) -> Result<EcdhKeypair, Error> {
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] = &[
* 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<Vec<u8>, 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) -> Vec<u8> {
match alg {
EcCurve::X25519 => OID_X25519_BYTES.to_vec(),
EcCurve::Ed25519 => OID_ED25519_BYTES.to_vec(),
EcCurve::P256 => OID_SECP256R1_BYTES.to_vec(),
EcCurve::P384 => OID_SECP384R1_BYTES.to_vec(),
EcCurve::P521 => OID_SECP521R1_BYTES.to_vec(),
}
}
const 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,
EcCurve::Ed25519 => CKM_EC_EDWARDS_KEY_PAIR_GEN,
EcCurve::X25519 => CKM_EC_MONTGOMERY_KEY_PAIR_GEN,
}
}
//
// Curve functions
//
pub fn ecdh_keygen(curve: &EcCurve) -> Result<EcdhKeypair, Error> {
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();
unsafe {
let sk = PK11_GenerateKeyPair(
*slot,
ckm,
oid_ptr.cast(),
&raw 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<Vec<u8>, Error> {
init()?;
unsafe {
let sk: crate::ScopedSECItem =
PK11_ExportDERPrivateKeyInfo(**key, ptr::null_mut()).into_result()?;
Ok(sk.into_vec())
}
}
pub fn import_ec_public_key_from_spki(spki: &[u8]) -> Result<PublicKey, Error> {
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()?;
let pk: PublicKey =
crate::p11::SECKEY_ExtractPublicKey(spki.as_mut().ok_or(Error::InvalidInput)?)
.into_result()?;
let handle = PK11_ImportPublicKey(*slot, *pk, PRBool::from(false));
if handle == pkcs11_bindings::CK_INVALID_HANDLE {
return Err(Error::InvalidInput);
}
Ok(pk)
}
}
pub fn import_ec_private_key_pkcs8(pki: &[u8]) -> Result<PrivateKey, Error> {
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,
&raw mut pk_ptr,
ptr::null_mut(),
))?;
let sk = EcdhPrivateKey::from_ptr(pk_ptr)?;
Ok(sk)
}
}
pub fn export_ec_private_key_from_raw(key: &PrivateKey) -> Result<Vec<u8>, 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<Vec<u8>, 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()?;
Ok(key.to_vec())
}
pub fn convert_to_public(sk: &PrivateKey) -> Result<PublicKey, Error> {
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<Vec<u8>, 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().ok_or(Error::InvalidInput)?,
mechanism,
ptr::null_mut(),
signature.as_mut(),
data_to_sign.as_mut(),
))?;
let signature = signature.as_slice().to_vec();
Ok(signature)
}
}
#[allow(clippy::allow_attributes)]
#[allow(clippy::useless_conversion)]
pub fn sign_ecdsa(private_key: &PrivateKey, data: &[u8]) -> Result<Vec<u8>, Error> {
sign(private_key, data, crate::p11::CKM_ECDSA.into())
}
#[allow(clippy::allow_attributes)]
#[allow(clippy::useless_conversion)]
pub fn sign_eddsa(private_key: &PrivateKey, data: &[u8]) -> Result<Vec<u8>, 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<bool, Error> {
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().ok_or(Error::InvalidInput)?,
mechanism,
ptr::null_mut(),
signature.as_mut(),
data_to_sign.as_mut(),
ptr::null_mut(),
);
match rv {
0 => Ok(true),
_ => Ok(false),
}
}
}
#[allow(clippy::allow_attributes)]
#[allow(clippy::useless_conversion)]
pub fn verify_ecdsa(public_key: &PublicKey, data: &[u8], signature: &[u8]) -> Result<bool, Error> {
verify(public_key, data, signature, crate::p11::CKM_ECDSA.into())
}
#[allow(clippy::allow_attributes)]
#[allow(clippy::useless_conversion)]
pub fn verify_eddsa(public_key: &PublicKey, data: &[u8], signature: &[u8]) -> Result<bool, Error> {
verify(public_key, data, signature, crate::p11::CKM_EDDSA.into())
}