diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2020-07-28 17:25:24 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2020-07-28 17:25:24 +0200 |
commit | 076e1bc52c3bad717b8a6b8322ebb0daf044793a (patch) | |
tree | 9925f0f964a80ad26944059c455994480b70a513 | |
parent | b9f1dac59c758826c7c92541d01f447179a1e4d2 (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.rs | 8 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle/ecdh.rs | 2 | ||||
-rw-r--r-- | openpgp/src/crypto/ecdh.rs | 14 | ||||
-rw-r--r-- | openpgp/src/packet/key.rs | 18 |
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(()) + } } |