Skip to content
File

Blob: firmware/crates/esp32-radio/src/platform/crypto/self_test/extended.rs

rust179 lines
1//! Device-only signature, key-exchange and rejection checks for crypto-self-test.
2use super::super::{ec, native, signature::Verifier};
3use dimpl::{
4 HashAlgorithm, SignatureAlgorithm,
5 crypto::{Buf, KeyProvider, SignatureVerifier, SupportedKxGroup},
6};
7use std::{thread, time::Duration};
8 
9const CERT: &[u8] = include_bytes!("fixtures/p384.der");
10const SHA256_SIG: &[u8] = include_bytes!("fixtures/p384-sha256.sig");
11const SHA384_SIG: &[u8] = include_bytes!("fixtures/p384-sha384.sig");
12const MESSAGE: &[u8] = b"Pocket Radio public crypto adapter test";
13const P256_CERT: &[u8] = include_bytes!(concat!(
14 env!("CARGO_MANIFEST_DIR"),
15 "/../radio-webrtc/tests/fixtures/certificate.der"
16));
17const P256_KEY: &[u8] = include_bytes!(concat!(
18 env!("CARGO_MANIFEST_DIR"),
19 "/../radio-webrtc/tests/fixtures/key.der"
20));
21 
22pub(super) fn run() {
23 let mut signer = ec::Keys
24 .load_private_key(P256_KEY)
25 .expect("native signing key test");
26 for algorithm in [HashAlgorithm::SHA256, HashAlgorithm::SHA384] {
27 let mut signature = Buf::new();
28 signer
29 .sign(MESSAGE, algorithm, &mut signature)
30 .expect("native P-256 signing test");
31 assert!(
32 dimpl::crypto::rust_crypto::default_provider()
33 .signature_verification
34 .verify_signature(
35 P256_CERT,
36 MESSAGE,
37 &signature,
38 algorithm,
39 SignatureAlgorithm::ECDSA
40 )
41 .is_ok(),
42 "native P-256 signature rejected by RustCrypto"
43 );
44 assert!(
45 Verifier
46 .verify_signature(
47 P256_CERT,
48 MESSAGE,
49 &signature,
50 algorithm,
51 SignatureAlgorithm::ECDSA
52 )
53 .is_ok(),
54 "native P-256 signature rejected"
55 );
56 thread::sleep(Duration::from_millis(1));
57 }
58 assert!(
59 ec::Keys.load_private_key(&[]).is_err(),
60 "empty private key accepted"
61 );
62 assert!(
63 ec::Keys.load_private_key(&P256_KEY[..20]).is_err(),
64 "truncated private key accepted"
65 );
66 let native = ec::P256
67 .start_exchange(Buf::new())
68 .expect("native ECDH setup test");
69 let base = dimpl::crypto::rust_crypto::default_provider();
70 let reference = base
71 .kx_groups
72 .iter()
73 .find(|group| group.name() == dimpl::NamedGroup::Secp256r1)
74 .unwrap()
75 .start_exchange(Buf::new())
76 .unwrap();
77 let n_public = native.pub_key().to_vec();
78 let r_public = reference.pub_key().to_vec();
79 let mut n_secret = Buf::new();
80 let mut r_secret = Buf::new();
81 native
82 .complete(&r_public, &mut n_secret)
83 .expect("native ECDH completion test");
84 reference.complete(&n_public, &mut r_secret).unwrap();
85 assert!(
86 n_secret[..] == r_secret[..],
87 "native ECDH differs from RustCrypto"
88 );
89 let mut off_curve = [0; 65];
90 off_curve[0] = 4; // Valid uncompressed encoding; (0, 0) is not on P-256.
91 for (point, description) in [
92 (&[0; 65][..], "invalid SEC1 encoding"),
93 (&off_curve[..], "off-curve point"),
94 (&n_public[..64], "truncated point"),
95 ] {
96 assert!(
97 ec::P256
98 .start_exchange(Buf::new())
99 .unwrap()
100 .complete(point, &mut Buf::new())
101 .is_err(),
102 "ECDH accepted {description}"
103 );
104 thread::sleep(Duration::from_millis(1));
105 }
106 let valid_point = n_public.as_slice().try_into().unwrap();
107 for scalar in [[0; 32], [0xff; 32]] {
108 assert!(
109 native::p256_shared(&scalar, valid_point).is_err(),
110 "ECDH accepted out-of-range private scalar"
111 );
112 }
113 for (hash, signature) in [
114 (HashAlgorithm::SHA256, SHA256_SIG),
115 (HashAlgorithm::SHA384, SHA384_SIG),
116 ] {
117 let result =
118 Verifier.verify_signature(CERT, MESSAGE, signature, hash, SignatureAlgorithm::ECDSA);
119 assert!(result.is_ok(), "P-384 valid signature rejected");
120 thread::sleep(Duration::from_millis(1));
121 assert!(
122 Verifier
123 .verify_signature(
124 CERT,
125 b"altered message",
126 signature,
127 hash,
128 SignatureAlgorithm::ECDSA
129 )
130 .is_err(),
131 "P-384 altered message accepted"
132 );
133 thread::sleep(Duration::from_millis(1));
134 let mut corrupt = signature.to_vec();
135 *corrupt.last_mut().unwrap() ^= 1;
136 assert!(
137 Verifier
138 .verify_signature(CERT, MESSAGE, &corrupt, hash, SignatureAlgorithm::ECDSA)
139 .is_err(),
140 "P-384 altered signature accepted"
141 );
142 thread::sleep(Duration::from_millis(1));
143 }
144 assert!(
145 Verifier
146 .verify_signature(
147 &CERT[..20],
148 MESSAGE,
149 SHA384_SIG,
150 HashAlgorithm::SHA384,
151 SignatureAlgorithm::ECDSA
152 )
153 .is_err(),
154 "truncated certificate accepted"
155 );
156 assert!(
157 native::verify_ec(&CERT[..20], MESSAGE, SHA384_SIG, 384).is_err(),
158 "native truncated certificate accepted"
159 );
160 let mut out = [0xa5; 32];
161 assert!(
162 native::ctr(&[0; 15], &[0; 16], &[0; 16], &mut out).is_err(),
163 "invalid AES key size accepted"
164 );
165 assert!(
166 native::ctr(&[0; 16], &[0; 16], &[0; 33], &mut out).is_err(),
167 "short CTR output accepted"
168 );
169 assert!(
170 native::gcm(false, &[0; 16], &[0; 12], &[], &[0; 17], &mut out).is_err(),
171 "short GCM output accepted"
172 );
173 assert!(
174 native::gcm(true, &[0; 16], &[0; 12], &[], &[0; 15], &mut out).is_err(),
175 "short GCM tag accepted"
176 );
177 crate::platform::log("Extended crypto security tests passed");
178}