variant_ssl/
mac_ctx.rs

1use crate::cvt;
2use crate::cvt_p;
3use crate::error::ErrorStack;
4use crate::mac::Mac;
5use foreign_types::ForeignType;
6use openssl_macros::corresponds;
7use std::ffi::CStr;
8use std::ptr;
9
10foreign_type_and_impl_send_sync! {
11    type CType = ffi::EVP_MAC_CTX;
12    fn drop = ffi::EVP_MAC_CTX_free;
13    fn clone = ffi::EVP_MAC_CTX_dup;
14
15    /// A context object used to perform MAC operations.
16    pub struct MacCtx;
17    /// A reference to a [`HmacCtx`].
18    pub struct MacCtxRef;
19}
20
21impl MacCtx {
22    /// Creates a new context.
23    #[corresponds(EVP_MAC_CTX_new)]
24    pub fn new(mac: Mac) -> Result<Self, ErrorStack> {
25        ffi::init();
26
27        unsafe {
28            let ptr = cvt_p(ffi::EVP_MAC_CTX_new(mac.as_ptr()))?;
29            Ok(MacCtx::from_ptr(ptr))
30        }
31    }
32
33    /// Set key and digest
34    pub fn init_ex(&mut self, key: Option<&[u8]>, md: &CStr) -> Result<(), ErrorStack> {
35        let key_field_name = CStr::from_bytes_with_nul(b"key\0").unwrap();
36        let digest_field_name = CStr::from_bytes_with_nul(b"digest\0").unwrap();
37
38        let key_len = key.map(|v| v.len()).unwrap_or_default();
39        let key = key.map(|v| v.as_ptr()).unwrap_or(ptr::null());
40
41        unsafe {
42            let param_key =
43                ffi::OSSL_PARAM_construct_octet_string(key_field_name.as_ptr(), key as _, key_len);
44            let param_digest = ffi::OSSL_PARAM_construct_utf8_string(
45                digest_field_name.as_ptr(),
46                md.as_ptr() as _,
47                md.to_bytes().len(),
48            );
49            let param_end = ffi::OSSL_PARAM_construct_end();
50
51            let params = [param_key, param_digest, param_end];
52
53            cvt(ffi::EVP_MAC_CTX_set_params(self.as_ptr(), params.as_ptr()))?;
54        }
55        Ok(())
56    }
57
58    /// Returns the MAC output size for the given context.
59    #[corresponds(EVP_MAC_CTX_get_mac_size)]
60    pub fn mac_size(&self) -> usize {
61        unsafe { ffi::EVP_MAC_CTX_get_mac_size(self.as_ptr()) }
62    }
63
64    /// Returns the MAC block size for the given context.
65    ///
66    /// Not all MAC algorithms support this.
67    #[corresponds(EVP_MAC_CTX_get_block_size)]
68    pub fn block_size(&self) -> usize {
69        unsafe { ffi::EVP_MAC_CTX_get_block_size(self.as_ptr()) }
70    }
71
72    /// Add data bytes to the MAC input.
73    #[corresponds(EVP_MAC_update)]
74    #[inline]
75    pub fn mac_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
76        unsafe {
77            cvt(ffi::EVP_MAC_update(
78                self.as_ptr(),
79                data.as_ptr() as *const _,
80                data.len(),
81            ))?;
82        }
83
84        Ok(())
85    }
86
87    /// Do the final computation and stores the result.
88    ///
89    /// If `out` is set to `None`, an upper bound on the number of bytes required for the output buffer will be
90    /// returned.
91    #[corresponds(EVP_MAC_final)]
92    #[inline]
93    pub fn mac_final(&mut self, out: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
94        let mut len = out.as_ref().map_or(0, |b| b.len());
95
96        unsafe {
97            cvt(ffi::EVP_MAC_final(
98                self.as_ptr(),
99                out.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
100                &mut len,
101                len,
102            ))?;
103        }
104
105        Ok(len)
106    }
107
108    /// Like [`Self::mac_final`] but appends the result to a [`Vec`].
109    pub fn mac_final_to_vec(&mut self, out: &mut Vec<u8>) -> Result<usize, ErrorStack> {
110        let base = out.len();
111        out.resize(base + self.mac_size(), 0);
112        let len = self.mac_final(Some(&mut out[base..]))?;
113        out.truncate(base + len);
114        Ok(len)
115    }
116}