use crate::Result;
use crate::cert::prelude::*;
use crate::packet::{header::BodyLength, key, Signature, Tag};
use crate::seal;
use crate::serialize::{
PacketRef,
Marshal, MarshalInto,
generic_serialize_into, generic_export_into,
};
impl Cert {
fn serialize_common(&self, o: &mut dyn std::io::Write, export: bool)
-> Result<()>
{
let primary = self.primary_key();
PacketRef::PublicKey(primary.key())
.serialize(o)?;
let serialize_sig =
|o: &mut dyn std::io::Write, sig: &Signature| -> Result<()>
{
if export {
if sig.exportable().is_ok() {
PacketRef::Signature(sig).export(o)?;
}
} else {
PacketRef::Signature(sig).serialize(o)?;
}
Ok(())
};
for s in primary.self_revocations() {
serialize_sig(o, s)?;
}
for s in primary.self_signatures() {
serialize_sig(o, s)?;
}
for s in primary.certifications() {
serialize_sig(o, s)?;
}
for s in primary.other_revocations() {
serialize_sig(o, s)?;
}
for u in self.userids() {
if export && ! u.self_signatures().chain(u.self_revocations()).any(
|s| s.exportable().is_ok())
{
continue;
}
PacketRef::UserID(u.userid()).serialize(o)?;
for s in u.self_revocations() {
serialize_sig(o, s)?;
}
for s in u.self_signatures() {
serialize_sig(o, s)?;
}
for s in u.certifications() {
serialize_sig(o, s)?;
}
for s in u.other_revocations() {
serialize_sig(o, s)?;
}
}
for u in self.user_attributes() {
if export && ! u.self_signatures().chain(u.self_revocations()).any(
|s| s.exportable().is_ok())
{
continue;
}
PacketRef::UserAttribute(u.user_attribute()).serialize(o)?;
for s in u.self_revocations() {
serialize_sig(o, s)?;
}
for s in u.self_signatures() {
serialize_sig(o, s)?;
}
for s in u.certifications() {
serialize_sig(o, s)?;
}
for s in u.other_revocations() {
serialize_sig(o, s)?;
}
}
for k in self.subkeys() {
if export && ! k.self_signatures().chain(k.self_revocations()).any(
|s| s.exportable().is_ok())
{
continue;
}
PacketRef::PublicSubkey(k.key()).serialize(o)?;
for s in k.self_revocations() {
serialize_sig(o, s)?;
}
for s in k.self_signatures() {
serialize_sig(o, s)?;
}
for s in k.certifications() {
serialize_sig(o, s)?;
}
for s in k.other_revocations() {
serialize_sig(o, s)?;
}
}
for u in self.unknowns() {
if export && ! u.certifications().any(
|s| s.exportable().is_ok())
{
continue;
}
PacketRef::Unknown(u.unknown()).serialize(o)?;
for s in u.self_revocations() {
serialize_sig(o, s)?;
}
for s in u.self_signatures() {
serialize_sig(o, s)?;
}
for s in u.certifications() {
serialize_sig(o, s)?;
}
for s in u.other_revocations() {
serialize_sig(o, s)?;
}
}
for s in self.bad_signatures() {
serialize_sig(o, s)?;
}
Ok(())
}
}
impl crate::serialize::Serialize for Cert {}
impl seal::Sealed for Cert {}
impl Marshal for Cert {
fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
self.serialize_common(o, false)
}
fn export(&self, o: &mut dyn std::io::Write) -> Result<()> {
self.serialize_common(o, true)
}
}
impl crate::serialize::SerializeInto for Cert {}
impl MarshalInto for Cert {
fn serialized_len(&self) -> usize {
let mut l = 0;
let primary = self.primary_key();
l += PacketRef::PublicKey(primary.key()).serialized_len();
for s in primary.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in primary.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in primary.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
for s in primary.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for u in self.userids() {
l += PacketRef::UserID(u.userid()).serialized_len();
for s in u.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
}
for u in self.user_attributes() {
l += PacketRef::UserAttribute(u.user_attribute()).serialized_len();
for s in u.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
}
for k in self.subkeys() {
l += PacketRef::PublicSubkey(k.key()).serialized_len();
for s in k.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in k.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in k.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
for s in k.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
}
for u in self.unknowns() {
l += PacketRef::Unknown(u.unknown()).serialized_len();
for s in u.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
}
for s in self.bad_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
l
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, self.serialized_len(), buf)
}
fn export_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_export_into(self, self.serialized_len(), buf)
}
}
impl Cert {
pub fn as_tsk<'a>(&'a self) -> TSK<'a> {
TSK::new(self)
}
}
pub struct TSK<'a> {
cert: &'a Cert,
filter: Option<Box<dyn Fn(&'a key::UnspecifiedSecret) -> bool + 'a>>,
emit_stubs: bool,
}
impl<'a> TSK<'a> {
fn new(cert: &'a Cert) -> Self {
Self {
cert,
filter: None,
emit_stubs: false,
}
}
pub fn set_filter<P>(mut self, predicate: P) -> Self
where P: 'a + Fn(&'a key::UnspecifiedSecret) -> bool
{
self.filter = Some(Box::new(predicate));
self
}
pub fn emit_secret_key_stubs(mut self, emit_stubs: bool) -> Self {
self.emit_stubs = emit_stubs;
self
}
fn serialize_common(&self, o: &mut dyn std::io::Write, export: bool)
-> Result<()>
{
let serialize_sig =
|o: &mut dyn std::io::Write, sig: &Signature| -> Result<()>
{
if export {
if sig.exportable().is_ok() {
PacketRef::Signature(sig).export(o)?;
}
} else {
PacketRef::Signature(sig).serialize(o)?;
}
Ok(())
};
let serialize_key =
|o: &mut dyn std::io::Write, key: &'a key::UnspecifiedSecret,
tag_public, tag_secret|
{
let tag = if key.has_secret()
&& self.filter.as_ref().map(|f| f(key)).unwrap_or(true) {
tag_secret
} else {
tag_public
};
if self.emit_stubs && (tag == Tag::PublicKey
|| tag == Tag::PublicSubkey) {
let stub = crate::crypto::S2K::Private {
tag: 101,
parameters: Some(vec![
0,
0x47,
0x4e,
0x55,
1
].into()),
};
let key_with_stub = key.clone()
.add_secret(key::SecretKeyMaterial::Encrypted(
key::Encrypted::new(
stub, 0.into(),
Some(crate::crypto::mpi::SecretKeyChecksum::Sum16),
vec![].into()))).0;
return match tag {
Tag::PublicKey =>
crate::Packet::SecretKey(key_with_stub.into())
.serialize(o),
Tag::PublicSubkey =>
crate::Packet::SecretSubkey(key_with_stub.into())
.serialize(o),
_ => unreachable!(),
};
}
match tag {
Tag::PublicKey =>
PacketRef::PublicKey(key.into()).serialize(o),
Tag::PublicSubkey =>
PacketRef::PublicSubkey(key.into()).serialize(o),
Tag::SecretKey =>
PacketRef::SecretKey(key.into()).serialize(o),
Tag::SecretSubkey =>
PacketRef::SecretSubkey(key.into()).serialize(o),
_ => unreachable!(),
}
};
let primary = self.cert.primary_key();
serialize_key(o, primary.key().into(),
Tag::PublicKey, Tag::SecretKey)?;
for s in primary.self_signatures() {
serialize_sig(o, s)?;
}
for s in primary.self_revocations() {
serialize_sig(o, s)?;
}
for s in primary.certifications() {
serialize_sig(o, s)?;
}
for s in primary.other_revocations() {
serialize_sig(o, s)?;
}
for u in self.cert.userids() {
if export && ! u.self_signatures().chain(u.self_revocations()).any(
|s| s.exportable().is_ok())
{
continue;
}
PacketRef::UserID(u.userid()).serialize(o)?;
for s in u.self_revocations() {
serialize_sig(o, s)?;
}
for s in u.self_signatures() {
serialize_sig(o, s)?;
}
for s in u.certifications() {
serialize_sig(o, s)?;
}
for s in u.other_revocations() {
serialize_sig(o, s)?;
}
}
for u in self.cert.user_attributes() {
if export && ! u.self_signatures().chain(u.self_revocations()).any(
|s| s.exportable().is_ok())
{
continue;
}
PacketRef::UserAttribute(u.user_attribute()).serialize(o)?;
for s in u.self_revocations() {
serialize_sig(o, s)?;
}
for s in u.self_signatures() {
serialize_sig(o, s)?;
}
for s in u.certifications() {
serialize_sig(o, s)?;
}
for s in u.other_revocations() {
serialize_sig(o, s)?;
}
}
for k in self.cert.subkeys() {
if export && ! k.self_signatures().chain(k.self_revocations()).any(
|s| s.exportable().is_ok())
{
continue;
}
serialize_key(o, k.key().into(),
Tag::PublicSubkey, Tag::SecretSubkey)?;
for s in k.self_revocations() {
serialize_sig(o, s)?;
}
for s in k.self_signatures() {
serialize_sig(o, s)?;
}
for s in k.certifications() {
serialize_sig(o, s)?;
}
for s in k.other_revocations() {
serialize_sig(o, s)?;
}
}
for u in self.cert.unknowns() {
if export && ! u.certifications().any(
|s| s.exportable().is_ok())
{
continue;
}
PacketRef::Unknown(&u.unknown()).serialize(o)?;
for s in u.self_revocations() {
serialize_sig(o, s)?;
}
for s in u.self_signatures() {
serialize_sig(o, s)?;
}
for s in u.certifications() {
serialize_sig(o, s)?;
}
for s in u.other_revocations() {
serialize_sig(o, s)?;
}
}
for s in self.cert.bad_signatures() {
serialize_sig(o, s)?;
}
Ok(())
}
}
impl<'a> crate::serialize::Serialize for TSK<'a> {}
impl<'a> seal::Sealed for TSK<'a> {}
impl<'a> Marshal for TSK<'a> {
fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
self.serialize_common(o, false)
}
fn export(&self, o: &mut dyn std::io::Write) -> Result<()> {
self.serialize_common(o, true)
}
}
impl<'a> crate::serialize::SerializeInto for TSK<'a> {}
impl<'a> MarshalInto for TSK<'a> {
fn serialized_len(&self) -> usize {
let mut l = 0;
let serialized_len_key
= |key: &'a key::UnspecifiedSecret, tag_public, tag_secret|
{
let tag = if key.has_secret()
&& self.filter.as_ref().map(|f| f(key)).unwrap_or(true) {
tag_secret
} else {
tag_public
};
if self.emit_stubs && (tag == Tag::PublicKey
|| tag == Tag::PublicSubkey) {
let l = key.net_len_key(false) + 8;
return 1
+ BodyLength::Full(l as u32).serialized_len()
+ l;
}
let packet = match tag {
Tag::PublicKey => PacketRef::PublicKey(key.into()),
Tag::PublicSubkey => PacketRef::PublicSubkey(key.into()),
Tag::SecretKey => PacketRef::SecretKey(key.into()),
Tag::SecretSubkey => PacketRef::SecretSubkey(key.into()),
_ => unreachable!(),
};
packet.serialized_len()
};
let primary = self.cert.primary_key();
l += serialized_len_key(primary.key().into(),
Tag::PublicKey, Tag::SecretKey);
for s in primary.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in primary.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in primary.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in primary.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
for u in self.cert.userids() {
l += PacketRef::UserID(u.userid()).serialized_len();
for s in u.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
}
for u in self.cert.user_attributes() {
l += PacketRef::UserAttribute(u.user_attribute()).serialized_len();
for s in u.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
}
for k in self.cert.subkeys() {
l += serialized_len_key(k.key().into(),
Tag::PublicSubkey, Tag::SecretSubkey);
for s in k.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in k.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in k.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in k.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
}
for u in self.cert.unknowns() {
l += PacketRef::Unknown(u.unknown()).serialized_len();
for s in u.self_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.self_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.other_revocations() {
l += PacketRef::Signature(s).serialized_len();
}
for s in u.certifications() {
l += PacketRef::Signature(s).serialized_len();
}
}
for s in self.cert.bad_signatures() {
l += PacketRef::Signature(s).serialized_len();
}
l
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, self.serialized_len(), buf)
}
fn export_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_export_into(self, self.serialized_len(), buf)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::vec_truncate;
use crate::parse::Parse;
use crate::packet::key;
use crate::policy::StandardPolicy as P;
#[test]
fn roundtrip_cert() {
for test in crate::tests::CERTS {
let cert = match Cert::from_bytes(test.bytes) {
Ok(t) => t,
Err(_) => continue,
};
assert!(! cert.is_tsk());
let buf = cert.as_tsk().to_vec().unwrap();
let cert_ = Cert::from_bytes(&buf).unwrap();
assert_eq!(cert, cert_, "roundtripping {}.pgp failed", test);
}
}
#[test]
fn roundtrip_tsk() {
for test in crate::tests::TSKS {
let cert = Cert::from_bytes(test.bytes).unwrap();
assert!(cert.is_tsk());
let mut buf = Vec::new();
cert.as_tsk().serialize(&mut buf).unwrap();
let cert_ = Cert::from_bytes(&buf).unwrap();
assert_eq!(cert, cert_, "roundtripping {}-private.pgp failed", test);
let mut buf = Vec::new();
cert.as_tsk().set_filter(|_| true).serialize(&mut buf).unwrap();
let cert_ = Cert::from_bytes(&buf).unwrap();
assert_eq!(cert, cert_, "roundtripping {}-private.pgp failed", test);
}
}
#[test]
fn reduce_to_cert_serialize() {
for test in crate::tests::TSKS {
let cert = Cert::from_bytes(test.bytes).unwrap();
assert!(cert.is_tsk());
let mut buf_cert = Vec::new();
cert.serialize(&mut buf_cert).unwrap();
let mut buf_tsk = Vec::new();
cert.as_tsk().set_filter(|_| false).serialize(&mut buf_tsk).unwrap();
let cert_ = Cert::from_bytes(&buf_cert).unwrap();
let tsk_ = Cert::from_bytes(&buf_tsk).unwrap();
assert_eq!(cert_, tsk_,
"reducing failed on {}-private.pgp: not Cert::eq",
test);
assert_eq!(buf_cert, buf_tsk,
"reducing failed on {}-private.pgp: serialized identity",
test);
}
}
#[test]
fn export() {
use crate::Packet;
use crate::cert::prelude::*;
use crate::types::{Curve, KeyFlags, SignatureType};
use crate::packet::{
signature, UserID, user_attribute::{UserAttribute, Subpacket},
key::Key4,
};
let p = &P::new();
let (cert, _) = CertBuilder::new().generate().unwrap();
let mut keypair = cert.primary_key().key().clone().parts_into_secret()
.unwrap().into_keypair().unwrap();
let key: key::SecretSubkey =
Key4::generate_ecc(false, Curve::Cv25519).unwrap().into();
let key_binding = key.bind(
&mut keypair, &cert,
signature::SignatureBuilder::new(SignatureType::SubkeyBinding)
.set_key_flags(
KeyFlags::empty().set_transport_encryption())
.unwrap()
.set_exportable_certification(false).unwrap()).unwrap();
let uid = UserID::from("foo");
let uid_binding = uid.bind(
&mut keypair, &cert,
signature::SignatureBuilder::from(
cert.primary_key().with_policy(p, None).unwrap()
.direct_key_signature().unwrap().clone())
.set_type(SignatureType::PositiveCertification)
.preserve_signature_creation_time().unwrap()
.set_exportable_certification(false).unwrap()).unwrap();
let ua = UserAttribute::new(&[
Subpacket::Unknown(2, b"foo".to_vec().into_boxed_slice()),
]).unwrap();
let ua_binding = ua.bind(
&mut keypair, &cert,
signature::SignatureBuilder::from(
cert.primary_key().with_policy(p, None).unwrap()
.direct_key_signature().unwrap().clone())
.set_type(SignatureType::PositiveCertification)
.preserve_signature_creation_time().unwrap()
.set_exportable_certification(false).unwrap()).unwrap();
let cert = cert.insert_packets(vec![
Packet::SecretSubkey(key), key_binding.into(),
uid.into(), uid_binding.into(),
ua.into(), ua_binding.into(),
]).unwrap();
assert_eq!(cert.subkeys().count(), 1);
cert.subkeys().nth(0).unwrap().binding_signature(p, None).unwrap();
assert_eq!(cert.userids().count(), 1);
assert!(cert.userids().with_policy(p, None).nth(0).is_some());
assert_eq!(cert.user_attributes().count(), 1);
assert!(cert.user_attributes().with_policy(p, None).nth(0).is_some());
let mut buf = Vec::new();
cert.export(&mut buf).unwrap();
let cert_ = Cert::from_bytes(&buf).unwrap();
assert_eq!(cert_.subkeys().count(), 0);
assert_eq!(cert_.userids().count(), 0);
assert_eq!(cert_.user_attributes().count(), 0);
let mut buf = vec![0; cert.serialized_len()];
let l = cert.export_into(&mut buf).unwrap();
vec_truncate(&mut buf, l);
let cert_ = Cert::from_bytes(&buf).unwrap();
assert_eq!(cert_.subkeys().count(), 0);
assert_eq!(cert_.userids().count(), 0);
assert_eq!(cert_.user_attributes().count(), 0);
let cert_ = Cert::from_bytes(&cert.export_to_vec().unwrap()).unwrap();
assert_eq!(cert_.subkeys().count(), 0);
assert_eq!(cert_.userids().count(), 0);
assert_eq!(cert_.user_attributes().count(), 0);
let mut buf = Vec::new();
cert.armored().export(&mut buf).unwrap();
let cert_ = Cert::from_bytes(&buf).unwrap();
assert_eq!(cert_.subkeys().count(), 0);
assert_eq!(cert_.userids().count(), 0);
assert_eq!(cert_.user_attributes().count(), 0);
let mut buf = vec![0; cert.serialized_len()];
let l = cert.armored().export_into(&mut buf).unwrap();
vec_truncate(&mut buf, l);
let cert_ = Cert::from_bytes(&buf).unwrap();
assert_eq!(cert_.subkeys().count(), 0);
assert_eq!(cert_.userids().count(), 0);
assert_eq!(cert_.user_attributes().count(), 0);
let cert_ =
Cert::from_bytes(&cert.armored().export_to_vec().unwrap()).unwrap();
assert_eq!(cert_.subkeys().count(), 0);
assert_eq!(cert_.userids().count(), 0);
assert_eq!(cert_.user_attributes().count(), 0);
let mut buf = Vec::new();
cert.as_tsk().export(&mut buf).unwrap();
let cert_ = Cert::from_bytes(&buf).unwrap();
assert_eq!(cert_.subkeys().count(), 0);
assert_eq!(cert_.userids().count(), 0);
assert_eq!(cert_.user_attributes().count(), 0);
let mut buf = vec![0; cert.serialized_len()];
let l = cert.as_tsk().export_into(&mut buf).unwrap();
vec_truncate(&mut buf, l);
let cert_ = Cert::from_bytes(&buf).unwrap();
assert_eq!(cert_.subkeys().count(), 0);
assert_eq!(cert_.userids().count(), 0);
assert_eq!(cert_.user_attributes().count(), 0);
let cert_ =
Cert::from_bytes(&cert.as_tsk().export_to_vec().unwrap()).unwrap();
assert_eq!(cert_.subkeys().count(), 0);
assert_eq!(cert_.userids().count(), 0);
assert_eq!(cert_.user_attributes().count(), 0);
}
#[test]
fn issue_613() -> Result<()> {
use crate::packet::key::*;
use crate::{types::*, crypto::S2K};
use crate::{*, cert::*, parse::Parse};
let p = &crate::policy::StandardPolicy::new();
let (cert, _) = CertBuilder::new().add_signing_subkey().generate()?;
assert_eq!(cert.keys().with_policy(p, None)
.alive().revoked(false).unencrypted_secret().count(), 2);
let buf = cert.as_tsk()
.set_filter(|k| k.fingerprint() != cert.fingerprint())
.emit_secret_key_stubs(true)
.to_vec()?;
let cert_ = Cert::from_bytes(&buf)?;
assert!(cert_.primary_key().has_secret());
assert_eq!(cert_.keys().with_policy(p, None)
.alive().revoked(false).unencrypted_secret().count(), 1);
if let Some(SecretKeyMaterial::Encrypted(sec)) =
cert_.primary_key().optional_secret()
{
assert_eq!(sec.algo(), SymmetricAlgorithm::Unencrypted);
if let S2K::Private { tag, .. } = sec.s2k() {
assert_eq!(*tag, 101);
} else {
panic!("expected proprietary S2K type");
}
} else {
panic!("expected ''encrypted'' secret key stub");
}
let buf_ = cert_.as_tsk().to_vec()?;
assert_eq!(buf, buf_);
Ok(())
}
}