mls_rs_crypto_openssl/
lib.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// Copyright by contributors to this project.
3// SPDX-License-Identifier: (Apache-2.0 OR MIT)
4
5pub mod aead;
6mod ec;
7pub mod ec_signer;
8pub mod ecdh;
9pub mod kdf;
10pub mod mac;
11
12#[cfg(feature = "x509")]
13pub mod x509;
14
15use aead::Aead;
16use mls_rs_crypto_hpke::{
17    context::{ContextR, ContextS},
18    dhkem::DhKem,
19    hpke::{Hpke, HpkeError},
20};
21use mls_rs_crypto_traits::{AeadType, KdfType, KemId, KemType};
22
23use ec::EcError;
24use ec_signer::{EcSigner, EcSignerError};
25use ecdh::Ecdh;
26use kdf::Kdf;
27use mac::{Hash, HashError};
28use openssl::error::ErrorStack;
29use thiserror::Error;
30
31use mls_rs_core::{
32    crypto::{
33        CipherSuite, CipherSuiteProvider, CryptoProvider, HpkeCiphertext, HpkePublicKey,
34        HpkeSecretKey, SignaturePublicKey, SignatureSecretKey,
35    },
36    error::{AnyError, IntoAnyError},
37};
38
39pub use openssl;
40use zeroize::Zeroizing;
41
42#[derive(Debug, Error)]
43pub enum OpensslCryptoError {
44    #[error(transparent)]
45    AeadError(AnyError),
46    #[error(transparent)]
47    HpkeError(#[from] HpkeError),
48    #[error(transparent)]
49    KdfError(AnyError),
50    #[error(transparent)]
51    HashError(#[from] HashError),
52    #[error(transparent)]
53    EcSignerError(#[from] EcSignerError),
54    #[error(transparent)]
55    OpensslError(#[from] ErrorStack),
56    #[error(transparent)]
57    EcError(#[from] EcError),
58}
59
60impl IntoAnyError for OpensslCryptoError {
61    fn into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self> {
62        Ok(self.into())
63    }
64}
65
66#[derive(Debug, Clone)]
67#[non_exhaustive]
68pub struct OpensslCryptoProvider {
69    pub enabled_cipher_suites: Vec<CipherSuite>,
70}
71
72impl OpensslCryptoProvider {
73    pub fn new() -> Self {
74        Default::default()
75    }
76
77    pub fn with_enabled_cipher_suites(enabled_cipher_suites: Vec<CipherSuite>) -> Self {
78        Self {
79            enabled_cipher_suites,
80        }
81    }
82
83    pub fn all_supported_cipher_suites() -> Vec<CipherSuite> {
84        CipherSuite::all().collect()
85    }
86}
87
88impl Default for OpensslCryptoProvider {
89    fn default() -> Self {
90        Self {
91            enabled_cipher_suites: Self::all_supported_cipher_suites(),
92        }
93    }
94}
95
96impl CryptoProvider for OpensslCryptoProvider {
97    type CipherSuiteProvider = OpensslCipherSuite<DhKem<Ecdh, Kdf>, Kdf, Aead>;
98
99    fn supported_cipher_suites(&self) -> Vec<CipherSuite> {
100        self.enabled_cipher_suites.clone()
101    }
102
103    fn cipher_suite_provider(
104        &self,
105        cipher_suite: CipherSuite,
106    ) -> Option<Self::CipherSuiteProvider> {
107        if !self.enabled_cipher_suites.contains(&cipher_suite) {
108            return None;
109        }
110
111        let kdf = Kdf::new(cipher_suite)?;
112        let ecdh = Ecdh::new(cipher_suite)?;
113        let kem_id = KemId::new(cipher_suite)?;
114        let kem = DhKem::new(ecdh, kdf.clone(), kem_id as u16, kem_id.n_secret());
115        let aead = Aead::new(cipher_suite)?;
116
117        OpensslCipherSuite::new(cipher_suite, kem, kdf, aead)
118    }
119}
120
121#[derive(Clone)]
122pub struct OpensslCipherSuite<KEM, KDF, AEAD>
123where
124    KEM: KemType + Clone,
125    KDF: KdfType + Clone,
126    AEAD: AeadType + Clone,
127{
128    cipher_suite: CipherSuite,
129    aead: AEAD,
130    kdf: KDF,
131    hash: Hash,
132    hpke: Hpke<KEM, KDF, AEAD>,
133    ec_signer: EcSigner,
134}
135
136impl<KEM, KDF, AEAD> OpensslCipherSuite<KEM, KDF, AEAD>
137where
138    KEM: KemType + Clone,
139    KDF: KdfType + Clone,
140    AEAD: AeadType + Clone,
141{
142    pub fn new(cipher_suite: CipherSuite, kem: KEM, kdf: KDF, aead: AEAD) -> Option<Self> {
143        let hpke = Hpke::new(kem, kdf.clone(), Some(aead.clone()));
144
145        Some(Self {
146            cipher_suite,
147            kdf,
148            aead,
149            hash: Hash::new(cipher_suite).ok()?,
150            hpke,
151            ec_signer: EcSigner::new(cipher_suite)?,
152        })
153    }
154
155    pub fn random_bytes(&self, out: &mut [u8]) -> Result<(), OpensslCryptoError> {
156        Ok(openssl::rand::rand_bytes(out)?)
157    }
158
159    pub fn import_der_public_signing_key(
160        &self,
161        der_data: &[u8],
162    ) -> Result<SignaturePublicKey, OpensslCryptoError> {
163        self.ec_signer
164            .signature_key_import_der_public(der_data)
165            .map_err(Into::into)
166    }
167
168    pub fn import_der_private_signing_key(
169        &self,
170        der_data: &[u8],
171    ) -> Result<SignatureSecretKey, OpensslCryptoError> {
172        self.ec_signer
173            .signature_key_import_der_private(der_data)
174            .map_err(Into::into)
175    }
176}
177
178#[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
179#[cfg_attr(all(target_arch = "wasm32", mls_build_async), maybe_async::must_be_async(?Send))]
180#[cfg_attr(
181    all(not(target_arch = "wasm32"), mls_build_async),
182    maybe_async::must_be_async
183)]
184impl<KEM, KDF, AEAD> CipherSuiteProvider for OpensslCipherSuite<KEM, KDF, AEAD>
185where
186    KEM: KemType + Clone + Send + Sync,
187    KDF: KdfType + Clone + Send + Sync,
188    AEAD: AeadType + Clone + Send + Sync,
189{
190    type Error = OpensslCryptoError;
191    // TODO exporter_secret in this struct is not zeroized
192    type HpkeContextS = ContextS<KDF, AEAD>;
193    type HpkeContextR = ContextR<KDF, AEAD>;
194
195    async fn hash(&self, data: &[u8]) -> Result<Vec<u8>, Self::Error> {
196        Ok(self.hash.hash(data)?)
197    }
198
199    async fn mac(&self, key: &[u8], data: &[u8]) -> Result<Vec<u8>, Self::Error> {
200        Ok(self.hash.mac(key, data)?)
201    }
202
203    async fn aead_seal(
204        &self,
205        key: &[u8],
206        data: &[u8],
207        aad: Option<&[u8]>,
208        nonce: &[u8],
209    ) -> Result<Vec<u8>, Self::Error> {
210        self.aead
211            .seal(key, data, aad, nonce)
212            .await
213            .map_err(|e| OpensslCryptoError::AeadError(e.into_any_error()))
214    }
215
216    async fn aead_open(
217        &self,
218        key: &[u8],
219        cipher_text: &[u8],
220        aad: Option<&[u8]>,
221        nonce: &[u8],
222    ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
223        self.aead
224            .open(key, cipher_text, aad, nonce)
225            .await
226            .map_err(|e| OpensslCryptoError::AeadError(e.into_any_error()))
227            .map(Zeroizing::new)
228    }
229
230    fn aead_key_size(&self) -> usize {
231        self.aead.key_size()
232    }
233
234    fn aead_nonce_size(&self) -> usize {
235        self.aead.nonce_size()
236    }
237
238    async fn kdf_expand(
239        &self,
240        prk: &[u8],
241        info: &[u8],
242        len: usize,
243    ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
244        self.kdf
245            .expand(prk, info, len)
246            .await
247            .map_err(|e| OpensslCryptoError::KdfError(e.into_any_error()))
248            .map(Zeroizing::new)
249    }
250
251    async fn kdf_extract(
252        &self,
253        salt: &[u8],
254        ikm: &[u8],
255    ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
256        self.kdf
257            .extract(salt, ikm)
258            .await
259            .map_err(|e| OpensslCryptoError::KdfError(e.into_any_error()))
260            .map(Zeroizing::new)
261    }
262
263    fn kdf_extract_size(&self) -> usize {
264        self.kdf.extract_size()
265    }
266
267    async fn hpke_seal(
268        &self,
269        remote_key: &HpkePublicKey,
270        info: &[u8],
271        aad: Option<&[u8]>,
272        pt: &[u8],
273    ) -> Result<HpkeCiphertext, Self::Error> {
274        Ok(self.hpke.seal(remote_key, info, None, aad, pt).await?)
275    }
276
277    async fn hpke_open(
278        &self,
279        ciphertext: &HpkeCiphertext,
280        local_secret: &HpkeSecretKey,
281        local_public: &HpkePublicKey,
282        info: &[u8],
283        aad: Option<&[u8]>,
284    ) -> Result<Vec<u8>, Self::Error> {
285        Ok(self
286            .hpke
287            .open(ciphertext, local_secret, local_public, info, None, aad)
288            .await?)
289    }
290
291    async fn hpke_setup_r(
292        &self,
293        enc: &[u8],
294        local_secret: &HpkeSecretKey,
295        local_public: &HpkePublicKey,
296        info: &[u8],
297    ) -> Result<Self::HpkeContextR, Self::Error> {
298        Ok(self
299            .hpke
300            .setup_receiver(enc, local_secret, local_public, info, None)
301            .await?)
302    }
303
304    async fn hpke_setup_s(
305        &self,
306        remote_key: &HpkePublicKey,
307        info: &[u8],
308    ) -> Result<(Vec<u8>, Self::HpkeContextS), Self::Error> {
309        Ok(self.hpke.setup_sender(remote_key, info, None).await?)
310    }
311
312    async fn kem_derive(&self, ikm: &[u8]) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error> {
313        Ok(self.hpke.derive(ikm).await?)
314    }
315
316    async fn kem_generate(&self) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error> {
317        Ok(self.hpke.generate().await?)
318    }
319
320    fn kem_public_key_validate(&self, key: &HpkePublicKey) -> Result<(), Self::Error> {
321        Ok(self.hpke.public_key_validate(key)?)
322    }
323
324    fn random_bytes(&self, out: &mut [u8]) -> Result<(), Self::Error> {
325        self.random_bytes(out)
326    }
327
328    fn cipher_suite(&self) -> CipherSuite {
329        self.cipher_suite
330    }
331
332    async fn sign(
333        &self,
334        secret_key: &SignatureSecretKey,
335        data: &[u8],
336    ) -> Result<Vec<u8>, Self::Error> {
337        Ok(self.ec_signer.sign(secret_key, data)?)
338    }
339
340    async fn verify(
341        &self,
342        public_key: &SignaturePublicKey,
343        signature: &[u8],
344        data: &[u8],
345    ) -> Result<(), Self::Error> {
346        Ok(self.ec_signer.verify(public_key, signature, data)?)
347    }
348
349    async fn signature_key_generate(
350        &self,
351    ) -> Result<(SignatureSecretKey, SignaturePublicKey), Self::Error> {
352        Ok(self.ec_signer.signature_key_generate()?)
353    }
354
355    async fn signature_key_derive_public(
356        &self,
357        secret_key: &SignatureSecretKey,
358    ) -> Result<SignaturePublicKey, Self::Error> {
359        Ok(self.ec_signer.signature_key_derive_public(secret_key)?)
360    }
361}
362
363#[cfg(not(mls_build_async))]
364#[test]
365fn mls_core_tests() {
366    // Uncomment this to generate the tests instead.
367    // mls_rs_core::crypto::test_suite::generate_tests(&OpensslCryptoProvider::new());
368    let provider = OpensslCryptoProvider::new();
369
370    mls_rs_core::crypto::test_suite::verify_tests(&provider, true);
371
372    for cs in OpensslCryptoProvider::all_supported_cipher_suites() {
373        let mut hpke = provider.cipher_suite_provider(cs).unwrap().hpke;
374
375        mls_rs_core::crypto::test_suite::verify_hpke_context_tests(&hpke, cs);
376        mls_rs_core::crypto::test_suite::verify_hpke_encap_tests(&mut hpke, cs);
377    }
378}