aws_nitro_enclaves_cose/crypto/
mod.rs

1//! (Signing) cryptography abstraction
2
3use crate::encrypt::CoseAlgorithm;
4use crate::error::CoseError;
5use crate::header_map::HeaderMap;
6#[cfg(feature = "openssl")]
7use ::openssl::symm::Cipher;
8use serde_repr::{Deserialize_repr, Serialize_repr};
9use std::str::FromStr;
10
11#[cfg(feature = "openssl")]
12mod openssl;
13
14#[cfg(feature = "openssl")]
15pub use self::openssl::Openssl;
16
17#[cfg(feature = "key_kms")]
18pub mod kms;
19#[cfg(feature = "key_openssl_pkey")]
20mod openssl_pkey;
21#[cfg(feature = "key_tpm")]
22pub mod tpm;
23
24/// A trait exposing a source of entropy
25pub trait Entropy {
26    /// Fill the provided `buff` with cryptographic random values.
27    fn rand_bytes(buff: &mut [u8]) -> Result<(), CoseError>;
28}
29
30/// A trait exposing various aead encryption algorithms.
31pub trait Encryption {
32    /// Encryption for AEAD ciphers such as AES GCM.
33    ///
34    /// Additional Authenticated Data (AEAD) can be provided in the `aad` field, and the authentication tag
35    /// will be copied into the `tag` field.
36    ///
37    /// The size of the `tag` buffer indicates the required size of the tag. While some ciphers support
38    /// a range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 bytes,
39    /// for example.
40    fn encrypt_aead(
41        algo: EncryptionAlgorithm,
42        key: &[u8],
43        iv: Option<&[u8]>,
44        aad: &[u8],
45        data: &[u8],
46        tag: &mut [u8],
47    ) -> Result<Vec<u8>, CoseError>;
48}
49
50/// Cryptographic algorithm that should be used with the `Encryption`/`Decryption` traits
51pub enum EncryptionAlgorithm {
52    /// 128-bit AES in Galois/Counter Mode
53    Aes128Gcm,
54    /// 192-bit AES in Galois/Counter Mode
55    Aes192Gcm,
56    /// 256-bit AES in Galois/Counter Mode
57    Aes256Gcm,
58}
59
60impl From<CoseAlgorithm> for EncryptionAlgorithm {
61    fn from(algo: CoseAlgorithm) -> EncryptionAlgorithm {
62        match algo {
63            CoseAlgorithm::AesGcm96_128_128 => EncryptionAlgorithm::Aes128Gcm,
64            CoseAlgorithm::AesGcm96_128_192 => EncryptionAlgorithm::Aes192Gcm,
65            CoseAlgorithm::AesGcm96_128_256 => EncryptionAlgorithm::Aes256Gcm,
66        }
67    }
68}
69
70#[cfg(feature = "openssl")]
71impl From<EncryptionAlgorithm> for Cipher {
72    fn from(algo: EncryptionAlgorithm) -> Cipher {
73        match algo {
74            EncryptionAlgorithm::Aes128Gcm => Cipher::aes_128_gcm(),
75            EncryptionAlgorithm::Aes192Gcm => Cipher::aes_192_gcm(),
76            EncryptionAlgorithm::Aes256Gcm => Cipher::aes_256_gcm(),
77        }
78    }
79}
80
81/// A trait exposing various aead decryption algorithms.
82pub trait Decryption {
83    /// Like `decrypt`, but for AEAD ciphers such as AES GCM.
84    ///
85    /// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag
86    /// should be provided in the `tag` field.
87    fn decrypt_aead(
88        algo: EncryptionAlgorithm,
89        key: &[u8],
90        iv: Option<&[u8]>,
91        aad: &[u8],
92        data: &[u8],
93        tag: &[u8],
94    ) -> Result<Vec<u8>, CoseError>;
95}
96
97/// Cryptographic hash algorithms that can be used with the `Hash` trait
98#[derive(Debug, Copy, Clone)]
99pub enum MessageDigest {
100    /// 256-bit Secure Hash Algorithm
101    Sha256,
102    /// 384-bit Secure Hash Algorithm
103    Sha384,
104    /// 512-bit Secure Hash Algorithm
105    Sha512,
106}
107
108#[cfg(feature = "openssl")]
109impl From<MessageDigest> for ::openssl::hash::MessageDigest {
110    fn from(digest: MessageDigest) -> Self {
111        match digest {
112            MessageDigest::Sha256 => ::openssl::hash::MessageDigest::sha256(),
113            MessageDigest::Sha384 => ::openssl::hash::MessageDigest::sha384(),
114            MessageDigest::Sha512 => ::openssl::hash::MessageDigest::sha512(),
115        }
116    }
117}
118
119/// A trait exposing various cryptographic hash algorithms
120pub trait Hash {
121    /// Computes the hash of the `data` with provided hash function
122    fn hash(digest: MessageDigest, data: &[u8]) -> Result<Vec<u8>, CoseError>;
123}
124
125/// A public key that can verify an existing signature
126pub trait SigningPublicKey {
127    /// This returns the signature algorithm and message digest to be used for this
128    /// public key.
129    fn get_parameters(&self) -> Result<(SignatureAlgorithm, MessageDigest), CoseError>;
130
131    /// Given a digest and a signature, returns a boolean whether the signature
132    /// was valid.
133    fn verify(&self, digest: &[u8], signature: &[u8]) -> Result<bool, CoseError>;
134}
135
136#[cfg(feature = "openssl")]
137fn merge_ec_signature(bytes_r: &[u8], bytes_s: &[u8], key_length: usize) -> Vec<u8> {
138    assert!(bytes_r.len() <= key_length);
139    assert!(bytes_s.len() <= key_length);
140
141    let mut signature_bytes = vec![0u8; key_length * 2];
142
143    // This is big-endian encoding so padding might be added at the start if the factor is
144    // too short.
145    let offset_copy = key_length - bytes_r.len();
146    signature_bytes[offset_copy..offset_copy + bytes_r.len()].copy_from_slice(bytes_r);
147
148    // This is big-endian encoding so padding might be added at the start if the factor is
149    // too short.
150    let offset_copy = key_length - bytes_s.len() + key_length;
151    signature_bytes[offset_copy..offset_copy + bytes_s.len()].copy_from_slice(bytes_s);
152
153    signature_bytes
154}
155
156/// A private key that can produce new signatures
157pub trait SigningPrivateKey: SigningPublicKey {
158    /// Given a digest, returns a signature
159    fn sign(&self, digest: &[u8]) -> Result<Vec<u8>, CoseError>;
160}
161
162/// Values from https://tools.ietf.org/html/rfc8152#section-8.1
163#[derive(Debug, Copy, Clone, Serialize_repr, Deserialize_repr)]
164#[repr(i8)]
165pub enum SignatureAlgorithm {
166    ///  ECDSA w/ SHA-256
167    ES256 = -7,
168    ///  ECDSA w/ SHA-384
169    ES384 = -35,
170    /// ECDSA w/ SHA-512
171    ES512 = -36,
172}
173
174impl SignatureAlgorithm {
175    /// Key length of the given signature algorithm
176    pub fn key_length(&self) -> usize {
177        match self {
178            SignatureAlgorithm::ES256 => 32,
179            SignatureAlgorithm::ES384 => 48,
180            // Not a typo
181            SignatureAlgorithm::ES512 => 66,
182        }
183    }
184
185    /// Suggested cryptographic hash function given a signature algorithm
186    pub fn suggested_message_digest(&self) -> MessageDigest {
187        match self {
188            SignatureAlgorithm::ES256 => MessageDigest::Sha256,
189            SignatureAlgorithm::ES384 => MessageDigest::Sha384,
190            SignatureAlgorithm::ES512 => MessageDigest::Sha512,
191        }
192    }
193}
194
195impl FromStr for SignatureAlgorithm {
196    type Err = CoseError;
197
198    fn from_str(s: &str) -> Result<Self, Self::Err> {
199        match s {
200            "ES256" => Ok(SignatureAlgorithm::ES256),
201            "ES384" => Ok(SignatureAlgorithm::ES384),
202            "ES512" => Ok(SignatureAlgorithm::ES512),
203            name => Err(CoseError::UnsupportedError(format!(
204                "Algorithm '{}' is not supported",
205                name
206            ))),
207        }
208    }
209}
210
211impl ToString for SignatureAlgorithm {
212    fn to_string(&self) -> String {
213        match self {
214            SignatureAlgorithm::ES256 => "ES256",
215            SignatureAlgorithm::ES384 => "ES384",
216            SignatureAlgorithm::ES512 => "ES512",
217        }
218        .to_string()
219    }
220}
221
222impl From<SignatureAlgorithm> for HeaderMap {
223    fn from(sig_alg: SignatureAlgorithm) -> Self {
224        // Convenience method for creating the map that would go into the signature structures
225        // Can be appended into a larger HeaderMap
226        // `1` is the index defined in the spec for Algorithm
227        let mut map = HeaderMap::new();
228        map.insert(1.into(), (sig_alg as i8).into());
229        map
230    }
231}