use std::cmp::Ordering;
use std::convert::TryFrom;
use std::fmt;
use std::ops::{Deref, DerefMut};
use crate::{
Error,
HashAlgorithm,
Packet,
PublicKeyAlgorithm,
Result,
SignatureType,
crypto::mpi,
packet::{
Signature,
signature::{
Signature4,
subpacket::{
SubpacketArea,
},
},
},
};
#[derive(Clone)]
pub struct Signature6 {
pub(crate) common: Signature4,
salt: Vec<u8>,
}
assert_send_and_sync!(Signature6);
impl TryFrom<Signature> for Signature6 {
type Error = anyhow::Error;
fn try_from(sig: Signature) -> Result<Self> {
match sig {
Signature::V6(sig) => Ok(sig),
sig => Err(
Error::InvalidArgument(
format!(
"Got a v{}, require a v6 signature",
sig.version()))
.into()),
}
}
}
impl Deref for Signature6 {
type Target = Signature4;
fn deref(&self) -> &Self::Target {
&self.common
}
}
impl DerefMut for Signature6 {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.common
}
}
impl fmt::Debug for Signature6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Signature6")
.field("version", &self.version())
.field("typ", &self.typ())
.field("pk_algo", &self.pk_algo())
.field("hash_algo", &self.hash_algo())
.field("hashed_area", self.hashed_area())
.field("unhashed_area", self.unhashed_area())
.field("additional_issuers", &self.additional_issuers)
.field("digest_prefix",
&crate::fmt::to_hex(&self.digest_prefix, false))
.field("salt", &crate::fmt::hex::encode(&self.salt))
.field(
"computed_digest",
&self
.computed_digest
.get()
.map(|hash| crate::fmt::to_hex(&hash[..], false)),
)
.field("level", &self.level)
.field("mpis", &self.mpis)
.finish()
}
}
impl PartialEq for Signature6 {
fn eq(&self, other: &Signature6) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for Signature6 {}
impl PartialOrd for Signature6 {
fn partial_cmp(&self, other: &Signature6) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Signature6 {
fn cmp(&self, other: &Signature6) -> Ordering {
self.common.cmp(&other.common)
.then_with(|| self.salt.cmp(&other.salt))
}
}
impl std::hash::Hash for Signature6 {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
use std::hash::Hash as StdHash;
StdHash::hash(&self.common, state);
StdHash::hash(&self.salt, state);
}
}
impl Signature6 {
pub(crate) fn from_common(mut common: Signature4, salt: Vec<u8>)
-> Result<Self>
{
common.fields.version = 6;
Ok(Signature6 { common, salt })
}
pub fn new(typ: SignatureType, pk_algo: PublicKeyAlgorithm,
hash_algo: HashAlgorithm, hashed_area: SubpacketArea,
unhashed_area: SubpacketArea,
digest_prefix: [u8; 2],
salt: Vec<u8>,
mpis: mpi::Signature) -> Result<Self> {
Signature6::from_common(
Signature4::new(typ, pk_algo, hash_algo,
hashed_area, unhashed_area,
digest_prefix, mpis),
salt)
}
pub fn pk_algo(&self) -> PublicKeyAlgorithm {
self.fields.pk_algo()
}
pub fn digest_prefix(&self) -> &[u8; 2] {
&self.digest_prefix
}
#[allow(dead_code)]
pub(crate) fn set_digest_prefix(&mut self, prefix: [u8; 2]) -> [u8; 2] {
::std::mem::replace(&mut self.digest_prefix, prefix)
}
pub fn salt(&self) -> &[u8] {
&self.salt
}
#[allow(dead_code)]
pub(crate) fn set_salt(&mut self, salt: Vec<u8>) -> Vec<u8> {
::std::mem::replace(&mut self.salt, salt)
}
pub fn mpis(&self) -> &mpi::Signature {
&self.mpis
}
#[allow(dead_code)]
pub(crate) fn set_mpis(&mut self, mpis: mpi::Signature) -> mpi::Signature
{
::std::mem::replace(&mut self.mpis, mpis)
}
pub fn computed_digest(&self) -> Option<&[u8]> {
self.computed_digest.get().map(|d| &d[..])
}
pub fn level(&self) -> usize {
self.level
}
pub fn exportable(&self) -> Result<()> {
if ! self.exportable_certification().unwrap_or(true) {
return Err(Error::InvalidOperation(
"Cannot export non-exportable certification".into()).into());
}
if self.revocation_keys().any(|r| r.sensitive()) {
return Err(Error::InvalidOperation(
"Cannot export signature with sensitive designated revoker"
.into()).into());
}
Ok(())
}
}
impl From<Signature6> for Packet {
fn from(s: Signature6) -> Self {
Packet::Signature(s.into())
}
}
impl From<Signature6> for super::Signature {
fn from(s: Signature6) -> Self {
super::Signature::V6(s)
}
}
#[cfg(test)]
use quickcheck::{Arbitrary, Gen};
#[cfg(test)]
use crate::packet::signature::ArbitraryBounded;
#[cfg(test)]
impl ArbitraryBounded for Signature6 {
fn arbitrary_bounded(g: &mut Gen, depth: usize) -> Self {
let common = Signature4::arbitrary_bounded(g, depth);
let salt_size = common.hash_algo().salt_size().unwrap_or(16);
let mut salt = vec![0u8; salt_size];
salt.iter_mut().for_each(|p| *p = u8::arbitrary(g));
Self::from_common(common, salt)
.expect("salt has the right size")
}
}
#[cfg(test)]
impl_arbitrary_with_bound!(Signature6);