use std::marker::PhantomData;
use digest::{typenum::Unsigned, OutputSizeUser};
use ecdsa::{
elliptic_curve::{generic_array::ArrayLength, CurveArithmetic},
hazmat::DigestPrimitive,
PrimeCurve, SignatureSize,
};
use signature::{hazmat::PrehashSigner, Keypair};
use crate::pgp::{
adapter::PublicKey as HPublicKey,
crypto::{
hash::{HashAlgorithm, KnownDigest},
public_key::PublicKeyAlgorithm,
},
errors::{ensure_eq, Result},
packet::{PubKeyInner, PublicKey},
types::{
EcdsaPublicParams, Fingerprint, KeyDetails, KeyId, KeyVersion, Mpi, Password, PublicParams,
SignatureBytes, SigningKey, Timestamp, VerifyingKey,
},
};
impl<C> HPublicKey for ecdsa::VerifyingKey<C>
where
Self: PgpEcdsaPublicKey,
C: PrimeCurve + CurveArithmetic,
{
const PGP_ALGORITHM: PublicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
fn pgp_parameters(&self) -> PublicParams {
let key = self.ecdsa_public_key();
PublicParams::ECDSA(key)
}
}
pub trait PgpEcdsaPublicKey {
fn ecdsa_public_key(&self) -> EcdsaPublicParams;
}
impl PgpEcdsaPublicKey for p256::ecdsa::VerifyingKey {
fn ecdsa_public_key(&self) -> EcdsaPublicParams {
let key = self.into();
EcdsaPublicParams::P256 { key }
}
}
#[derive(derive_more::Debug)]
#[debug("EcdsaSigner({public_key:?})")]
pub struct EcdsaSigner<T, C> {
inner: T,
public_key: PublicKey,
_signature: PhantomData<C>,
}
impl<C, T> EcdsaSigner<T, C>
where
T: Keypair,
T::VerifyingKey: HPublicKey,
{
pub fn new(inner: T, version: KeyVersion, created_at: Timestamp) -> Result<Self> {
let public_key = PubKeyInner::new(
version,
<T as Keypair>::VerifyingKey::PGP_ALGORITHM,
created_at,
None,
inner.verifying_key().pgp_parameters(),
)?;
let public_key = PublicKey::from_inner(public_key)?;
Ok(Self {
inner,
public_key,
_signature: PhantomData,
})
}
pub fn public_key(&self) -> &PublicKey {
&self.public_key
}
}
impl<C, T> Keypair for EcdsaSigner<T, C>
where
T: Keypair,
{
type VerifyingKey = T::VerifyingKey;
fn verifying_key(&self) -> Self::VerifyingKey {
self.inner.verifying_key()
}
}
impl<C, T> EcdsaSigner<T, C>
where
C: PrimeCurve + DigestPrimitive,
SignatureSize<C>: ArrayLength<u8>,
T: PrehashSigner<ecdsa::Signature<C>>,
C::Digest: KnownDigest,
{
fn sign_prehash(&self, hash: HashAlgorithm, prehash: &[u8]) -> Result<Vec<Vec<u8>>> {
ensure_eq!(
hash,
C::Digest::HASH_ALGORITHM,
"signer only supports {}",
C::Digest::HASH_ALGORITHM
);
ensure_eq!(
prehash.len(),
<C::Digest as OutputSizeUser>::OutputSize::USIZE,
"Prehashed digest length mismatch, expected {}",
<C::Digest as OutputSizeUser>::OutputSize::USIZE
);
let signature = self.inner.sign_prehash(prehash)?;
let (r, s) = signature.split_bytes();
Ok(vec![r.to_vec(), s.to_vec()])
}
}
impl<C, T> SigningKey for EcdsaSigner<T, C>
where
C: PrimeCurve + DigestPrimitive,
SignatureSize<C>: ArrayLength<u8>,
T: PrehashSigner<ecdsa::Signature<C>>,
C::Digest: KnownDigest,
{
fn sign(
&self,
_key_pw: &Password,
hash: HashAlgorithm,
prehashed_data: &[u8],
) -> Result<SignatureBytes> {
let sig = self.sign_prehash(hash, prehashed_data)?;
let mpis = sig.iter().map(|v| Mpi::from_slice(&v[..])).collect();
Ok(SignatureBytes::Mpis(mpis))
}
fn hash_alg(&self) -> HashAlgorithm {
C::Digest::HASH_ALGORITHM
}
}
impl<C, T> KeyDetails for EcdsaSigner<T, C> {
fn version(&self) -> KeyVersion {
self.public_key.version()
}
fn fingerprint(&self) -> Fingerprint {
self.public_key.fingerprint()
}
fn legacy_key_id(&self) -> KeyId {
self.public_key.legacy_key_id()
}
fn algorithm(&self) -> PublicKeyAlgorithm {
self.public_key.algorithm()
}
fn created_at(&self) -> Timestamp {
self.public_key.created_at()
}
fn expiration(&self) -> Option<u16> {
self.public_key.expiration()
}
fn public_params(&self) -> &PublicParams {
self.public_key.public_params()
}
}
impl<C, T> VerifyingKey for EcdsaSigner<T, C> {
fn verify(&self, hash: HashAlgorithm, data: &[u8], sig: &SignatureBytes) -> Result<()> {
self.public_key.verify(hash, data, sig)
}
}