summaryrefslogtreecommitdiffstats
path: root/openpgp/src/types
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-01-02 17:12:03 +0100
committerJustus Winter <justus@sequoia-pgp.org>2020-01-02 17:52:40 +0100
commit60e1d354f8bde0db5f5808e395c082cfce726d0d (patch)
tree5cc79fd9d41a05c8fe8d8c3461a41871e3aa3deb /openpgp/src/types
parenteab85ce1df7f67f0b92f33db1c62d997e5829165 (diff)
openpgp: Fix roundtripping of KeyFlags, add test.
- In particular, preserve any padding.
Diffstat (limited to 'openpgp/src/types')
-rw-r--r--openpgp/src/types/key_flags.rs41
-rw-r--r--openpgp/src/types/mod.rs12
2 files changed, 50 insertions, 3 deletions
diff --git a/openpgp/src/types/key_flags.rs b/openpgp/src/types/key_flags.rs
index 815018dd..9d461565 100644
--- a/openpgp/src/types/key_flags.rs
+++ b/openpgp/src/types/key_flags.rs
@@ -14,6 +14,8 @@ pub struct KeyFlags{
is_split_key: bool,
is_group_key: bool,
unknown: Box<[u8]>,
+ /// Original length, including trailing zeros.
+ pad_to: usize,
}
impl Default for KeyFlags {
@@ -50,6 +52,9 @@ impl fmt::Debug for KeyFlags {
f.write_str(
&crate::fmt::hex::encode_pretty(&self.unknown))?;
}
+ if self.pad_to > self.unknown.len() {
+ write!(f, "+padding({} bytes)", self.pad_to - self.unknown.len())?;
+ }
Ok(())
}
@@ -66,7 +71,9 @@ impl Eq for KeyFlags {}
impl PartialOrd for KeyFlags {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
let mut a_bits = self.to_vec();
+ crate::types::bitfield_remove_padding(&mut a_bits);
let mut b_bits = other.to_vec();
+ crate::types::bitfield_remove_padding(&mut b_bits);
let len = cmp::max(a_bits.len(), b_bits.len());
while a_bits.len() < len { a_bits.push(0); }
@@ -126,6 +133,8 @@ impl KeyFlags {
/// Creates a new instance from `bits`.
pub fn new<B: AsRef<[u8]>>(bits: B) -> Self {
let bits = bits.as_ref();
+ let mut pad_to = 0;
+
let for_certification = bits.get(0)
.map(|x| x & KEY_FLAG_CERTIFY != 0).unwrap_or(false);
let for_signing = bits.get(0)
@@ -151,14 +160,14 @@ impl KeyFlags {
KEY_FLAG_GROUP_KEY | KEY_FLAG_SPLIT_KEY
) ^ 0xff;
- while cpy.last().cloned() == Some(0) { cpy.pop(); }
+ pad_to = crate::types::bitfield_remove_padding(&mut cpy);
cpy.into_boxed_slice()
};
KeyFlags{
for_certification, for_signing, for_transport_encryption,
for_storage_encryption, for_authentication, is_split_key,
- is_group_key, unknown: unk
+ is_group_key, unknown: unk, pad_to,
}
}
@@ -181,7 +190,19 @@ impl KeyFlags {
if self.for_storage_encryption { ret[0] |= KEY_FLAG_ENCRYPT_AT_REST; }
if self.for_authentication { ret[0] |= KEY_FLAG_AUTHENTICATE; }
if self.is_split_key { ret[0] |= KEY_FLAG_SPLIT_KEY; }
- if self.is_group_key { ret[0] |= KEY_FLAG_GROUP_KEY }
+ if self.is_group_key { ret[0] |= KEY_FLAG_GROUP_KEY; }
+
+ // Corner case: empty flag field. We initialized ret to
+ // vec![0] for easy setting of flags. See if any of the above
+ // was set.
+ if ret.len() == 1 && ret[0] == 0 {
+ // Nope. Trim this byte.
+ ret.pop();
+ }
+
+ for _ in ret.len()..self.pad_to {
+ ret.push(0);
+ }
ret
}
@@ -319,4 +340,18 @@ mod tests {
assert!(!(enc < sig));
assert!(!(enc > sig));
}
+
+ quickcheck! {
+ fn roundtrip(raw: Vec<u8>) -> bool {
+ let val = KeyFlags::new(&raw);
+ assert_eq!(raw, val.to_vec());
+
+ // Check that equality ignores padding.
+ let mut val_without_padding = val.clone();
+ val_without_padding.pad_to = val.unknown.len();
+ assert_eq!(val, val_without_padding);
+
+ true
+ }
+ }
}
diff --git a/openpgp/src/types/mod.rs b/openpgp/src/types/mod.rs
index 01ada8f7..ac6811d5 100644
--- a/openpgp/src/types/mod.rs
+++ b/openpgp/src/types/mod.rs
@@ -21,6 +21,18 @@ pub use self::server_preferences::KeyServerPreferences;
mod timestamp;
pub use timestamp::{Timestamp, Duration};
+/// Removes padding bytes from bitfields.
+///
+/// Returns the size of the original bitfield, i.e. the number of
+/// bytes the output has to be padded to when serialized.
+pub(crate) fn bitfield_remove_padding(b: &mut Vec<u8>) -> usize {
+ let pad_to = b.len();
+ while b.last() == Some(&0) {
+ b.pop();
+ }
+ pad_to
+}
+
/// The OpenPGP public key algorithms as defined in [Section 9.1 of
/// RFC 4880], and [Section 5 of RFC 6637].
///