blob: 06702facba14a905e4fc2e57811bba765855bf81 [file] [log] [blame]
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