summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-07-28 17:25:24 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-07-28 17:25:24 +0200
commit076e1bc52c3bad717b8a6b8322ebb0daf044793a (patch)
tree9925f0f964a80ad26944059c455994480b70a513
parentb9f1dac59c758826c7c92541d01f447179a1e4d2 (diff)
openpgp: Explicitly handle plaintexts being too large.
- Fixes undefined behavior (a likely crash) in pkcs5_pad.
-rw-r--r--openpgp/src/crypto/backend/nettle/asymmetric.rs8
-rw-r--r--openpgp/src/crypto/backend/nettle/ecdh.rs2
-rw-r--r--openpgp/src/crypto/ecdh.rs14
-rw-r--r--openpgp/src/packet/key.rs18
4 files changed, 36 insertions, 6 deletions
diff --git a/openpgp/src/crypto/backend/nettle/asymmetric.rs b/openpgp/src/crypto/backend/nettle/asymmetric.rs
index e6f6eb72..c2af71e8 100644
--- a/openpgp/src/crypto/backend/nettle/asymmetric.rs
+++ b/openpgp/src/crypto/backend/nettle/asymmetric.rs
@@ -227,7 +227,13 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> {
match self.mpis() {
mpi::PublicKey::RSA { e, n } => {
// The ciphertext has the length of the modulus.
- let mut esk = vec![0u8; n.value().len()];
+ let ciphertext_len = n.value().len();
+ if data.len() + 11 > ciphertext_len {
+ return Err(Error::InvalidArgument(
+ "Plaintext data too large".into()).into());
+ }
+
+ let mut esk = vec![0u8; ciphertext_len];
let mut rng = Yarrow::default();
let pk = rsa::PublicKey::new(n.value(), e.value())?;
rsa::encrypt_pkcs1(&pk, &mut rng, data,
diff --git a/openpgp/src/crypto/backend/nettle/ecdh.rs b/openpgp/src/crypto/backend/nettle/ecdh.rs
index c6bd5552..f3f820b5 100644
--- a/openpgp/src/crypto/backend/nettle/ecdh.rs
+++ b/openpgp/src/crypto/backend/nettle/ecdh.rs
@@ -138,7 +138,7 @@ pub fn encrypt_shared<R>(recipient: &Key<key::PublicParts, R>,
// m = sym_alg_ID || session key || checksum || pkcs5_padding;
let mut m = Vec::with_capacity(40);
m.extend_from_slice(session_key);
- let m = pkcs5_pad(m.into(), 40);
+ let m = pkcs5_pad(m.into(), 40)?;
// Note: We always pad up to 40 bytes to obfuscate the
// length of the symmetric key.
diff --git a/openpgp/src/crypto/ecdh.rs b/openpgp/src/crypto/ecdh.rs
index 399a670d..5f815afd 100644
--- a/openpgp/src/crypto/ecdh.rs
+++ b/openpgp/src/crypto/ecdh.rs
@@ -38,7 +38,13 @@ pub fn kdf(x: &Protected, obits: usize, hash: HashAlgorithm, param: &[u8])
/// See [Section 8 of RFC 6637].
///
/// [Section 8 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-8
-pub fn pkcs5_pad(sk: Protected, target_len: usize) -> Protected {
+pub fn pkcs5_pad(sk: Protected, target_len: usize) -> Result<Protected> {
+ if sk.len() > target_len {
+ return Err(Error::InvalidArgument(
+ "Plaintext data too large".into()).into());
+ }
+
+ // !!! THIS FUNCTION MUST NOT FAIL FROM THIS POINT ON !!!
let mut buf: Vec<u8> = unsafe {
sk.into_vec()
};
@@ -48,7 +54,7 @@ pub fn pkcs5_pad(sk: Protected, target_len: usize) -> Protected {
buf.push(missing as u8);
}
assert_eq!(buf.len(), target_len);
- buf.into()
+ Ok(buf.into())
}
/// Removes PKCS5 padding from a session key.
@@ -257,12 +263,12 @@ mod tests {
#[test]
fn pkcs5_padding() {
- let v = pkcs5_pad(vec![0, 0, 0].into(), 8);
+ let v = pkcs5_pad(vec![0, 0, 0].into(), 8).unwrap();
assert_eq!(&v, &Protected::from(&[0, 0, 0, 5, 5, 5, 5, 5][..]));
let v = pkcs5_unpad(v, 3).unwrap();
assert_eq!(&v, &Protected::from(&[0, 0, 0][..]));
- let v = pkcs5_pad(vec![].into(), 8);
+ let v = pkcs5_pad(vec![].into(), 8).unwrap();
assert_eq!(&v, &Protected::from(&[8, 8, 8, 8, 8, 8, 8, 8][..]));
let v = pkcs5_unpad(v, 0).unwrap();
assert_eq!(&v, &Protected::from(&[][..]));
diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs
index 7eb6abcf..d6c97a80 100644
--- a/openpgp/src/packet/key.rs
+++ b/openpgp/src/packet/key.rs
@@ -1865,4 +1865,22 @@ mod tests {
}
assert!(pki == pks.len() && ski == sks.len());
}
+
+ #[test]
+ fn encrypt_huge_plaintext() -> Result<()> {
+ let sk = crate::crypto::SessionKey::new(256);
+ let rsa2k: Key<SecretParts, UnspecifiedRole> =
+ Key4::generate_rsa(2048)?.into();
+ assert!(destructures_to!(
+ crate::Error::InvalidArgument(_) =
+ rsa2k.encrypt(&sk).unwrap_err().downcast().unwrap()));
+
+ let cv25519: Key<SecretParts, UnspecifiedRole> =
+ Key4::generate_ecc(false, Curve::Cv25519)?.into();
+ assert!(destructures_to!(
+ crate::Error::InvalidArgument(_) =
+ cv25519.encrypt(&sk).unwrap_err().downcast().unwrap()));
+
+ Ok(())
+ }
}