use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::TryInto;
use std::hash::{Hash, Hasher};
use std::sync::Mutex;
use std::ops::{Deref, DerefMut};
use std::fmt;
use std::io;
use std::cmp;
use std::time;
use quickcheck::{Arbitrary, Gen};
use crate::{
Error,
Result,
packet::Signature,
packet::signature::{self, Signature4, ArbitraryBounded},
packet::key,
packet::Key,
Fingerprint,
KeyID,
SignatureType,
serialize::MarshalInto,
};
use crate::types::{
AEADAlgorithm,
CompressionAlgorithm,
Duration,
Features,
HashAlgorithm,
KeyFlags,
KeyServerPreferences,
PublicKeyAlgorithm,
ReasonForRevocation,
RevocationKey,
SymmetricAlgorithm,
Timestamp,
};
lazy_static!{
pub static ref CLOCK_SKEW_TOLERANCE: time::Duration
= time::Duration::new(30 * 60, 0);
}
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash)]
#[derive(Clone, Copy)]
pub enum SubpacketTag {
SignatureCreationTime,
SignatureExpirationTime,
ExportableCertification,
TrustSignature,
RegularExpression,
Revocable,
KeyExpirationTime,
PlaceholderForBackwardCompatibility,
PreferredSymmetricAlgorithms,
RevocationKey,
Issuer,
NotationData,
PreferredHashAlgorithms,
PreferredCompressionAlgorithms,
KeyServerPreferences,
PreferredKeyServer,
PrimaryUserID,
PolicyURI,
KeyFlags,
SignersUserID,
ReasonForRevocation,
Features,
SignatureTarget,
EmbeddedSignature,
IssuerFingerprint,
PreferredAEADAlgorithms,
IntendedRecipient,
Reserved(u8),
Private(u8),
Unknown(u8),
}
impl fmt::Display for SubpacketTag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl From<u8> for SubpacketTag {
fn from(u: u8) -> Self {
match u {
2 => SubpacketTag::SignatureCreationTime,
3 => SubpacketTag::SignatureExpirationTime,
4 => SubpacketTag::ExportableCertification,
5 => SubpacketTag::TrustSignature,
6 => SubpacketTag::RegularExpression,
7 => SubpacketTag::Revocable,
9 => SubpacketTag::KeyExpirationTime,
10 => SubpacketTag::PlaceholderForBackwardCompatibility,
11 => SubpacketTag::PreferredSymmetricAlgorithms,
12 => SubpacketTag::RevocationKey,
16 => SubpacketTag::Issuer,
20 => SubpacketTag::NotationData,
21 => SubpacketTag::PreferredHashAlgorithms,
22 => SubpacketTag::PreferredCompressionAlgorithms,
23 => SubpacketTag::KeyServerPreferences,
24 => SubpacketTag::PreferredKeyServer,
25 => SubpacketTag::PrimaryUserID,
26 => SubpacketTag::PolicyURI,
27 => SubpacketTag::KeyFlags,
28 => SubpacketTag::SignersUserID,
29 => SubpacketTag::ReasonForRevocation,
30 => SubpacketTag::Features,
31 => SubpacketTag::SignatureTarget,
32 => SubpacketTag::EmbeddedSignature,
33 => SubpacketTag::IssuerFingerprint,
34 => SubpacketTag::PreferredAEADAlgorithms,
35 => SubpacketTag::IntendedRecipient,
0| 1| 8| 13| 14| 15| 17| 18| 19 => SubpacketTag::Reserved(u),
100..=110 => SubpacketTag::Private(u),
_ => SubpacketTag::Unknown(u),
}
}
}
impl From<SubpacketTag> for u8 {
fn from(t: SubpacketTag) -> Self {
match t {
SubpacketTag::SignatureCreationTime => 2,
SubpacketTag::SignatureExpirationTime => 3,
SubpacketTag::ExportableCertification => 4,
SubpacketTag::TrustSignature => 5,
SubpacketTag::RegularExpression => 6,
SubpacketTag::Revocable => 7,
SubpacketTag::KeyExpirationTime => 9,
SubpacketTag::PlaceholderForBackwardCompatibility => 10,
SubpacketTag::PreferredSymmetricAlgorithms => 11,
SubpacketTag::RevocationKey => 12,
SubpacketTag::Issuer => 16,
SubpacketTag::NotationData => 20,
SubpacketTag::PreferredHashAlgorithms => 21,
SubpacketTag::PreferredCompressionAlgorithms => 22,
SubpacketTag::KeyServerPreferences => 23,
SubpacketTag::PreferredKeyServer => 24,
SubpacketTag::PrimaryUserID => 25,
SubpacketTag::PolicyURI => 26,
SubpacketTag::KeyFlags => 27,
SubpacketTag::SignersUserID => 28,
SubpacketTag::ReasonForRevocation => 29,
SubpacketTag::Features => 30,
SubpacketTag::SignatureTarget => 31,
SubpacketTag::EmbeddedSignature => 32,
SubpacketTag::IssuerFingerprint => 33,
SubpacketTag::PreferredAEADAlgorithms => 34,
SubpacketTag::IntendedRecipient => 35,
SubpacketTag::Reserved(u) => u,
SubpacketTag::Private(u) => u,
SubpacketTag::Unknown(u) => u,
}
}
}
impl Arbitrary for SubpacketTag {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
u8::arbitrary(g).into()
}
}
#[cfg(test)]
mod tests {
use super::*;
quickcheck! {
fn roundtrip(tag: SubpacketTag) -> bool {
let val: u8 = tag.clone().into();
tag == SubpacketTag::from(val)
}
}
quickcheck! {
fn parse(tag: SubpacketTag) -> bool {
match tag {
SubpacketTag::Reserved(u) =>
(u == 0 || u == 1 || u == 8
|| u == 13 || u == 14 || u == 15
|| u == 17 || u == 18 || u == 19),
SubpacketTag::Private(u) => u >= 100 && u <= 110,
SubpacketTag::Unknown(u) => (u > 33 && u < 100) || u > 110,
_ => true
}
}
}
}
pub struct SubpacketArea {
packets: Vec<Subpacket>,
parsed: Mutex<RefCell<Option<HashMap<SubpacketTag, usize>>>>,
}
impl ArbitraryBounded for SubpacketArea {
fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self {
use rand::Rng;
let mut a = Self::default();
for _ in 0..g.gen_range(0, 32) {
let _ = a.add(ArbitraryBounded::arbitrary_bounded(g, depth));
}
a
}
}
impl_arbitrary_with_bound!(SubpacketArea);
impl Default for SubpacketArea {
fn default() -> Self {
Self::new(Default::default())
}
}
impl Clone for SubpacketArea {
fn clone(&self) -> Self {
Self::new(self.packets.clone())
}
}
impl PartialEq for SubpacketArea {
fn eq(&self, other: &SubpacketArea) -> bool {
self.packets == other.packets
}
}
impl Eq for SubpacketArea {}
impl Hash for SubpacketArea {
fn hash<H: Hasher>(&self, state: &mut H) {
self.packets.hash(state);
}
}
impl fmt::Debug for SubpacketArea {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list()
.entries(self.iter())
.finish()
}
}
impl<'a> IntoIterator for &'a SubpacketArea {
type Item = &'a Subpacket;
type IntoIter = std::slice::Iter<'a, Subpacket>;
fn into_iter(self) -> Self::IntoIter {
self.packets.iter()
}
}
impl SubpacketArea {
pub fn new(packets: Vec<Subpacket>) -> SubpacketArea {
SubpacketArea {
packets,
parsed: Mutex::new(RefCell::new(None)),
}
}
fn cache_init(&self) {
if self.parsed.lock().unwrap().borrow().is_none() {
let mut hash = HashMap::new();
for (i, sp) in self.packets.iter().enumerate() {
hash.insert(sp.tag(), i);
}
*self.parsed.lock().unwrap().borrow_mut() = Some(hash);
}
}
fn cache_invalidate(&self) {
*self.parsed.lock().unwrap().borrow_mut() = None;
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a Subpacket> {
self.packets.iter()
}
pub fn lookup(&self, tag: SubpacketTag) -> Option<&Subpacket> {
self.cache_init();
match self.parsed.lock().unwrap().borrow().as_ref().unwrap().get(&tag) {
Some(&n) => Some(&self.packets[n]),
None => None,
}
}
pub fn add(&mut self, packet: Subpacket) -> Result<()> {
if self.serialized_len() + packet.serialized_len()
> ::std::u16::MAX as usize
{
return Err(Error::MalformedPacket(
"Subpacket area exceeds maximum size".into()).into());
}
self.cache_invalidate();
self.packets.push(packet);
Ok(())
}
pub fn replace(&mut self, packet: Subpacket) -> Result<()> {
if self.iter().filter_map(|sp| if sp.tag() != packet.tag() {
Some(sp.serialized_len())
} else {
None
}).sum::<usize>() > std::u16::MAX as usize {
return Err(Error::MalformedPacket(
"Subpacket area exceeds maximum size".into()).into());
}
self.remove_all(packet.tag());
self.packets.push(packet);
Ok(())
}
pub fn remove_all(&mut self, tag: SubpacketTag) {
self.cache_invalidate();
self.packets.retain(|sp| sp.tag() != tag);
}
pub fn clear(&mut self) {
self.cache_invalidate();
self.packets.clear();
}
pub fn sort(&mut self) {
self.cache_invalidate();
self.packets.sort_by(|a, b| u8::from(a.tag()).cmp(&b.tag().into()));
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct NotationData {
flags: NotationDataFlags,
name: String,
value: Vec<u8>,
}
impl Arbitrary for NotationData {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
NotationData {
flags: Arbitrary::arbitrary(g),
name: Arbitrary::arbitrary(g),
value: Arbitrary::arbitrary(g),
}
}
}
impl NotationData {
pub fn new<N, V, F>(name: N, value: V, flags: F) -> Self
where N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
Self {
flags: flags.into().unwrap_or_default(),
name: name.as_ref().into(),
value: value.as_ref().into(),
}
}
pub fn flags(&self) -> NotationDataFlags {
self.flags
}
pub fn name(&self) -> &str {
&self.name
}
pub fn value(&self) -> &[u8] {
&self.value
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct NotationDataFlags(u32);
impl Default for NotationDataFlags {
fn default() -> Self {
NotationDataFlags(0)
}
}
impl From<u32> for NotationDataFlags {
fn from(v: u32) -> Self {
Self(v)
}
}
impl Arbitrary for NotationDataFlags {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
u32::arbitrary(g).into()
}
}
impl fmt::Debug for NotationDataFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut d = f.debug_struct("NotationDataFlags");
d.field("human_readable", &self.human_readable());
let other = self.0 & !NOTATION_DATA_FLAG_HUMAN_READABLE;
if other > 0 {
d.field("other", &crate::fmt::hex::encode(&other.to_be_bytes()));
}
d.finish()
}
}
const NOTATION_DATA_FLAG_HUMAN_READABLE: u32 = 0x80000000;
impl NotationDataFlags {
pub fn human_readable(&self) -> bool {
self.0 & NOTATION_DATA_FLAG_HUMAN_READABLE > 0
}
pub fn set_human_readable(mut self, value: bool) -> Self {
if value {
self.0 |= NOTATION_DATA_FLAG_HUMAN_READABLE;
} else {
self.0 &= ! NOTATION_DATA_FLAG_HUMAN_READABLE;
}
self
}
pub(crate) fn raw(&self) -> u32 {
self.0
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum SubpacketValue {
Unknown {
tag: SubpacketTag,
body: Vec<u8>
},
SignatureCreationTime(Timestamp),
SignatureExpirationTime(Duration),
ExportableCertification(bool),
TrustSignature {
level: u8,
trust: u8,
},
RegularExpression(Vec<u8>),
Revocable(bool),
KeyExpirationTime(Duration),
PreferredSymmetricAlgorithms(Vec<SymmetricAlgorithm>),
RevocationKey(RevocationKey),
Issuer(KeyID),
NotationData(NotationData),
PreferredHashAlgorithms(Vec<HashAlgorithm>),
PreferredCompressionAlgorithms(Vec<CompressionAlgorithm>),
KeyServerPreferences(KeyServerPreferences),
PreferredKeyServer(Vec<u8>),
PrimaryUserID(bool),
PolicyURI(Vec<u8>),
KeyFlags(KeyFlags),
SignersUserID(Vec<u8>),
ReasonForRevocation {
code: ReasonForRevocation,
reason: Vec<u8>,
},
Features(Features),
SignatureTarget {
pk_algo: PublicKeyAlgorithm,
hash_algo: HashAlgorithm,
digest: Vec<u8>,
},
EmbeddedSignature(Signature),
IssuerFingerprint(Fingerprint),
PreferredAEADAlgorithms(Vec<AEADAlgorithm>),
IntendedRecipient(Fingerprint),
#[doc(hidden)] __Nonexhaustive,
}
impl ArbitraryBounded for SubpacketValue {
fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self {
use rand::Rng;
use self::SubpacketValue::*;
loop {
break match g.gen_range(0, 26) {
0 => SignatureCreationTime(Arbitrary::arbitrary(g)),
1 => SignatureExpirationTime(Arbitrary::arbitrary(g)),
2 => ExportableCertification(Arbitrary::arbitrary(g)),
3 => TrustSignature {
level: Arbitrary::arbitrary(g),
trust: Arbitrary::arbitrary(g),
},
4 => RegularExpression(Arbitrary::arbitrary(g)),
5 => Revocable(Arbitrary::arbitrary(g)),
6 => KeyExpirationTime(Arbitrary::arbitrary(g)),
7 => PreferredSymmetricAlgorithms(Arbitrary::arbitrary(g)),
8 => RevocationKey(Arbitrary::arbitrary(g)),
9 => Issuer(Arbitrary::arbitrary(g)),
10 => NotationData(Arbitrary::arbitrary(g)),
11 => PreferredHashAlgorithms(Arbitrary::arbitrary(g)),
12 => PreferredCompressionAlgorithms(Arbitrary::arbitrary(g)),
13 => KeyServerPreferences(Arbitrary::arbitrary(g)),
14 => PreferredKeyServer(Arbitrary::arbitrary(g)),
15 => PrimaryUserID(Arbitrary::arbitrary(g)),
16 => PolicyURI(Arbitrary::arbitrary(g)),
17 => KeyFlags(Arbitrary::arbitrary(g)),
18 => SignersUserID(Arbitrary::arbitrary(g)),
19 => ReasonForRevocation {
code: Arbitrary::arbitrary(g),
reason: Arbitrary::arbitrary(g),
},
20 => Features(Arbitrary::arbitrary(g)),
21 => SignatureTarget {
pk_algo: Arbitrary::arbitrary(g),
hash_algo: Arbitrary::arbitrary(g),
digest: Arbitrary::arbitrary(g),
},
22 if depth == 0 => continue,
22 => EmbeddedSignature(
ArbitraryBounded::arbitrary_bounded(g, depth - 1)),
23 => IssuerFingerprint(Arbitrary::arbitrary(g)),
24 => PreferredAEADAlgorithms(Arbitrary::arbitrary(g)),
25 => IntendedRecipient(Arbitrary::arbitrary(g)),
_ => unreachable!(),
}
}
}
}
impl_arbitrary_with_bound!(SubpacketValue);
impl SubpacketValue {
pub fn tag(&self) -> SubpacketTag {
use self::SubpacketValue::*;
match &self {
SignatureCreationTime(_) => SubpacketTag::SignatureCreationTime,
SignatureExpirationTime(_) =>
SubpacketTag::SignatureExpirationTime,
ExportableCertification(_) =>
SubpacketTag::ExportableCertification,
TrustSignature { .. } => SubpacketTag::TrustSignature,
RegularExpression(_) => SubpacketTag::RegularExpression,
Revocable(_) => SubpacketTag::Revocable,
KeyExpirationTime(_) => SubpacketTag::KeyExpirationTime,
PreferredSymmetricAlgorithms(_) =>
SubpacketTag::PreferredSymmetricAlgorithms,
RevocationKey { .. } => SubpacketTag::RevocationKey,
Issuer(_) => SubpacketTag::Issuer,
NotationData(_) => SubpacketTag::NotationData,
PreferredHashAlgorithms(_) =>
SubpacketTag::PreferredHashAlgorithms,
PreferredCompressionAlgorithms(_) =>
SubpacketTag::PreferredCompressionAlgorithms,
KeyServerPreferences(_) => SubpacketTag::KeyServerPreferences,
PreferredKeyServer(_) => SubpacketTag::PreferredKeyServer,
PrimaryUserID(_) => SubpacketTag::PrimaryUserID,
PolicyURI(_) => SubpacketTag::PolicyURI,
KeyFlags(_) => SubpacketTag::KeyFlags,
SignersUserID(_) => SubpacketTag::SignersUserID,
ReasonForRevocation { .. } => SubpacketTag::ReasonForRevocation,
Features(_) => SubpacketTag::Features,
SignatureTarget { .. } => SubpacketTag::SignatureTarget,
EmbeddedSignature(_) => SubpacketTag::EmbeddedSignature,
IssuerFingerprint(_) => SubpacketTag::IssuerFingerprint,
PreferredAEADAlgorithms(_) =>
SubpacketTag::PreferredAEADAlgorithms,
IntendedRecipient(_) => SubpacketTag::IntendedRecipient,
Unknown { tag, .. } => *tag,
__Nonexhaustive => unreachable!(),
}
}
}
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct Subpacket {
pub(crate)
length: SubpacketLength,
critical: bool,
value: SubpacketValue,
}
impl ArbitraryBounded for Subpacket {
fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self {
Subpacket::new(ArbitraryBounded::arbitrary_bounded(g, depth),
Arbitrary::arbitrary(g)).unwrap()
}
}
impl_arbitrary_with_bound!(Subpacket);
impl fmt::Debug for Subpacket {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = f.debug_struct("Subpacket");
if self.length.raw.is_some() {
s.field("length", &self.length);
}
if self.critical {
s.field("critical", &self.critical);
}
s.field("value", &self.value);
s.finish()
}
}
impl Subpacket {
pub fn new(value: SubpacketValue, critical: bool)
-> Result<Subpacket> {
Ok(Self::with_length(
SubpacketLength::from(1 + value.serialized_len() as u32),
value, critical))
}
pub(crate) fn with_length(length: SubpacketLength,
value: SubpacketValue,
critical: bool)
-> Subpacket {
Subpacket {
length,
critical,
value,
}
}
pub fn critical(&self) -> bool {
self.critical
}
pub fn tag(&self) -> SubpacketTag {
self.value.tag()
}
pub fn value(&self) -> &SubpacketValue {
&self.value
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub(crate) struct SubpacketLength {
len: u32,
raw: Option<Vec<u8>>,
}
impl From<u32> for SubpacketLength {
fn from(len: u32) -> Self {
SubpacketLength {
len, raw: None,
}
}
}
impl SubpacketLength {
pub(crate) fn new(len: u32, raw: Option<Vec<u8>>) -> Self {
Self { len, raw }
}
pub(crate) fn serialize(&self, sink: &mut dyn std::io::Write)
-> io::Result<()> {
let v = self.len;
if let Some(ref raw) = self.raw {
sink.write_all(raw)
} else if v < 192 {
sink.write_all(&[v as u8])
} else if v < 16320 {
let v = v - 192 + (192 << 8);
sink.write_all(&[(v >> 8) as u8,
(v >> 0) as u8])
} else {
sink.write_all(&[(v >> 24) as u8,
(v >> 16) as u8,
(v >> 8) as u8,
(v >> 0) as u8])
}
}
pub(crate) fn len(&self) -> usize {
self.len as usize
}
pub(crate) fn serialized_len(&self) -> usize {
if let Some(ref raw) = self.raw {
raw.len()
} else {
Self::len_optimal_encoding(self.len)
}
}
pub(crate) fn len_optimal_encoding(len: u32) -> usize {
if len < 192 {
1
} else if len < 16320 {
2
} else {
5
}
}
}
impl SubpacketArea {
fn subpacket(&self, tag: SubpacketTag) -> Option<&Subpacket> {
self.lookup(tag)
}
fn subpackets(&self, target: SubpacketTag)
-> impl Iterator<Item = &Subpacket> {
self.iter().filter(move |sp| sp.tag() == target)
}
pub fn signature_creation_time(&self) -> Option<time::SystemTime> {
if let Some(sb)
= self.subpacket(SubpacketTag::SignatureCreationTime) {
if let SubpacketValue::SignatureCreationTime(v) = sb.value {
Some(v.into())
} else {
None
}
} else {
None
}
}
pub fn signature_validity_period(&self) -> Option<time::Duration> {
if let Some(sb)
= self.subpacket(SubpacketTag::SignatureExpirationTime) {
if let SubpacketValue::SignatureExpirationTime(v) = sb.value {
Some(v.into())
} else {
None
}
} else {
None
}
}
pub fn exportable_certification(&self) -> Option<bool> {
if let Some(sb)
= self.subpacket(SubpacketTag::ExportableCertification) {
if let SubpacketValue::ExportableCertification(v) = sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn trust_signature(&self) -> Option<(u8, u8)> {
if let Some(sb) = self.subpacket(SubpacketTag::TrustSignature) {
if let SubpacketValue::TrustSignature{ level, trust } = sb.value {
Some((level, trust))
} else {
None
}
} else {
None
}
}
pub fn regular_expression(&self) -> Option<&[u8]> {
if let Some(sb)
= self.subpacket(SubpacketTag::RegularExpression) {
if let SubpacketValue::RegularExpression(ref v) = sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn revocable(&self) -> Option<bool> {
if let Some(sb)
= self.subpacket(SubpacketTag::Revocable) {
if let SubpacketValue::Revocable(v) = sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn key_validity_period(&self) -> Option<time::Duration> {
if let Some(sb)
= self.subpacket(SubpacketTag::KeyExpirationTime) {
if let SubpacketValue::KeyExpirationTime(v) = sb.value {
Some(v.into())
} else {
None
}
} else {
None
}
}
pub fn preferred_symmetric_algorithms(&self)
-> Option<&[SymmetricAlgorithm]> {
if let Some(sb)
= self.subpacket(
SubpacketTag::PreferredSymmetricAlgorithms) {
if let SubpacketValue::PreferredSymmetricAlgorithms(v)
= &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn revocation_keys(&self)
-> impl Iterator<Item = &RevocationKey>
{
self.subpackets(SubpacketTag::RevocationKey).filter_map(|sb| {
if let SubpacketValue::RevocationKey(rk) = &sb.value {
Some(rk)
} else {
None
}
})
}
pub fn issuer(&self) -> Option<&KeyID> {
if let Some(sb)
= self.subpacket(SubpacketTag::Issuer) {
if let SubpacketValue::Issuer(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn notation_data(&self) -> Vec<&NotationData> {
self.iter().filter_map(|sb| {
if let SubpacketValue::NotationData(v) = &sb.value {
Some(v)
} else {
None
}
}).collect()
}
pub fn notation<N>(&self, name: N) -> Vec<&[u8]>
where N: AsRef<str>
{
self.subpackets(SubpacketTag::NotationData)
.into_iter().filter_map(|s| match s.value {
SubpacketValue::NotationData(ref v)
if v.name == name.as_ref() => Some(&v.value[..]),
_ => None,
})
.collect()
}
pub fn preferred_hash_algorithms(&self) -> Option<&[HashAlgorithm]> {
if let Some(sb)
= self.subpacket(
SubpacketTag::PreferredHashAlgorithms) {
if let SubpacketValue::PreferredHashAlgorithms(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn preferred_compression_algorithms(&self)
-> Option<&[CompressionAlgorithm]>
{
if let Some(sb)
= self.subpacket(
SubpacketTag::PreferredCompressionAlgorithms) {
if let SubpacketValue::PreferredCompressionAlgorithms(v)
= &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn key_server_preferences(&self) -> Option<KeyServerPreferences> {
if let Some(sb) = self.subpacket(SubpacketTag::KeyServerPreferences) {
if let SubpacketValue::KeyServerPreferences(v) = &sb.value {
Some(v.clone())
} else {
None
}
} else {
None
}
}
pub fn preferred_key_server(&self) -> Option<&[u8]> {
if let Some(sb)
= self.subpacket(SubpacketTag::PreferredKeyServer) {
if let SubpacketValue::PreferredKeyServer(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn primary_userid(&self) -> Option<bool> {
if let Some(sb)
= self.subpacket(SubpacketTag::PrimaryUserID) {
if let SubpacketValue::PrimaryUserID(v) = sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn policy_uri(&self) -> Option<&[u8]> {
if let Some(sb)
= self.subpacket(SubpacketTag::PolicyURI) {
if let SubpacketValue::PolicyURI(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn key_flags(&self) -> Option<KeyFlags> {
if let Some(sb) = self.subpacket(SubpacketTag::KeyFlags) {
if let SubpacketValue::KeyFlags(v) = &sb.value {
Some(v.clone())
} else {
None
}
} else {
None
}
}
pub fn signers_user_id(&self) -> Option<&[u8]> {
if let Some(sb)
= self.subpacket(SubpacketTag::SignersUserID) {
if let SubpacketValue::SignersUserID(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn reason_for_revocation(&self)
-> Option<(ReasonForRevocation, &[u8])> {
if let Some(sb) = self.subpacket(SubpacketTag::ReasonForRevocation) {
if let SubpacketValue::ReasonForRevocation {
code, reason,
} = &sb.value {
Some((*code, reason))
} else {
None
}
} else {
None
}
}
pub fn features(&self) -> Option<Features> {
if let Some(sb) = self.subpacket(SubpacketTag::Features) {
if let SubpacketValue::Features(v) = &sb.value {
Some(v.clone())
} else {
None
}
} else {
None
}
}
pub fn signature_target(&self) -> Option<(PublicKeyAlgorithm,
HashAlgorithm,
&[u8])> {
if let Some(sb) = self.subpacket(SubpacketTag::SignatureTarget) {
if let SubpacketValue::SignatureTarget {
pk_algo, hash_algo, digest,
} = &sb.value {
Some((*pk_algo, *hash_algo, digest))
} else {
None
}
} else {
None
}
}
pub fn embedded_signature(&self) -> Option<&Signature> {
if let Some(sb)
= self.subpacket(SubpacketTag::EmbeddedSignature) {
if let SubpacketValue::EmbeddedSignature(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn issuer_fingerprint(&self) -> Option<&Fingerprint> {
if let Some(sb)
= self.subpacket(SubpacketTag::IssuerFingerprint) {
if let SubpacketValue::IssuerFingerprint(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn preferred_aead_algorithms(&self)
-> Option<&[AEADAlgorithm]> {
if let Some(sb)
= self.subpacket(
SubpacketTag::PreferredAEADAlgorithms) {
if let SubpacketValue::PreferredAEADAlgorithms(v)
= &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn intended_recipients(&self) -> Vec<Fingerprint> {
self.iter().filter_map(|sp| match sp.value() {
SubpacketValue::IntendedRecipient(fp) => Some(fp.clone()),
_ => None,
}).collect()
}
}
#[derive(Clone, Default, PartialEq, Eq, Hash)]
pub struct SubpacketAreas {
hashed_area: SubpacketArea,
unhashed_area: SubpacketArea,
}
impl ArbitraryBounded for SubpacketAreas {
fn arbitrary_bounded<G: Gen>(g: &mut G, depth: usize) -> Self {
SubpacketAreas::new(ArbitraryBounded::arbitrary_bounded(g, depth),
ArbitraryBounded::arbitrary_bounded(g, depth))
}
}
impl_arbitrary_with_bound!(SubpacketAreas);
impl Deref for SubpacketAreas {
type Target = SubpacketArea;
fn deref(&self) -> &Self::Target {
&self.hashed_area
}
}
impl DerefMut for SubpacketAreas {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.hashed_area
}
}
impl SubpacketAreas {
pub fn new(hashed_area: SubpacketArea,
unhashed_area: SubpacketArea) -> Self {
Self {
hashed_area,
unhashed_area,
}
}
pub fn hashed_area(&self) -> &SubpacketArea {
&self.hashed_area
}
pub fn hashed_area_mut(&mut self) -> &mut SubpacketArea {
&mut self.hashed_area
}
pub fn unhashed_area(&self) -> &SubpacketArea {
&self.unhashed_area
}
pub fn unhashed_area_mut(&mut self) -> &mut SubpacketArea {
&mut self.unhashed_area
}
pub fn sort(&mut self) {
self.hashed_area.sort();
self.unhashed_area.sort();
}
fn subpacket<'a>(&'a self, tag: SubpacketTag) -> Option<&Subpacket> {
if let Some(sb) = self.hashed_area().lookup(tag) {
return Some(sb);
}
if !(tag == SubpacketTag::Issuer
|| tag == SubpacketTag::IssuerFingerprint
|| tag == SubpacketTag::EmbeddedSignature) {
return None;
}
self.unhashed_area().lookup(tag)
}
pub fn signature_expiration_time(&self) -> Option<time::SystemTime> {
match (self.signature_creation_time(), self.signature_validity_period())
{
(Some(ct), Some(vp)) if vp.as_secs() > 0 => Some(ct + vp),
_ => None,
}
}
pub fn signature_alive<T, U>(&self, time: T, clock_skew_tolerance: U)
-> Result<()>
where T: Into<Option<time::SystemTime>>,
U: Into<Option<time::Duration>>
{
let (time, tolerance)
= match (time.into(), clock_skew_tolerance.into()) {
(None, None) =>
(time::SystemTime::now(),
*CLOCK_SKEW_TOLERANCE),
(None, Some(tolerance)) =>
(time::SystemTime::now(),
tolerance),
(Some(time), None) =>
(time, time::Duration::new(0, 0)),
(Some(time), Some(tolerance)) =>
(time, tolerance)
};
match (self.signature_creation_time(), self.signature_validity_period())
{
(None, _) =>
Err(Error::MalformedPacket("no signature creation time".into())
.into()),
(Some(c), Some(e)) if e.as_secs() > 0 && (c + e) <= time =>
Err(Error::Expired(c + e).into()),
(Some(c), _) if cmp::max(c, time::UNIX_EPOCH + tolerance)
- tolerance > time =>
Err(Error::NotYetLive(cmp::max(c, time::UNIX_EPOCH + tolerance)
- tolerance).into()),
_ => Ok(()),
}
}
pub fn key_expiration_time<P, R>(&self, key: &Key<P, R>)
-> Option<time::SystemTime>
where P: key::KeyParts,
R: key::KeyRole,
{
match self.key_validity_period() {
Some(vp) if vp.as_secs() > 0 => Some(key.creation_time() + vp),
_ => None,
}
}
pub fn key_alive<P, R, T>(&self, key: &Key<P, R>, t: T) -> Result<()>
where P: key::KeyParts,
R: key::KeyRole,
T: Into<Option<time::SystemTime>>
{
let t = t.into()
.unwrap_or_else(|| time::SystemTime::now());
match self.key_validity_period() {
Some(e) if e.as_secs() > 0 && key.creation_time() + e <= t =>
Err(Error::Expired(key.creation_time() + e).into()),
_ if key.creation_time() > t =>
Err(Error::NotYetLive(key.creation_time()).into()),
_ => Ok(()),
}
}
pub fn issuer(&self) -> Option<&KeyID> {
if let Some(sb)
= self.subpacket(SubpacketTag::Issuer) {
if let SubpacketValue::Issuer(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn embedded_signature(&self) -> Option<&Signature> {
if let Some(sb)
= self.subpacket(SubpacketTag::EmbeddedSignature) {
if let SubpacketValue::EmbeddedSignature(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
pub fn issuer_fingerprint(&self) -> Option<&Fingerprint> {
if let Some(sb)
= self.subpacket(SubpacketTag::IssuerFingerprint) {
if let SubpacketValue::IssuerFingerprint(v) = &sb.value {
Some(v)
} else {
None
}
} else {
None
}
}
}
impl Deref for Signature4 {
type Target = signature::Builder;
fn deref(&self) -> &Self::Target {
&self.fields
}
}
impl DerefMut for Signature4 {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.fields
}
}
impl Signature4 {
pub fn version(&self) -> u8 {
self.fields.version()
}
pub fn typ(&self) -> SignatureType {
self.fields.typ()
}
pub fn pk_algo(&self) -> PublicKeyAlgorithm {
self.fields.pk_algo()
}
pub fn hash_algo(&self) -> HashAlgorithm {
self.fields.hash_algo()
}
}
impl signature::Builder {
pub fn set_signature_creation_time<T>(mut self, creation_time: T)
-> Result<Self>
where T: Into<time::SystemTime>
{
self.hashed_area.replace(Subpacket::new(
SubpacketValue::SignatureCreationTime(
creation_time.into().try_into()?),
true)?)?;
Ok(self)
}
pub fn set_signature_validity_period(mut self,
expiration: Option<time::Duration>)
-> Result<Self> {
if let Some(e) = expiration {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::SignatureExpirationTime(e.try_into()?),
true)?)?;
} else {
self.hashed_area.remove_all(SubpacketTag::SignatureExpirationTime);
}
Ok(self)
}
pub fn set_signature_expiration_time(self,
expiration: Option<time::SystemTime>)
-> Result<Self> {
if let Some(e) = expiration.map(crate::types::normalize_systemtime) {
let vp = if let Some(ct) = self.signature_creation_time() {
match e.duration_since(ct) {
Ok(v) => v,
Err(_) => return Err(Error::InvalidArgument(
format!("Expiration time {:?} predates creation time \
{:?}", e, ct)).into()),
}
} else {
return Err(Error::MalformedPacket(
"No creation time subpacket".into()).into());
};
self.set_signature_validity_period(Some(vp))
} else {
self.set_signature_validity_period(None)
}
}
pub fn set_exportable_certification(mut self, exportable: bool)
-> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::ExportableCertification(exportable),
true)?)?;
Ok(self)
}
pub fn set_trust_signature(mut self, level: u8, trust: u8)
-> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::TrustSignature {
level,
trust,
},
true)?)?;
Ok(self)
}
pub fn set_regular_expression<R>(mut self, re: R) -> Result<Self>
where R: AsRef<[u8]>
{
self.hashed_area.replace(Subpacket::new(
SubpacketValue::RegularExpression(re.as_ref().to_vec()),
true)?)?;
Ok(self)
}
pub fn set_revocable(mut self, revocable: bool) -> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::Revocable(revocable),
true)?)?;
Ok(self)
}
pub fn set_key_validity_period(mut self,
expiration: Option<time::Duration>)
-> Result<Self> {
if let Some(e) = expiration {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::KeyExpirationTime(e.try_into()?),
true)?)?;
} else {
self.hashed_area.remove_all(SubpacketTag::KeyExpirationTime);
}
Ok(self)
}
pub fn set_key_expiration_time<P, R>(
self,
key: &Key<P, R>,
expiration: Option<time::SystemTime>)
-> Result<Self>
where P: key::KeyParts,
R: key::KeyRole,
{
if let Some(e) = expiration.map(crate::types::normalize_systemtime) {
let ct = key.creation_time();
let vp = match e.duration_since(ct) {
Ok(v) => v,
Err(_) => return Err(Error::InvalidArgument(
format!("Expiration time {:?} predates creation time \
{:?}", e, ct)).into()),
};
self.set_key_validity_period(Some(vp))
} else {
self.set_key_validity_period(None)
}
}
pub fn set_preferred_symmetric_algorithms(mut self,
preferences: Vec<SymmetricAlgorithm>)
-> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::PreferredSymmetricAlgorithms(preferences),
false)?)?;
Ok(self)
}
pub fn set_revocation_key(mut self, rk: RevocationKey) -> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::RevocationKey(rk),
true)?)?;
Ok(self)
}
pub fn set_issuer(mut self, id: KeyID) -> Result<Self> {
self.unhashed_area.replace(Subpacket::new(
SubpacketValue::Issuer(id),
false)?)?;
Ok(self)
}
pub fn set_notation<N, V, F>(mut self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
self.hashed_area.packets.retain(|s| {
match s.value {
SubpacketValue::NotationData(ref v)
if v.name == name.as_ref() => false,
_ => true,
}
});
self.add_notation(name.as_ref(), value.as_ref(),
flags.into().unwrap_or_default(),
critical)
}
pub fn add_notation<N, V, F>(mut self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
self.hashed_area.add(Subpacket::new(SubpacketValue::NotationData(
NotationData::new(name.as_ref(), value.as_ref(),
flags.into().unwrap_or_default())),
critical)?)?;
Ok(self)
}
pub fn set_preferred_hash_algorithms(mut self,
preferences: Vec<HashAlgorithm>)
-> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::PreferredHashAlgorithms(preferences),
false)?)?;
Ok(self)
}
pub fn set_preferred_compression_algorithms(mut self,
preferences: Vec<CompressionAlgorithm>)
-> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::PreferredCompressionAlgorithms(preferences),
false)?)?;
Ok(self)
}
pub fn set_key_server_preferences(mut self,
preferences: KeyServerPreferences)
-> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::KeyServerPreferences(preferences),
false)?)?;
Ok(self)
}
pub fn set_preferred_key_server<U>(mut self, uri: U)
-> Result<Self>
where U: AsRef<[u8]>,
{
self.hashed_area.replace(Subpacket::new(
SubpacketValue::PreferredKeyServer(uri.as_ref().to_vec()),
false)?)?;
Ok(self)
}
pub fn set_primary_userid(mut self, primary: bool) -> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::PrimaryUserID(primary),
true)?)?;
Ok(self)
}
pub fn set_policy_uri<U>(mut self, uri: U) -> Result<Self>
where U: AsRef<[u8]>,
{
self.hashed_area.replace(Subpacket::new(
SubpacketValue::PolicyURI(uri.as_ref().to_vec()),
false)?)?;
Ok(self)
}
pub fn set_key_flags(mut self, flags: &KeyFlags) -> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::KeyFlags(flags.clone()),
true)?)?;
Ok(self)
}
pub fn set_signers_user_id<U>(mut self, uid: U) -> Result<Self>
where U: AsRef<[u8]>,
{
self.hashed_area.replace(Subpacket::new(
SubpacketValue::SignersUserID(uid.as_ref().to_vec()),
true)?)?;
Ok(self)
}
pub fn set_reason_for_revocation<R>(mut self, code: ReasonForRevocation,
reason: R)
-> Result<Self>
where R: AsRef<[u8]>,
{
self.hashed_area.replace(Subpacket::new(
SubpacketValue::ReasonForRevocation {
code,
reason: reason.as_ref().to_vec(),
},
false)?)?;
Ok(self)
}
pub fn set_features(mut self, features: &Features) -> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::Features(features.clone()),
false)?)?;
Ok(self)
}
pub fn set_signature_target<D>(mut self,
pk_algo: PublicKeyAlgorithm,
hash_algo: HashAlgorithm,
digest: D)
-> Result<Self>
where D: AsRef<[u8]>,
{
self.hashed_area.replace(Subpacket::new(
SubpacketValue::SignatureTarget {
pk_algo,
hash_algo,
digest: digest.as_ref().to_vec(),
},
true)?)?;
Ok(self)
}
pub fn set_embedded_signature(mut self, signature: Signature)
-> Result<Self> {
self.unhashed_area.replace(Subpacket::new(
SubpacketValue::EmbeddedSignature(signature),
true)?)?;
Ok(self)
}
pub fn set_issuer_fingerprint(mut self, fp: Fingerprint) -> Result<Self> {
self.unhashed_area.replace(Subpacket::new(
SubpacketValue::IssuerFingerprint(fp),
false)?)?;
Ok(self)
}
pub fn set_preferred_aead_algorithms(mut self,
preferences: Vec<AEADAlgorithm>)
-> Result<Self> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::PreferredAEADAlgorithms(preferences),
false)?)?;
Ok(self)
}
pub fn set_intended_recipients(mut self, recipients: Vec<Fingerprint>)
-> Result<Self> {
self.hashed_area.remove_all(SubpacketTag::IntendedRecipient);
for fp in recipients.into_iter() {
self.hashed_area.add(
Subpacket::new(SubpacketValue::IntendedRecipient(fp), false)?)?;
}
Ok(self)
}
}
#[test]
fn accessors() {
use crate::types::Curve;
let pk_algo = PublicKeyAlgorithm::EdDSA;
let hash_algo = HashAlgorithm::SHA512;
let hash = hash_algo.context().unwrap();
let mut sig = signature::Builder::new(crate::types::SignatureType::Binary);
let mut key: crate::packet::key::SecretKey =
crate::packet::key::Key4::generate_ecc(true, Curve::Ed25519).unwrap().into();
let mut keypair = key.clone().into_keypair().unwrap();
use std::convert::TryFrom;
let now: time::SystemTime =
Timestamp::try_from(time::SystemTime::now()).unwrap().into();
sig = sig.set_signature_creation_time(now).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.signature_creation_time(), Some(now));
let zero_s = time::Duration::new(0, 0);
let minute = time::Duration::new(60, 0);
let five_minutes = 5 * minute;
let ten_minutes = 10 * minute;
sig = sig.set_signature_validity_period(Some(five_minutes)).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.signature_validity_period(), Some(five_minutes));
assert!(sig_.signature_alive(None, zero_s).is_ok());
assert!(sig_.signature_alive(now, zero_s).is_ok());
assert!(!sig_.signature_alive(now - five_minutes, zero_s).is_ok());
assert!(!sig_.signature_alive(now + ten_minutes, zero_s).is_ok());
sig = sig.set_signature_validity_period(None).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.signature_validity_period(), None);
assert!(sig_.signature_alive(None, zero_s).is_ok());
assert!(sig_.signature_alive(now, zero_s).is_ok());
assert!(!sig_.signature_alive(now - five_minutes, zero_s).is_ok());
assert!(sig_.signature_alive(now + ten_minutes, zero_s).is_ok());
sig = sig.set_exportable_certification(true).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.exportable_certification(), Some(true));
sig = sig.set_exportable_certification(false).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.exportable_certification(), Some(false));
sig = sig.set_trust_signature(2, 3).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.trust_signature(), Some((2, 3)));
sig = sig.set_regular_expression(b"foobar").unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.regular_expression(), Some(&b"foobar"[..]));
sig = sig.set_revocable(true).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.revocable(), Some(true));
sig = sig.set_revocable(false).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.revocable(), Some(false));
key.set_creation_time(now).unwrap();
sig = sig.set_key_validity_period(Some(five_minutes)).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.key_validity_period(), Some(five_minutes));
assert!(sig_.key_alive(&key, None).is_ok());
assert!(sig_.key_alive(&key, now).is_ok());
assert!(!sig_.key_alive(&key, now - five_minutes).is_ok());
assert!(!sig_.key_alive(&key, now + ten_minutes).is_ok());
sig = sig.set_key_validity_period(None).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.key_validity_period(), None);
assert!(sig_.key_alive(&key, None).is_ok());
assert!(sig_.key_alive(&key, now).is_ok());
assert!(!sig_.key_alive(&key, now - five_minutes).is_ok());
assert!(sig_.key_alive(&key, now + ten_minutes).is_ok());
let pref = vec![SymmetricAlgorithm::AES256,
SymmetricAlgorithm::AES192,
SymmetricAlgorithm::AES128];
sig = sig.set_preferred_symmetric_algorithms(pref.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.preferred_symmetric_algorithms(), Some(&pref[..]));
let fp = Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb");
let rk = RevocationKey::new(pk_algo, fp.clone(), true);
sig = sig.set_revocation_key(rk.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.revocation_keys().nth(0).unwrap(), &rk);
sig = sig.set_issuer(fp.clone().into()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.issuer(), Some(&fp.clone().into()));
let pref = vec![HashAlgorithm::SHA512,
HashAlgorithm::SHA384,
HashAlgorithm::SHA256];
sig = sig.set_preferred_hash_algorithms(pref.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.preferred_hash_algorithms(), Some(&pref[..]));
let pref = vec![CompressionAlgorithm::BZip2,
CompressionAlgorithm::Zlib,
CompressionAlgorithm::Zip];
sig = sig.set_preferred_compression_algorithms(pref.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.preferred_compression_algorithms(), Some(&pref[..]));
let pref = KeyServerPreferences::default()
.set_no_modify(true);
sig = sig.set_key_server_preferences(pref.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.key_server_preferences().unwrap(), pref);
sig = sig.set_primary_userid(true).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.primary_userid(), Some(true));
sig = sig.set_primary_userid(false).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.primary_userid(), Some(false));
sig = sig.set_policy_uri(b"foobar").unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.policy_uri(), Some(&b"foobar"[..]));
let key_flags = KeyFlags::default()
.set_certification(true)
.set_signing(true);
sig = sig.set_key_flags(&key_flags).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.key_flags().unwrap(), key_flags);
sig = sig.set_signers_user_id(b"foobar").unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.signers_user_id(), Some(&b"foobar"[..]));
sig = sig.set_reason_for_revocation(ReasonForRevocation::KeyRetired,
b"foobar").unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.reason_for_revocation(),
Some((ReasonForRevocation::KeyRetired, &b"foobar"[..])));
let feats = Features::default().set_mdc(true);
sig = sig.set_features(&feats).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.features().unwrap(), feats);
let feats = Features::default().set_aead(true);
sig = sig.set_features(&feats).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.features().unwrap(), feats);
let digest = vec![0; hash_algo.context().unwrap().digest_size()];
sig = sig.set_signature_target(pk_algo, hash_algo, &digest).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.signature_target(), Some((pk_algo.into(),
hash_algo.into(),
&digest[..])));
let embedded_sig = sig_.clone();
sig = sig.set_embedded_signature(embedded_sig.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.embedded_signature(), Some(&embedded_sig));
sig = sig.set_issuer_fingerprint(fp.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.issuer_fingerprint(), Some(&fp));
let pref = vec![AEADAlgorithm::EAX,
AEADAlgorithm::OCB];
sig = sig.set_preferred_aead_algorithms(pref.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.preferred_aead_algorithms(), Some(&pref[..]));
let fps = vec![
Fingerprint::from_bytes(b"aaaaaaaaaaaaaaaaaaaa"),
Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb"),
];
sig = sig.set_intended_recipients(fps.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.intended_recipients(), fps);
sig = sig.set_notation("test@example.org", &[0, 1, 2], None, false)
.unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.notation("test@example.org"), vec![&[0, 1, 2]]);
sig = sig.add_notation("test@example.org", &[3, 4, 5], None, false)
.unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.notation("test@example.org"), vec![&[0, 1, 2],
&[3, 4, 5]]);
sig = sig.set_notation("test@example.org", &[6, 7, 8], None, false)
.unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
assert_eq!(sig_.notation("test@example.org"), vec![&[6, 7, 8]]);
}
#[cfg(feature = "compression-deflate")]
#[test]
fn subpacket_test_1 () {
use crate::Packet;
use crate::PacketPile;
use crate::parse::Parse;
let pile = PacketPile::from_bytes(crate::tests::message("signed.gpg")).unwrap();
eprintln!("PacketPile has {} top-level packets.", pile.children().len());
eprintln!("PacketPile: {:?}", pile);
let mut count = 0;
for p in pile.descendants() {
if let &Packet::Signature(ref sig) = p {
count += 1;
let mut got2 = false;
let mut got16 = false;
let mut got33 = false;
for i in 0..255 {
if let Some(sb) = sig.subpacket(i.into()) {
if i == 2 {
got2 = true;
assert!(!sb.critical);
} else if i == 16 {
got16 = true;
assert!(!sb.critical);
} else if i == 33 {
got33 = true;
assert!(!sb.critical);
} else {
panic!("Unexpectedly found subpacket {}", i);
}
}
}
assert!(got2 && got16 && got33);
let fp = sig.issuer_fingerprint().unwrap().to_string();
assert!(
fp == "7FAF 6ED7 2381 4355 7BDF 7ED2 6863 C9AD 5B4D 22D3"
|| fp == "C03F A641 1B03 AE12 5764 6118 7223 B566 78E0 2528");
let hex = format!("{:X}", sig.issuer_fingerprint().unwrap());
assert!(
hex == "7FAF6ED7238143557BDF7ED26863C9AD5B4D22D3"
|| hex == "C03FA6411B03AE12576461187223B56678E02528");
}
}
assert_eq!(count, 2);
}
#[test]
fn subpacket_test_2() {
use crate::Packet;
use crate::parse::Parse;
use crate::PacketPile;
let pile = PacketPile::from_bytes(
crate::tests::key("subpackets/shaw.gpg")).unwrap();
if let (Some(&Packet::PublicKey(ref key)),
Some(&Packet::Signature(ref sig)))
= (pile.children().nth(0), pile.children().nth(2))
{
assert_eq!(sig.signature_creation_time(),
Some(Timestamp::from(1515791508).into()));
assert_eq!(sig.subpacket(SubpacketTag::SignatureCreationTime),
Some(&Subpacket {
length: 5.into(),
critical: false,
value: SubpacketValue::SignatureCreationTime(
1515791508.into())
}));
assert!(sig.signature_alive(None, None).is_ok());
assert_eq!(sig.key_validity_period(),
Some(Duration::from(63072000).into()));
assert_eq!(sig.subpacket(SubpacketTag::KeyExpirationTime),
Some(&Subpacket {
length: 5.into(),
critical: false,
value: SubpacketValue::KeyExpirationTime(
63072000.into())
}));
assert!(sig.key_alive(
key,
key.creation_time() + time::Duration::new(63072000 - 1, 0))
.is_ok());
assert!(! sig.key_alive(
key,
key.creation_time() + time::Duration::new(63072000, 0))
.is_ok());
assert_eq!(sig.preferred_symmetric_algorithms(),
Some(&[SymmetricAlgorithm::AES256,
SymmetricAlgorithm::AES192,
SymmetricAlgorithm::AES128,
SymmetricAlgorithm::TripleDES][..]));
assert_eq!(sig.subpacket(SubpacketTag::PreferredSymmetricAlgorithms),
Some(&Subpacket {
length: 5.into(),
critical: false,
value: SubpacketValue::PreferredSymmetricAlgorithms(
vec![SymmetricAlgorithm::AES256,
SymmetricAlgorithm::AES192,
SymmetricAlgorithm::AES128,
SymmetricAlgorithm::TripleDES]
)}));
assert_eq!(sig.preferred_hash_algorithms(),
Some(&[HashAlgorithm::SHA256,
HashAlgorithm::SHA384,
HashAlgorithm::SHA512,
HashAlgorithm::SHA224,
HashAlgorithm::SHA1][..]));
assert_eq!(sig.subpacket(SubpacketTag::PreferredHashAlgorithms),
Some(&Subpacket {
length: 6.into(),
critical: false,
value: SubpacketValue::PreferredHashAlgorithms(
vec![HashAlgorithm::SHA256,
HashAlgorithm::SHA384,
HashAlgorithm::SHA512,
HashAlgorithm::SHA224,
HashAlgorithm::SHA1]
)}));
assert_eq!(sig.preferred_compression_algorithms(),
Some(&[CompressionAlgorithm::Zlib,
CompressionAlgorithm::BZip2,
CompressionAlgorithm::Zip][..]));
assert_eq!(sig.subpacket(SubpacketTag::PreferredCompressionAlgorithms),
Some(&Subpacket {
length: 4.into(),
critical: false,
value: SubpacketValue::PreferredCompressionAlgorithms(
vec![CompressionAlgorithm::Zlib,
CompressionAlgorithm::BZip2,
CompressionAlgorithm::Zip]
)}));
assert_eq!(sig.key_server_preferences().unwrap(),
KeyServerPreferences::default().set_no_modify(true));
assert_eq!(sig.subpacket(SubpacketTag::KeyServerPreferences),
Some(&Subpacket {
length: 2.into(),
critical: false,
value: SubpacketValue::KeyServerPreferences(
KeyServerPreferences::default().set_no_modify(true)),
}));
assert!(sig.key_flags().unwrap().for_certification());
assert!(sig.key_flags().unwrap().for_signing());
assert_eq!(sig.subpacket(SubpacketTag::KeyFlags),
Some(&Subpacket {
length: 2.into(),
critical: false,
value: SubpacketValue::KeyFlags(
KeyFlags::default().set_certification(true).set_signing(true))
}));
assert_eq!(sig.features().unwrap(), Features::default().set_mdc(true));
assert_eq!(sig.subpacket(SubpacketTag::Features),
Some(&Subpacket {
length: 2.into(),
critical: false,
value: SubpacketValue::Features(
Features::default().set_mdc(true))
}));
let keyid = "F004 B9A4 5C58 6126".parse().unwrap();
assert_eq!(sig.issuer(), Some(&keyid));
assert_eq!(sig.subpacket(SubpacketTag::Issuer),
Some(&Subpacket {
length: 9.into(),
critical: false,
value: SubpacketValue::Issuer(keyid)
}));
let fp = "361A96BDE1A65B6D6C25AE9FF004B9A45C586126".parse().unwrap();
assert_eq!(sig.issuer_fingerprint(), Some(&fp));
assert_eq!(sig.subpacket(SubpacketTag::IssuerFingerprint),
Some(&Subpacket {
length: 22.into(),
critical: false,
value: SubpacketValue::IssuerFingerprint(fp)
}));
let n = NotationData {
flags: NotationDataFlags::default().set_human_readable(true),
name: "rank@navy.mil".into(),
value: b"midshipman".to_vec()
};
assert_eq!(sig.notation_data(), vec![&n]);
assert_eq!(sig.subpacket(SubpacketTag::NotationData),
Some(&Subpacket {
length: 32.into(),
critical: false,
value: SubpacketValue::NotationData(n.clone())
}));
assert_eq!(sig.subpackets(SubpacketTag::NotationData)
.collect::<Vec<_>>(),
vec![&Subpacket {
length: 32.into(),
critical: false,
value: SubpacketValue::NotationData(n.clone())
}]);
} else {
panic!("Expected signature!");
}
if let Some(&Packet::Signature(ref sig)) = pile.children().nth(3) {
assert_eq!(sig.signature_creation_time(),
Some(Timestamp::from(1515791490).into()));
assert_eq!(sig.subpacket(SubpacketTag::SignatureCreationTime),
Some(&Subpacket {
length: 5.into(),
critical: false,
value: SubpacketValue::SignatureCreationTime(
1515791490.into())
}));
assert_eq!(sig.exportable_certification(), Some(false));
assert_eq!(sig.subpacket(SubpacketTag::ExportableCertification),
Some(&Subpacket {
length: 2.into(),
critical: false,
value: SubpacketValue::ExportableCertification(false)
}));
}
let pile = PacketPile::from_bytes(
crate::tests::key("subpackets/marven.gpg")).unwrap();
if let Some(&Packet::Signature(ref sig)) = pile.children().nth(1) {
assert_eq!(sig.signature_creation_time(),
Some(Timestamp::from(1515791376).into()));
assert_eq!(sig.subpacket(SubpacketTag::SignatureCreationTime),
Some(&Subpacket {
length: 5.into(),
critical: false,
value: SubpacketValue::SignatureCreationTime(
1515791376.into())
}));
assert_eq!(sig.revocable(), Some(false));
assert_eq!(sig.subpacket(SubpacketTag::Revocable),
Some(&Subpacket {
length: 2.into(),
critical: false,
value: SubpacketValue::Revocable(false)
}));
let fp = "361A96BDE1A65B6D6C25AE9FF004B9A45C586126".parse().unwrap();
let rk = RevocationKey::new(PublicKeyAlgorithm::RSAEncryptSign,
fp, false);
assert_eq!(sig.revocation_keys().nth(0).unwrap(), &rk);
assert_eq!(sig.subpacket(SubpacketTag::RevocationKey),
Some(&Subpacket {
length: 23.into(),
critical: false,
value: SubpacketValue::RevocationKey(rk),
}));
let keyid = "CEAD 0621 0934 7957".parse().unwrap();
assert_eq!(sig.issuer(), Some(&keyid));
assert_eq!(sig.subpacket(SubpacketTag::Issuer),
Some(&Subpacket {
length: 9.into(),
critical: false,
value: SubpacketValue::Issuer(keyid)
}));
let fp = "B59B8817F519DCE10AFD85E4CEAD062109347957".parse().unwrap();
assert_eq!(sig.issuer_fingerprint(), Some(&fp));
assert_eq!(sig.subpacket(SubpacketTag::IssuerFingerprint),
Some(&Subpacket {
length: 22.into(),
critical: false,
value: SubpacketValue::IssuerFingerprint(fp)
}));
assert_eq!(sig.notation_data().len(), 0);
assert_eq!(sig.subpacket(SubpacketTag::NotationData),
None);
assert_eq!(sig.subpackets(SubpacketTag::NotationData).count(), 0);
} else {
panic!("Expected signature!");
}
if let Some(&Packet::Signature(ref sig)) = pile.children().nth(6) {
assert_eq!(sig.signature_creation_time(),
Some(Timestamp::from(1515886658).into()));
assert_eq!(sig.subpacket(SubpacketTag::SignatureCreationTime),
Some(&Subpacket {
length: 5.into(),
critical: false,
value: SubpacketValue::SignatureCreationTime(
1515886658.into())
}));
assert_eq!(sig.reason_for_revocation(),
Some((ReasonForRevocation::Unspecified,
&b"Forgot to set a sig expiration."[..])));
assert_eq!(sig.subpacket(SubpacketTag::ReasonForRevocation),
Some(&Subpacket {
length: 33.into(),
critical: false,
value: SubpacketValue::ReasonForRevocation {
code: ReasonForRevocation::Unspecified,
reason: b"Forgot to set a sig expiration.".to_vec(),
},
}));
}
if let Some(&Packet::Signature(ref sig)) = pile.children().nth(7) {
assert_eq!(sig.signature_creation_time(),
Some(Timestamp::from(1515791467).into()));
assert_eq!(sig.subpacket(SubpacketTag::SignatureCreationTime),
Some(&Subpacket {
length: 5.into(),
critical: false,
value: SubpacketValue::SignatureCreationTime(
1515791467.into())
}));
let n1 = NotationData {
flags: NotationDataFlags::default().set_human_readable(true),
name: "rank@navy.mil".into(),
value: b"third lieutenant".to_vec()
};
let n2 = NotationData {
flags: NotationDataFlags::default().set_human_readable(true),
name: "foo@navy.mil".into(),
value: b"bar".to_vec()
};
let n3 = NotationData {
flags: NotationDataFlags::default().set_human_readable(true),
name: "whistleblower@navy.mil".into(),
value: b"true".to_vec()
};
assert_eq!(sig.notation_data(), vec![&n1, &n2, &n3]);
assert_eq!(sig.subpacket(SubpacketTag::NotationData),
Some(&Subpacket {
length: 35.into(),
critical: false,
value: SubpacketValue::NotationData(n3.clone())
}));
assert_eq!(sig.subpackets(SubpacketTag::NotationData)
.collect::<Vec<_>>(),
vec![
&Subpacket {
length: 38.into(),
critical: false,
value: SubpacketValue::NotationData(n1)
},
&Subpacket {
length: 24.into(),
critical: false,
value: SubpacketValue::NotationData(n2)
},
&Subpacket {
length: 35.into(),
critical: false,
value: SubpacketValue::NotationData(n3)
},
]);
}
if let Some(&Packet::Signature(ref sig)) = pile.children().nth(8) {
assert_eq!(sig.signature_creation_time(),
Some(Timestamp::from(1515791223).into()));
assert_eq!(sig.subpacket(SubpacketTag::SignatureCreationTime),
Some(&Subpacket {
length: 5.into(),
critical: false,
value: SubpacketValue::SignatureCreationTime(
1515791223.into())
}));
assert_eq!(sig.trust_signature(), Some((2, 120)));
assert_eq!(sig.subpacket(SubpacketTag::TrustSignature),
Some(&Subpacket {
length: 3.into(),
critical: false,
value: SubpacketValue::TrustSignature {
level: 2,
trust: 120,
},
}));
let regex = &b"<[^>]+[@.]navy\\.mil>$"[..];
assert_eq!(sig.regular_expression(), Some(regex));
assert_eq!(sig.subpacket(SubpacketTag::RegularExpression),
Some(&Subpacket {
length: 23.into(),
critical: true,
value: SubpacketValue::RegularExpression(regex.to_vec())
}));
}
if let Some(&Packet::Signature(ref sig)) = pile.children().nth(11) {
assert_eq!(sig.key_validity_period(),
Some(Duration::from(63072000).into()));
assert_eq!(sig.subpacket(SubpacketTag::KeyExpirationTime),
Some(&Subpacket {
length: 5.into(),
critical: false,
value: SubpacketValue::KeyExpirationTime(
63072000.into())
}));
let keyid = "CEAD 0621 0934 7957".parse().unwrap();
assert_eq!(sig.issuer(), Some(&keyid));
assert_eq!(sig.subpacket(SubpacketTag::Issuer),
Some(&Subpacket {
length: 9.into(),
critical: false,
value: SubpacketValue::Issuer(keyid)
}));
let fp = "B59B8817F519DCE10AFD85E4CEAD062109347957".parse().unwrap();
assert_eq!(sig.issuer_fingerprint(), Some(&fp));
assert_eq!(sig.subpacket(SubpacketTag::IssuerFingerprint),
Some(&Subpacket {
length: 22.into(),
critical: false,
value: SubpacketValue::IssuerFingerprint(fp)
}));
assert!(sig.embedded_signature().is_some());
assert!(sig.subpacket(SubpacketTag::EmbeddedSignature)
.is_some());
}
}
#[test]
fn issuer_default() -> Result<()> {
use crate::types::Curve;
let hash_algo = HashAlgorithm::SHA512;
let hash = hash_algo.context()?;
let sig = signature::Builder::new(crate::types::SignatureType::Binary);
let key: crate::packet::key::SecretKey =
crate::packet::key::Key4::generate_ecc(true, Curve::Ed25519)?.into();
let mut keypair = key.into_keypair()?;
let sig_ = sig.sign_hash(&mut keypair, hash.clone())?;
assert_eq!(sig_.issuer(), Some(&keypair.public().keyid()));
assert_eq!(sig_.issuer_fingerprint(), Some(&keypair.public().fingerprint()));
let fp = Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb");
let mut sig = signature::Builder::new(crate::types::SignatureType::Binary);
sig = sig.set_issuer(fp.clone().into())?;
let sig_ = sig.clone().sign_hash(&mut keypair, hash.clone())?;
assert_eq!(sig_.issuer(), Some(&fp.clone().into()));
assert!(sig_.issuer_fingerprint().is_none());
let mut sig = signature::Builder::new(crate::types::SignatureType::Binary);
sig = sig.set_issuer_fingerprint(fp.clone())?;
let sig_ = sig.clone().sign_hash(&mut keypair, hash.clone())?;
assert_eq!(sig_.issuer_fingerprint(), Some(&fp));
assert!(sig_.issuer().is_none());
Ok(())
}