blob: 806bd877a8fa881b05264015b059b4a41b727419 [file] [log] [blame]
Cindy Lin6ec3c2b2024-05-16 07:39:23 +00001// Copyright 2024, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Implements mls_rs_core's CryptoProvider and CipherSuiteProvider backed by BoringSSL.
16
17pub mod aead;
18pub mod ecdh;
19pub mod eddsa;
20pub mod hash;
21pub mod hpke;
22pub mod kdf;
23
24#[cfg(test)]
25mod test_helpers;
26
27use mls_rs_core::crypto::{
28 CipherSuite, CipherSuiteProvider, CryptoProvider, HpkeCiphertext, HpkePublicKey, HpkeSecretKey,
29 SignaturePublicKey, SignatureSecretKey,
30};
31use mls_rs_core::error::{AnyError, IntoAnyError};
32use mls_rs_crypto_traits::{AeadType, KdfType, KemType};
33use thiserror::Error;
34use zeroize::Zeroizing;
35
36use aead::AeadWrapper;
37use ecdh::Ecdh;
38use eddsa::{EdDsa, EdDsaError};
39use hash::{Hash, HashError};
40use hpke::{ContextR, ContextS, DhKem, Hpke, HpkeError};
41use kdf::Kdf;
42
43/// Errors returned from BoringsslCryptoProvider.
44#[derive(Debug, Error)]
45pub enum BoringsslCryptoError {
46 /// Error returned from hash functions and HMACs.
47 #[error(transparent)]
48 HashError(#[from] HashError),
49 /// Error returned from KEMs.
50 #[error(transparent)]
51 KemError(AnyError),
52 /// Error returned from KDFs.
53 #[error(transparent)]
54 KdfError(AnyError),
55 /// Error returned from AEADs.
56 #[error(transparent)]
57 AeadError(AnyError),
58 /// Error returned from HPKE.
59 #[error(transparent)]
60 HpkeError(#[from] HpkeError),
61 /// Error returned from EdDSA.
62 #[error(transparent)]
63 EdDsaError(#[from] EdDsaError),
64}
65
66impl IntoAnyError for BoringsslCryptoError {
67 fn into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self> {
68 Ok(self.into())
69 }
70}
71
72/// CryptoProvider trait implementation backed by BoringSSL.
73#[derive(Debug, Clone)]
74#[non_exhaustive]
75pub struct BoringsslCryptoProvider {
76 /// Available cipher suites.
77 pub enabled_cipher_suites: Vec<CipherSuite>,
78}
79
80impl BoringsslCryptoProvider {
81 /// Creates a new BoringsslCryptoProvider.
82 pub fn new() -> Self {
83 Default::default()
84 }
85
86 /// Sets the enabled cipher suites.
87 pub fn with_enabled_cipher_suites(enabled_cipher_suites: Vec<CipherSuite>) -> Self {
88 Self { enabled_cipher_suites }
89 }
90
91 /// Returns all available cipher suites.
92 pub fn all_supported_cipher_suites() -> Vec<CipherSuite> {
93 vec![CipherSuite::CURVE25519_AES128, CipherSuite::CURVE25519_CHACHA]
94 }
95}
96
97impl Default for BoringsslCryptoProvider {
98 fn default() -> Self {
99 Self { enabled_cipher_suites: Self::all_supported_cipher_suites() }
100 }
101}
102
103impl CryptoProvider for BoringsslCryptoProvider {
104 type CipherSuiteProvider = BoringsslCipherSuite<DhKem<Ecdh, Kdf>, Kdf, AeadWrapper>;
105
106 fn supported_cipher_suites(&self) -> Vec<CipherSuite> {
107 self.enabled_cipher_suites.clone()
108 }
109
110 fn cipher_suite_provider(
111 &self,
112 cipher_suite: CipherSuite,
113 ) -> Option<Self::CipherSuiteProvider> {
114 if !self.enabled_cipher_suites.contains(&cipher_suite) {
115 return None;
116 }
117
118 let ecdh = Ecdh::new(cipher_suite)?;
119 let kdf = Kdf::new(cipher_suite)?;
120 let kem = DhKem::new(cipher_suite, ecdh, kdf.clone())?;
121 let aead = AeadWrapper::new(cipher_suite)?;
122
123 BoringsslCipherSuite::new(cipher_suite, kem, kdf, aead)
124 }
125}
126
127/// CipherSuiteProvider trait implementation backed by BoringSSL.
128#[derive(Clone)]
129pub struct BoringsslCipherSuite<KEM, KDF, AEAD>
130where
131 KEM: KemType + Clone,
132 KDF: KdfType + Clone,
133 AEAD: AeadType + Clone,
134{
135 cipher_suite: CipherSuite,
136 hash: Hash,
137 kem: KEM,
138 kdf: KDF,
139 aead: AEAD,
140 hpke: Hpke,
141 eddsa: EdDsa,
142}
143
144impl<KEM, KDF, AEAD> BoringsslCipherSuite<KEM, KDF, AEAD>
145where
146 KEM: KemType + Clone,
147 KDF: KdfType + Clone,
148 AEAD: AeadType + Clone,
149{
150 /// Creates a new BoringsslCipherSuite.
151 pub fn new(cipher_suite: CipherSuite, kem: KEM, kdf: KDF, aead: AEAD) -> Option<Self> {
152 Some(Self {
153 cipher_suite,
154 hash: Hash::new(cipher_suite).ok()?,
155 kem,
156 kdf,
157 aead,
158 hpke: Hpke::new(cipher_suite),
159 eddsa: EdDsa::new(cipher_suite)?,
160 })
161 }
162
163 /// Returns random bytes generated via BoringSSL.
164 pub fn random_bytes(&self, out: &mut [u8]) -> Result<(), BoringsslCryptoError> {
165 bssl_crypto::rand_bytes(out);
166 Ok(())
167 }
168}
169
170#[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
171#[cfg_attr(all(target_arch = "wasm32", mls_build_async), maybe_async::must_be_async(?Send))]
172#[cfg_attr(all(not(target_arch = "wasm32"), mls_build_async), maybe_async::must_be_async)]
173impl<KEM, KDF, AEAD> CipherSuiteProvider for BoringsslCipherSuite<KEM, KDF, AEAD>
174where
175 KEM: KemType + Clone + Send + Sync,
176 KDF: KdfType + Clone + Send + Sync,
177 AEAD: AeadType + Clone + Send + Sync,
178{
179 type Error = BoringsslCryptoError;
180 type HpkeContextS = ContextS;
181 type HpkeContextR = ContextR;
182
183 fn cipher_suite(&self) -> CipherSuite {
184 self.cipher_suite
185 }
186
187 fn random_bytes(&self, out: &mut [u8]) -> Result<(), Self::Error> {
188 self.random_bytes(out)
189 }
190
191 async fn hash(&self, data: &[u8]) -> Result<Vec<u8>, Self::Error> {
192 Ok(self.hash.hash(data))
193 }
194
195 async fn mac(&self, key: &[u8], data: &[u8]) -> Result<Vec<u8>, Self::Error> {
196 Ok(self.hash.mac(key, data)?)
197 }
198
199 async fn kem_generate(&self) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error> {
200 self.kem.generate().await.map_err(|e| BoringsslCryptoError::KemError(e.into_any_error()))
201 }
202
203 async fn kem_derive(&self, ikm: &[u8]) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error> {
204 self.kem.derive(ikm).await.map_err(|e| BoringsslCryptoError::KemError(e.into_any_error()))
205 }
206
207 fn kem_public_key_validate(&self, key: &HpkePublicKey) -> Result<(), Self::Error> {
208 self.kem
209 .public_key_validate(key)
210 .map_err(|e| BoringsslCryptoError::KemError(e.into_any_error()))
211 }
212
213 async fn kdf_extract(
214 &self,
215 salt: &[u8],
216 ikm: &[u8],
217 ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
218 self.kdf
219 .extract(salt, ikm)
220 .await
221 .map_err(|e| BoringsslCryptoError::KdfError(e.into_any_error()))
222 .map(Zeroizing::new)
223 }
224
225 async fn kdf_expand(
226 &self,
227 prk: &[u8],
228 info: &[u8],
229 len: usize,
230 ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
231 self.kdf
232 .expand(prk, info, len)
233 .await
234 .map_err(|e| BoringsslCryptoError::KdfError(e.into_any_error()))
235 .map(Zeroizing::new)
236 }
237
238 fn kdf_extract_size(&self) -> usize {
239 self.kdf.extract_size()
240 }
241
242 async fn aead_seal(
243 &self,
244 key: &[u8],
245 data: &[u8],
246 aad: Option<&[u8]>,
247 nonce: &[u8],
248 ) -> Result<Vec<u8>, Self::Error> {
249 self.aead
250 .seal(key, data, aad, nonce)
251 .await
252 .map_err(|e| BoringsslCryptoError::AeadError(e.into_any_error()))
253 }
254
255 async fn aead_open(
256 &self,
257 key: &[u8],
258 cipher_text: &[u8],
259 aad: Option<&[u8]>,
260 nonce: &[u8],
261 ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
262 self.aead
263 .open(key, cipher_text, aad, nonce)
264 .await
265 .map_err(|e| BoringsslCryptoError::AeadError(e.into_any_error()))
266 .map(Zeroizing::new)
267 }
268
269 fn aead_key_size(&self) -> usize {
270 self.aead.key_size()
271 }
272
273 fn aead_nonce_size(&self) -> usize {
274 self.aead.nonce_size()
275 }
276
277 async fn hpke_setup_s(
278 &self,
279 remote_key: &HpkePublicKey,
280 info: &[u8],
281 ) -> Result<(Vec<u8>, Self::HpkeContextS), Self::Error> {
282 Ok(self.hpke.setup_sender(remote_key, info).await?)
283 }
284
285 async fn hpke_seal(
286 &self,
287 remote_key: &HpkePublicKey,
288 info: &[u8],
289 aad: Option<&[u8]>,
290 pt: &[u8],
291 ) -> Result<HpkeCiphertext, Self::Error> {
292 Ok(self.hpke.seal(remote_key, info, aad, pt).await?)
293 }
294
295 async fn hpke_setup_r(
296 &self,
297 enc: &[u8],
298 local_secret: &HpkeSecretKey,
299 // Other implementations use `_local_public` to skip derivation of the public from the
300 // private key for the KEM decapsulation step, but BoringSSL's API does not accept a public
301 // key and instead derives it under the hood.
302 _local_public: &HpkePublicKey,
303 info: &[u8],
304 ) -> Result<Self::HpkeContextR, Self::Error> {
305 Ok(self.hpke.setup_receiver(enc, local_secret, info).await?)
306 }
307
308 async fn hpke_open(
309 &self,
310 ciphertext: &HpkeCiphertext,
311 local_secret: &HpkeSecretKey,
312 // Other implementations use `_local_public` to skip derivation of the public from the
313 // private key for hpke_setup_r()'s KEM decapsulation step, but BoringSSL's API does not
314 // accept a public key and instead derives it under the hood.
315 _local_public: &HpkePublicKey,
316 info: &[u8],
317 aad: Option<&[u8]>,
318 ) -> Result<Vec<u8>, Self::Error> {
319 Ok(self.hpke.open(ciphertext, local_secret, info, aad).await?)
320 }
321
322 async fn signature_key_generate(
323 &self,
324 ) -> Result<(SignatureSecretKey, SignaturePublicKey), Self::Error> {
325 Ok(self.eddsa.signature_key_generate()?)
326 }
327
328 async fn signature_key_derive_public(
329 &self,
330 secret_key: &SignatureSecretKey,
331 ) -> Result<SignaturePublicKey, Self::Error> {
332 Ok(self.eddsa.signature_key_derive_public(secret_key)?)
333 }
334
335 async fn sign(
336 &self,
337 secret_key: &SignatureSecretKey,
338 data: &[u8],
339 ) -> Result<Vec<u8>, Self::Error> {
340 Ok(self.eddsa.sign(secret_key, data)?)
341 }
342
343 async fn verify(
344 &self,
345 public_key: &SignaturePublicKey,
346 signature: &[u8],
347 data: &[u8],
348 ) -> Result<(), Self::Error> {
349 Ok(self.eddsa.verify(public_key, signature, data)?)
350 }
351}
352
353#[cfg(all(not(mls_build_async), test))]
354mod test {
355 use super::BoringsslCryptoProvider;
356 use crate::test_helpers::decode_hex;
357 use mls_rs_core::crypto::{
358 CipherSuite, CipherSuiteProvider, CryptoProvider, HpkeContextR, HpkeContextS,
359 HpkePublicKey, HpkeSecretKey, SignaturePublicKey, SignatureSecretKey,
360 };
361
362 fn get_cipher_suites() -> Vec<CipherSuite> {
363 vec![CipherSuite::CURVE25519_AES128, CipherSuite::CURVE25519_CHACHA]
364 }
365
366 #[test]
367 fn supported_cipher_suites() {
368 let bssl = BoringsslCryptoProvider::new();
369 assert_eq!(bssl.supported_cipher_suites().len(), 2);
370 }
371
372 #[test]
373 fn unsupported_cipher_suites() {
374 let bssl = BoringsslCryptoProvider::new();
375 for suite in vec![
376 CipherSuite::P256_AES128,
377 CipherSuite::CURVE448_AES256,
378 CipherSuite::P521_AES256,
379 CipherSuite::CURVE448_CHACHA,
380 CipherSuite::P384_AES256,
381 ] {
382 assert!(bssl.cipher_suite_provider(suite).is_none());
383 }
384 }
385
386 #[test]
387 fn cipher_suite() {
388 let bssl = BoringsslCryptoProvider::new();
389 for suite in get_cipher_suites() {
390 let crypto = bssl.cipher_suite_provider(suite).unwrap();
391 assert_eq!(crypto.cipher_suite(), suite);
392 }
393 }
394
395 #[test]
396 fn random_bytes() {
397 let bssl = BoringsslCryptoProvider::new();
398 for suite in get_cipher_suites() {
399 let crypto = bssl.cipher_suite_provider(suite).unwrap();
400 let mut buf = [0; 32];
401 let _ = crypto.random_bytes(&mut buf);
402 }
403 }
404
405 #[test]
406 fn hash() {
407 let bssl = BoringsslCryptoProvider::new();
408 for suite in get_cipher_suites() {
409 let crypto = bssl.cipher_suite_provider(suite).unwrap();
410 assert_eq!(
411 crypto.hash(&decode_hex::<4>("74ba2521")).unwrap(),
412 // bssl_crypto::hmac test vector.
413 decode_hex::<32>(
414 "b16aa56be3880d18cd41e68384cf1ec8c17680c45a02b1575dc1518923ae8b0e"
415 )
416 );
417 }
418 }
419
420 #[test]
421 fn mac() {
422 let bssl = BoringsslCryptoProvider::new();
423 for suite in get_cipher_suites() {
424 let crypto = bssl.cipher_suite_provider(suite).unwrap();
425 // bssl_crypto::hmac test vector.
426 let expected = vec![
427 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
428 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
429 0x2e, 0x32, 0xcf, 0xf7,
430 ];
431 let key: [u8; 20] = [0x0b; 20];
432 let data = b"Hi There";
433
434 assert_eq!(crypto.mac(&key, data).unwrap(), expected);
435 }
436 }
437
438 #[test]
439 fn kem_generate() {
440 let bssl = BoringsslCryptoProvider::new();
441 for suite in get_cipher_suites() {
442 let crypto = bssl.cipher_suite_provider(suite).unwrap();
443 assert!(crypto.kem_generate().is_ok());
444 }
445 }
446
447 #[test]
448 fn kem_derive() {
449 let bssl = BoringsslCryptoProvider::new();
450 for suite in get_cipher_suites() {
451 let crypto = bssl.cipher_suite_provider(suite).unwrap();
452 // https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.1.1
453 let ikm: [u8; 32] =
454 decode_hex("7268600d403fce431561aef583ee1613527cff655c1343f29812e66706df3234");
455 let expected_sk = HpkeSecretKey::from(
456 decode_hex::<32>(
457 "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736",
458 )
459 .to_vec(),
460 );
461 let expected_pk = HpkePublicKey::from(
462 decode_hex::<32>(
463 "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431",
464 )
465 .to_vec(),
466 );
467
468 let (sk, pk) = crypto.kem_derive(&ikm).unwrap();
469 assert_eq!(sk, expected_sk);
470 assert_eq!(pk, expected_pk);
471 }
472 }
473
474 #[test]
475 fn kem_public_key_validate() {
476 let bssl = BoringsslCryptoProvider::new();
477 for suite in get_cipher_suites() {
478 let crypto = bssl.cipher_suite_provider(suite).unwrap();
479 // https://www.rfc-editor.org/rfc/rfc7748.html#section-6.1
480 let public_key = HpkePublicKey::from(
481 decode_hex::<32>(
482 "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a",
483 )
484 .to_vec(),
485 );
486 assert!(crypto.kem_public_key_validate(&public_key).is_ok());
487 }
488 }
489
490 #[test]
491 fn kdf_extract_and_expand() {
492 let bssl = BoringsslCryptoProvider::new();
493 for suite in get_cipher_suites() {
494 let crypto = bssl.cipher_suite_provider(suite).unwrap();
495 // https://www.rfc-editor.org/rfc/rfc5869.html#appendix-A.1
496 let ikm: [u8; 22] = decode_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
497 let salt: [u8; 13] = decode_hex("000102030405060708090a0b0c");
498 let info: [u8; 10] = decode_hex("f0f1f2f3f4f5f6f7f8f9");
499 let expected_prk: [u8; 32] =
500 decode_hex("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5");
501 let expected_okm : [u8; 42] = decode_hex(
502 "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
503 );
504
505 let prk = crypto.kdf_extract(&salt, &ikm).unwrap();
506 assert_eq!(prk.as_ref(), expected_prk);
507 assert_eq!(crypto.kdf_expand(&prk.as_ref(), &info, 42).unwrap().as_ref(), expected_okm);
508 }
509 }
510
511 #[test]
512 fn kdf_extract_size() {
513 let bssl = BoringsslCryptoProvider::new();
514 for suite in get_cipher_suites() {
515 let crypto = bssl.cipher_suite_provider(suite).unwrap();
516 assert_eq!(crypto.kdf_extract_size(), 32);
517 }
518 }
519
520 #[test]
521 fn aead() {
522 let bssl = BoringsslCryptoProvider::new();
523 for suite in get_cipher_suites() {
524 let crypto = bssl.cipher_suite_provider(suite).unwrap();
525 let key = vec![42u8; crypto.aead_key_size()];
526 let associated_data = vec![42u8, 12];
527 let nonce = vec![42u8; crypto.aead_nonce_size()];
528 let plaintext = b"message";
529
530 let ciphertext =
531 crypto.aead_seal(&key, plaintext, Some(&associated_data), &nonce).unwrap();
532 assert_eq!(
533 plaintext,
534 crypto
535 .aead_open(&key, ciphertext.as_slice(), Some(&associated_data), &nonce)
536 .unwrap()
537 .as_slice()
538 );
539 }
540 }
541
542 #[test]
543 fn hpke_setup_seal_open_export() {
544 let bssl = BoringsslCryptoProvider::new();
545 for suite in get_cipher_suites() {
546 let crypto = bssl.cipher_suite_provider(suite).unwrap();
547 // https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.1.1
548 let receiver_pub_key = HpkePublicKey::from(
549 decode_hex::<32>(
550 "3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d",
551 )
552 .to_vec(),
553 );
554 let receiver_priv_key = HpkeSecretKey::from(
555 decode_hex::<32>(
556 "4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8",
557 )
558 .to_vec(),
559 );
560
561 let info = b"some_info";
562 let plaintext = b"plaintext";
563 let associated_data = b"some_ad";
564 let exporter_ctx = b"export_ctx";
565
566 let (enc, mut sender_ctx) = crypto.hpke_setup_s(&receiver_pub_key, info).unwrap();
567 let mut receiver_ctx =
568 crypto.hpke_setup_r(&enc, &receiver_priv_key, &receiver_pub_key, info).unwrap();
569 let ct = sender_ctx.seal(Some(associated_data), plaintext).unwrap();
570 assert_eq!(plaintext.as_ref(), receiver_ctx.open(Some(associated_data), &ct).unwrap(),);
571 assert_eq!(
572 sender_ctx.export(exporter_ctx, 32).unwrap(),
573 receiver_ctx.export(exporter_ctx, 32).unwrap(),
574 );
575 }
576 }
577
578 #[test]
579 fn hpke_seal_open() {
580 let bssl = BoringsslCryptoProvider::new();
581 for suite in get_cipher_suites() {
582 let crypto = bssl.cipher_suite_provider(suite).unwrap();
583 // https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.1.1
584 let receiver_pub_key = HpkePublicKey::from(
585 decode_hex::<32>(
586 "3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d",
587 )
588 .to_vec(),
589 );
590 let receiver_priv_key = HpkeSecretKey::from(
591 decode_hex::<32>(
592 "4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8",
593 )
594 .to_vec(),
595 );
596
597 let info = b"some_info";
598 let plaintext = b"plaintext";
599 let associated_data = b"some_ad";
600
601 let ct = crypto
602 .hpke_seal(&receiver_pub_key, info, Some(associated_data), plaintext)
603 .unwrap();
604 assert_eq!(
605 plaintext.as_ref(),
606 crypto
607 .hpke_open(
608 &ct,
609 &receiver_priv_key,
610 &receiver_pub_key,
611 info,
612 Some(associated_data)
613 )
614 .unwrap(),
615 );
616 }
617 }
618
619 #[test]
620 fn signature_key_generate() {
621 let bssl = BoringsslCryptoProvider::new();
622 for suite in get_cipher_suites() {
623 let crypto = bssl.cipher_suite_provider(suite).unwrap();
624 assert!(crypto.signature_key_generate().is_ok());
625 }
626 }
627
628 #[test]
629 fn signature_key_derive_public() {
630 let bssl = BoringsslCryptoProvider::new();
631 for suite in get_cipher_suites() {
632 let crypto = bssl.cipher_suite_provider(suite).unwrap();
633 // Test 1 from https://www.rfc-editor.org/rfc/rfc8032#section-7.1
634 let private_key = SignatureSecretKey::from(
635 decode_hex::<32>(
636 "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
637 )
638 .to_vec(),
639 );
640 let expected_public_key = SignaturePublicKey::from(
641 decode_hex::<32>(
642 "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
643 )
644 .to_vec(),
645 );
646
647 assert_eq!(
648 crypto.signature_key_derive_public(&private_key).unwrap(),
649 expected_public_key
650 );
651 }
652 }
653
654 #[test]
655 fn sign_verify() {
656 let bssl = BoringsslCryptoProvider::new();
657 for suite in get_cipher_suites() {
658 let crypto = bssl.cipher_suite_provider(suite).unwrap();
659 // Test 3 from https://www.rfc-editor.org/rfc/rfc8032#section-7.1
660 let private_key = SignatureSecretKey::from(
661 decode_hex::<32>(
662 "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
663 )
664 .to_vec(),
665 );
666 let data: [u8; 2] = decode_hex("af82");
667 let expected_sig = decode_hex::<64>("6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a").to_vec();
668
669 let sig = crypto.sign(&private_key, &data).unwrap();
670 assert_eq!(sig, expected_sig);
671
672 let public_key = crypto.signature_key_derive_public(&private_key).unwrap();
673 assert!(crypto.verify(&public_key, &sig, &data).is_ok());
674 }
675 }
676}