192f3ab15Sopenharmony_ci//! The message digest context.
292f3ab15Sopenharmony_ci//!
392f3ab15Sopenharmony_ci//! # Examples
492f3ab15Sopenharmony_ci//!
592f3ab15Sopenharmony_ci//! Compute the SHA256 checksum of data
692f3ab15Sopenharmony_ci//!
792f3ab15Sopenharmony_ci//! ```
892f3ab15Sopenharmony_ci//! use openssl::md::Md;
992f3ab15Sopenharmony_ci//! use openssl::md_ctx::MdCtx;
1092f3ab15Sopenharmony_ci//!
1192f3ab15Sopenharmony_ci//! let mut ctx = MdCtx::new().unwrap();
1292f3ab15Sopenharmony_ci//! ctx.digest_init(Md::sha256()).unwrap();
1392f3ab15Sopenharmony_ci//! ctx.digest_update(b"Some Crypto Text").unwrap();
1492f3ab15Sopenharmony_ci//! let mut digest = [0; 32];
1592f3ab15Sopenharmony_ci//! ctx.digest_final(&mut digest).unwrap();
1692f3ab15Sopenharmony_ci//!
1792f3ab15Sopenharmony_ci//! assert_eq!(
1892f3ab15Sopenharmony_ci//!     digest,
1992f3ab15Sopenharmony_ci//!     *b"\x60\x78\x56\x38\x8a\xca\x5c\x51\x83\xc4\xd1\x4d\xc8\xf9\xcc\xf2\
2092f3ab15Sopenharmony_ci//!        \xa5\x21\xb3\x10\x93\x72\xfa\xd6\x7c\x55\xf5\xc9\xe3\xd1\x83\x19",
2192f3ab15Sopenharmony_ci//! );
2292f3ab15Sopenharmony_ci//! ```
2392f3ab15Sopenharmony_ci//!
2492f3ab15Sopenharmony_ci//! Sign and verify data with RSA and SHA256
2592f3ab15Sopenharmony_ci//!
2692f3ab15Sopenharmony_ci//! ```
2792f3ab15Sopenharmony_ci//! use openssl::md::Md;
2892f3ab15Sopenharmony_ci//! use openssl::md_ctx::MdCtx;
2992f3ab15Sopenharmony_ci//! use openssl::pkey::PKey;
3092f3ab15Sopenharmony_ci//! use openssl::rsa::Rsa;
3192f3ab15Sopenharmony_ci//!
3292f3ab15Sopenharmony_ci//! // Generate a random RSA key.
3392f3ab15Sopenharmony_ci//! let key = Rsa::generate(4096).unwrap();
3492f3ab15Sopenharmony_ci//! let key = PKey::from_rsa(key).unwrap();
3592f3ab15Sopenharmony_ci//!
3692f3ab15Sopenharmony_ci//! let text = b"Some Crypto Text";
3792f3ab15Sopenharmony_ci//!
3892f3ab15Sopenharmony_ci//! // Create the signature.
3992f3ab15Sopenharmony_ci//! let mut ctx = MdCtx::new().unwrap();
4092f3ab15Sopenharmony_ci//! ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap();
4192f3ab15Sopenharmony_ci//! ctx.digest_sign_update(text).unwrap();
4292f3ab15Sopenharmony_ci//! let mut signature = vec![];
4392f3ab15Sopenharmony_ci//! ctx.digest_sign_final_to_vec(&mut signature).unwrap();
4492f3ab15Sopenharmony_ci//!
4592f3ab15Sopenharmony_ci//! // Verify the signature.
4692f3ab15Sopenharmony_ci//! let mut ctx = MdCtx::new().unwrap();
4792f3ab15Sopenharmony_ci//! ctx.digest_verify_init(Some(Md::sha256()), &key).unwrap();
4892f3ab15Sopenharmony_ci//! ctx.digest_verify_update(text).unwrap();
4992f3ab15Sopenharmony_ci//! let valid = ctx.digest_verify_final(&signature).unwrap();
5092f3ab15Sopenharmony_ci//! assert!(valid);
5192f3ab15Sopenharmony_ci//! ```
5292f3ab15Sopenharmony_ci//!
5392f3ab15Sopenharmony_ci
5492f3ab15Sopenharmony_ci#![cfg_attr(
5592f3ab15Sopenharmony_ci    not(boringssl),
5692f3ab15Sopenharmony_ci    doc = r#"\
5792f3ab15Sopenharmony_ciCompute and verify an HMAC-SHA256
5892f3ab15Sopenharmony_ci
5992f3ab15Sopenharmony_ci```
6092f3ab15Sopenharmony_ciuse openssl::md::Md;
6192f3ab15Sopenharmony_ciuse openssl::md_ctx::MdCtx;
6292f3ab15Sopenharmony_ciuse openssl::memcmp;
6392f3ab15Sopenharmony_ciuse openssl::pkey::PKey;
6492f3ab15Sopenharmony_ci
6592f3ab15Sopenharmony_ci// Create a key with the HMAC secret.
6692f3ab15Sopenharmony_cilet key = PKey::hmac(b"my secret").unwrap();
6792f3ab15Sopenharmony_ci
6892f3ab15Sopenharmony_cilet text = b"Some Crypto Text";
6992f3ab15Sopenharmony_ci
7092f3ab15Sopenharmony_ci// Compute the HMAC.
7192f3ab15Sopenharmony_cilet mut ctx = MdCtx::new().unwrap();
7292f3ab15Sopenharmony_cictx.digest_sign_init(Some(Md::sha256()), &key).unwrap();
7392f3ab15Sopenharmony_cictx.digest_sign_update(text).unwrap();
7492f3ab15Sopenharmony_cilet mut hmac = vec![];
7592f3ab15Sopenharmony_cictx.digest_sign_final_to_vec(&mut hmac).unwrap();
7692f3ab15Sopenharmony_ci
7792f3ab15Sopenharmony_ci// Verify the HMAC. You can't use MdCtx to do this; instead use a constant time equality check.
7892f3ab15Sopenharmony_ci# let target = hmac.clone();
7992f3ab15Sopenharmony_cilet valid = memcmp::eq(&hmac, &target);
8092f3ab15Sopenharmony_ciassert!(valid);
8192f3ab15Sopenharmony_ci```"#
8292f3ab15Sopenharmony_ci)]
8392f3ab15Sopenharmony_ci
8492f3ab15Sopenharmony_ciuse crate::error::ErrorStack;
8592f3ab15Sopenharmony_ciuse crate::md::MdRef;
8692f3ab15Sopenharmony_ciuse crate::pkey::{HasPrivate, HasPublic, PKeyRef};
8792f3ab15Sopenharmony_ciuse crate::pkey_ctx::PkeyCtxRef;
8892f3ab15Sopenharmony_ciuse crate::{cvt, cvt_n, cvt_p};
8992f3ab15Sopenharmony_ciuse cfg_if::cfg_if;
9092f3ab15Sopenharmony_ciuse foreign_types::{ForeignType, ForeignTypeRef};
9192f3ab15Sopenharmony_ciuse openssl_macros::corresponds;
9292f3ab15Sopenharmony_ciuse std::convert::TryFrom;
9392f3ab15Sopenharmony_ciuse std::ptr;
9492f3ab15Sopenharmony_ci
9592f3ab15Sopenharmony_cicfg_if! {
9692f3ab15Sopenharmony_ci    if #[cfg(any(ossl110, boringssl))] {
9792f3ab15Sopenharmony_ci        use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
9892f3ab15Sopenharmony_ci    } else {
9992f3ab15Sopenharmony_ci        use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
10092f3ab15Sopenharmony_ci    }
10192f3ab15Sopenharmony_ci}
10292f3ab15Sopenharmony_ci
10392f3ab15Sopenharmony_ciforeign_type_and_impl_send_sync! {
10492f3ab15Sopenharmony_ci    type CType = ffi::EVP_MD_CTX;
10592f3ab15Sopenharmony_ci    fn drop = EVP_MD_CTX_free;
10692f3ab15Sopenharmony_ci
10792f3ab15Sopenharmony_ci    pub struct MdCtx;
10892f3ab15Sopenharmony_ci    /// A reference to an [`MdCtx`].
10992f3ab15Sopenharmony_ci    pub struct MdCtxRef;
11092f3ab15Sopenharmony_ci}
11192f3ab15Sopenharmony_ci
11292f3ab15Sopenharmony_ciimpl MdCtx {
11392f3ab15Sopenharmony_ci    /// Creates a new context.
11492f3ab15Sopenharmony_ci    #[corresponds(EVP_MD_CTX_new)]
11592f3ab15Sopenharmony_ci    #[inline]
11692f3ab15Sopenharmony_ci    pub fn new() -> Result<Self, ErrorStack> {
11792f3ab15Sopenharmony_ci        ffi::init();
11892f3ab15Sopenharmony_ci
11992f3ab15Sopenharmony_ci        unsafe {
12092f3ab15Sopenharmony_ci            let ptr = cvt_p(EVP_MD_CTX_new())?;
12192f3ab15Sopenharmony_ci            Ok(MdCtx::from_ptr(ptr))
12292f3ab15Sopenharmony_ci        }
12392f3ab15Sopenharmony_ci    }
12492f3ab15Sopenharmony_ci}
12592f3ab15Sopenharmony_ci
12692f3ab15Sopenharmony_ciimpl MdCtxRef {
12792f3ab15Sopenharmony_ci    /// Initializes the context to compute the digest of data.
12892f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestInit_ex)]
12992f3ab15Sopenharmony_ci    #[inline]
13092f3ab15Sopenharmony_ci    pub fn digest_init(&mut self, digest: &MdRef) -> Result<(), ErrorStack> {
13192f3ab15Sopenharmony_ci        unsafe {
13292f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestInit_ex(
13392f3ab15Sopenharmony_ci                self.as_ptr(),
13492f3ab15Sopenharmony_ci                digest.as_ptr(),
13592f3ab15Sopenharmony_ci                ptr::null_mut(),
13692f3ab15Sopenharmony_ci            ))?;
13792f3ab15Sopenharmony_ci        }
13892f3ab15Sopenharmony_ci
13992f3ab15Sopenharmony_ci        Ok(())
14092f3ab15Sopenharmony_ci    }
14192f3ab15Sopenharmony_ci
14292f3ab15Sopenharmony_ci    /// Initializes the context to compute the signature of data.
14392f3ab15Sopenharmony_ci    ///
14492f3ab15Sopenharmony_ci    /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured.
14592f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestSignInit)]
14692f3ab15Sopenharmony_ci    #[inline]
14792f3ab15Sopenharmony_ci    pub fn digest_sign_init<'a, T>(
14892f3ab15Sopenharmony_ci        &'a mut self,
14992f3ab15Sopenharmony_ci        digest: Option<&MdRef>,
15092f3ab15Sopenharmony_ci        pkey: &PKeyRef<T>,
15192f3ab15Sopenharmony_ci    ) -> Result<&'a mut PkeyCtxRef<T>, ErrorStack>
15292f3ab15Sopenharmony_ci    where
15392f3ab15Sopenharmony_ci        T: HasPrivate,
15492f3ab15Sopenharmony_ci    {
15592f3ab15Sopenharmony_ci        unsafe {
15692f3ab15Sopenharmony_ci            let mut p = ptr::null_mut();
15792f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestSignInit(
15892f3ab15Sopenharmony_ci                self.as_ptr(),
15992f3ab15Sopenharmony_ci                &mut p,
16092f3ab15Sopenharmony_ci                digest.map_or(ptr::null(), |p| p.as_ptr()),
16192f3ab15Sopenharmony_ci                ptr::null_mut(),
16292f3ab15Sopenharmony_ci                pkey.as_ptr(),
16392f3ab15Sopenharmony_ci            ))?;
16492f3ab15Sopenharmony_ci            Ok(PkeyCtxRef::from_ptr_mut(p))
16592f3ab15Sopenharmony_ci        }
16692f3ab15Sopenharmony_ci    }
16792f3ab15Sopenharmony_ci
16892f3ab15Sopenharmony_ci    /// Initializes the context to verify the signature of data.
16992f3ab15Sopenharmony_ci    ///
17092f3ab15Sopenharmony_ci    /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured.
17192f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestVerifyInit)]
17292f3ab15Sopenharmony_ci    #[inline]
17392f3ab15Sopenharmony_ci    pub fn digest_verify_init<'a, T>(
17492f3ab15Sopenharmony_ci        &'a mut self,
17592f3ab15Sopenharmony_ci        digest: Option<&MdRef>,
17692f3ab15Sopenharmony_ci        pkey: &PKeyRef<T>,
17792f3ab15Sopenharmony_ci    ) -> Result<&'a mut PkeyCtxRef<T>, ErrorStack>
17892f3ab15Sopenharmony_ci    where
17992f3ab15Sopenharmony_ci        T: HasPublic,
18092f3ab15Sopenharmony_ci    {
18192f3ab15Sopenharmony_ci        unsafe {
18292f3ab15Sopenharmony_ci            let mut p = ptr::null_mut();
18392f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestVerifyInit(
18492f3ab15Sopenharmony_ci                self.as_ptr(),
18592f3ab15Sopenharmony_ci                &mut p,
18692f3ab15Sopenharmony_ci                digest.map_or(ptr::null(), |p| p.as_ptr()),
18792f3ab15Sopenharmony_ci                ptr::null_mut(),
18892f3ab15Sopenharmony_ci                pkey.as_ptr(),
18992f3ab15Sopenharmony_ci            ))?;
19092f3ab15Sopenharmony_ci            Ok(PkeyCtxRef::from_ptr_mut(p))
19192f3ab15Sopenharmony_ci        }
19292f3ab15Sopenharmony_ci    }
19392f3ab15Sopenharmony_ci
19492f3ab15Sopenharmony_ci    /// Updates the context with more data.
19592f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestUpdate)]
19692f3ab15Sopenharmony_ci    #[inline]
19792f3ab15Sopenharmony_ci    pub fn digest_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
19892f3ab15Sopenharmony_ci        unsafe {
19992f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestUpdate(
20092f3ab15Sopenharmony_ci                self.as_ptr(),
20192f3ab15Sopenharmony_ci                data.as_ptr() as *const _,
20292f3ab15Sopenharmony_ci                data.len(),
20392f3ab15Sopenharmony_ci            ))?;
20492f3ab15Sopenharmony_ci        }
20592f3ab15Sopenharmony_ci
20692f3ab15Sopenharmony_ci        Ok(())
20792f3ab15Sopenharmony_ci    }
20892f3ab15Sopenharmony_ci
20992f3ab15Sopenharmony_ci    /// Updates the context with more data.
21092f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestSignUpdate)]
21192f3ab15Sopenharmony_ci    #[inline]
21292f3ab15Sopenharmony_ci    pub fn digest_sign_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
21392f3ab15Sopenharmony_ci        unsafe {
21492f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestSignUpdate(
21592f3ab15Sopenharmony_ci                self.as_ptr(),
21692f3ab15Sopenharmony_ci                data.as_ptr() as *const _,
21792f3ab15Sopenharmony_ci                data.len(),
21892f3ab15Sopenharmony_ci            ))?;
21992f3ab15Sopenharmony_ci        }
22092f3ab15Sopenharmony_ci
22192f3ab15Sopenharmony_ci        Ok(())
22292f3ab15Sopenharmony_ci    }
22392f3ab15Sopenharmony_ci
22492f3ab15Sopenharmony_ci    /// Updates the context with more data.
22592f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestVerifyUpdate)]
22692f3ab15Sopenharmony_ci    #[inline]
22792f3ab15Sopenharmony_ci    pub fn digest_verify_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
22892f3ab15Sopenharmony_ci        unsafe {
22992f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestVerifyUpdate(
23092f3ab15Sopenharmony_ci                self.as_ptr(),
23192f3ab15Sopenharmony_ci                data.as_ptr() as *const _,
23292f3ab15Sopenharmony_ci                data.len(),
23392f3ab15Sopenharmony_ci            ))?;
23492f3ab15Sopenharmony_ci        }
23592f3ab15Sopenharmony_ci
23692f3ab15Sopenharmony_ci        Ok(())
23792f3ab15Sopenharmony_ci    }
23892f3ab15Sopenharmony_ci
23992f3ab15Sopenharmony_ci    /// Copies the computed digest into the buffer, returning the number of bytes written.
24092f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestFinal)]
24192f3ab15Sopenharmony_ci    #[inline]
24292f3ab15Sopenharmony_ci    pub fn digest_final(&mut self, out: &mut [u8]) -> Result<usize, ErrorStack> {
24392f3ab15Sopenharmony_ci        let mut len = u32::try_from(out.len()).unwrap_or(u32::MAX);
24492f3ab15Sopenharmony_ci
24592f3ab15Sopenharmony_ci        unsafe {
24692f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestFinal(
24792f3ab15Sopenharmony_ci                self.as_ptr(),
24892f3ab15Sopenharmony_ci                out.as_mut_ptr(),
24992f3ab15Sopenharmony_ci                &mut len,
25092f3ab15Sopenharmony_ci            ))?;
25192f3ab15Sopenharmony_ci        }
25292f3ab15Sopenharmony_ci
25392f3ab15Sopenharmony_ci        Ok(len as usize)
25492f3ab15Sopenharmony_ci    }
25592f3ab15Sopenharmony_ci
25692f3ab15Sopenharmony_ci    /// Copies the computed digest into the buffer.
25792f3ab15Sopenharmony_ci    ///
25892f3ab15Sopenharmony_ci    /// Requires OpenSSL 1.1.1 or newer.
25992f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestFinalXOF)]
26092f3ab15Sopenharmony_ci    #[inline]
26192f3ab15Sopenharmony_ci    #[cfg(ossl111)]
26292f3ab15Sopenharmony_ci    pub fn digest_final_xof(&mut self, out: &mut [u8]) -> Result<(), ErrorStack> {
26392f3ab15Sopenharmony_ci        unsafe {
26492f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestFinalXOF(
26592f3ab15Sopenharmony_ci                self.as_ptr(),
26692f3ab15Sopenharmony_ci                out.as_mut_ptr(),
26792f3ab15Sopenharmony_ci                out.len(),
26892f3ab15Sopenharmony_ci            ))?;
26992f3ab15Sopenharmony_ci        }
27092f3ab15Sopenharmony_ci
27192f3ab15Sopenharmony_ci        Ok(())
27292f3ab15Sopenharmony_ci    }
27392f3ab15Sopenharmony_ci
27492f3ab15Sopenharmony_ci    /// Signs the computed digest.
27592f3ab15Sopenharmony_ci    ///
27692f3ab15Sopenharmony_ci    /// If `out` is set to `None`, an upper bound on the number of bytes required for the output buffer will be
27792f3ab15Sopenharmony_ci    /// returned.
27892f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestSignFinal)]
27992f3ab15Sopenharmony_ci    #[inline]
28092f3ab15Sopenharmony_ci    pub fn digest_sign_final(&mut self, out: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
28192f3ab15Sopenharmony_ci        let mut len = out.as_ref().map_or(0, |b| b.len());
28292f3ab15Sopenharmony_ci
28392f3ab15Sopenharmony_ci        unsafe {
28492f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestSignFinal(
28592f3ab15Sopenharmony_ci                self.as_ptr(),
28692f3ab15Sopenharmony_ci                out.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
28792f3ab15Sopenharmony_ci                &mut len,
28892f3ab15Sopenharmony_ci            ))?;
28992f3ab15Sopenharmony_ci        }
29092f3ab15Sopenharmony_ci
29192f3ab15Sopenharmony_ci        Ok(len)
29292f3ab15Sopenharmony_ci    }
29392f3ab15Sopenharmony_ci
29492f3ab15Sopenharmony_ci    /// Like [`Self::digest_sign_final`] but appends the signature to a [`Vec`].
29592f3ab15Sopenharmony_ci    pub fn digest_sign_final_to_vec(&mut self, out: &mut Vec<u8>) -> Result<usize, ErrorStack> {
29692f3ab15Sopenharmony_ci        let base = out.len();
29792f3ab15Sopenharmony_ci        let len = self.digest_sign_final(None)?;
29892f3ab15Sopenharmony_ci        out.resize(base + len, 0);
29992f3ab15Sopenharmony_ci        let len = self.digest_sign_final(Some(&mut out[base..]))?;
30092f3ab15Sopenharmony_ci        out.truncate(base + len);
30192f3ab15Sopenharmony_ci        Ok(len)
30292f3ab15Sopenharmony_ci    }
30392f3ab15Sopenharmony_ci
30492f3ab15Sopenharmony_ci    /// Verifies the provided signature.
30592f3ab15Sopenharmony_ci    ///
30692f3ab15Sopenharmony_ci    /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error
30792f3ab15Sopenharmony_ci    /// occurred.
30892f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestVerifyFinal)]
30992f3ab15Sopenharmony_ci    #[inline]
31092f3ab15Sopenharmony_ci    pub fn digest_verify_final(&mut self, signature: &[u8]) -> Result<bool, ErrorStack> {
31192f3ab15Sopenharmony_ci        unsafe {
31292f3ab15Sopenharmony_ci            let r = cvt_n(ffi::EVP_DigestVerifyFinal(
31392f3ab15Sopenharmony_ci                self.as_ptr(),
31492f3ab15Sopenharmony_ci                signature.as_ptr() as *mut _,
31592f3ab15Sopenharmony_ci                signature.len(),
31692f3ab15Sopenharmony_ci            ))?;
31792f3ab15Sopenharmony_ci            Ok(r == 1)
31892f3ab15Sopenharmony_ci        }
31992f3ab15Sopenharmony_ci    }
32092f3ab15Sopenharmony_ci
32192f3ab15Sopenharmony_ci    /// Computes the signature of the data in `from`.
32292f3ab15Sopenharmony_ci    ///
32392f3ab15Sopenharmony_ci    /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be
32492f3ab15Sopenharmony_ci    /// returned.
32592f3ab15Sopenharmony_ci    ///
32692f3ab15Sopenharmony_ci    /// Requires OpenSSL 1.1.1 or newer.
32792f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestSign)]
32892f3ab15Sopenharmony_ci    #[cfg(ossl111)]
32992f3ab15Sopenharmony_ci    #[inline]
33092f3ab15Sopenharmony_ci    pub fn digest_sign(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
33192f3ab15Sopenharmony_ci        let mut len = to.as_ref().map_or(0, |b| b.len());
33292f3ab15Sopenharmony_ci
33392f3ab15Sopenharmony_ci        unsafe {
33492f3ab15Sopenharmony_ci            cvt(ffi::EVP_DigestSign(
33592f3ab15Sopenharmony_ci                self.as_ptr(),
33692f3ab15Sopenharmony_ci                to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
33792f3ab15Sopenharmony_ci                &mut len,
33892f3ab15Sopenharmony_ci                from.as_ptr(),
33992f3ab15Sopenharmony_ci                from.len(),
34092f3ab15Sopenharmony_ci            ))?;
34192f3ab15Sopenharmony_ci        }
34292f3ab15Sopenharmony_ci
34392f3ab15Sopenharmony_ci        Ok(len)
34492f3ab15Sopenharmony_ci    }
34592f3ab15Sopenharmony_ci
34692f3ab15Sopenharmony_ci    /// Like [`Self::digest_sign`] but appends the signature to a [`Vec`].
34792f3ab15Sopenharmony_ci    #[cfg(ossl111)]
34892f3ab15Sopenharmony_ci    pub fn digest_sign_to_vec(
34992f3ab15Sopenharmony_ci        &mut self,
35092f3ab15Sopenharmony_ci        from: &[u8],
35192f3ab15Sopenharmony_ci        to: &mut Vec<u8>,
35292f3ab15Sopenharmony_ci    ) -> Result<usize, ErrorStack> {
35392f3ab15Sopenharmony_ci        let base = to.len();
35492f3ab15Sopenharmony_ci        let len = self.digest_sign(from, None)?;
35592f3ab15Sopenharmony_ci        to.resize(base + len, 0);
35692f3ab15Sopenharmony_ci        let len = self.digest_sign(from, Some(&mut to[base..]))?;
35792f3ab15Sopenharmony_ci        to.truncate(base + len);
35892f3ab15Sopenharmony_ci        Ok(len)
35992f3ab15Sopenharmony_ci    }
36092f3ab15Sopenharmony_ci
36192f3ab15Sopenharmony_ci    /// Verifies the signature of the data in `data`.
36292f3ab15Sopenharmony_ci    ///
36392f3ab15Sopenharmony_ci    /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error
36492f3ab15Sopenharmony_ci    /// occurred.
36592f3ab15Sopenharmony_ci    ///
36692f3ab15Sopenharmony_ci    /// Requires OpenSSL 1.1.1 or newer.
36792f3ab15Sopenharmony_ci    #[corresponds(EVP_DigestVerify)]
36892f3ab15Sopenharmony_ci    #[cfg(ossl111)]
36992f3ab15Sopenharmony_ci    #[inline]
37092f3ab15Sopenharmony_ci    pub fn digest_verify(&mut self, data: &[u8], signature: &[u8]) -> Result<bool, ErrorStack> {
37192f3ab15Sopenharmony_ci        unsafe {
37292f3ab15Sopenharmony_ci            let r = cvt(ffi::EVP_DigestVerify(
37392f3ab15Sopenharmony_ci                self.as_ptr(),
37492f3ab15Sopenharmony_ci                signature.as_ptr(),
37592f3ab15Sopenharmony_ci                signature.len(),
37692f3ab15Sopenharmony_ci                data.as_ptr(),
37792f3ab15Sopenharmony_ci                data.len(),
37892f3ab15Sopenharmony_ci            ))?;
37992f3ab15Sopenharmony_ci            Ok(r == 1)
38092f3ab15Sopenharmony_ci        }
38192f3ab15Sopenharmony_ci    }
38292f3ab15Sopenharmony_ci
38392f3ab15Sopenharmony_ci    /// Returns the size of the message digest, i.e. the size of the hash
38492f3ab15Sopenharmony_ci    #[corresponds(EVP_MD_CTX_size)]
38592f3ab15Sopenharmony_ci    #[inline]
38692f3ab15Sopenharmony_ci    pub fn size(&self) -> usize {
38792f3ab15Sopenharmony_ci        unsafe { ffi::EVP_MD_CTX_size(self.as_ptr()) as usize }
38892f3ab15Sopenharmony_ci    }
38992f3ab15Sopenharmony_ci
39092f3ab15Sopenharmony_ci    /// Resets the underlying EVP_MD_CTX instance
39192f3ab15Sopenharmony_ci    #[corresponds(EVP_MD_CTX_reset)]
39292f3ab15Sopenharmony_ci    #[cfg(ossl111)]
39392f3ab15Sopenharmony_ci    #[inline]
39492f3ab15Sopenharmony_ci    pub fn reset(&mut self) -> Result<(), ErrorStack> {
39592f3ab15Sopenharmony_ci        unsafe {
39692f3ab15Sopenharmony_ci            let _ = cvt(ffi::EVP_MD_CTX_reset(self.as_ptr()))?;
39792f3ab15Sopenharmony_ci            Ok(())
39892f3ab15Sopenharmony_ci        }
39992f3ab15Sopenharmony_ci    }
40092f3ab15Sopenharmony_ci}
40192f3ab15Sopenharmony_ci
40292f3ab15Sopenharmony_ci#[cfg(test)]
40392f3ab15Sopenharmony_cimod test {
40492f3ab15Sopenharmony_ci    use super::*;
40592f3ab15Sopenharmony_ci    use crate::md::Md;
40692f3ab15Sopenharmony_ci    use crate::pkey::PKey;
40792f3ab15Sopenharmony_ci    use crate::rsa::Rsa;
40892f3ab15Sopenharmony_ci
40992f3ab15Sopenharmony_ci    #[test]
41092f3ab15Sopenharmony_ci    fn verify_fail() {
41192f3ab15Sopenharmony_ci        let key1 = Rsa::generate(4096).unwrap();
41292f3ab15Sopenharmony_ci        let key1 = PKey::from_rsa(key1).unwrap();
41392f3ab15Sopenharmony_ci
41492f3ab15Sopenharmony_ci        let md = Md::sha256();
41592f3ab15Sopenharmony_ci        let data = b"Some Crypto Text";
41692f3ab15Sopenharmony_ci
41792f3ab15Sopenharmony_ci        let mut ctx = MdCtx::new().unwrap();
41892f3ab15Sopenharmony_ci        ctx.digest_sign_init(Some(md), &key1).unwrap();
41992f3ab15Sopenharmony_ci        ctx.digest_sign_update(data).unwrap();
42092f3ab15Sopenharmony_ci        let mut signature = vec![];
42192f3ab15Sopenharmony_ci        ctx.digest_sign_final_to_vec(&mut signature).unwrap();
42292f3ab15Sopenharmony_ci
42392f3ab15Sopenharmony_ci        let bad_data = b"Some Crypto text";
42492f3ab15Sopenharmony_ci
42592f3ab15Sopenharmony_ci        ctx.digest_verify_init(Some(md), &key1).unwrap();
42692f3ab15Sopenharmony_ci        ctx.digest_verify_update(bad_data).unwrap();
42792f3ab15Sopenharmony_ci        let valid = ctx.digest_verify_final(&signature).unwrap();
42892f3ab15Sopenharmony_ci        assert!(!valid);
42992f3ab15Sopenharmony_ci    }
43092f3ab15Sopenharmony_ci
43192f3ab15Sopenharmony_ci    #[test]
43292f3ab15Sopenharmony_ci    fn verify_success() {
43392f3ab15Sopenharmony_ci        let key1 = Rsa::generate(2048).unwrap();
43492f3ab15Sopenharmony_ci        let key1 = PKey::from_rsa(key1).unwrap();
43592f3ab15Sopenharmony_ci
43692f3ab15Sopenharmony_ci        let md = Md::sha256();
43792f3ab15Sopenharmony_ci        let data = b"Some Crypto Text";
43892f3ab15Sopenharmony_ci
43992f3ab15Sopenharmony_ci        let mut ctx = MdCtx::new().unwrap();
44092f3ab15Sopenharmony_ci        ctx.digest_sign_init(Some(md), &key1).unwrap();
44192f3ab15Sopenharmony_ci        ctx.digest_sign_update(data).unwrap();
44292f3ab15Sopenharmony_ci        let mut signature = vec![];
44392f3ab15Sopenharmony_ci        ctx.digest_sign_final_to_vec(&mut signature).unwrap();
44492f3ab15Sopenharmony_ci
44592f3ab15Sopenharmony_ci        let good_data = b"Some Crypto Text";
44692f3ab15Sopenharmony_ci
44792f3ab15Sopenharmony_ci        ctx.digest_verify_init(Some(md), &key1).unwrap();
44892f3ab15Sopenharmony_ci        ctx.digest_verify_update(good_data).unwrap();
44992f3ab15Sopenharmony_ci        let valid = ctx.digest_verify_final(&signature).unwrap();
45092f3ab15Sopenharmony_ci        assert!(valid);
45192f3ab15Sopenharmony_ci    }
45292f3ab15Sopenharmony_ci
45392f3ab15Sopenharmony_ci    #[test]
45492f3ab15Sopenharmony_ci    fn verify_with_public_success() {
45592f3ab15Sopenharmony_ci        let rsa = Rsa::generate(2048).unwrap();
45692f3ab15Sopenharmony_ci        let key1 = PKey::from_rsa(rsa.clone()).unwrap();
45792f3ab15Sopenharmony_ci
45892f3ab15Sopenharmony_ci        let md = Md::sha256();
45992f3ab15Sopenharmony_ci        let data = b"Some Crypto Text";
46092f3ab15Sopenharmony_ci
46192f3ab15Sopenharmony_ci        let mut ctx = MdCtx::new().unwrap();
46292f3ab15Sopenharmony_ci        ctx.digest_sign_init(Some(md), &key1).unwrap();
46392f3ab15Sopenharmony_ci        ctx.digest_sign_update(data).unwrap();
46492f3ab15Sopenharmony_ci        let mut signature = vec![];
46592f3ab15Sopenharmony_ci        ctx.digest_sign_final_to_vec(&mut signature).unwrap();
46692f3ab15Sopenharmony_ci
46792f3ab15Sopenharmony_ci        let good_data = b"Some Crypto Text";
46892f3ab15Sopenharmony_ci
46992f3ab15Sopenharmony_ci        // try to verify using only public components of the key
47092f3ab15Sopenharmony_ci        let n = rsa.n().to_owned().unwrap();
47192f3ab15Sopenharmony_ci        let e = rsa.e().to_owned().unwrap();
47292f3ab15Sopenharmony_ci
47392f3ab15Sopenharmony_ci        let rsa = Rsa::from_public_components(n, e).unwrap();
47492f3ab15Sopenharmony_ci        let key1 = PKey::from_rsa(rsa).unwrap();
47592f3ab15Sopenharmony_ci
47692f3ab15Sopenharmony_ci        ctx.digest_verify_init(Some(md), &key1).unwrap();
47792f3ab15Sopenharmony_ci        ctx.digest_verify_update(good_data).unwrap();
47892f3ab15Sopenharmony_ci        let valid = ctx.digest_verify_final(&signature).unwrap();
47992f3ab15Sopenharmony_ci        assert!(valid);
48092f3ab15Sopenharmony_ci    }
48192f3ab15Sopenharmony_ci
48292f3ab15Sopenharmony_ci    #[test]
48392f3ab15Sopenharmony_ci    fn verify_md_ctx_size() {
48492f3ab15Sopenharmony_ci        let mut ctx = MdCtx::new().unwrap();
48592f3ab15Sopenharmony_ci        ctx.digest_init(Md::sha224()).unwrap();
48692f3ab15Sopenharmony_ci        assert_eq!(Md::sha224().size(), ctx.size());
48792f3ab15Sopenharmony_ci        assert_eq!(Md::sha224().size(), 28);
48892f3ab15Sopenharmony_ci
48992f3ab15Sopenharmony_ci        let mut ctx = MdCtx::new().unwrap();
49092f3ab15Sopenharmony_ci        ctx.digest_init(Md::sha256()).unwrap();
49192f3ab15Sopenharmony_ci        assert_eq!(Md::sha256().size(), ctx.size());
49292f3ab15Sopenharmony_ci        assert_eq!(Md::sha256().size(), 32);
49392f3ab15Sopenharmony_ci
49492f3ab15Sopenharmony_ci        let mut ctx = MdCtx::new().unwrap();
49592f3ab15Sopenharmony_ci        ctx.digest_init(Md::sha384()).unwrap();
49692f3ab15Sopenharmony_ci        assert_eq!(Md::sha384().size(), ctx.size());
49792f3ab15Sopenharmony_ci        assert_eq!(Md::sha384().size(), 48);
49892f3ab15Sopenharmony_ci
49992f3ab15Sopenharmony_ci        let mut ctx = MdCtx::new().unwrap();
50092f3ab15Sopenharmony_ci        ctx.digest_init(Md::sha512()).unwrap();
50192f3ab15Sopenharmony_ci        assert_eq!(Md::sha512().size(), ctx.size());
50292f3ab15Sopenharmony_ci        assert_eq!(Md::sha512().size(), 64);
50392f3ab15Sopenharmony_ci    }
50492f3ab15Sopenharmony_ci
50592f3ab15Sopenharmony_ci    #[test]
50692f3ab15Sopenharmony_ci    #[cfg(ossl111)]
50792f3ab15Sopenharmony_ci    fn verify_md_ctx_reset() {
50892f3ab15Sopenharmony_ci        let hello_expected =
50992f3ab15Sopenharmony_ci            hex::decode("185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969")
51092f3ab15Sopenharmony_ci                .unwrap();
51192f3ab15Sopenharmony_ci        let world_expected =
51292f3ab15Sopenharmony_ci            hex::decode("78ae647dc5544d227130a0682a51e30bc7777fbb6d8a8f17007463a3ecd1d524")
51392f3ab15Sopenharmony_ci                .unwrap();
51492f3ab15Sopenharmony_ci        // Calculate SHA-256 digest of "Hello"
51592f3ab15Sopenharmony_ci        let mut ctx = MdCtx::new().unwrap();
51692f3ab15Sopenharmony_ci        ctx.digest_init(Md::sha256()).unwrap();
51792f3ab15Sopenharmony_ci        ctx.digest_update(b"Hello").unwrap();
51892f3ab15Sopenharmony_ci        let mut result = vec![0; 32];
51992f3ab15Sopenharmony_ci        let result_len = ctx.digest_final(result.as_mut_slice()).unwrap();
52092f3ab15Sopenharmony_ci        assert_eq!(result_len, result.len());
52192f3ab15Sopenharmony_ci        // Validate result of "Hello"
52292f3ab15Sopenharmony_ci        assert_eq!(result, hello_expected);
52392f3ab15Sopenharmony_ci
52492f3ab15Sopenharmony_ci        // Create new context
52592f3ab15Sopenharmony_ci        let mut ctx = MdCtx::new().unwrap();
52692f3ab15Sopenharmony_ci        // Initialize and update to "Hello"
52792f3ab15Sopenharmony_ci        ctx.digest_init(Md::sha256()).unwrap();
52892f3ab15Sopenharmony_ci        ctx.digest_update(b"Hello").unwrap();
52992f3ab15Sopenharmony_ci        // Now reset, init to SHA-256 and use "World"
53092f3ab15Sopenharmony_ci        ctx.reset().unwrap();
53192f3ab15Sopenharmony_ci        ctx.digest_init(Md::sha256()).unwrap();
53292f3ab15Sopenharmony_ci        ctx.digest_update(b"World").unwrap();
53392f3ab15Sopenharmony_ci
53492f3ab15Sopenharmony_ci        let mut reset_result = vec![0; 32];
53592f3ab15Sopenharmony_ci        let result_len = ctx.digest_final(reset_result.as_mut_slice()).unwrap();
53692f3ab15Sopenharmony_ci        assert_eq!(result_len, reset_result.len());
53792f3ab15Sopenharmony_ci        // Validate result of digest of "World"
53892f3ab15Sopenharmony_ci        assert_eq!(reset_result, world_expected);
53992f3ab15Sopenharmony_ci    }
54092f3ab15Sopenharmony_ci}
541