File
Blob: firmware/crates/esp32-radio/src/platform/crypto/ec.rs
| 1 | //! EC protocol traits with Rust-owned secret bytes and synchronous native calls. |
| 2 | use super::{hashes, native}; |
| 3 | use dimpl::{ |
| 4 | CryptoError, CryptoOperation, HashAlgorithm, NamedGroup, SignatureAlgorithm, |
| 5 | crypto::{ActiveKeyExchange, Buf, KeyProvider, SigningKey, SupportedKxGroup}, |
| 6 | }; |
| 7 | use zeroize::Zeroizing; |
| 8 | |
| 9 | #[derive(Debug)] |
| 10 | pub(super) struct P256; |
| 11 | pub(super) static GROUPS: &[&dyn SupportedKxGroup] = &[&P256]; |
| 12 | |
| 13 | struct Exchange { |
| 14 | secret: Zeroizing<[u8; 32]>, |
| 15 | public: Buf, |
| 16 | } |
| 17 | impl std::fmt::Debug for Exchange { |
| 18 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 19 | f.debug_struct("P256Exchange").finish_non_exhaustive() |
| 20 | } |
| 21 | } |
| 22 | impl SupportedKxGroup for P256 { |
| 23 | fn name(&self) -> NamedGroup { |
| 24 | NamedGroup::Secp256r1 |
| 25 | } |
| 26 | fn start_exchange(&self, mut public: Buf) -> Result<Box<dyn ActiveKeyExchange>, CryptoError> { |
| 27 | let (secret, bytes) = native::p256_keygen() |
| 28 | .map_err(|_| CryptoError::OperationFailed(CryptoOperation::StartKeyExchange))?; |
| 29 | public.clear(); |
| 30 | public.extend_from_slice(&bytes); |
| 31 | Ok(Box::new(Exchange { secret, public })) |
| 32 | } |
| 33 | } |
| 34 | impl ActiveKeyExchange for Exchange { |
| 35 | fn pub_key(&self) -> &[u8] { |
| 36 | &self.public |
| 37 | } |
| 38 | fn group(&self) -> NamedGroup { |
| 39 | NamedGroup::Secp256r1 |
| 40 | } |
| 41 | fn complete(self: Box<Self>, peer: &[u8], out: &mut Buf) -> Result<(), CryptoError> { |
| 42 | let peer: &[u8; 65] = peer |
| 43 | .try_into() |
| 44 | .map_err(|_| CryptoError::OperationFailed(CryptoOperation::CompleteKeyExchange))?; |
| 45 | let value = native::p256_shared(&self.secret, peer) |
| 46 | .map_err(|_| CryptoError::OperationFailed(CryptoOperation::CompleteKeyExchange))?; |
| 47 | out.clear(); |
| 48 | out.extend_from_slice(value.as_ref()); |
| 49 | Ok(()) |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | #[derive(Debug)] |
| 54 | pub(super) struct Keys; |
| 55 | struct Signer { |
| 56 | der: Zeroizing<Vec<u8>>, |
| 57 | bits: i32, |
| 58 | } |
| 59 | impl std::fmt::Debug for Signer { |
| 60 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 61 | f.debug_struct("EcSigningKey") |
| 62 | .field("bits", &self.bits) |
| 63 | .finish_non_exhaustive() |
| 64 | } |
| 65 | } |
| 66 | impl KeyProvider for Keys { |
| 67 | fn load_private_key(&self, der: &[u8]) -> Result<Box<dyn SigningKey>, CryptoError> { |
| 68 | let bits = native::key_info(der) |
| 69 | .map_err(|_| CryptoError::OperationFailed(CryptoOperation::LoadPrivateKey))?; |
| 70 | Ok(Box::new(Signer { |
| 71 | der: Zeroizing::new(der.to_vec()), |
| 72 | bits, |
| 73 | })) |
| 74 | } |
| 75 | } |
| 76 | impl SigningKey for Signer { |
| 77 | fn algorithm(&self) -> SignatureAlgorithm { |
| 78 | SignatureAlgorithm::ECDSA |
| 79 | } |
| 80 | fn hash_algorithm(&self) -> HashAlgorithm { |
| 81 | if self.bits == 256 { |
| 82 | HashAlgorithm::SHA256 |
| 83 | } else { |
| 84 | HashAlgorithm::SHA384 |
| 85 | } |
| 86 | } |
| 87 | fn supported_hash_algorithms(&self) -> &[HashAlgorithm] { |
| 88 | &[HashAlgorithm::SHA256, HashAlgorithm::SHA384] |
| 89 | } |
| 90 | fn sign(&mut self, data: &[u8], hash: HashAlgorithm, out: &mut Buf) -> Result<(), CryptoError> { |
| 91 | let bits = hashes::bits(hash).ok_or(CryptoError::UnsupportedSignaturePair { |
| 92 | signature: SignatureAlgorithm::ECDSA, |
| 93 | hash, |
| 94 | })?; |
| 95 | let mut signature = [0; 128]; |
| 96 | let used = native::sign(&self.der, data, bits, &mut signature) |
| 97 | .map_err(|_| CryptoError::OperationFailed(CryptoOperation::Sign))?; |
| 98 | out.clear(); |
| 99 | out.extend_from_slice(&signature[..used]); |
| 100 | Ok(()) |
| 101 | } |
| 102 | } |