use std::ptr;
use boring::error::ErrorStack;
use foreign_types::ForeignType;
use rustls::{SignatureScheme, pki_types::alg_id};
use rustls_pki_types::{InvalidSignature, SignatureVerificationAlgorithm};
use crate::helper::{cvt_p, log_and_map};
#[derive(Debug)]
pub struct BoringEdVerifier(SignatureScheme);
impl BoringEdVerifier {
pub const ED25519: Self = Self(SignatureScheme::ED25519);
pub const ED448: Self = Self(SignatureScheme::ED448);
}
impl SignatureVerificationAlgorithm for BoringEdVerifier {
fn verify_signature(
&self,
public_key: &[u8],
message: &[u8],
signature: &[u8],
) -> Result<(), rustls_pki_types::InvalidSignature> {
let public_key = ed_public_key_for_scheme(public_key, self.0)
.map_err(|e| log_and_map("ed_public_key_for_scheme", e, InvalidSignature))?;
let mut verifier = ed_verifier_from_params(public_key.as_ref())
.map_err(|e| log_and_map("ed_verifier_from_params", e, InvalidSignature))?;
verifier.verify_oneshot(signature, message).map_or_else(
|_| Err(InvalidSignature),
|res| if res { Ok(()) } else { Err(InvalidSignature) },
)
}
fn public_key_alg_id(&self) -> rustls_pki_types::AlgorithmIdentifier {
self.signature_alg_id()
}
fn signature_alg_id(&self) -> rustls_pki_types::AlgorithmIdentifier {
match self.0 {
SignatureScheme::ED25519 => alg_id::ED25519,
SignatureScheme::ED448 => {
rustls_pki_types::AlgorithmIdentifier::from_slice(&[0x06, 0x03, 0x2B, 0x65, 0x71])
}
_ => unreachable!("BoringEdVerifier only supports configured EdDSA schemes"),
}
}
fn fips(&self) -> bool {
false
}
}
fn ed_verifier_from_params(
key: &boring::pkey::PKeyRef<boring::pkey::Public>,
) -> Result<boring::sign::Verifier<'_>, ErrorStack> {
boring::sign::Verifier::new_without_digest(key)
}
fn ed_public_key_for_scheme(
spki_spk: &[u8],
scheme: SignatureScheme,
) -> Result<boring::pkey::PKey<boring::pkey::Public>, ErrorStack> {
let nid = boring::nid::Nid::from_raw(match scheme {
SignatureScheme::ED25519 => boring_sys::EVP_PKEY_ED25519,
SignatureScheme::ED448 => boring_sys::EVP_PKEY_ED448,
_ => return Err(ErrorStack::get()),
});
public_key(spki_spk, nid)
}
pub fn public_key(
spki_spk: &[u8],
nid: boring::nid::Nid,
) -> Result<boring::pkey::PKey<boring::pkey::Public>, ErrorStack> {
Ok(unsafe {
let pkey = cvt_p(boring_sys::EVP_PKEY_new_raw_public_key(
nid.as_raw(),
ptr::null_mut(),
spki_spk.as_ptr(),
spki_spk.len(),
))?;
boring::pkey::PKey::from_ptr(pkey)
})
}