use crate::bio::{MemBio, MemBioBuf};
use crate::error::ErrorStack;
use native_ossl_sys as sys;
use std::marker::PhantomData;
use std::sync::Arc;
pub struct Public;
pub struct Private;
pub struct Params;
mod sealed {
pub trait HasParams {}
impl HasParams for super::Public {}
impl HasParams for super::Private {}
impl HasParams for super::Params {}
pub trait HasPublic: HasParams {}
impl HasPublic for super::Public {}
impl HasPublic for super::Private {}
pub trait HasPrivate: HasPublic {}
impl HasPrivate for super::Private {}
}
pub trait HasParams: sealed::HasParams {}
impl<T: sealed::HasParams> HasParams for T {}
pub trait HasPublic: sealed::HasPublic {}
impl<T: sealed::HasPublic> HasPublic for T {}
pub trait HasPrivate: sealed::HasPrivate {}
impl<T: sealed::HasPrivate> HasPrivate for T {}
pub struct Pkey<T> {
ptr: *mut sys::EVP_PKEY,
_role: PhantomData<T>,
}
unsafe impl<T> Send for Pkey<T> {}
unsafe impl<T> Sync for Pkey<T> {}
impl<T> Clone for Pkey<T> {
fn clone(&self) -> Self {
unsafe { sys::EVP_PKEY_up_ref(self.ptr) };
Pkey {
ptr: self.ptr,
_role: PhantomData,
}
}
}
impl<T> Drop for Pkey<T> {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_free(self.ptr) };
}
}
impl<T: HasParams> Pkey<T> {
#[must_use]
pub unsafe fn from_ptr(ptr: *mut sys::EVP_PKEY) -> Self {
Pkey {
ptr,
_role: PhantomData,
}
}
#[must_use]
pub fn as_ptr(&self) -> *mut sys::EVP_PKEY {
self.ptr
}
#[must_use]
pub fn bits(&self) -> u32 {
u32::try_from(unsafe { sys::EVP_PKEY_get_bits(self.ptr) }).unwrap_or(0)
}
#[must_use]
pub fn security_bits(&self) -> u32 {
u32::try_from(unsafe { sys::EVP_PKEY_get_security_bits(self.ptr) }).unwrap_or(0)
}
#[must_use]
pub fn is_a(&self, name: &std::ffi::CStr) -> bool {
unsafe { sys::EVP_PKEY_is_a(self.ptr, name.as_ptr()) == 1 }
}
#[must_use]
pub fn public_eq<U: HasPublic>(&self, other: &Pkey<U>) -> bool
where
T: HasPublic,
{
unsafe { sys::EVP_PKEY_eq(self.ptr, other.ptr) == 1 }
}
pub fn get_params(&self, params: &mut crate::params::Params<'_>) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_get_params(self.ptr, params.as_mut_ptr()))
}
pub fn public_key_to_der(&self) -> Result<Vec<u8>, ErrorStack>
where
T: HasPublic,
{
let len = unsafe { sys::i2d_PUBKEY(self.ptr, std::ptr::null_mut()) };
if len < 0 {
return Err(ErrorStack::drain());
}
let mut buf = vec![0u8; usize::try_from(len).unwrap_or(0)];
let mut out_ptr = buf.as_mut_ptr();
let written = unsafe { sys::i2d_PUBKEY(self.ptr, std::ptr::addr_of_mut!(out_ptr)) };
if written < 0 {
return Err(ErrorStack::drain());
}
buf.truncate(usize::try_from(written).unwrap_or(0));
Ok(buf)
}
}
impl Pkey<Private> {
#[cfg(feature = "fips-provider")]
pub unsafe fn keydata(&self) -> *mut std::ffi::c_void {
self.ptr
.cast::<u8>()
.add(native_ossl_sys::fips_internal::EVP_PKEY_KEYDATA_OFFSET)
.cast::<*mut std::ffi::c_void>()
.read()
}
pub fn from_pem(pem: &[u8]) -> Result<Self, ErrorStack> {
let bio = MemBioBuf::new(pem)?;
let ptr = unsafe {
sys::PEM_read_bio_PrivateKey(
bio.as_ptr(),
std::ptr::null_mut(),
None,
std::ptr::null_mut(),
)
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { Pkey::from_ptr(ptr) })
}
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
let mut bio = MemBio::new()?;
let rc = unsafe {
sys::PEM_write_bio_PrivateKey(
bio.as_ptr(),
self.ptr,
std::ptr::null(),
std::ptr::null_mut(),
0,
None,
std::ptr::null_mut(),
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
Ok(bio.into_vec())
}
pub fn from_pem_in(ctx: &Arc<crate::lib_ctx::LibCtx>, pem: &[u8]) -> Result<Self, ErrorStack> {
let bio = MemBioBuf::new(pem)?;
let ptr = unsafe {
sys::PEM_read_bio_PrivateKey_ex(
bio.as_ptr(),
std::ptr::null_mut(),
None,
std::ptr::null_mut(),
ctx.as_ptr(),
std::ptr::null(),
)
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { Pkey::from_ptr(ptr) })
}
pub fn from_der(der: &[u8]) -> Result<Self, ErrorStack> {
let bio = MemBioBuf::new(der)?;
let ptr = unsafe { sys::d2i_PrivateKey_bio(bio.as_ptr(), std::ptr::null_mut()) };
if ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { Pkey::from_ptr(ptr) })
}
pub fn from_pem_passphrase(pem: &[u8], passphrase: &[u8]) -> Result<Self, ErrorStack> {
extern "C" fn passwd_cb(
buf: *mut std::ffi::c_char,
size: std::ffi::c_int,
_rwflag: std::ffi::c_int,
u: *mut std::ffi::c_void,
) -> std::ffi::c_int {
let pw: &[u8] = unsafe { *(u as *const &[u8]) };
let max_len = usize::try_from(size).unwrap_or(0);
let n = pw.len().min(max_len);
unsafe { std::ptr::copy_nonoverlapping(pw.as_ptr(), buf.cast::<u8>(), n) };
i32::try_from(n).unwrap()
}
let bio = MemBioBuf::new(pem)?;
let pw: &[u8] = passphrase;
let ptr = unsafe {
sys::PEM_read_bio_PrivateKey(
bio.as_ptr(),
std::ptr::null_mut(),
Some(passwd_cb),
std::ptr::addr_of!(pw).cast::<std::ffi::c_void>().cast_mut(),
)
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { Pkey::from_ptr(ptr) })
}
pub fn to_pem_encrypted(
&self,
cipher: &crate::cipher::CipherAlg,
passphrase: &[u8],
) -> Result<Vec<u8>, ErrorStack> {
let mut bio = MemBio::new()?;
let rc = unsafe {
sys::PEM_write_bio_PKCS8PrivateKey(
bio.as_ptr(),
self.ptr,
cipher.as_ptr(),
passphrase.as_ptr().cast(),
i32::try_from(passphrase.len()).expect("passphrase too long"),
None,
std::ptr::null_mut(),
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
Ok(bio.into_vec())
}
pub fn to_pkcs8_der(&self) -> Result<Vec<u8>, ErrorStack> {
let mut bio = MemBio::new()?;
let rc = unsafe { sys::i2d_PKCS8PrivateKeyInfo_bio(bio.as_ptr(), self.ptr) };
if rc != 1 {
return Err(ErrorStack::drain());
}
Ok(bio.into_vec())
}
}
impl Pkey<Public> {
pub fn from_pem(pem: &[u8]) -> Result<Self, ErrorStack> {
let bio = MemBioBuf::new(pem)?;
let ptr = unsafe {
sys::PEM_read_bio_PUBKEY(
bio.as_ptr(),
std::ptr::null_mut(),
None,
std::ptr::null_mut(),
)
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { Pkey::from_ptr(ptr) })
}
pub fn from_pem_in(ctx: &Arc<crate::lib_ctx::LibCtx>, pem: &[u8]) -> Result<Self, ErrorStack> {
let bio = MemBioBuf::new(pem)?;
let ptr = unsafe {
sys::PEM_read_bio_PUBKEY_ex(
bio.as_ptr(),
std::ptr::null_mut(),
None,
std::ptr::null_mut(),
ctx.as_ptr(),
std::ptr::null(),
)
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { Pkey::from_ptr(ptr) })
}
pub fn from_der(der: &[u8]) -> Result<Self, ErrorStack> {
let bio = MemBioBuf::new(der)?;
let ptr = unsafe { sys::d2i_PUBKEY_bio(bio.as_ptr(), std::ptr::null_mut()) };
if ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { Pkey::from_ptr(ptr) })
}
pub fn to_pem(&self) -> Result<Vec<u8>, ErrorStack> {
let mut bio = MemBio::new()?;
let rc = unsafe { sys::PEM_write_bio_PUBKEY(bio.as_ptr(), self.ptr) };
if rc != 1 {
return Err(ErrorStack::drain());
}
Ok(bio.into_vec())
}
}
impl From<Pkey<Private>> for Pkey<Public> {
fn from(k: Pkey<Private>) -> Self {
unsafe { sys::EVP_PKEY_up_ref(k.ptr) };
Pkey {
ptr: k.ptr,
_role: PhantomData,
}
}
}
const PKEY_PUBLIC_KEY: i32 = 0x86;
const PKEY_KEYPAIR: i32 = 0x87;
fn pkey_fromdata(
ctx: Option<&Arc<crate::lib_ctx::LibCtx>>,
pkey_type: &std::ffi::CStr,
params: &crate::params::Params<'_>,
selection: i32,
) -> Result<*mut sys::EVP_PKEY, ErrorStack> {
let libctx = ctx.map_or(std::ptr::null_mut(), |c| c.as_ptr());
let pctx =
unsafe { sys::EVP_PKEY_CTX_new_from_name(libctx, pkey_type.as_ptr(), std::ptr::null()) };
if pctx.is_null() {
return Err(ErrorStack::drain());
}
let rc = unsafe { sys::EVP_PKEY_fromdata_init(pctx) };
if rc != 1 {
unsafe { sys::EVP_PKEY_CTX_free(pctx) };
return Err(ErrorStack::drain());
}
let mut pkey: *mut sys::EVP_PKEY = std::ptr::null_mut();
let rc = unsafe {
sys::EVP_PKEY_fromdata(
pctx,
std::ptr::addr_of_mut!(pkey),
selection,
params.as_ptr().cast_mut(),
)
};
unsafe { sys::EVP_PKEY_CTX_free(pctx) };
if rc != 1 || pkey.is_null() {
return Err(ErrorStack::drain());
}
Ok(pkey)
}
fn pkey_todata(
ptr: *mut sys::EVP_PKEY,
selection: i32,
) -> Result<crate::params::Params<'static>, ErrorStack> {
let mut out: *mut sys::OSSL_PARAM = std::ptr::null_mut();
let rc = unsafe { sys::EVP_PKEY_todata(ptr, selection, std::ptr::addr_of_mut!(out)) };
if rc != 1 || out.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { crate::params::Params::from_owned_ptr(out) })
}
impl Pkey<Private> {
pub fn from_params(
ctx: Option<&Arc<crate::lib_ctx::LibCtx>>,
pkey_type: &std::ffi::CStr,
params: &crate::params::Params<'_>,
) -> Result<Self, ErrorStack> {
pkey_fromdata(ctx, pkey_type, params, PKEY_KEYPAIR)
.map(|ptr| unsafe { Pkey::from_ptr(ptr) })
}
pub fn export(&self) -> Result<crate::params::Params<'static>, ErrorStack> {
pkey_todata(self.ptr, PKEY_KEYPAIR)
}
}
impl Pkey<Public> {
pub fn from_params(
ctx: Option<&Arc<crate::lib_ctx::LibCtx>>,
pkey_type: &std::ffi::CStr,
params: &crate::params::Params<'_>,
) -> Result<Self, ErrorStack> {
pkey_fromdata(ctx, pkey_type, params, PKEY_PUBLIC_KEY)
.map(|ptr| unsafe { Pkey::from_ptr(ptr) })
}
pub fn export(&self) -> Result<crate::params::Params<'static>, ErrorStack> {
pkey_todata(self.ptr, PKEY_PUBLIC_KEY)
}
}
pub struct KeygenCtx {
ptr: *mut sys::EVP_PKEY_CTX,
}
impl KeygenCtx {
pub fn new(name: &std::ffi::CStr) -> Result<Self, ErrorStack> {
let ptr = unsafe {
sys::EVP_PKEY_CTX_new_from_name(std::ptr::null_mut(), name.as_ptr(), std::ptr::null())
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
let rc = unsafe { sys::EVP_PKEY_keygen_init(ptr) };
if rc != 1 {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
return Err(ErrorStack::drain());
}
Ok(KeygenCtx { ptr })
}
pub fn set_params(&mut self, params: &crate::params::Params<'_>) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_CTX_set_params(self.ptr, params.as_ptr()))
}
pub fn generate(&mut self) -> Result<Pkey<Private>, ErrorStack> {
let mut key: *mut sys::EVP_PKEY = std::ptr::null_mut();
crate::ossl_call!(sys::EVP_PKEY_keygen(self.ptr, std::ptr::addr_of_mut!(key)))?;
if key.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { Pkey::from_ptr(key) })
}
}
impl Drop for KeygenCtx {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ptr) };
}
}
#[derive(Default)]
pub struct SignInit<'a> {
pub digest: Option<&'a crate::digest::DigestAlg>,
pub params: Option<&'a crate::params::Params<'a>>,
}
pub struct Signer {
ctx: crate::digest::DigestCtx,
_key: Pkey<Private>,
}
impl Signer {
pub fn new(key: &Pkey<Private>, init: &SignInit<'_>) -> Result<Self, ErrorStack> {
let ctx = alloc_digest_ctx()?;
let md_name_ptr = if let Some(d) = init.digest {
let p = unsafe { sys::OBJ_nid2sn(d.nid()) };
if p.is_null() {
return Err(ErrorStack::drain());
}
p
} else {
std::ptr::null()
};
let params_ptr = init
.params
.map_or(crate::params::null_params(), crate::params::Params::as_ptr);
let rc = unsafe {
sys::EVP_DigestSignInit_ex(
ctx.as_ptr(),
std::ptr::null_mut(),
md_name_ptr,
std::ptr::null_mut(),
std::ptr::null(),
key.ptr,
params_ptr,
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
Ok(Signer {
ctx,
_key: key.clone(),
})
}
pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_DigestSignUpdate(
self.ctx.as_ptr(),
data.as_ptr().cast(),
data.len()
))
}
pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
let mut siglen: usize = 0;
let rc = unsafe {
sys::EVP_DigestSignFinal(
self.ctx.as_ptr(),
std::ptr::null_mut(),
std::ptr::addr_of_mut!(siglen),
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
let mut sig = vec![0u8; siglen];
let rc = unsafe {
sys::EVP_DigestSignFinal(
self.ctx.as_ptr(),
sig.as_mut_ptr(),
std::ptr::addr_of_mut!(siglen),
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
sig.truncate(siglen);
Ok(sig)
}
pub fn sign_oneshot(&mut self, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
let mut siglen: usize = 0;
let rc = unsafe {
sys::EVP_DigestSign(
self.ctx.as_ptr(),
std::ptr::null_mut(),
std::ptr::addr_of_mut!(siglen),
data.as_ptr(),
data.len(),
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
let mut sig = vec![0u8; siglen];
let rc = unsafe {
sys::EVP_DigestSign(
self.ctx.as_ptr(),
sig.as_mut_ptr(),
std::ptr::addr_of_mut!(siglen),
data.as_ptr(),
data.len(),
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
sig.truncate(siglen);
Ok(sig)
}
}
pub struct Verifier {
ctx: crate::digest::DigestCtx,
_key: Pkey<Public>,
}
impl Verifier {
pub fn new(key: &Pkey<Public>, init: &SignInit<'_>) -> Result<Self, ErrorStack> {
let ctx = alloc_digest_ctx()?;
let md_name_ptr = if let Some(d) = init.digest {
let p = unsafe { sys::OBJ_nid2sn(d.nid()) };
if p.is_null() {
return Err(ErrorStack::drain());
}
p
} else {
std::ptr::null()
};
let params_ptr = init
.params
.map_or(crate::params::null_params(), crate::params::Params::as_ptr);
let rc = unsafe {
sys::EVP_DigestVerifyInit_ex(
ctx.as_ptr(),
std::ptr::null_mut(),
md_name_ptr,
std::ptr::null_mut(),
std::ptr::null(),
key.ptr,
params_ptr,
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
Ok(Verifier {
ctx,
_key: key.clone(),
})
}
pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_DigestVerifyUpdate(
self.ctx.as_ptr(),
data.as_ptr().cast(),
data.len()
))
}
pub fn verify(&mut self, signature: &[u8]) -> Result<bool, ErrorStack> {
let rc = unsafe {
sys::EVP_DigestVerifyFinal(self.ctx.as_ptr(), signature.as_ptr(), signature.len())
};
match rc {
1 => Ok(true),
0 => Ok(false),
_ => Err(ErrorStack::drain()),
}
}
pub fn verify_oneshot(&mut self, data: &[u8], signature: &[u8]) -> Result<bool, ErrorStack> {
let rc = unsafe {
sys::EVP_DigestVerify(
self.ctx.as_ptr(),
signature.as_ptr(),
signature.len(),
data.as_ptr(),
data.len(),
)
};
match rc {
1 => Ok(true),
0 => Ok(false),
_ => Err(ErrorStack::drain()),
}
}
}
fn alloc_digest_ctx() -> Result<crate::digest::DigestCtx, ErrorStack> {
let ctx_ptr = unsafe { sys::EVP_MD_CTX_new() };
if ctx_ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(unsafe { crate::digest::DigestCtx::from_ptr(ctx_ptr) })
}
pub struct DeriveCtx {
ptr: *mut sys::EVP_PKEY_CTX,
}
impl DeriveCtx {
pub fn new(key: &Pkey<Private>) -> Result<Self, ErrorStack> {
let ptr = unsafe {
sys::EVP_PKEY_CTX_new_from_pkey(std::ptr::null_mut(), key.ptr, std::ptr::null())
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
crate::ossl_call!(sys::EVP_PKEY_derive_init(ptr)).map_err(|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
})?;
Ok(DeriveCtx { ptr })
}
pub fn set_peer(&mut self, peer: &Pkey<Public>) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_derive_set_peer(self.ptr, peer.ptr))
}
pub fn derive(&mut self, out: &mut [u8]) -> Result<usize, ErrorStack> {
let mut len = out.len();
crate::ossl_call!(sys::EVP_PKEY_derive(
self.ptr,
out.as_mut_ptr(),
std::ptr::addr_of_mut!(len)
))?;
Ok(len)
}
pub fn derive_len(&mut self) -> Result<usize, ErrorStack> {
let mut len: usize = 0;
crate::ossl_call!(sys::EVP_PKEY_derive(
self.ptr,
std::ptr::null_mut(),
std::ptr::addr_of_mut!(len)
))?;
Ok(len)
}
}
impl Drop for DeriveCtx {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ptr) };
}
}
pub struct PkeyEncryptCtx {
ptr: *mut sys::EVP_PKEY_CTX,
}
impl PkeyEncryptCtx {
pub fn new(
key: &Pkey<Public>,
params: Option<&crate::params::Params<'_>>,
) -> Result<Self, ErrorStack> {
let ptr = unsafe {
sys::EVP_PKEY_CTX_new_from_pkey(std::ptr::null_mut(), key.ptr, std::ptr::null())
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
crate::ossl_call!(sys::EVP_PKEY_encrypt_init(ptr)).map_err(|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
})?;
let ctx = PkeyEncryptCtx { ptr };
if let Some(p) = params {
crate::ossl_call!(sys::EVP_PKEY_CTX_set_params(ctx.ptr, p.as_ptr())).map_err(|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
})?;
}
Ok(ctx)
}
pub fn set_params(&mut self, params: &crate::params::Params<'_>) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_CTX_set_params(self.ptr, params.as_ptr()))
}
pub fn encrypt(
&mut self,
plaintext: &[u8],
ciphertext: &mut [u8],
) -> Result<usize, ErrorStack> {
let mut outlen = ciphertext.len();
crate::ossl_call!(sys::EVP_PKEY_encrypt(
self.ptr,
ciphertext.as_mut_ptr(),
std::ptr::addr_of_mut!(outlen),
plaintext.as_ptr(),
plaintext.len()
))?;
Ok(outlen)
}
pub fn encrypt_len(&mut self, plaintext_len: usize) -> Result<usize, ErrorStack> {
let mut outlen: usize = 0;
crate::ossl_call!(sys::EVP_PKEY_encrypt(
self.ptr,
std::ptr::null_mut(),
std::ptr::addr_of_mut!(outlen),
std::ptr::null(),
plaintext_len
))?;
Ok(outlen)
}
}
impl Drop for PkeyEncryptCtx {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ptr) };
}
}
pub struct PkeyDecryptCtx {
ptr: *mut sys::EVP_PKEY_CTX,
}
impl PkeyDecryptCtx {
pub fn new(
key: &Pkey<Private>,
params: Option<&crate::params::Params<'_>>,
) -> Result<Self, ErrorStack> {
let ptr = unsafe {
sys::EVP_PKEY_CTX_new_from_pkey(std::ptr::null_mut(), key.ptr, std::ptr::null())
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
crate::ossl_call!(sys::EVP_PKEY_decrypt_init(ptr)).map_err(|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
})?;
let ctx = PkeyDecryptCtx { ptr };
if let Some(p) = params {
crate::ossl_call!(sys::EVP_PKEY_CTX_set_params(ctx.ptr, p.as_ptr())).map_err(|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
})?;
}
Ok(ctx)
}
pub fn set_params(&mut self, params: &crate::params::Params<'_>) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_CTX_set_params(self.ptr, params.as_ptr()))
}
pub fn decrypt(
&mut self,
ciphertext: &[u8],
plaintext: &mut [u8],
) -> Result<usize, ErrorStack> {
let mut outlen = plaintext.len();
crate::ossl_call!(sys::EVP_PKEY_decrypt(
self.ptr,
plaintext.as_mut_ptr(),
std::ptr::addr_of_mut!(outlen),
ciphertext.as_ptr(),
ciphertext.len()
))?;
Ok(outlen)
}
}
impl Drop for PkeyDecryptCtx {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ptr) };
}
}
#[cfg(ossl320)]
pub struct EncapResult {
pub wrapped_key: Vec<u8>,
pub shared_secret: Vec<u8>,
}
#[cfg(ossl320)]
pub struct EncapCtx {
ptr: *mut sys::EVP_PKEY_CTX,
}
#[cfg(ossl320)]
impl EncapCtx {
pub fn new(key: &Pkey<Public>) -> Result<Self, ErrorStack> {
let ptr = unsafe {
sys::EVP_PKEY_CTX_new_from_pkey(std::ptr::null_mut(), key.ptr, std::ptr::null())
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
crate::ossl_call!(sys::EVP_PKEY_encapsulate_init(ptr, std::ptr::null())).map_err(|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
})?;
Ok(EncapCtx { ptr })
}
pub fn encapsulate(&mut self) -> Result<EncapResult, ErrorStack> {
let mut wkeylen: usize = 0;
let mut sslen: usize = 0;
let rc = unsafe {
sys::EVP_PKEY_encapsulate(
self.ptr,
std::ptr::null_mut(),
std::ptr::addr_of_mut!(wkeylen),
std::ptr::null_mut(),
std::ptr::addr_of_mut!(sslen),
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
let mut wrapped_key = vec![0u8; wkeylen];
let mut shared_secret = vec![0u8; sslen];
crate::ossl_call!(sys::EVP_PKEY_encapsulate(
self.ptr,
wrapped_key.as_mut_ptr(),
std::ptr::addr_of_mut!(wkeylen),
shared_secret.as_mut_ptr(),
std::ptr::addr_of_mut!(sslen)
))?;
wrapped_key.truncate(wkeylen);
shared_secret.truncate(sslen);
Ok(EncapResult {
wrapped_key,
shared_secret,
})
}
}
#[cfg(ossl320)]
impl Drop for EncapCtx {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ptr) };
}
}
#[cfg(ossl320)]
pub struct DecapCtx {
ptr: *mut sys::EVP_PKEY_CTX,
}
#[cfg(ossl320)]
impl DecapCtx {
pub fn new(key: &Pkey<Private>) -> Result<Self, ErrorStack> {
let ptr = unsafe {
sys::EVP_PKEY_CTX_new_from_pkey(std::ptr::null_mut(), key.ptr, std::ptr::null())
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
crate::ossl_call!(sys::EVP_PKEY_decapsulate_init(ptr, std::ptr::null())).map_err(|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
})?;
Ok(DecapCtx { ptr })
}
pub fn decapsulate(&mut self, wrapped_key: &[u8]) -> Result<Vec<u8>, ErrorStack> {
let mut sslen: usize = 0;
let rc = unsafe {
sys::EVP_PKEY_decapsulate(
self.ptr,
std::ptr::null_mut(),
std::ptr::addr_of_mut!(sslen),
wrapped_key.as_ptr(),
wrapped_key.len(),
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
let mut ss = vec![0u8; sslen];
crate::ossl_call!(sys::EVP_PKEY_decapsulate(
self.ptr,
ss.as_mut_ptr(),
std::ptr::addr_of_mut!(sslen),
wrapped_key.as_ptr(),
wrapped_key.len()
))?;
ss.truncate(sslen);
Ok(ss)
}
}
#[cfg(ossl320)]
impl Drop for DecapCtx {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ptr) };
}
}
pub struct RawSigner {
ctx: *mut sys::EVP_PKEY_CTX,
}
unsafe impl Send for RawSigner {}
impl RawSigner {
pub fn new(
key: &Pkey<Private>,
libctx: Option<&Arc<crate::lib_ctx::LibCtx>>,
) -> Result<Self, ErrorStack> {
let lctx = libctx.map_or(std::ptr::null_mut(), |c| c.as_ptr());
let ptr = unsafe { sys::EVP_PKEY_CTX_new_from_pkey(lctx, key.ptr, std::ptr::null()) };
if ptr.is_null() {
return Err(ErrorStack::drain());
}
crate::ossl_call!(sys::EVP_PKEY_sign_init(ptr)).map_err(|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
})?;
Ok(RawSigner { ctx: ptr })
}
pub fn set_params(&mut self, params: &crate::params::Params<'_>) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_CTX_set_params(self.ctx, params.as_ptr()))
}
pub fn sign_len(&mut self, tbs_len: usize) -> Result<usize, ErrorStack> {
let mut siglen: usize = 0;
crate::ossl_call!(sys::EVP_PKEY_sign(
self.ctx,
std::ptr::null_mut(),
std::ptr::addr_of_mut!(siglen),
std::ptr::null(),
tbs_len,
))?;
Ok(siglen)
}
pub fn sign(&mut self, tbs: &[u8], sig: &mut [u8]) -> Result<usize, ErrorStack> {
let mut siglen = sig.len();
crate::ossl_call!(sys::EVP_PKEY_sign(
self.ctx,
sig.as_mut_ptr(),
std::ptr::addr_of_mut!(siglen),
tbs.as_ptr(),
tbs.len(),
))?;
Ok(siglen)
}
pub fn sign_alloc(&mut self, tbs: &[u8]) -> Result<Vec<u8>, ErrorStack> {
let siglen = self.sign_len(tbs.len())?;
let mut sig = vec![0u8; siglen];
let written = self.sign(tbs, &mut sig)?;
sig.truncate(written);
Ok(sig)
}
}
impl Drop for RawSigner {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ctx) };
}
}
pub struct RawVerifier {
ctx: *mut sys::EVP_PKEY_CTX,
}
unsafe impl Send for RawVerifier {}
impl RawVerifier {
pub fn new<T: HasPublic>(
key: &Pkey<T>,
libctx: Option<&Arc<crate::lib_ctx::LibCtx>>,
) -> Result<Self, ErrorStack> {
let lctx = libctx.map_or(std::ptr::null_mut(), |c| c.as_ptr());
let ptr = unsafe { sys::EVP_PKEY_CTX_new_from_pkey(lctx, key.ptr, std::ptr::null()) };
if ptr.is_null() {
return Err(ErrorStack::drain());
}
crate::ossl_call!(sys::EVP_PKEY_verify_init(ptr)).map_err(|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
})?;
Ok(RawVerifier { ctx: ptr })
}
pub fn set_params(&mut self, params: &crate::params::Params<'_>) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_CTX_set_params(self.ctx, params.as_ptr()))
}
pub fn verify(&mut self, tbs: &[u8], sig: &[u8]) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_verify(
self.ctx,
sig.as_ptr(),
sig.len(),
tbs.as_ptr(),
tbs.len(),
))
}
}
impl Drop for RawVerifier {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ctx) };
}
}
#[cfg(ossl320)]
pub struct SigAlg {
ptr: *mut sys::EVP_SIGNATURE,
}
#[cfg(ossl320)]
unsafe impl Send for SigAlg {}
#[cfg(ossl320)]
unsafe impl Sync for SigAlg {}
#[cfg(ossl320)]
impl SigAlg {
pub fn fetch(
name: &std::ffi::CStr,
props: Option<&std::ffi::CStr>,
) -> Result<Self, ErrorStack> {
let props_ptr = props.map_or(std::ptr::null(), std::ffi::CStr::as_ptr);
let ptr =
unsafe { sys::EVP_SIGNATURE_fetch(std::ptr::null_mut(), name.as_ptr(), props_ptr) };
if ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(SigAlg { ptr })
}
pub fn fetch_in(
ctx: &Arc<crate::lib_ctx::LibCtx>,
name: &std::ffi::CStr,
props: Option<&std::ffi::CStr>,
) -> Result<Self, ErrorStack> {
let props_ptr = props.map_or(std::ptr::null(), std::ffi::CStr::as_ptr);
let ptr = unsafe { sys::EVP_SIGNATURE_fetch(ctx.as_ptr(), name.as_ptr(), props_ptr) };
if ptr.is_null() {
return Err(ErrorStack::drain());
}
Ok(SigAlg { ptr })
}
}
#[cfg(ossl320)]
impl Clone for SigAlg {
fn clone(&self) -> Self {
unsafe { sys::EVP_SIGNATURE_up_ref(self.ptr) };
SigAlg { ptr: self.ptr }
}
}
#[cfg(ossl320)]
impl Drop for SigAlg {
fn drop(&mut self) {
unsafe { sys::EVP_SIGNATURE_free(self.ptr) };
}
}
#[cfg(ossl320)]
pub struct MessageSigner {
ctx: *mut sys::EVP_PKEY_CTX,
}
#[cfg(ossl320)]
unsafe impl Send for MessageSigner {}
#[cfg(ossl320)]
impl MessageSigner {
pub fn new(
key: &Pkey<Private>,
alg: &mut SigAlg,
params: Option<&crate::params::Params<'_>>,
) -> Result<Self, ErrorStack> {
let ptr = unsafe {
sys::EVP_PKEY_CTX_new_from_pkey(std::ptr::null_mut(), key.ptr, std::ptr::null())
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
let params_ptr = params.map_or(crate::params::null_params(), crate::params::Params::as_ptr);
crate::ossl_call!(sys::EVP_PKEY_sign_message_init(ptr, alg.ptr, params_ptr)).map_err(
|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
},
)?;
Ok(MessageSigner { ctx: ptr })
}
pub fn supports_streaming(&mut self) -> bool {
unsafe { sys::ERR_set_mark() };
let probe: [u8; 0] = [];
let rc = unsafe { sys::EVP_PKEY_sign_message_update(self.ctx, probe.as_ptr(), 0) };
unsafe { sys::ERR_pop_to_mark() };
rc == 1
}
pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_sign_message_update(
self.ctx,
data.as_ptr(),
data.len(),
))
}
pub fn sig_len(&mut self) -> Result<usize, ErrorStack> {
let mut siglen: usize = 0;
crate::ossl_call!(sys::EVP_PKEY_sign_message_final(
self.ctx,
std::ptr::null_mut(),
std::ptr::addr_of_mut!(siglen),
))?;
Ok(siglen)
}
pub fn finish(self, sig: &mut [u8]) -> Result<usize, ErrorStack> {
let mut siglen = sig.len();
let rc = unsafe {
sys::EVP_PKEY_sign_message_final(
self.ctx,
sig.as_mut_ptr(),
std::ptr::addr_of_mut!(siglen),
)
};
if rc != 1 {
return Err(ErrorStack::drain());
}
Ok(siglen)
}
pub fn sign_oneshot(self, data: &[u8], sig: &mut [u8]) -> Result<usize, ErrorStack> {
let rc_upd =
unsafe { sys::EVP_PKEY_sign_message_update(self.ctx, data.as_ptr(), data.len()) };
if rc_upd != 1 {
return Err(ErrorStack::drain());
}
let mut siglen = sig.len();
let rc_fin = unsafe {
sys::EVP_PKEY_sign_message_final(
self.ctx,
sig.as_mut_ptr(),
std::ptr::addr_of_mut!(siglen),
)
};
if rc_fin != 1 {
return Err(ErrorStack::drain());
}
Ok(siglen)
}
}
#[cfg(ossl320)]
impl Drop for MessageSigner {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ctx) };
}
}
#[cfg(ossl320)]
pub struct MessageVerifier {
ctx: *mut sys::EVP_PKEY_CTX,
}
#[cfg(ossl320)]
unsafe impl Send for MessageVerifier {}
#[cfg(ossl320)]
impl MessageVerifier {
pub fn new<T: HasPublic>(
key: &Pkey<T>,
alg: &mut SigAlg,
params: Option<&crate::params::Params<'_>>,
) -> Result<Self, ErrorStack> {
let ptr = unsafe {
sys::EVP_PKEY_CTX_new_from_pkey(std::ptr::null_mut(), key.ptr, std::ptr::null())
};
if ptr.is_null() {
return Err(ErrorStack::drain());
}
let params_ptr = params.map_or(crate::params::null_params(), crate::params::Params::as_ptr);
crate::ossl_call!(sys::EVP_PKEY_verify_message_init(ptr, alg.ptr, params_ptr)).map_err(
|e| {
unsafe { sys::EVP_PKEY_CTX_free(ptr) };
e
},
)?;
Ok(MessageVerifier { ctx: ptr })
}
pub fn set_params(&mut self, params: &crate::params::Params<'_>) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_CTX_set_params(self.ctx, params.as_ptr()))
}
pub fn set_signature(&mut self, sig: &[u8]) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_CTX_set_signature(
self.ctx,
sig.as_ptr(),
sig.len()
))
}
pub fn supports_streaming(&mut self) -> bool {
unsafe { sys::ERR_set_mark() };
let probe: [u8; 0] = [];
let rc = unsafe { sys::EVP_PKEY_verify_message_update(self.ctx, probe.as_ptr(), 0) };
unsafe { sys::ERR_pop_to_mark() };
rc == 1
}
pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
crate::ossl_call!(sys::EVP_PKEY_verify_message_update(
self.ctx,
data.as_ptr(),
data.len(),
))
}
pub fn finish(self) -> Result<(), ErrorStack> {
let rc = unsafe { sys::EVP_PKEY_verify_message_final(self.ctx) };
if rc != 1 {
return Err(ErrorStack::drain());
}
Ok(())
}
pub fn verify_oneshot(self, data: &[u8], sig: &[u8]) -> Result<(), ErrorStack> {
let rc_set = unsafe { sys::EVP_PKEY_CTX_set_signature(self.ctx, sig.as_ptr(), sig.len()) };
if rc_set != 1 {
return Err(ErrorStack::drain());
}
let rc_upd =
unsafe { sys::EVP_PKEY_verify_message_update(self.ctx, data.as_ptr(), data.len()) };
if rc_upd != 1 {
return Err(ErrorStack::drain());
}
let rc_fin = unsafe { sys::EVP_PKEY_verify_message_final(self.ctx) };
if rc_fin != 1 {
return Err(ErrorStack::drain());
}
Ok(())
}
}
#[cfg(ossl320)]
impl Drop for MessageVerifier {
fn drop(&mut self) {
unsafe { sys::EVP_PKEY_CTX_free(self.ctx) };
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ed25519_sign_verify() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let priv_key = kgen.generate().unwrap();
let pub_key = Pkey::<Public>::from(priv_key.clone());
let msg = b"hello world";
let init = SignInit::default();
let mut signer = Signer::new(&priv_key, &init).unwrap();
let sig = signer.sign_oneshot(msg).unwrap();
assert!(!sig.is_empty());
let mut verifier = Verifier::new(&pub_key, &init).unwrap();
assert!(verifier.verify_oneshot(msg, &sig).unwrap());
}
#[test]
fn ed25519_verify_wrong_msg_fails() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let priv_key = kgen.generate().unwrap();
let pub_key = Pkey::<Public>::from(priv_key.clone());
let mut signer = Signer::new(&priv_key, &SignInit::default()).unwrap();
let sig = signer.sign_oneshot(b"correct").unwrap();
let mut verifier = Verifier::new(&pub_key, &SignInit::default()).unwrap();
assert!(!verifier.verify_oneshot(b"tampered", &sig).unwrap());
}
#[test]
fn x25519_derive() {
let mut kgen_a = KeygenCtx::new(c"X25519").unwrap();
let priv_a = kgen_a.generate().unwrap();
let mut kgen_b = KeygenCtx::new(c"X25519").unwrap();
let priv_b = kgen_b.generate().unwrap();
let pub_b = Pkey::<Public>::from(priv_b);
let mut derive = DeriveCtx::new(&priv_a).unwrap();
derive.set_peer(&pub_b).unwrap();
let len = derive.derive_len().unwrap();
assert_eq!(len, 32);
let mut ss = vec![0u8; len];
let n = derive.derive(&mut ss).unwrap();
assert_eq!(n, 32);
assert_ne!(ss, [0u8; 32]);
}
#[test]
fn pem_round_trip() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let priv_key = kgen.generate().unwrap();
let pem = priv_key.to_pem().unwrap();
assert!(!pem.is_empty());
assert!(pem.starts_with(b"-----BEGIN"));
let priv_key2 = Pkey::<Private>::from_pem(&pem).unwrap();
assert_eq!(priv_key.bits(), priv_key2.bits());
assert!(priv_key.is_a(c"ED25519"));
}
#[test]
fn ed25519_metadata() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let key = kgen.generate().unwrap();
assert_eq!(key.bits(), 256);
assert_eq!(key.security_bits(), 128);
assert!(key.is_a(c"ED25519"));
}
#[test]
fn ecdsa_p256_raw_sign_verify() {
let mut kgen = KeygenCtx::new(c"EC").unwrap();
let params = crate::params::ParamBuilder::new()
.unwrap()
.push_utf8_string(c"group", c"P-256")
.unwrap()
.build()
.unwrap();
kgen.set_params(¶ms).unwrap();
let priv_key = kgen.generate().unwrap();
let pub_key = Pkey::<Public>::from(priv_key.clone());
let tbs: [u8; 32] = *b"0123456789abcdef0123456789abcdef";
let mut signer = RawSigner::new(&priv_key, None).unwrap();
let sig = signer.sign_alloc(&tbs).unwrap();
assert!(!sig.is_empty());
let mut verifier = RawVerifier::new(&pub_key, None).unwrap();
verifier.verify(&tbs, &sig).unwrap();
}
#[test]
fn ecdsa_p256_raw_verify_tampered_fails() {
let mut kgen = KeygenCtx::new(c"EC").unwrap();
let params = crate::params::ParamBuilder::new()
.unwrap()
.push_utf8_string(c"group", c"P-256")
.unwrap()
.build()
.unwrap();
kgen.set_params(¶ms).unwrap();
let priv_key = kgen.generate().unwrap();
let pub_key = Pkey::<Public>::from(priv_key.clone());
let tbs: [u8; 32] = *b"0123456789abcdef0123456789abcdef";
let mut signer = RawSigner::new(&priv_key, None).unwrap();
let mut sig = signer.sign_alloc(&tbs).unwrap();
if let Some(b) = sig.last_mut() {
*b ^= 0xff;
}
let mut verifier = RawVerifier::new(&pub_key, None).unwrap();
assert!(verifier.verify(&tbs, &sig).is_err());
}
#[cfg(ossl320)]
#[test]
fn sig_alg_fetch_clone_drop() {
let alg = SigAlg::fetch(c"ML-DSA-44", None).unwrap();
let alg2 = alg.clone();
drop(alg);
drop(alg2); }
#[cfg(ossl320)]
#[test]
fn message_signer_construction_and_streaming_probe() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let priv_key = kgen.generate().unwrap();
let mut alg = SigAlg::fetch(c"ED25519", None).unwrap();
let mut signer = MessageSigner::new(&priv_key, &mut alg, None).unwrap();
let _streaming = signer.supports_streaming();
assert_eq!(crate::error::ErrorStack::drain().errors().count(), 0);
}
#[cfg(ossl320)]
#[test]
fn message_verifier_construction() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let priv_key = kgen.generate().unwrap();
let pub_key = Pkey::<Public>::from(priv_key.clone());
let mut alg = SigAlg::fetch(c"ED25519", None).unwrap();
let _verifier = MessageVerifier::new(&pub_key, &mut alg, None).unwrap();
}
#[test]
fn encrypted_pem_round_trip() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let key = kgen.generate().unwrap();
let cipher = crate::cipher::CipherAlg::fetch(c"AES-256-CBC", None).unwrap();
let pem = key.to_pem_encrypted(&cipher, b"s3cret").unwrap();
assert!(pem.starts_with(b"-----BEGIN ENCRYPTED PRIVATE KEY-----"));
let key2 = Pkey::<Private>::from_pem_passphrase(&pem, b"s3cret").unwrap();
assert!(key.public_eq(&key2));
}
#[test]
fn encrypted_pem_wrong_passphrase_fails() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let key = kgen.generate().unwrap();
let cipher = crate::cipher::CipherAlg::fetch(c"AES-256-CBC", None).unwrap();
let pem = key.to_pem_encrypted(&cipher, b"correct").unwrap();
assert!(Pkey::<Private>::from_pem_passphrase(&pem, b"wrong").is_err());
}
#[test]
fn pkcs8_der_round_trip() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let key = kgen.generate().unwrap();
let der = key.to_pkcs8_der().unwrap();
assert!(!der.is_empty());
let key2 = Pkey::<Private>::from_der(&der).unwrap();
assert!(key.public_eq(&key2));
}
#[test]
fn pubkey_from_pem_in_roundtrip() {
let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
let priv_key = kgen.generate().unwrap();
let pub_pem = Pkey::<Public>::from(priv_key).to_pem().unwrap();
let lib_ctx = Arc::new(crate::lib_ctx::LibCtx::new().unwrap());
let pub_key = Pkey::<Public>::from_pem_in(&lib_ctx, &pub_pem).unwrap();
assert!(!pub_key.to_pem().unwrap().is_empty());
}
}