Revert^2 "Update to work with new BoringSSL" am: 2a93b21a43
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/openssl/+/2470948
Change-Id: I254a0112c1cb3ee266d908140140447ec58e5152
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/README.android b/README.android
index 6499cfe..1957c30 100644
--- a/README.android
+++ b/README.android
@@ -29,3 +29,13 @@
Android.bp builds correctly by running `m libopenssl`.
7. Commit the changes and upload the CL.
8. `external/rust/crates/openssl-macros` should also be updated at the same time.
+
+## Generating patch files
+
+If you make changes to this repo that is not in upstream `rust-openssl` yet, please generate a
+patch file to keep track of those changes.
+
+1. Commit your changes
+2. Create the patch file: `git diff -u HEAD~ > <XXXX-topic>.diff` where XXXX is the number to track
+ the order of the patches to apply.
+3. Amend the patch file into your CL `git add -A && git commit --amend`
diff --git a/patches/0001-cfgs.diff b/patches/0001-cfgs.diff
new file mode 100644
index 0000000..f118c41
--- /dev/null
+++ b/patches/0001-cfgs.diff
@@ -0,0 +1,271 @@
+diff --git a/.cargo/config.toml b/.cargo/config.toml
+new file mode 100644
+index 0000000..e2b197d
+--- /dev/null
++++ b/.cargo/config.toml
+@@ -0,0 +1,2 @@
++[patch.crates-io]
++bssl-ffi = { package = "bssl-sys", version = "0.1.0", path = "../../../boringssl/build/rust", optional=true }
+diff --git a/src/cipher.rs b/src/cipher.rs
+index ab5f49d..84a8265 100644
+--- a/src/cipher.rs
++++ b/src/cipher.rs
+@@ -208,6 +208,7 @@ impl Cipher {
+ unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb1() as *mut _) }
+ }
+
++ #[cfg(not(boringssl))]
+ pub fn aes_192_cfb128() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb128() as *mut _) }
+ }
+@@ -253,6 +254,7 @@ impl Cipher {
+ unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb1() as *mut _) }
+ }
+
++ #[cfg(not(boringssl))]
+ pub fn aes_256_cfb128() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb128() as *mut _) }
+ }
+@@ -282,11 +284,13 @@ impl Cipher {
+ }
+
+ #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
++ #[cfg(not(boringssl))]
+ pub fn bf_cbc() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_bf_cbc() as *mut _) }
+ }
+
+ #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
++ #[cfg(not(boringssl))]
+ pub fn bf_ecb() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_bf_ecb() as *mut _) }
+ }
+diff --git a/src/encrypt.rs b/src/encrypt.rs
+index 3cb10fc..34a9eb8 100644
+--- a/src/encrypt.rs
++++ b/src/encrypt.rs
+@@ -148,7 +148,7 @@ impl<'a> Encrypter<'a> {
+ /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`].
+ ///
+ /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html
+- #[cfg(any(ossl102, libressl310))]
++ #[cfg(any(ossl102, libressl310, boringssl))]
+ pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md(
+@@ -352,7 +352,7 @@ impl<'a> Decrypter<'a> {
+ /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`].
+ ///
+ /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html
+- #[cfg(any(ossl102, libressl310))]
++ #[cfg(any(ossl102, libressl310, boringssl))]
+ pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md(
+diff --git a/src/lib.rs b/src/lib.rs
+index 891651e..f149bfd 100644
+--- a/src/lib.rs
++++ b/src/lib.rs
+@@ -120,6 +120,9 @@
+ #![doc(html_root_url = "https://docs.rs/openssl/0.10")]
+ #![warn(rust_2018_idioms)]
+
++#[cfg(all(soong, boringssl))]
++extern crate bssl_ffi as ffi;
++
+ #[doc(inline)]
+ pub use ffi::init;
+
+@@ -155,6 +158,10 @@ pub mod ex_data;
+ #[cfg(not(any(libressl, ossl300)))]
+ pub mod fips;
+ pub mod hash;
++#[cfg(boringssl)]
++pub mod hkdf;
++#[cfg(boringssl)]
++pub mod hmac;
+ #[cfg(ossl300)]
+ pub mod lib_ctx;
+ pub mod md;
+diff --git a/src/pkey.rs b/src/pkey.rs
+index 7d438eb..7eaf068 100644
+--- a/src/pkey.rs
++++ b/src/pkey.rs
+@@ -47,7 +47,7 @@ use crate::dh::Dh;
+ use crate::dsa::Dsa;
+ use crate::ec::EcKey;
+ use crate::error::ErrorStack;
+-#[cfg(ossl110)]
++#[cfg(any(boringssl, ossl110))]
+ use crate::pkey_ctx::PkeyCtx;
+ use crate::rsa::Rsa;
+ use crate::symm::Cipher;
+@@ -89,11 +89,11 @@ impl Id {
+ #[cfg(ossl110)]
+ pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF);
+
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
+ #[cfg(ossl111)]
+ pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub const X25519: Id = Id(ffi::EVP_PKEY_X25519);
+ #[cfg(ossl111)]
+ pub const X448: Id = Id(ffi::EVP_PKEY_X448);
+@@ -243,7 +243,7 @@ where
+ /// This function only works for algorithms that support raw public keys.
+ /// Currently this is: [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
+ #[corresponds(EVP_PKEY_get_raw_public_key)]
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub fn raw_public_key(&self) -> Result<Vec<u8>, ErrorStack> {
+ unsafe {
+ let mut len = 0;
+@@ -294,7 +294,7 @@ where
+ /// This function only works for algorithms that support raw private keys.
+ /// Currently this is: [`Id::HMAC`], [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
+ #[corresponds(EVP_PKEY_get_raw_private_key)]
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub fn raw_private_key(&self) -> Result<Vec<u8>, ErrorStack> {
+ unsafe {
+ let mut len = 0;
+@@ -475,7 +475,7 @@ impl PKey<Private> {
+ ctx.keygen()
+ }
+
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ fn generate_eddsa(id: Id) -> Result<PKey<Private>, ErrorStack> {
+ let mut ctx = PkeyCtx::new_id(id)?;
+ ctx.keygen_init()?;
+@@ -505,7 +505,7 @@ impl PKey<Private> {
+ /// assert_eq!(secret.len(), 32);
+ /// # Ok(()) }
+ /// ```
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub fn generate_x25519() -> Result<PKey<Private>, ErrorStack> {
+ PKey::generate_eddsa(Id::X25519)
+ }
+@@ -559,7 +559,7 @@ impl PKey<Private> {
+ /// assert_eq!(signature.len(), 64);
+ /// # Ok(()) }
+ /// ```
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
+ PKey::generate_eddsa(Id::ED25519)
+ }
+@@ -709,7 +709,7 @@ impl PKey<Private> {
+ ///
+ /// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448
+ #[corresponds(EVP_PKEY_new_raw_private_key)]
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub fn private_key_from_raw_bytes(
+ bytes: &[u8],
+ key_type: Id,
+@@ -750,7 +750,7 @@ impl PKey<Public> {
+ ///
+ /// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448
+ #[corresponds(EVP_PKEY_new_raw_public_key)]
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub fn public_key_from_raw_bytes(
+ bytes: &[u8],
+ key_type: Id,
+diff --git a/src/sign.rs b/src/sign.rs
+index 457ff12..4de8ad0 100644
+--- a/src/sign.rs
++++ b/src/sign.rs
+@@ -290,7 +290,7 @@ impl<'a> Signer<'a> {
+ self.len_intern()
+ }
+
+- #[cfg(not(ossl111))]
++ #[cfg(not(any(boringssl, ossl111)))]
+ fn len_intern(&self) -> Result<usize, ErrorStack> {
+ unsafe {
+ let mut len = 0;
+@@ -303,7 +303,7 @@ impl<'a> Signer<'a> {
+ }
+ }
+
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ fn len_intern(&self) -> Result<usize, ErrorStack> {
+ unsafe {
+ let mut len = 0;
+@@ -360,7 +360,7 @@ impl<'a> Signer<'a> {
+ /// OpenSSL documentation at [`EVP_DigestSign`].
+ ///
+ /// [`EVP_DigestSign`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSign.html
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub fn sign_oneshot(
+ &mut self,
+ sig_buf: &mut [u8],
+@@ -382,7 +382,7 @@ impl<'a> Signer<'a> {
+ /// Returns the signature.
+ ///
+ /// This is a simple convenience wrapper over `len` and `sign_oneshot`.
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub fn sign_oneshot_to_vec(&mut self, data_buf: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+ let mut sig_buf = vec![0; self.len()?];
+ let len = self.sign_oneshot(&mut sig_buf, data_buf)?;
+@@ -594,7 +594,7 @@ impl<'a> Verifier<'a> {
+ /// OpenSSL documentation at [`EVP_DigestVerify`].
+ ///
+ /// [`EVP_DigestVerify`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestVerify.html
+- #[cfg(ossl111)]
++ #[cfg(any(boringssl, ossl111))]
+ pub fn verify_oneshot(&mut self, signature: &[u8], buf: &[u8]) -> Result<bool, ErrorStack> {
+ unsafe {
+ let r = ffi::EVP_DigestVerify(
+diff --git a/src/symm.rs b/src/symm.rs
+index c75bbc0..beff5fc 100644
+--- a/src/symm.rs
++++ b/src/symm.rs
+@@ -119,6 +119,7 @@ impl Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_cfb1()) }
+ }
+
++ #[cfg(not(boringssl))]
+ pub fn aes_128_cfb128() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_128_cfb128()) }
+ }
+@@ -164,6 +165,7 @@ impl Cipher {
+ unsafe { Cipher(ffi::EVP_aes_192_cfb1()) }
+ }
+
++ #[cfg(not(boringssl))]
+ pub fn aes_192_cfb128() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_192_cfb128()) }
+ }
+@@ -214,6 +216,7 @@ impl Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_cfb1()) }
+ }
+
++ #[cfg(not(boringssl))]
+ pub fn aes_256_cfb128() -> Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_cfb128()) }
+ }
+@@ -242,12 +245,12 @@ impl Cipher {
+ unsafe { Cipher(ffi::EVP_aes_256_ocb()) }
+ }
+
+- #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
++ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_BF")))]
+ pub fn bf_cbc() -> Cipher {
+ unsafe { Cipher(ffi::EVP_bf_cbc()) }
+ }
+
+- #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
++ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_BF")))]
+ pub fn bf_ecb() -> Cipher {
+ unsafe { Cipher(ffi::EVP_bf_ecb()) }
+ }
diff --git a/patches/0002-ec.diff b/patches/0002-ec.diff
new file mode 100644
index 0000000..1a27bbe
--- /dev/null
+++ b/patches/0002-ec.diff
@@ -0,0 +1,31 @@
+diff --git a/src/ec.rs b/src/ec.rs
+index a6a6dc9..88dcaaf 100644
+--- a/src/ec.rs
++++ b/src/ec.rs
+@@ -908,6 +908,26 @@ impl EcKey<Private> {
+ EcKey<Private>,
+ ffi::d2i_ECPrivateKey
+ }
++
++ /// Decodes a DER-encoded elliptic curve private key structure for the specified curve.
++ #[corresponds(EC_KEY_parse_private_key)]
++ #[cfg(boringssl)]
++ pub fn private_key_from_der_for_group(
++ der: &[u8],
++ group: &EcGroupRef,
++ ) -> Result<EcKey<Private>, ErrorStack> {
++ unsafe {
++ let mut cbs = ffi::CBS {
++ data: der.as_ptr(),
++ len: der.len(),
++ };
++ cvt_p(ffi::EC_KEY_parse_private_key(
++ &mut cbs as *mut ffi::CBS,
++ group.as_ptr(),
++ ))
++ .map(|p| EcKey::from_ptr(p))
++ }
++ }
+ }
+
+ impl<T> Clone for EcKey<T> {
diff --git a/patches/0003-hkdf.diff b/patches/0003-hkdf.diff
new file mode 100644
index 0000000..d99ab7f
--- /dev/null
+++ b/patches/0003-hkdf.diff
@@ -0,0 +1,95 @@
+diff --git a/src/hkdf.rs b/src/hkdf.rs
+new file mode 100644
+index 0000000..cc7e5b3
+--- /dev/null
++++ b/src/hkdf.rs
+@@ -0,0 +1,89 @@
++use crate::cvt;
++use crate::error::ErrorStack;
++use crate::md::MdRef;
++use foreign_types::ForeignTypeRef;
++use openssl_macros::corresponds;
++
++/// Computes HKDF (as specified by RFC 5869).
++///
++/// HKDF is an Extract-and-Expand algorithm. It does not do any key stretching,
++/// and as such, is not suited to be used alone to generate a key from a
++/// password.
++#[corresponds(HKDF)]
++#[inline]
++pub fn hkdf(
++ out_key: &mut [u8],
++ md: &MdRef,
++ secret: &[u8],
++ salt: &[u8],
++ info: &[u8],
++) -> Result<(), ErrorStack> {
++ unsafe {
++ cvt(ffi::HKDF(
++ out_key.as_mut_ptr(),
++ out_key.len(),
++ md.as_ptr(),
++ secret.as_ptr(),
++ secret.len(),
++ salt.as_ptr(),
++ salt.len(),
++ info.as_ptr(),
++ info.len(),
++ ))?;
++ }
++
++ Ok(())
++}
++
++/// Computes a HKDF PRK (as specified by RFC 5869).
++///
++/// WARNING: This function orders the inputs differently from RFC 5869
++/// specification. Double-check which parameter is the secret/IKM and which is
++/// the salt when using.
++#[corresponds(HKDF_extract)]
++#[inline]
++pub fn hkdf_extract<'a>(
++ out_key: &'a mut [u8],
++ md: &MdRef,
++ secret: &[u8],
++ salt: &[u8],
++) -> Result<&'a [u8], ErrorStack> {
++ let mut out_len = out_key.len();
++ unsafe {
++ cvt(ffi::HKDF_extract(
++ out_key.as_mut_ptr(),
++ &mut out_len,
++ md.as_ptr(),
++ secret.as_ptr(),
++ secret.len(),
++ salt.as_ptr(),
++ salt.len(),
++ ))?;
++ }
++
++ Ok(&out_key[..out_len])
++}
++
++/// Computes a HKDF OKM (as specified by RFC 5869).
++#[corresponds(HKDF_expand)]
++#[inline]
++pub fn hkdf_expand(
++ out_key: &mut [u8],
++ md: &MdRef,
++ prk: &[u8],
++ info: &[u8],
++) -> Result<(), ErrorStack> {
++ unsafe {
++ cvt(ffi::HKDF_expand(
++ out_key.as_mut_ptr(),
++ out_key.len(),
++ md.as_ptr(),
++ prk.as_ptr(),
++ prk.len(),
++ info.as_ptr(),
++ info.len(),
++ ))?;
++ }
++
++ Ok(())
++}
diff --git a/patches/0004-hmac.diff b/patches/0004-hmac.diff
new file mode 100644
index 0000000..e9000d2
--- /dev/null
+++ b/patches/0004-hmac.diff
@@ -0,0 +1,74 @@
+diff --git a/src/hmac.rs b/src/hmac.rs
+new file mode 100644
+index 0000000..601ae01
+--- /dev/null
++++ b/src/hmac.rs
+@@ -0,0 +1,68 @@
++use crate::cvt_p;
++use crate::error::ErrorStack;
++use crate::md::MdRef;
++use foreign_types::ForeignTypeRef;
++use openssl_macros::corresponds;
++use libc::{c_void, c_uint};
++use std::convert::TryFrom;
++
++/// Computes the HMAC as a one-shot operation.
++///
++/// Calculates the HMAC of data, using the given |key|
++/// and hash function |md|, and returns the result re-using the space from
++/// buffer |out|. On entry, |out| must contain at least |EVP_MD_size| bytes
++/// of space. The actual length of the result is used to resize the returned
++/// slice. An output size of |EVP_MAX_MD_SIZE| will always be large enough.
++/// It returns a resized |out| or ErrorStack on error.
++#[corresponds(HMAC)]
++#[inline]
++pub fn hmac<'a>(
++ md: &MdRef,
++ key: &[u8],
++ data: &[u8],
++ out: &'a mut [u8]
++) -> Result<&'a [u8], ErrorStack> {
++ let mut out_len = c_uint::try_from(out.len()).unwrap();
++ unsafe {
++ cvt_p(ffi::HMAC(
++ md.as_ptr(),
++ key.as_ptr() as *const c_void,
++ key.len(),
++ data.as_ptr(),
++ data.len(),
++ out.as_mut_ptr(),
++ &mut out_len
++ ))?;
++ }
++ Ok(&out[..out_len as usize])
++}
++
++#[cfg(test)]
++mod tests {
++ use super::*;
++ use crate::md::Md;
++ use crate::memcmp;
++
++ const SHA_256_DIGEST_SIZE:usize = 32;
++
++ #[test]
++ fn hmac_sha256_test() {
++ let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
++ let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE];
++ let key:[u8; 20] = [0x0b; 20];
++ let data = b"Hi There";
++ let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
++ expect!(memcmp::eq(&hmac_result, &expected_hmac));
++ }
++
++ #[test]
++ fn hmac_sha256_test_big_buffer() {
++ let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
++ let mut out: [u8; 100] = [0; 100];
++ let key:[u8;20] = [0x0b; 20];
++ let data = b"Hi There";
++ let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
++ expect_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE);
++ expect!(memcmp::eq(&hmac_result, &expected_hmac));
++ }
++}
diff --git a/patches/0005-hmac_ctx_wrappers.diff b/patches/0005-hmac_ctx_wrappers.diff
new file mode 100644
index 0000000..305f5bc
--- /dev/null
+++ b/patches/0005-hmac_ctx_wrappers.diff
@@ -0,0 +1,228 @@
+diff --git a/src/hmac.rs b/src/hmac.rs
+index 601ae01..465781e 100644
+--- a/src/hmac.rs
++++ b/src/hmac.rs
+@@ -1,10 +1,12 @@
+-use crate::cvt_p;
+ use crate::error::ErrorStack;
+ use crate::md::MdRef;
++use crate::{cvt, cvt_p};
++use ffi::HMAC_CTX;
+ use foreign_types::ForeignTypeRef;
++use libc::{c_uint, c_void};
+ use openssl_macros::corresponds;
+-use libc::{c_void, c_uint};
+ use std::convert::TryFrom;
++use std::ptr;
+
+ /// Computes the HMAC as a one-shot operation.
+ ///
+@@ -20,8 +22,9 @@ pub fn hmac<'a>(
+ md: &MdRef,
+ key: &[u8],
+ data: &[u8],
+- out: &'a mut [u8]
++ out: &'a mut [u8],
+ ) -> Result<&'a [u8], ErrorStack> {
++ assert!(out.len() >= md.size());
+ let mut out_len = c_uint::try_from(out.len()).unwrap();
+ unsafe {
+ cvt_p(ffi::HMAC(
+@@ -31,38 +34,184 @@ pub fn hmac<'a>(
+ data.as_ptr(),
+ data.len(),
+ out.as_mut_ptr(),
+- &mut out_len
+- ))?;
++ &mut out_len,
++ ))?;
+ }
+ Ok(&out[..out_len as usize])
+ }
+
++/// A context object used to perform HMAC operations.
++///
++/// HMAC is a MAC (message authentication code), i.e. a keyed hash function used for message
++/// authentication, which is based on a hash function.
++///
++/// Note: Only available in boringssl. For openssl, use `PKey::hmac` instead.
++#[cfg(boringssl)]
++pub struct HmacCtx {
++ ctx: *mut HMAC_CTX,
++ output_size: usize,
++}
++
++#[cfg(boringssl)]
++impl HmacCtx {
++ /// Creates a new [HmacCtx] to use the hash function `md` and key `key`.
++ #[corresponds(HMAC_Init_ex)]
++ pub fn new(key: &[u8], md: &MdRef) -> Result<Self, ErrorStack> {
++ unsafe {
++ // Safety: If an error occurred, the resulting null from HMAC_CTX_new is converted into
++ // ErrorStack in the returned result by `cvt_p`.
++ let ctx = cvt_p(ffi::HMAC_CTX_new())?;
++ // Safety:
++ // - HMAC_Init_ex must be called with a context previously created with HMAC_CTX_new,
++ // which is the line above.
++ // - HMAC_Init_ex may return an error if key is null but the md is different from
++ // before. This is avoided here since key is guaranteed to be non-null.
++ cvt(ffi::HMAC_Init_ex(
++ ctx,
++ key.as_ptr() as *const c_void,
++ key.len(),
++ md.as_ptr(),
++ ptr::null_mut(),
++ ))?;
++ Ok(Self {
++ ctx,
++ output_size: md.size(),
++ })
++ }
++ }
++
++ /// `update` can be called repeatedly with chunks of the message `data` to be authenticated.
++ #[corresponds(HMAC_Update)]
++ pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
++ unsafe {
++ // Safety: HMAC_Update returns 0 on error, and that is converted into ErrorStack in the
++ // returned result by `cvt`.
++ cvt(ffi::HMAC_Update(self.ctx, data.as_ptr(), data.len())).map(|_| ())
++ }
++ }
++
++ /// Finishes the HMAC process, and places the message authentication code in `output`.
++ /// The number of bytes written to `output` is returned.
++ ///
++ /// # Panics
++ ///
++ /// Panics if the `output` is smaller than the required size. The output size is indicated by
++ /// `md.size()` for the `Md` instance passed in [new]. An output size of |EVP_MAX_MD_SIZE| will
++ /// always be large enough.
++ #[corresponds(HMAC_Final)]
++ pub fn finalize(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> {
++ assert!(output.len() >= self.output_size);
++ unsafe {
++ // Safety: The length assertion above makes sure that `HMAC_Final` will not write longer
++ // than the length of `output`.
++ let mut size: c_uint = 0;
++ cvt(ffi::HMAC_Final(
++ self.ctx,
++ output.as_mut_ptr(),
++ &mut size as *mut c_uint,
++ ))
++ .map(|_| size as usize)
++ }
++ }
++}
++
++impl Drop for HmacCtx {
++ #[corresponds(HMAC_CTX_free)]
++ fn drop(&mut self) {
++ unsafe {
++ ffi::HMAC_CTX_free(self.ctx);
++ }
++ }
++}
++
+ #[cfg(test)]
+ mod tests {
+ use super::*;
+ use crate::md::Md;
+- use crate::memcmp;
+
+- const SHA_256_DIGEST_SIZE:usize = 32;
++ const SHA_256_DIGEST_SIZE: usize = 32;
+
+ #[test]
+ fn hmac_sha256_test() {
+- let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
++ let expected_hmac = [
++ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
++ 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
++ 0x2e, 0x32, 0xcf, 0xf7,
++ ];
+ let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE];
+- let key:[u8; 20] = [0x0b; 20];
++ let key: [u8; 20] = [0x0b; 20];
+ let data = b"Hi There";
+- let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
+- expect!(memcmp::eq(&hmac_result, &expected_hmac));
++ let hmac_result =
++ hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
++ assert_eq!(&hmac_result, &expected_hmac);
++ }
++
++ #[test]
++ #[should_panic]
++ fn hmac_sha256_output_too_short() {
++ let mut out = vec![0_u8; 1];
++ let key: [u8; 20] = [0x0b; 20];
++ let data = b"Hi There";
++ hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
+ }
+
+ #[test]
+ fn hmac_sha256_test_big_buffer() {
+- let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
++ let expected_hmac = [
++ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
++ 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
++ 0x2e, 0x32, 0xcf, 0xf7,
++ ];
+ let mut out: [u8; 100] = [0; 100];
+- let key:[u8;20] = [0x0b; 20];
++ let key: [u8; 20] = [0x0b; 20];
++ let data = b"Hi There";
++ let hmac_result =
++ hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
++ assert_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE);
++ assert_eq!(&hmac_result, &expected_hmac);
++ }
++
++ #[test]
++ fn hmac_sha256_update_test() {
++ let expected_hmac = [
++ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
++ 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
++ 0x2e, 0x32, 0xcf, 0xf7,
++ ];
++ let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE];
++ let key: [u8; 20] = [0x0b; 20];
+ let data = b"Hi There";
+- let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
+- expect_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE);
+- expect!(memcmp::eq(&hmac_result, &expected_hmac));
++ let mut hmac_ctx = HmacCtx::new(&key, Md::sha256()).unwrap();
++ hmac_ctx.update(data).unwrap();
++ let size = hmac_ctx.finalize(&mut out).unwrap();
++ assert_eq!(&out, &expected_hmac);
++ assert_eq!(size, SHA_256_DIGEST_SIZE);
++ }
++
++ #[test]
++ fn hmac_sha256_update_chunks_test() {
++ let expected_hmac = [
++ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
++ 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
++ 0x2e, 0x32, 0xcf, 0xf7,
++ ];
++ let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE];
++ let key: [u8; 20] = [0x0b; 20];
++ let mut hmac_ctx = HmacCtx::new(&key, Md::sha256()).unwrap();
++ hmac_ctx.update(b"Hi").unwrap();
++ hmac_ctx.update(b" There").unwrap();
++ let size = hmac_ctx.finalize(&mut out).unwrap();
++ assert_eq!(&out, &expected_hmac);
++ assert_eq!(size, SHA_256_DIGEST_SIZE);
++ }
++
++ #[test]
++ #[should_panic]
++ fn hmac_sha256_update_output_too_short() {
++ let mut out = vec![0_u8; 1];
++ let key: [u8; 20] = [0x0b; 20];
++ let mut hmac_ctx = HmacCtx::new(&key, Md::sha256()).unwrap();
++ hmac_ctx.update(b"Hi There").unwrap();
++ hmac_ctx.finalize(&mut out).unwrap();
+ }
+ }
diff --git a/patches/0006-x509.diff b/patches/0006-x509.diff
new file mode 100644
index 0000000..244e775
--- /dev/null
+++ b/patches/0006-x509.diff
@@ -0,0 +1,54 @@
+diff --git a/src/x509/mod.rs b/src/x509/mod.rs
+index edd54aa..45f2467 100644
+--- a/src/x509/mod.rs
++++ b/src/x509/mod.rs
+@@ -353,6 +353,19 @@ impl X509Builder {
+ unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
+ }
+
++ /// Signs the certificate with a private key but without a digest.
++ ///
++ /// This is the only way to sign with Ed25519 keys as BoringSSL doesn't support the null
++ /// message digest.
++ #[cfg(boringssl)]
++ #[corresponds(X509_sign)]
++ pub fn sign_without_digest<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
++ where
++ T: HasPrivate,
++ {
++ unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), ptr::null())).map(|_| ()) }
++ }
++
+ /// Consumes the builder, returning the certificate.
+ pub fn build(self) -> X509 {
+ self.0
+@@ -1260,6 +1273,29 @@ impl X509ReqBuilder {
+ }
+ }
+
++ /// Sign the request using a private key without a digest.
++ ///
++ /// This is the only way to sign with Ed25519 keys as BoringSSL doesn't support the null
++ /// message digest.
++ ///
++ /// This corresponds to [`X509_REQ_sign`].
++ ///
++ /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html
++ #[cfg(boringssl)]
++ pub fn sign_without_digest<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
++ where
++ T: HasPrivate,
++ {
++ unsafe {
++ cvt(ffi::X509_REQ_sign(
++ self.0.as_ptr(),
++ key.as_ptr(),
++ ptr::null(),
++ ))
++ .map(|_| ())
++ }
++ }
++
+ /// Returns the `X509Req`.
+ pub fn build(self) -> X509Req {
+ self.0
diff --git a/patches/local_changes.diff b/patches/local_changes.diff
deleted file mode 100644
index 06702fa..0000000
--- a/patches/local_changes.diff
+++ /dev/null
@@ -1,525 +0,0 @@
-diff --git a/.cargo/config.toml b/.cargo/config.toml
-new file mode 100644
-index 0000000..e2b197d
---- /dev/null
-+++ b/.cargo/config.toml
-@@ -0,0 +1,2 @@
-+[patch.crates-io]
-+bssl-ffi = { package = "bssl-sys", version = "0.1.0", path = "../../../boringssl/build/rust", optional=true }
-diff --git a/src/cipher.rs b/src/cipher.rs
-index ab5f49d..84a8265 100644
---- a/src/cipher.rs
-+++ b/src/cipher.rs
-@@ -208,6 +208,7 @@ impl Cipher {
- unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb1() as *mut _) }
- }
-
-+ #[cfg(not(boringssl))]
- pub fn aes_192_cfb128() -> &'static CipherRef {
- unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb128() as *mut _) }
- }
-@@ -253,6 +254,7 @@ impl Cipher {
- unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb1() as *mut _) }
- }
-
-+ #[cfg(not(boringssl))]
- pub fn aes_256_cfb128() -> &'static CipherRef {
- unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb128() as *mut _) }
- }
-@@ -282,11 +284,13 @@ impl Cipher {
- }
-
- #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
-+ #[cfg(not(boringssl))]
- pub fn bf_cbc() -> &'static CipherRef {
- unsafe { CipherRef::from_ptr(ffi::EVP_bf_cbc() as *mut _) }
- }
-
- #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
-+ #[cfg(not(boringssl))]
- pub fn bf_ecb() -> &'static CipherRef {
- unsafe { CipherRef::from_ptr(ffi::EVP_bf_ecb() as *mut _) }
- }
-diff --git a/src/ec.rs b/src/ec.rs
-index a6a6dc9..88dcaaf 100644
---- a/src/ec.rs
-+++ b/src/ec.rs
-@@ -908,6 +908,26 @@ impl EcKey<Private> {
- EcKey<Private>,
- ffi::d2i_ECPrivateKey
- }
-+
-+ /// Decodes a DER-encoded elliptic curve private key structure for the specified curve.
-+ #[corresponds(EC_KEY_parse_private_key)]
-+ #[cfg(boringssl)]
-+ pub fn private_key_from_der_for_group(
-+ der: &[u8],
-+ group: &EcGroupRef,
-+ ) -> Result<EcKey<Private>, ErrorStack> {
-+ unsafe {
-+ let mut cbs = ffi::CBS {
-+ data: der.as_ptr(),
-+ len: der.len(),
-+ };
-+ cvt_p(ffi::EC_KEY_parse_private_key(
-+ &mut cbs as *mut ffi::CBS,
-+ group.as_ptr(),
-+ ))
-+ .map(|p| EcKey::from_ptr(p))
-+ }
-+ }
- }
-
- impl<T> Clone for EcKey<T> {
-diff --git a/src/encrypt.rs b/src/encrypt.rs
-index 3cb10fc..34a9eb8 100644
---- a/src/encrypt.rs
-+++ b/src/encrypt.rs
-@@ -148,7 +148,7 @@ impl<'a> Encrypter<'a> {
- /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`].
- ///
- /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html
-- #[cfg(any(ossl102, libressl310))]
-+ #[cfg(any(ossl102, libressl310, boringssl))]
- pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
- unsafe {
- cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md(
-@@ -352,7 +352,7 @@ impl<'a> Decrypter<'a> {
- /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`].
- ///
- /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html
-- #[cfg(any(ossl102, libressl310))]
-+ #[cfg(any(ossl102, libressl310, boringssl))]
- pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
- unsafe {
- cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md(
-diff --git a/src/hkdf.rs b/src/hkdf.rs
-new file mode 100644
-index 0000000..cc7e5b3
---- /dev/null
-+++ b/src/hkdf.rs
-@@ -0,0 +1,89 @@
-+use crate::cvt;
-+use crate::error::ErrorStack;
-+use crate::md::MdRef;
-+use foreign_types::ForeignTypeRef;
-+use openssl_macros::corresponds;
-+
-+/// Computes HKDF (as specified by RFC 5869).
-+///
-+/// HKDF is an Extract-and-Expand algorithm. It does not do any key stretching,
-+/// and as such, is not suited to be used alone to generate a key from a
-+/// password.
-+#[corresponds(HKDF)]
-+#[inline]
-+pub fn hkdf(
-+ out_key: &mut [u8],
-+ md: &MdRef,
-+ secret: &[u8],
-+ salt: &[u8],
-+ info: &[u8],
-+) -> Result<(), ErrorStack> {
-+ unsafe {
-+ cvt(ffi::HKDF(
-+ out_key.as_mut_ptr(),
-+ out_key.len(),
-+ md.as_ptr(),
-+ secret.as_ptr(),
-+ secret.len(),
-+ salt.as_ptr(),
-+ salt.len(),
-+ info.as_ptr(),
-+ info.len(),
-+ ))?;
-+ }
-+
-+ Ok(())
-+}
-+
-+/// Computes a HKDF PRK (as specified by RFC 5869).
-+///
-+/// WARNING: This function orders the inputs differently from RFC 5869
-+/// specification. Double-check which parameter is the secret/IKM and which is
-+/// the salt when using.
-+#[corresponds(HKDF_extract)]
-+#[inline]
-+pub fn hkdf_extract<'a>(
-+ out_key: &'a mut [u8],
-+ md: &MdRef,
-+ secret: &[u8],
-+ salt: &[u8],
-+) -> Result<&'a [u8], ErrorStack> {
-+ let mut out_len = out_key.len();
-+ unsafe {
-+ cvt(ffi::HKDF_extract(
-+ out_key.as_mut_ptr(),
-+ &mut out_len,
-+ md.as_ptr(),
-+ secret.as_ptr(),
-+ secret.len(),
-+ salt.as_ptr(),
-+ salt.len(),
-+ ))?;
-+ }
-+
-+ Ok(&out_key[..out_len])
-+}
-+
-+/// Computes a HKDF OKM (as specified by RFC 5869).
-+#[corresponds(HKDF_expand)]
-+#[inline]
-+pub fn hkdf_expand(
-+ out_key: &mut [u8],
-+ md: &MdRef,
-+ prk: &[u8],
-+ info: &[u8],
-+) -> Result<(), ErrorStack> {
-+ unsafe {
-+ cvt(ffi::HKDF_expand(
-+ out_key.as_mut_ptr(),
-+ out_key.len(),
-+ md.as_ptr(),
-+ prk.as_ptr(),
-+ prk.len(),
-+ info.as_ptr(),
-+ info.len(),
-+ ))?;
-+ }
-+
-+ Ok(())
-+}
-diff --git a/src/hmac.rs b/src/hmac.rs
-new file mode 100644
-index 0000000..601ae01
---- /dev/null
-+++ b/src/hmac.rs
-@@ -0,0 +1,68 @@
-+use crate::cvt_p;
-+use crate::error::ErrorStack;
-+use crate::md::MdRef;
-+use foreign_types::ForeignTypeRef;
-+use openssl_macros::corresponds;
-+use libc::{c_void, c_uint};
-+use std::convert::TryFrom;
-+
-+/// Computes the HMAC as a one-shot operation.
-+///
-+/// Calculates the HMAC of data, using the given |key|
-+/// and hash function |md|, and returns the result re-using the space from
-+/// buffer |out|. On entry, |out| must contain at least |EVP_MD_size| bytes
-+/// of space. The actual length of the result is used to resize the returned
-+/// slice. An output size of |EVP_MAX_MD_SIZE| will always be large enough.
-+/// It returns a resized |out| or ErrorStack on error.
-+#[corresponds(HMAC)]
-+#[inline]
-+pub fn hmac<'a>(
-+ md: &MdRef,
-+ key: &[u8],
-+ data: &[u8],
-+ out: &'a mut [u8]
-+) -> Result<&'a [u8], ErrorStack> {
-+ let mut out_len = c_uint::try_from(out.len()).unwrap();
-+ unsafe {
-+ cvt_p(ffi::HMAC(
-+ md.as_ptr(),
-+ key.as_ptr() as *const c_void,
-+ key.len(),
-+ data.as_ptr(),
-+ data.len(),
-+ out.as_mut_ptr(),
-+ &mut out_len
-+ ))?;
-+ }
-+ Ok(&out[..out_len as usize])
-+}
-+
-+#[cfg(test)]
-+mod tests {
-+ use super::*;
-+ use crate::md::Md;
-+ use crate::memcmp;
-+
-+ const SHA_256_DIGEST_SIZE:usize = 32;
-+
-+ #[test]
-+ fn hmac_sha256_test() {
-+ let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
-+ let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE];
-+ let key:[u8; 20] = [0x0b; 20];
-+ let data = b"Hi There";
-+ let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
-+ expect!(memcmp::eq(&hmac_result, &expected_hmac));
-+ }
-+
-+ #[test]
-+ fn hmac_sha256_test_big_buffer() {
-+ let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
-+ let mut out: [u8; 100] = [0; 100];
-+ let key:[u8;20] = [0x0b; 20];
-+ let data = b"Hi There";
-+ let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
-+ expect_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE);
-+ expect!(memcmp::eq(&hmac_result, &expected_hmac));
-+ }
-+}
-diff --git a/src/lib.rs b/src/lib.rs
-index 891651e..48b7ed1 100644
---- a/src/lib.rs
-+++ b/src/lib.rs
-@@ -120,6 +120,9 @@
- #![doc(html_root_url = "https://docs.rs/openssl/0.10")]
- #![warn(rust_2018_idioms)]
-
-+#[cfg(all(soong, boringssl))]
-+extern crate bssl_ffi as ffi;
-+
- #[doc(inline)]
- pub use ffi::init;
-
-@@ -155,6 +158,10 @@ pub mod ex_data;
- #[cfg(not(any(libressl, ossl300)))]
- pub mod fips;
- pub mod hash;
-+#[cfg(boringssl)]
-+pub mod hkdf;
-+#[cfg(boringssl)]
-+pub mod hmac;
- #[cfg(ossl300)]
- pub mod lib_ctx;
- pub mod md;
-diff --git a/src/pkey.rs b/src/pkey.rs
-index 7d438eb..7eaf068 100644
---- a/src/pkey.rs
-+++ b/src/pkey.rs
-@@ -47,7 +47,7 @@ use crate::dh::Dh;
- use crate::dsa::Dsa;
- use crate::ec::EcKey;
- use crate::error::ErrorStack;
--#[cfg(ossl110)]
-+#[cfg(any(boringssl, ossl110))]
- use crate::pkey_ctx::PkeyCtx;
- use crate::rsa::Rsa;
- use crate::symm::Cipher;
-@@ -89,11 +89,11 @@ impl Id {
- #[cfg(ossl110)]
- pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF);
-
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
- #[cfg(ossl111)]
- pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub const X25519: Id = Id(ffi::EVP_PKEY_X25519);
- #[cfg(ossl111)]
- pub const X448: Id = Id(ffi::EVP_PKEY_X448);
-@@ -243,7 +243,7 @@ where
- /// This function only works for algorithms that support raw public keys.
- /// Currently this is: [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
- #[corresponds(EVP_PKEY_get_raw_public_key)]
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub fn raw_public_key(&self) -> Result<Vec<u8>, ErrorStack> {
- unsafe {
- let mut len = 0;
-@@ -294,7 +294,7 @@ where
- /// This function only works for algorithms that support raw private keys.
- /// Currently this is: [`Id::HMAC`], [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`].
- #[corresponds(EVP_PKEY_get_raw_private_key)]
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub fn raw_private_key(&self) -> Result<Vec<u8>, ErrorStack> {
- unsafe {
- let mut len = 0;
-@@ -475,7 +475,7 @@ impl PKey<Private> {
- ctx.keygen()
- }
-
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- fn generate_eddsa(id: Id) -> Result<PKey<Private>, ErrorStack> {
- let mut ctx = PkeyCtx::new_id(id)?;
- ctx.keygen_init()?;
-@@ -505,7 +505,7 @@ impl PKey<Private> {
- /// assert_eq!(secret.len(), 32);
- /// # Ok(()) }
- /// ```
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub fn generate_x25519() -> Result<PKey<Private>, ErrorStack> {
- PKey::generate_eddsa(Id::X25519)
- }
-@@ -559,7 +559,7 @@ impl PKey<Private> {
- /// assert_eq!(signature.len(), 64);
- /// # Ok(()) }
- /// ```
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
- PKey::generate_eddsa(Id::ED25519)
- }
-@@ -709,7 +709,7 @@ impl PKey<Private> {
- ///
- /// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448
- #[corresponds(EVP_PKEY_new_raw_private_key)]
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub fn private_key_from_raw_bytes(
- bytes: &[u8],
- key_type: Id,
-@@ -750,7 +750,7 @@ impl PKey<Public> {
- ///
- /// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448
- #[corresponds(EVP_PKEY_new_raw_public_key)]
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub fn public_key_from_raw_bytes(
- bytes: &[u8],
- key_type: Id,
-diff --git a/src/sign.rs b/src/sign.rs
-index 457ff12..4de8ad0 100644
---- a/src/sign.rs
-+++ b/src/sign.rs
-@@ -290,7 +290,7 @@ impl<'a> Signer<'a> {
- self.len_intern()
- }
-
-- #[cfg(not(ossl111))]
-+ #[cfg(not(any(boringssl, ossl111)))]
- fn len_intern(&self) -> Result<usize, ErrorStack> {
- unsafe {
- let mut len = 0;
-@@ -303,7 +303,7 @@ impl<'a> Signer<'a> {
- }
- }
-
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- fn len_intern(&self) -> Result<usize, ErrorStack> {
- unsafe {
- let mut len = 0;
-@@ -360,7 +360,7 @@ impl<'a> Signer<'a> {
- /// OpenSSL documentation at [`EVP_DigestSign`].
- ///
- /// [`EVP_DigestSign`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSign.html
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub fn sign_oneshot(
- &mut self,
- sig_buf: &mut [u8],
-@@ -382,7 +382,7 @@ impl<'a> Signer<'a> {
- /// Returns the signature.
- ///
- /// This is a simple convenience wrapper over `len` and `sign_oneshot`.
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub fn sign_oneshot_to_vec(&mut self, data_buf: &[u8]) -> Result<Vec<u8>, ErrorStack> {
- let mut sig_buf = vec![0; self.len()?];
- let len = self.sign_oneshot(&mut sig_buf, data_buf)?;
-@@ -594,7 +594,7 @@ impl<'a> Verifier<'a> {
- /// OpenSSL documentation at [`EVP_DigestVerify`].
- ///
- /// [`EVP_DigestVerify`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestVerify.html
-- #[cfg(ossl111)]
-+ #[cfg(any(boringssl, ossl111))]
- pub fn verify_oneshot(&mut self, signature: &[u8], buf: &[u8]) -> Result<bool, ErrorStack> {
- unsafe {
- let r = ffi::EVP_DigestVerify(
-diff --git a/src/symm.rs b/src/symm.rs
-index c75bbc0..beff5fc 100644
---- a/src/symm.rs
-+++ b/src/symm.rs
-@@ -119,6 +119,7 @@ impl Cipher {
- unsafe { Cipher(ffi::EVP_aes_128_cfb1()) }
- }
-
-+ #[cfg(not(boringssl))]
- pub fn aes_128_cfb128() -> Cipher {
- unsafe { Cipher(ffi::EVP_aes_128_cfb128()) }
- }
-@@ -164,6 +165,7 @@ impl Cipher {
- unsafe { Cipher(ffi::EVP_aes_192_cfb1()) }
- }
-
-+ #[cfg(not(boringssl))]
- pub fn aes_192_cfb128() -> Cipher {
- unsafe { Cipher(ffi::EVP_aes_192_cfb128()) }
- }
-@@ -214,6 +216,7 @@ impl Cipher {
- unsafe { Cipher(ffi::EVP_aes_256_cfb1()) }
- }
-
-+ #[cfg(not(boringssl))]
- pub fn aes_256_cfb128() -> Cipher {
- unsafe { Cipher(ffi::EVP_aes_256_cfb128()) }
- }
-@@ -242,12 +245,12 @@ impl Cipher {
- unsafe { Cipher(ffi::EVP_aes_256_ocb()) }
- }
-
-- #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
-+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_BF")))]
- pub fn bf_cbc() -> Cipher {
- unsafe { Cipher(ffi::EVP_bf_cbc()) }
- }
-
-- #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
-+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_BF")))]
- pub fn bf_ecb() -> Cipher {
- unsafe { Cipher(ffi::EVP_bf_ecb()) }
- }
-diff --git a/src/x509/mod.rs b/src/x509/mod.rs
-index edd54aa..45f2467 100644
---- a/src/x509/mod.rs
-+++ b/src/x509/mod.rs
-@@ -353,6 +353,19 @@ impl X509Builder {
- unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
- }
-
-+ /// Signs the certificate with a private key but without a digest.
-+ ///
-+ /// This is the only way to sign with Ed25519 keys as BoringSSL doesn't support the null
-+ /// message digest.
-+ #[cfg(boringssl)]
-+ #[corresponds(X509_sign)]
-+ pub fn sign_without_digest<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
-+ where
-+ T: HasPrivate,
-+ {
-+ unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), ptr::null())).map(|_| ()) }
-+ }
-+
- /// Consumes the builder, returning the certificate.
- pub fn build(self) -> X509 {
- self.0
-@@ -1260,6 +1273,29 @@ impl X509ReqBuilder {
- }
- }
-
-+ /// Sign the request using a private key without a digest.
-+ ///
-+ /// This is the only way to sign with Ed25519 keys as BoringSSL doesn't support the null
-+ /// message digest.
-+ ///
-+ /// This corresponds to [`X509_REQ_sign`].
-+ ///
-+ /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html
-+ #[cfg(boringssl)]
-+ pub fn sign_without_digest<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
-+ where
-+ T: HasPrivate,
-+ {
-+ unsafe {
-+ cvt(ffi::X509_REQ_sign(
-+ self.0.as_ptr(),
-+ key.as_ptr(),
-+ ptr::null(),
-+ ))
-+ .map(|_| ())
-+ }
-+ }
-+
- /// Returns the `X509Req`.
- pub fn build(self) -> X509Req {
- self.0
diff --git a/src/hmac.rs b/src/hmac.rs
index 601ae01..465781e 100644
--- a/src/hmac.rs
+++ b/src/hmac.rs
@@ -1,10 +1,12 @@
-use crate::cvt_p;
use crate::error::ErrorStack;
use crate::md::MdRef;
+use crate::{cvt, cvt_p};
+use ffi::HMAC_CTX;
use foreign_types::ForeignTypeRef;
+use libc::{c_uint, c_void};
use openssl_macros::corresponds;
-use libc::{c_void, c_uint};
use std::convert::TryFrom;
+use std::ptr;
/// Computes the HMAC as a one-shot operation.
///
@@ -20,8 +22,9 @@
md: &MdRef,
key: &[u8],
data: &[u8],
- out: &'a mut [u8]
+ out: &'a mut [u8],
) -> Result<&'a [u8], ErrorStack> {
+ assert!(out.len() >= md.size());
let mut out_len = c_uint::try_from(out.len()).unwrap();
unsafe {
cvt_p(ffi::HMAC(
@@ -31,38 +34,184 @@
data.as_ptr(),
data.len(),
out.as_mut_ptr(),
- &mut out_len
- ))?;
+ &mut out_len,
+ ))?;
}
Ok(&out[..out_len as usize])
}
+/// A context object used to perform HMAC operations.
+///
+/// HMAC is a MAC (message authentication code), i.e. a keyed hash function used for message
+/// authentication, which is based on a hash function.
+///
+/// Note: Only available in boringssl. For openssl, use `PKey::hmac` instead.
+#[cfg(boringssl)]
+pub struct HmacCtx {
+ ctx: *mut HMAC_CTX,
+ output_size: usize,
+}
+
+#[cfg(boringssl)]
+impl HmacCtx {
+ /// Creates a new [HmacCtx] to use the hash function `md` and key `key`.
+ #[corresponds(HMAC_Init_ex)]
+ pub fn new(key: &[u8], md: &MdRef) -> Result<Self, ErrorStack> {
+ unsafe {
+ // Safety: If an error occurred, the resulting null from HMAC_CTX_new is converted into
+ // ErrorStack in the returned result by `cvt_p`.
+ let ctx = cvt_p(ffi::HMAC_CTX_new())?;
+ // Safety:
+ // - HMAC_Init_ex must be called with a context previously created with HMAC_CTX_new,
+ // which is the line above.
+ // - HMAC_Init_ex may return an error if key is null but the md is different from
+ // before. This is avoided here since key is guaranteed to be non-null.
+ cvt(ffi::HMAC_Init_ex(
+ ctx,
+ key.as_ptr() as *const c_void,
+ key.len(),
+ md.as_ptr(),
+ ptr::null_mut(),
+ ))?;
+ Ok(Self {
+ ctx,
+ output_size: md.size(),
+ })
+ }
+ }
+
+ /// `update` can be called repeatedly with chunks of the message `data` to be authenticated.
+ #[corresponds(HMAC_Update)]
+ pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
+ unsafe {
+ // Safety: HMAC_Update returns 0 on error, and that is converted into ErrorStack in the
+ // returned result by `cvt`.
+ cvt(ffi::HMAC_Update(self.ctx, data.as_ptr(), data.len())).map(|_| ())
+ }
+ }
+
+ /// Finishes the HMAC process, and places the message authentication code in `output`.
+ /// The number of bytes written to `output` is returned.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the `output` is smaller than the required size. The output size is indicated by
+ /// `md.size()` for the `Md` instance passed in [new]. An output size of |EVP_MAX_MD_SIZE| will
+ /// always be large enough.
+ #[corresponds(HMAC_Final)]
+ pub fn finalize(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> {
+ assert!(output.len() >= self.output_size);
+ unsafe {
+ // Safety: The length assertion above makes sure that `HMAC_Final` will not write longer
+ // than the length of `output`.
+ let mut size: c_uint = 0;
+ cvt(ffi::HMAC_Final(
+ self.ctx,
+ output.as_mut_ptr(),
+ &mut size as *mut c_uint,
+ ))
+ .map(|_| size as usize)
+ }
+ }
+}
+
+impl Drop for HmacCtx {
+ #[corresponds(HMAC_CTX_free)]
+ fn drop(&mut self) {
+ unsafe {
+ ffi::HMAC_CTX_free(self.ctx);
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
use crate::md::Md;
- use crate::memcmp;
- const SHA_256_DIGEST_SIZE:usize = 32;
+ const SHA_256_DIGEST_SIZE: usize = 32;
#[test]
fn hmac_sha256_test() {
- let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
+ let expected_hmac = [
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
+ 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
+ 0x2e, 0x32, 0xcf, 0xf7,
+ ];
let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE];
- let key:[u8; 20] = [0x0b; 20];
+ let key: [u8; 20] = [0x0b; 20];
let data = b"Hi There";
- let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
- expect!(memcmp::eq(&hmac_result, &expected_hmac));
+ let hmac_result =
+ hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
+ assert_eq!(&hmac_result, &expected_hmac);
+ }
+
+ #[test]
+ #[should_panic]
+ fn hmac_sha256_output_too_short() {
+ let mut out = vec![0_u8; 1];
+ let key: [u8; 20] = [0x0b; 20];
+ let data = b"Hi There";
+ hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
}
#[test]
fn hmac_sha256_test_big_buffer() {
- let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7];
+ let expected_hmac = [
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
+ 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
+ 0x2e, 0x32, 0xcf, 0xf7,
+ ];
let mut out: [u8; 100] = [0; 100];
- let key:[u8;20] = [0x0b; 20];
+ let key: [u8; 20] = [0x0b; 20];
let data = b"Hi There";
- let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
- expect_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE);
- expect!(memcmp::eq(&hmac_result, &expected_hmac));
+ let hmac_result =
+ hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac");
+ assert_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE);
+ assert_eq!(&hmac_result, &expected_hmac);
+ }
+
+ #[test]
+ fn hmac_sha256_update_test() {
+ let expected_hmac = [
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
+ 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
+ 0x2e, 0x32, 0xcf, 0xf7,
+ ];
+ let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE];
+ let key: [u8; 20] = [0x0b; 20];
+ let data = b"Hi There";
+ let mut hmac_ctx = HmacCtx::new(&key, Md::sha256()).unwrap();
+ hmac_ctx.update(data).unwrap();
+ let size = hmac_ctx.finalize(&mut out).unwrap();
+ assert_eq!(&out, &expected_hmac);
+ assert_eq!(size, SHA_256_DIGEST_SIZE);
+ }
+
+ #[test]
+ fn hmac_sha256_update_chunks_test() {
+ let expected_hmac = [
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
+ 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
+ 0x2e, 0x32, 0xcf, 0xf7,
+ ];
+ let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE];
+ let key: [u8; 20] = [0x0b; 20];
+ let mut hmac_ctx = HmacCtx::new(&key, Md::sha256()).unwrap();
+ hmac_ctx.update(b"Hi").unwrap();
+ hmac_ctx.update(b" There").unwrap();
+ let size = hmac_ctx.finalize(&mut out).unwrap();
+ assert_eq!(&out, &expected_hmac);
+ assert_eq!(size, SHA_256_DIGEST_SIZE);
+ }
+
+ #[test]
+ #[should_panic]
+ fn hmac_sha256_update_output_too_short() {
+ let mut out = vec![0_u8; 1];
+ let key: [u8; 20] = [0x0b; 20];
+ let mut hmac_ctx = HmacCtx::new(&key, Md::sha256()).unwrap();
+ hmac_ctx.update(b"Hi There").unwrap();
+ hmac_ctx.finalize(&mut out).unwrap();
}
}