use crate::{Error, Result};
use crate::crypto::asymmetric::KeyPair;
use crate::crypto::backend::interface::Asymmetric;
use crate::crypto::backend::openssl::der;
use crate::crypto::mpi;
use crate::crypto::mpi::{ProtectedMPI, MPI};
use crate::crypto::mem::Protected;
use crate::crypto::SessionKey;
use crate::packet::key::{Key4, SecretParts};
use crate::packet::{key, Key};
use crate::types::{Curve, HashAlgorithm, PublicKeyAlgorithm};
use std::convert::{TryFrom, TryInto};
use std::time::SystemTime;
use ossl::{
pkey::{EccData, EvpPkey, EvpPkeyType, DsaData, MlkeyData, PkeyData, RsaData, SlhDsaKeyData},
asymcipher::{EncAlg, EncOp, OsslAsymcipher},
signature::{OsslSignature, SigAlg, SigOp},
};
use std::ffi::CStr;
const E: &CStr = unsafe { CStr::from_ptr(b"e\0".as_ptr() as *const _) };
const N: &CStr = unsafe { CStr::from_ptr(b"n\0".as_ptr() as *const _) };
const D: &CStr = unsafe { CStr::from_ptr(b"d\0".as_ptr() as *const _) };
const RSA: &CStr = unsafe { CStr::from_ptr(b"RSA\0".as_ptr() as *const _) };
fn not_set() -> anyhow::Error {
Error::InvalidOperation("a required value was not set".into())
.into()
}
pub fn wrong_key() -> anyhow::Error {
Error::InvalidOperation("an unexpected key type was returned".into())
.into()
}
macro_rules! slhdsa {
($generate_key:ident,
$priv_type:ty,
$sign:ident,
$verify:ident,
$evp_pkey_type:ident,
$n:literal,
$sig_alg:ident,
$sig_size:literal) =>
{
fn $generate_key() -> Result<(Protected, $priv_type)>
{
let ctx = super::context();
let key = EvpPkey::generate(
&ctx, EvpPkeyType::$evp_pkey_type)?;
match key.export()? {
PkeyData::SlhDsaKey(SlhDsaKeyData {
ref pubkey,
ref prikey,
..
}) => {
let pubkey = pubkey.as_ref().expect("to be set");
let prikey = prikey.as_ref().expect("to be set");
assert_eq!(pubkey.len(), 2 * $n);
assert_eq!(prikey.len(), 4 * $n);
let mut public = [0; 2 * $n];
public.copy_from_slice(&pubkey);
let private = Protected::from(prikey);
Ok((private, public.into()))
},
_ => Err(wrong_key()),
}
}
fn $sign(secret: &Protected, digest: &[u8])
-> Result<Box<[u8; $sig_size]>>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::$evp_pkey_type,
PkeyData::SlhDsaKey(SlhDsaKeyData {
pubkey: None,
prikey: Some(secret.into()),
})
)?;
let mut signer = OsslSignature::new(
&ctx, SigOp::Sign, SigAlg::$sig_alg, &mut key, None)?;
let mut signature = Box::new([0; $sig_size]);
signer.sign(digest, Some(&mut signature[..]))?;
Ok(signature)
}
fn $verify(public: &[u8; 2 * $n], digest: &[u8],
signature: &[u8; $sig_size])
-> Result<bool>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::$evp_pkey_type,
PkeyData::SlhDsaKey(SlhDsaKeyData {
pubkey: Some(public.to_vec()),
prikey: None,
})
)?;
let mut verifier = OsslSignature::new(
&ctx, SigOp::Verify, SigAlg::$sig_alg, &mut key, None)?;
Ok(verifier.verify(digest, Some(&signature[..])).is_ok())
}
};
}
impl Asymmetric for super::Backend {
fn supports_algo(algo: PublicKeyAlgorithm) -> bool {
use PublicKeyAlgorithm::*;
let pqc = ossl::api_level() >= (3, 5, 0);
#[allow(deprecated)]
match algo {
X25519 | Ed25519 |
X448 | Ed448 |
RSAEncryptSign | RSAEncrypt | RSASign => true,
DSA => true,
ECDH | ECDSA | EdDSA => true,
MLDSA65_Ed25519 | MLDSA87_Ed448 => pqc,
SLHDSA128s | SLHDSA128f | SLHDSA256s => pqc,
MLKEM768_X25519 | MLKEM1024_X448 => pqc,
ElGamalEncrypt | ElGamalEncryptSign |
Private(_) | Unknown(_)
=> false,
}
}
fn supports_curve(curve: &Curve) -> bool {
if matches!(curve, Curve::Ed25519 | Curve::Cv25519) {
true
} else {
EvpPkeyType::try_from(curve).is_ok()
}
}
fn x25519_generate_key() -> Result<(Protected, [u8; 32])> {
let ctx = super::context();
let key = EvpPkey::generate(&ctx, EvpPkeyType::X25519)?;
match key.export()? {
PkeyData::Ecc(EccData { ref pubkey, ref prikey }) =>
Ok((prikey.as_ref().ok_or_else(not_set)?.into(),
pubkey.as_ref().ok_or_else(not_set)?.as_slice().try_into()?)),
_ => Err(wrong_key()),
}
}
fn x25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
let ctx = super::context();
let key = EvpPkey::import(
&ctx, EvpPkeyType::X25519,
PkeyData::Ecc(EccData {
pubkey: None,
prikey: Some(secret.into()),
})
)?;
match key.export()? {
PkeyData::Ecc(EccData { ref pubkey, .. }) => {
Ok(pubkey.as_ref().ok_or_else(not_set)?.as_slice().try_into()?)
},
_ => Err(wrong_key()),
}
}
fn x25519_shared_point(secret: &Protected, public: &[u8; 32])
-> Result<Protected> {
let ctx = super::context();
let mut public = EvpPkey::import(
&ctx, EvpPkeyType::X25519,
PkeyData::Ecc(EccData {
pubkey: Some(public.to_vec()),
prikey: None,
})
)?;
let mut secret = EvpPkey::import(
&ctx, EvpPkeyType::X25519,
PkeyData::Ecc(EccData {
pubkey: None,
prikey: Some(secret.into()),
})
)?;
let mut deriver = ossl::derive::EcdhDerive::new(&ctx, &mut secret)?;
let mut shared: Protected = vec![0; 32].into();
deriver.derive(&mut public, &mut shared)?;
Ok(shared)
}
fn x448_generate_key() -> Result<(Protected, [u8; 56])> {
let ctx = super::context();
let key = EvpPkey::generate(&ctx, EvpPkeyType::X448)?;
match key.export()? {
PkeyData::Ecc(EccData { ref pubkey, ref prikey }) =>
Ok((prikey.as_ref().ok_or_else(not_set)?.into(),
pubkey.as_ref().ok_or_else(not_set)?.as_slice().try_into()?)),
_ => Err(wrong_key()),
}
}
fn x448_derive_public(secret: &Protected) -> Result<[u8; 56]> {
let ctx = super::context();
let key = EvpPkey::import(
&ctx, EvpPkeyType::X448,
PkeyData::Ecc(EccData {
pubkey: None,
prikey: Some(secret.into()),
})
)?;
match key.export()? {
PkeyData::Ecc(EccData { ref pubkey, .. }) => {
Ok(pubkey.as_ref().ok_or_else(not_set)?.as_slice().try_into()?)
},
_ => Err(wrong_key()),
}
}
fn x448_shared_point(secret: &Protected, public: &[u8; 56])
-> Result<Protected> {
let ctx = super::context();
let mut public = EvpPkey::import(
&ctx, EvpPkeyType::X448,
PkeyData::Ecc(EccData {
pubkey: Some(public.to_vec()),
prikey: None,
})
)?;
let mut secret = EvpPkey::import(
&ctx, EvpPkeyType::X448,
PkeyData::Ecc(EccData {
pubkey: None,
prikey: Some(secret.into()),
})
)?;
let mut deriver = ossl::derive::EcdhDerive::new(&ctx, &mut secret)?;
let mut shared: Protected = vec![0; 56].into();
deriver.derive(&mut public, &mut shared)?;
Ok(shared)
}
fn ed25519_generate_key() -> Result<(Protected, [u8; 32])> {
let ctx = super::context();
let key = EvpPkey::generate(&ctx, EvpPkeyType::Ed25519)?;
match key.export()? {
PkeyData::Ecc(EccData { ref pubkey, ref prikey }) =>
Ok((prikey.as_ref().ok_or_else(not_set)?.into(),
pubkey.as_ref().ok_or_else(not_set)?.as_slice().try_into()?)),
_ => Err(wrong_key()),
}
}
fn ed25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
let ctx = super::context();
let key = EvpPkey::import(
&ctx, EvpPkeyType::Ed25519,
PkeyData::Ecc(EccData {
pubkey: None,
prikey: Some(secret.into()),
})
)?;
match key.export()? {
PkeyData::Ecc(EccData { ref pubkey, .. }) => {
Ok(pubkey.as_ref().ok_or_else(not_set)?.as_slice().try_into()?)
},
_ => Err(wrong_key()),
}
}
fn ed25519_sign(secret: &Protected, public: &[u8; 32], digest: &[u8])
-> Result<[u8; 64]> {
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Ed25519,
PkeyData::Ecc(EccData {
pubkey: Some(public.to_vec()),
prikey: Some(secret.into()),
})
)?;
let mut signer = OsslSignature::new(
&ctx, SigOp::Sign, SigAlg::Ed25519, &mut key, None)?;
let mut signature = [0; 64];
signer.sign(digest, Some(&mut signature))?;
Ok(signature)
}
fn ed25519_verify(public: &[u8; 32], digest: &[u8], signature: &[u8; 64])
-> Result<bool> {
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Ed25519,
PkeyData::Ecc(EccData {
pubkey: Some(public.to_vec()),
prikey: None,
})
)?;
let mut verifier = OsslSignature::new(
&ctx, SigOp::Verify, SigAlg::Ed25519, &mut key, None)?;
Ok(verifier.verify(digest, Some(&signature[..])).is_ok())
}
fn ed448_generate_key() -> Result<(Protected, [u8; 57])> {
let ctx = super::context();
let key = EvpPkey::generate(&ctx, EvpPkeyType::Ed448)?;
match key.export()? {
PkeyData::Ecc(EccData { ref pubkey, ref prikey }) =>
Ok((prikey.as_ref().ok_or_else(not_set)?.into(),
pubkey.as_ref().ok_or_else(not_set)?.as_slice().try_into()?)),
_ => Err(wrong_key()),
}
}
fn ed448_derive_public(secret: &Protected) -> Result<[u8; 57]> {
let ctx = super::context();
let key = EvpPkey::import(
&ctx, EvpPkeyType::Ed448,
PkeyData::Ecc(EccData {
pubkey: None,
prikey: Some(secret.into()),
})
)?;
match key.export()? {
PkeyData::Ecc(EccData { ref pubkey, .. }) => {
Ok(pubkey.as_ref().ok_or_else(not_set)?.as_slice().try_into()?)
},
_ => Err(wrong_key()),
}
}
fn ed448_sign(secret: &Protected, public: &[u8; 57], digest: &[u8])
-> Result<[u8; 114]> {
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Ed448,
PkeyData::Ecc(EccData {
pubkey: Some(public.to_vec()),
prikey: Some(secret.into()),
})
)?;
let mut signer = OsslSignature::new(
&ctx, SigOp::Sign, SigAlg::Ed448, &mut key, None)?;
let mut signature = [0; 114];
signer.sign(digest, Some(&mut signature))?;
Ok(signature)
}
fn ed448_verify(public: &[u8; 57], digest: &[u8], signature: &[u8; 114])
-> Result<bool> {
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Ed448,
PkeyData::Ecc(EccData {
pubkey: Some(public.to_vec()),
prikey: None,
})
)?;
let mut verifier = OsslSignature::new(
&ctx, SigOp::Verify, SigAlg::Ed448, &mut key, None)?;
Ok(verifier.verify(digest, Some(&signature[..])).is_ok())
}
fn dsa_generate_key(p_bits: usize)
-> Result<(MPI, MPI, MPI, MPI, ProtectedMPI)>
{
let ctx = super::context();
let key = EvpPkey::generate(&ctx, EvpPkeyType::Dsa(p_bits))?;
match key.export()? {
PkeyData::Dsa(key) => {
Ok((key.p.into(), key.q.into(), key.g.into(),
key.pub_key.into(), key.priv_key.expect("to be set").into()))
},
_ => Err(wrong_key()),
}
}
fn dsa_sign(x: &ProtectedMPI,
p: &MPI, q: &MPI, g: &MPI, y: &MPI,
digest: &[u8])
-> Result<(MPI, MPI)>
{
let ctx = super::context();
let pbits = p.bits();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Dsa(pbits),
PkeyData::Dsa(DsaData {
p: p.value().into(),
q: q.value().into(),
g: g.value().into(),
priv_key: Some(x.into()),
pub_key: y.value().into(),
}),
)?;
let mut signer = OsslSignature::new(
&ctx, SigOp::Sign, SigAlg::Dsa, &mut key, None)?;
let sig_len = signer.sign(digest, None)?;
let mut signature = vec![0u8; sig_len];
let sig_len = signer.sign(digest, Some(&mut signature))?;
signature.truncate(sig_len);
let (r, s) = der::parse_sig_r_s(&signature)?;
Ok((MPI::new(r), MPI::new(s)))
}
fn dsa_verify(p: &MPI, q: &MPI, g: &MPI, y: &MPI,
digest: &[u8],
r: &MPI, s: &MPI)
-> Result<bool>
{
let ctx = super::context();
let pbits = p.bits();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Dsa(pbits),
PkeyData::Dsa(DsaData {
p: p.value().into(),
q: q.value().into(),
g: g.value().into(),
priv_key: None,
pub_key: y.value().into(),
}),
)?;
let mut signature = Vec::new();
der::encode_sig_r_s(&mut signature, r.value(), s.value())?;
let mut verifier = OsslSignature::new(
&ctx, SigOp::Verify, SigAlg::Dsa, &mut key, None)?;
Ok(verifier.verify(digest, Some(&signature)).is_ok())
}
fn mldsa65_generate_key() -> Result<(Protected, Box<[u8; 1952]>)> {
let ctx = super::context();
let key = EvpPkey::generate(&ctx, EvpPkeyType::Mldsa65)?;
match key.export()? {
PkeyData::Mlkey(MlkeyData { ref pubkey, ref seed, .. }) => {
let pubkey = pubkey.as_ref().expect("to be set");
let mut public = Box::new([0; 1952]);
let l = public.len().min(pubkey.len());
public[..l].copy_from_slice(&pubkey[..l]);
Ok((seed.as_ref().ok_or_else(not_set)?.into(), public))
},
_ => Err(wrong_key()),
}
}
fn mldsa65_sign(secret: &Protected, digest: &[u8])
-> Result<Box<[u8; 3309]>>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Mldsa65,
PkeyData::Mlkey(MlkeyData {
pubkey: None,
prikey: None,
seed: Some(secret.into()),
})
)?;
let mut signer = OsslSignature::new(
&ctx, SigOp::Sign, SigAlg::Mldsa65, &mut key, None)?;
let mut signature = Box::new([0; 3309]);
signer.sign(digest, Some(&mut signature[..]))?;
Ok(signature)
}
fn mldsa65_verify(public: &[u8; 1952], digest: &[u8], signature: &[u8; 3309])
-> Result<bool>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Mldsa65,
PkeyData::Mlkey(MlkeyData {
pubkey: Some(public.to_vec()),
prikey: None,
seed: None,
})
)?;
let mut verifier = OsslSignature::new(
&ctx, SigOp::Verify, SigAlg::Mldsa65, &mut key, None)?;
Ok(verifier.verify(digest, Some(&signature[..])).is_ok())
}
fn mldsa87_generate_key() -> Result<(Protected, Box<[u8; 2592]>)> {
let ctx = super::context();
let key = EvpPkey::generate(&ctx, EvpPkeyType::Mldsa87)?;
match key.export()? {
PkeyData::Mlkey(MlkeyData { ref pubkey, ref seed, .. }) => {
let pubkey = pubkey.as_ref().expect("to be set");
let mut public = Box::new([0; 2592]);
let l = public.len().min(pubkey.len());
public[..l].copy_from_slice(&pubkey[..l]);
Ok((seed.as_ref().ok_or_else(not_set)?.into(), public))
},
_ => Err(wrong_key()),
}
}
fn mldsa87_sign(secret: &Protected, digest: &[u8])
-> Result<Box<[u8; 4627]>>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Mldsa87,
PkeyData::Mlkey(MlkeyData {
pubkey: None,
prikey: None,
seed: Some(secret.into()),
})
)?;
let mut signer = OsslSignature::new(
&ctx, SigOp::Sign, SigAlg::Mldsa87, &mut key, None)?;
let mut signature = Box::new([0; 4627]);
signer.sign(digest, Some(&mut signature[..]))?;
Ok(signature)
}
fn mldsa87_verify(public: &[u8; 2592], digest: &[u8], signature: &[u8; 4627])
-> Result<bool>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::Mldsa87,
PkeyData::Mlkey(MlkeyData {
pubkey: Some(public.to_vec()),
prikey: None,
seed: None,
})
)?;
let mut verifier = OsslSignature::new(
&ctx, SigOp::Verify, SigAlg::Mldsa87, &mut key, None)?;
Ok(verifier.verify(digest, Some(&signature[..])).is_ok())
}
slhdsa!(slhdsa128s_generate_key,
[u8; 32],
slhdsa128s_sign,
slhdsa128s_verify,
SlhdsaShake128s,
16,
SlhdsaShake128s,
7856);
slhdsa!(slhdsa128f_generate_key,
[u8; 32],
slhdsa128f_sign,
slhdsa128f_verify,
SlhdsaShake128f,
16,
SlhdsaShake128f,
17088);
slhdsa!(slhdsa256s_generate_key,
Box<[u8; 64]>,
slhdsa256s_sign,
slhdsa256s_verify,
SlhdsaShake256s,
32,
SlhdsaShake256s,
29792);
fn mlkem768_generate_key() -> Result<(Protected, Box<[u8; 1184]>)> {
let ctx = super::context();
let key = EvpPkey::generate(&ctx, EvpPkeyType::MlKem768)?;
match key.export()? {
PkeyData::Mlkey(MlkeyData { ref pubkey, ref seed, .. }) => {
let pubkey = pubkey.as_ref().expect("to be set");
let mut public = Box::new([0; 1184]);
let l = public.len().min(pubkey.len());
public[..l].copy_from_slice(&pubkey[..l]);
Ok((seed.as_ref().ok_or_else(not_set)?.into(), public))
},
_ => Err(wrong_key()),
}
}
fn mlkem768_encapsulate(public: &[u8; 1184])
-> Result<(Box<[u8; 1088]>, Protected)>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::MlKem768,
PkeyData::Mlkey(MlkeyData {
pubkey: Some(public.to_vec()),
prikey: None,
seed: None,
})
)?;
let mut encryptor = OsslAsymcipher::new(
&ctx, EncOp::Encapsulate, &mut key, None)?;
let mut ciphertext = Protected::from(vec![0; 1088]);
let (keyshare, l) =
encryptor.encapsulate(&mut ciphertext)?;
debug_assert_eq!(l, 1088);
debug_assert_eq!(ciphertext.len(), l);
let mut boxed_ciphertext = Box::new([0; 1088]);
boxed_ciphertext.copy_from_slice(&ciphertext);
Ok((boxed_ciphertext, Protected::from(keyshare)))
}
fn mlkem768_decapsulate(secret: &Protected,
ciphertext: &[u8; 1088])
-> Result<Protected>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::MlKem768,
PkeyData::Mlkey(MlkeyData {
pubkey: None,
prikey: None,
seed: Some(secret.into()),
})
)?;
let mut encryptor = OsslAsymcipher::new(
&ctx, EncOp::Decapsulate, &mut key, None)?;
let keyshare = encryptor.decapsulate(&ciphertext[..])?;
debug_assert_eq!(keyshare.len(), 32);
Ok(keyshare.into())
}
fn mlkem1024_generate_key() -> Result<(Protected, Box<[u8; 1568]>)> {
let ctx = super::context();
let key = EvpPkey::generate(&ctx, EvpPkeyType::MlKem1024)?;
match key.export()? {
PkeyData::Mlkey(MlkeyData { ref pubkey, ref seed, .. }) => {
let pubkey = pubkey.as_ref().expect("to be set");
let mut public = Box::new([0; 1568]);
let l = public.len().min(pubkey.len());
public[..l].copy_from_slice(&pubkey[..l]);
Ok((seed.as_ref().ok_or_else(not_set)?.into(), public))
},
_ => Err(wrong_key()),
}
}
fn mlkem1024_encapsulate(public: &[u8; 1568])
-> Result<(Box<[u8; 1568]>, Protected)>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::MlKem1024,
PkeyData::Mlkey(MlkeyData {
pubkey: Some(public.to_vec()),
prikey: None,
seed: None,
})
)?;
let mut encryptor = OsslAsymcipher::new(
&ctx, EncOp::Encapsulate, &mut key, None)?;
let mut ciphertext = Protected::from(vec![0; 1568]);
let (keyshare, l) =
encryptor.encapsulate(&mut ciphertext)?;
debug_assert_eq!(l, 1568);
debug_assert_eq!(ciphertext.len(), l);
let mut boxed_ciphertext = Box::new([0; 1568]);
boxed_ciphertext.copy_from_slice(&ciphertext);
Ok((boxed_ciphertext, Protected::from(keyshare)))
}
fn mlkem1024_decapsulate(secret: &Protected,
ciphertext: &[u8; 1568])
-> Result<Protected>
{
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, EvpPkeyType::MlKem1024,
PkeyData::Mlkey(MlkeyData {
pubkey: None,
prikey: None,
seed: Some(secret.into()),
})
)?;
let mut encryptor = OsslAsymcipher::new(
&ctx, EncOp::Decapsulate, &mut key, None)?;
let keyshare = encryptor.decapsulate(&ciphertext[..])?;
debug_assert_eq!(keyshare.len(), 32);
Ok(keyshare.into())
}
}
impl KeyPair {
pub(crate) fn sign_backend(&self,
secret: &mpi::SecretKeyMaterial,
hash_algo: HashAlgorithm,
digest: &[u8])
-> Result<mpi::Signature>
{
use crate::PublicKeyAlgorithm::*;
#[allow(deprecated)]
match (self.public().pk_algo(), self.public().mpis(), secret) {
(
RSAEncryptSign,
mpi::PublicKey::RSA { e, n },
mpi::SecretKeyMaterial::RSA { d, .. },
)
| (
RSASign,
mpi::PublicKey::RSA { e, n },
mpi::SecretKeyMaterial::RSA { d, .. },
) => {
let ctx = super::context();
const MAX_OID_SIZE: usize = 20;
let mut v = Vec::with_capacity(MAX_OID_SIZE + digest.len());
v.extend(hash_algo.oid()?);
v.extend(digest);
let mut params = ossl::OsslParamBuilder::with_capacity(3);
params.add_bn(E, e.value())?;
params.add_bn(N, n.value())?;
params.add_bn(D, d.value())?;
let params = params.finalize();
let mut key = EvpPkey::fromdata(
&ctx, RSA, ossl::bindings::EVP_PKEY_KEYPAIR, ¶ms)?;
let mut signer = OsslSignature::new(
&ctx, SigOp::Sign, SigAlg::Rsa, &mut key, None)?;
let size = signer.sign(&v, None)?;
let mut signature = vec![0; size];
let real_size =
signer.sign(&v, Some(&mut signature))?;
crate::vec_truncate(&mut signature, real_size);
Ok(mpi::Signature::RSA {
s: signature.into(),
})
}
(
PublicKeyAlgorithm::ECDSA,
mpi::PublicKey::ECDSA { curve, q },
mpi::SecretKeyMaterial::ECDSA { scalar },
) => {
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, curve.try_into()?,
PkeyData::Ecc(EccData {
pubkey: Some(q.value().to_vec()),
prikey: Some(
ossl::OsslSecret::from_slice(scalar.value())),
})
)?;
let mut signer = OsslSignature::new(
&ctx, SigOp::Sign, SigAlg::Ecdsa, &mut key, None)?;
let size = signer.sign(digest, None)?;
let mut signature = vec![0; size];
let real_size =
signer.sign(digest, Some(&mut signature))?;
crate::vec_truncate(&mut signature, real_size);
let (r, s) = der::parse_sig_r_s(&signature)?;
Ok(mpi::Signature::ECDSA {
r: MPI::new(r),
s: MPI::new(s),
})
}
(pk_algo, _, _) => Err(crate::Error::InvalidOperation(format!(
"unsupported combination of algorithm {:?}, key {:?}, \
and secret key {:?} by OpenSSL backend",
pk_algo,
self.public(),
self.secret()
))
.into()),
}
}
}
impl TryFrom<&Curve> for EvpPkeyType {
type Error = crate::Error;
fn try_from(c: &Curve) -> std::result::Result<Self, Self::Error> {
match c {
Curve::NistP256 => Ok(EvpPkeyType::P256),
Curve::NistP384 => Ok(EvpPkeyType::P384),
Curve::NistP521 => Ok(EvpPkeyType::P521),
Curve::BrainpoolP256 => Ok(EvpPkeyType::BrainpoolP256r1),
Curve::BrainpoolP384 => Ok(EvpPkeyType::BrainpoolP384r1),
Curve::BrainpoolP512 => Ok(EvpPkeyType::BrainpoolP512r1),
c => Err(Error::UnsupportedEllipticCurve(c.clone()))?,
}
}
}
impl KeyPair {
pub(crate) fn decrypt_backend(
&self,
secret: &mpi::SecretKeyMaterial,
ciphertext: &mpi::Ciphertext,
plaintext_len: Option<usize>,
) -> Result<SessionKey> {
use crate::crypto::mpi::PublicKey;
Ok(match (self.public().mpis(), secret, ciphertext) {
(
PublicKey::RSA { ref e, ref n },
mpi::SecretKeyMaterial::RSA { d, .. },
mpi::Ciphertext::RSA { ref c },
) => {
let ctx = super::context();
let mut params = ossl::OsslParamBuilder::with_capacity(3);
params.add_bn(E, e.value())?;
params.add_bn(N, n.value())?;
params.add_bn(D, d.value())?;
let params = params.finalize();
let mut key = EvpPkey::fromdata(
&ctx, RSA, ossl::bindings::EVP_PKEY_KEYPAIR, ¶ms)?;
let params = ossl::asymcipher::rsa_enc_params(
EncAlg::RsaPkcs1_5, None)?;
let mut decryptor = OsslAsymcipher::new(
&ctx, EncOp::Decrypt, &mut key, Some(¶ms))?;
let size = decryptor.decrypt(c.value(), None)?;
let mut buf: Protected = vec![0; size].into();
let real_size =
decryptor.decrypt(c.value(), Some(&mut buf))?;
let mut plaintext: Protected = vec![0; real_size].into();
plaintext[..].copy_from_slice(&buf[..real_size]);
plaintext.into()
}
(
PublicKey::ECDH { .. },
mpi::SecretKeyMaterial::ECDH { .. },
mpi::Ciphertext::ECDH { .. },
) => crate::crypto::ecdh::decrypt(self.public(), secret,
ciphertext,
plaintext_len)?,
(public, secret, ciphertext) => {
return Err(crate::Error::InvalidOperation(format!(
"unsupported combination of key pair {:?}/{:?} \
and ciphertext {:?}",
public, secret, ciphertext
))
.into())
}
})
}
}
impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> {
pub(crate) fn encrypt_backend(&self, data: &SessionKey) -> Result<mpi::Ciphertext> {
use PublicKeyAlgorithm::*;
#[allow(deprecated)]
match self.pk_algo() {
RSAEncryptSign | RSAEncrypt => match self.mpis() {
mpi::PublicKey::RSA { e, n } => {
let ciphertext_len = n.value().len();
if data.len() + 11 > ciphertext_len {
return Err(crate::Error::InvalidArgument(
"Plaintext data too large".into(),
)
.into());
}
let ctx = super::context();
let mut params = ossl::OsslParamBuilder::with_capacity(2);
params.add_bn(E, e.value())?;
params.add_bn(N, n.value())?;
let params = params.finalize();
let mut key = EvpPkey::fromdata(
&ctx, RSA, ossl::bindings::EVP_PKEY_PUBLIC_KEY, ¶ms)?;
let params = ossl::asymcipher::rsa_enc_params(
EncAlg::RsaPkcs1_5, None)?;
let mut encryptor = OsslAsymcipher::new(
&ctx, EncOp::Encrypt, &mut key, Some(¶ms))?;
let size = encryptor.encrypt(data, None)?;
let mut buf = vec![0; size];
let real_size =
encryptor.encrypt(data, Some(&mut buf))?;
crate::vec_truncate(&mut buf, real_size);
Ok(mpi::Ciphertext::RSA {
c: buf.into(),
})
}
pk => Err(crate::Error::MalformedPacket(format!(
"Key: Expected RSA public key, got {:?}",
pk
))
.into()),
},
ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(), data),
RSASign | DSA | ECDSA | EdDSA | Ed25519 | Ed448 |
MLDSA65_Ed25519 | MLDSA87_Ed448
| SLHDSA128s | SLHDSA128f | SLHDSA256s =>
Err(Error::InvalidOperation(
format!("{} is not an encryption algorithm", self.pk_algo())
).into()),
X25519 | X448 | ElGamalEncrypt | ElGamalEncryptSign |
MLKEM768_X25519 | MLKEM1024_X448 | Private(_) | Unknown(_) =>
Err(Error::UnsupportedPublicKeyAlgorithm(self.pk_algo()).into()),
}
}
pub(crate) fn verify_backend(
&self,
sig: &mpi::Signature,
hash_algo: HashAlgorithm,
digest: &[u8],
) -> Result<()> {
let ok = match (self.mpis(), sig) {
(mpi::PublicKey::RSA { e, n }, mpi::Signature::RSA { s }) => {
let ctx = super::context();
let mut params = ossl::OsslParamBuilder::with_capacity(2);
params.add_bn(E, e.value())?;
params.add_bn(N, n.value())?;
let params = params.finalize();
let mut key = EvpPkey::fromdata(
&ctx, RSA, ossl::bindings::EVP_PKEY_PUBLIC_KEY, ¶ms)?;
let mut verifier = OsslSignature::new(
&ctx, SigOp::Verify, SigAlg::Rsa, &mut key, None)?;
let mut v = vec![];
v.extend(hash_algo.oid()?);
v.extend(digest);
verifier.verify(&v, Some(s.value())).is_ok()
}
(mpi::PublicKey::ECDSA { curve, q }, mpi::Signature::ECDSA { r, s }) => {
let ctx = super::context();
let mut key = EvpPkey::import(
&ctx, curve.try_into()?,
PkeyData::Ecc(EccData {
pubkey: Some(q.value().to_vec()),
prikey: None,
})
)?;
let mut signature = Vec::new();
der::encode_sig_r_s(&mut signature, r.value(), s.value())?;
let mut verifier = OsslSignature::new(
&ctx, SigOp::Verify, SigAlg::Ecdsa, &mut key, None)?;
verifier.verify(digest, Some(&signature)).is_ok()
}
_ => {
return Err(crate::Error::MalformedPacket(format!(
"unsupported combination of key {} and signature {:?}.",
self.pk_algo(),
sig
))
.into())
}
};
if ok {
Ok(())
} else {
Err(crate::Error::ManipulatedMessage.into())
}
}
}
impl<R> Key4<SecretParts, R>
where
R: key::KeyRole,
{
pub fn import_secret_rsa<T>(d: &[u8], p: &[u8], q: &[u8], ctime: T) -> Result<Self>
where
T: Into<Option<SystemTime>>,
{
let (p, q) = crate::crypto::rsa_sort_raw_pq(p, q);
let (e, key_data) = RsaData::from_dpq(d, p, q)?;
let ctx = super::context();
let key = EvpPkey::import(
&ctx, EvpPkeyType::Rsa(0, vec![]),
PkeyData::Rsa(key_data))?;
Self::make_rsa(&e, key, ctime.into())
}
pub fn generate_rsa(bits: usize) -> Result<Self> {
let ctx = super::context();
let e = 65537_i32.to_be_bytes();
let key = EvpPkey::generate(
&ctx, EvpPkeyType::Rsa(bits, e.to_vec()))?;
Self::make_rsa(&e, key, None)
}
fn make_rsa(e: &[u8], key: EvpPkey, ctime: Option<SystemTime>)
-> Result<Self>
{
use ossl::pkey::PkeyData;
match key.export()? {
PkeyData::Rsa(mut key) => {
use crate::crypto::raw_bigint_cmp;
use std::cmp::Ordering;
if raw_bigint_cmp(key.p.as_ref().expect("to be set"),
key.q.as_ref().expect("to be set"))
== Ordering::Greater
{
std::mem::swap(&mut key.p, &mut key.q);
}
let u = key.inverse_p_mod_q()?;
Self::with_secret(
ctime.unwrap_or_else(crate::now),
PublicKeyAlgorithm::RSAEncryptSign,
mpi::PublicKey::RSA {
e: MPI::new(&e),
n: MPI::new(key.n.as_ref()),
},
mpi::SecretKeyMaterial::RSA {
d: key.d.as_ref().expect("to be set").into(),
p: key.p.as_ref().expect("to be set").into(),
q: key.q.as_ref().expect("to be set").into(),
u: u.into(),
}
.into())
},
_ => Err(Error::InvalidOperation(
"got the wrong key type".into()).into()),
}
}
pub(crate) fn generate_ecc_backend(for_signing: bool, curve: Curve)
-> Result<(PublicKeyAlgorithm,
mpi::PublicKey,
mpi::SecretKeyMaterial)>
{
let ctx = super::context();
let key = EvpPkey::generate(&ctx, (&curve).try_into()?)?;
let hash = crate::crypto::ecdh::default_ecdh_kdf_hash(&curve);
let sym = crate::crypto::ecdh::default_ecdh_kek_cipher(&curve);
match key.export()? {
PkeyData::Ecc(key) => {
let q = key.pubkey.as_ref().expect("to be set").clone().into();
let scalar = key.prikey.as_ref().expect("to be set").into();
if for_signing {
Ok((
PublicKeyAlgorithm::ECDSA,
mpi::PublicKey::ECDSA { curve, q },
mpi::SecretKeyMaterial::ECDSA { scalar },
))
} else {
Ok((
PublicKeyAlgorithm::ECDH,
mpi::PublicKey::ECDH {
curve, q, hash, sym,
},
mpi::SecretKeyMaterial::ECDH { scalar },
))
}
},
_ => Err(Error::InvalidOperation(
"got the wrong key type".into()).into()),
}
}
}