summaryrefslogtreecommitdiffstats
path: root/openpgp/src/cert.rs
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2020-10-16 18:59:01 +0200
committerNeal H. Walfield <neal@pep.foundation>2020-10-18 08:16:39 +0200
commite2fbf5b9d442f156ee433a3e46c98ec3dc89cc61 (patch)
treeddc3e436866ea5cf9c8776647fbc9ec68a30250a /openpgp/src/cert.rs
parent3b1856444ef7c618f78f987868ee336207dca62d (diff)
openpgp: Change Cert::into_packets to not drop any information.
- Change `Cert::into_packets` to return the underlying packets. That is don't drop secret key material like `Cert::serialize` does.
Diffstat (limited to 'openpgp/src/cert.rs')
-rw-r--r--openpgp/src/cert.rs45
1 files changed, 42 insertions, 3 deletions
diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs
index 97bb233e..bcfd79be 100644
--- a/openpgp/src/cert.rs
+++ b/openpgp/src/cert.rs
@@ -1264,6 +1264,20 @@ impl Cert {
/// Converts the certificate into an iterator over a sequence of
/// packets.
///
+ /// **WARNING**: When serializing a `Cert`, any secret key
+ /// material is dropped. In order to serialize the secret key
+ /// material, it is first necessary to convert the `Cert` into a
+ /// [`TSK`] and serialize that. This behavior makes it harder to
+ /// accidentally leak secret key material. *This function is
+ /// different.* If a key contains secret key material, it is
+ /// exported as a [`SecretKey`] or [`SecretSubkey`], as
+ /// appropriate. This means that **if you serialize the resulting
+ /// packets, the secret key material will be serialized too**.
+ ///
+ /// [`TSK`]: serialize/struct.TSK.html
+ /// [`SecretKey`]: enum.Packet.html#variant.SecretKey
+ /// [`SecretSubkey`]: enum.Packet.html#variant.SecretSubkey
+ ///
/// # Examples
///
/// ```
@@ -1280,10 +1294,34 @@ impl Cert {
/// # }
/// ```
pub fn into_packets(self) -> impl Iterator<Item=Packet> {
- self.primary.into_packets()
+ fn rewrite(mut p: impl Iterator<Item=Packet>)
+ -> impl Iterator<Item=Packet>
+ {
+ let k: Packet = match p.next().unwrap() {
+ Packet::PublicKey(k) => {
+ if k.has_secret() {
+ Packet::SecretKey(k.parts_into_secret().unwrap())
+ } else {
+ Packet::PublicKey(k)
+ }
+ }
+ Packet::PublicSubkey(k) => {
+ if k.has_secret() {
+ Packet::SecretSubkey(k.parts_into_secret().unwrap())
+ } else {
+ Packet::PublicSubkey(k)
+ }
+ }
+ _ => unreachable!(),
+ };
+
+ std::iter::once(k).chain(p)
+ }
+
+ rewrite(self.primary.into_packets())
.chain(self.userids.into_iter().flat_map(|b| b.into_packets()))
.chain(self.user_attributes.into_iter().flat_map(|b| b.into_packets()))
- .chain(self.subkeys.into_iter().flat_map(|b| b.into_packets()))
+ .chain(self.subkeys.into_iter().flat_map(|b| rewrite(b.into_packets())))
.chain(self.unknowns.into_iter().flat_map(|b| b.into_packets()))
.chain(self.bad.into_iter().map(|s| s.into()))
}
@@ -4701,7 +4739,8 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
.into_children()
.filter(|pkt| {
match pkt {
- &Packet::PublicKey(_) | &Packet::PublicSubkey(_) => true,
+ &Packet::PublicKey(_) | &Packet::PublicSubkey(_)
+ | &Packet::SecretKey(_) | &Packet::SecretSubkey(_) => true,
&Packet::Signature(ref sig) => {
sig.typ() == SignatureType::DirectKey
|| sig.typ() == SignatureType::SubkeyBinding