| 1 | use alloc::boxed::Box; |
| 2 | |
| 3 | use super::ring_like::aead; |
| 4 | use crate::crypto::KeyExchangeAlgorithm; |
| 5 | use crate::crypto::cipher::{ |
| 6 | AeadKey, InboundOpaqueMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter, |
| 7 | NONCE_LEN, Nonce, Tls12AeadAlgorithm, UnsupportedOperationError, make_tls12_aad, |
| 8 | }; |
| 9 | use crate::crypto::tls12::PrfUsingHmac; |
| 10 | use crate::enums::{CipherSuite, SignatureScheme}; |
| 11 | use crate::error::Error; |
| 12 | use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; |
| 13 | use crate::msgs::message::{ |
| 14 | InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, |
| 15 | }; |
| 16 | use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite}; |
| 17 | use crate::tls12::Tls12CipherSuite; |
| 18 | |
| 19 | /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256. |
| 20 | pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = |
| 21 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
| 22 | common: CipherSuiteCommon { |
| 23 | suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, |
| 24 | hash_provider: &super::hash::SHA256, |
| 25 | confidentiality_limit: u64::MAX, |
| 26 | }, |
| 27 | kx: KeyExchangeAlgorithm::ECDHE, |
| 28 | sign: TLS12_ECDSA_SCHEMES, |
| 29 | aead_alg: &ChaCha20Poly1305, |
| 30 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), |
| 31 | }); |
| 32 | |
| 33 | /// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 |
| 34 | pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = |
| 35 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
| 36 | common: CipherSuiteCommon { |
| 37 | suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, |
| 38 | hash_provider: &super::hash::SHA256, |
| 39 | confidentiality_limit: u64::MAX, |
| 40 | }, |
| 41 | kx: KeyExchangeAlgorithm::ECDHE, |
| 42 | sign: TLS12_RSA_SCHEMES, |
| 43 | aead_alg: &ChaCha20Poly1305, |
| 44 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), |
| 45 | }); |
| 46 | |
| 47 | /// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 |
| 48 | pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = |
| 49 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
| 50 | common: CipherSuiteCommon { |
| 51 | suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
| 52 | hash_provider: &super::hash::SHA256, |
| 53 | confidentiality_limit: 1 << 24, |
| 54 | }, |
| 55 | kx: KeyExchangeAlgorithm::ECDHE, |
| 56 | sign: TLS12_RSA_SCHEMES, |
| 57 | aead_alg: &AES128_GCM, |
| 58 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), |
| 59 | }); |
| 60 | |
| 61 | /// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 |
| 62 | pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = |
| 63 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
| 64 | common: CipherSuiteCommon { |
| 65 | suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, |
| 66 | hash_provider: &super::hash::SHA384, |
| 67 | confidentiality_limit: 1 << 24, |
| 68 | }, |
| 69 | kx: KeyExchangeAlgorithm::ECDHE, |
| 70 | sign: TLS12_RSA_SCHEMES, |
| 71 | aead_alg: &AES256_GCM, |
| 72 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384), |
| 73 | }); |
| 74 | |
| 75 | /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 |
| 76 | pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = |
| 77 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
| 78 | common: CipherSuiteCommon { |
| 79 | suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
| 80 | hash_provider: &super::hash::SHA256, |
| 81 | confidentiality_limit: 1 << 24, |
| 82 | }, |
| 83 | kx: KeyExchangeAlgorithm::ECDHE, |
| 84 | sign: TLS12_ECDSA_SCHEMES, |
| 85 | aead_alg: &AES128_GCM, |
| 86 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), |
| 87 | }); |
| 88 | |
| 89 | /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 |
| 90 | pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = |
| 91 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
| 92 | common: CipherSuiteCommon { |
| 93 | suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, |
| 94 | hash_provider: &super::hash::SHA384, |
| 95 | confidentiality_limit: 1 << 24, |
| 96 | }, |
| 97 | kx: KeyExchangeAlgorithm::ECDHE, |
| 98 | sign: TLS12_ECDSA_SCHEMES, |
| 99 | aead_alg: &AES256_GCM, |
| 100 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384), |
| 101 | }); |
| 102 | |
| 103 | static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[ |
| 104 | SignatureScheme::ED25519, |
| 105 | SignatureScheme::ECDSA_NISTP521_SHA512, |
| 106 | SignatureScheme::ECDSA_NISTP384_SHA384, |
| 107 | SignatureScheme::ECDSA_NISTP256_SHA256, |
| 108 | ]; |
| 109 | |
| 110 | static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[ |
| 111 | SignatureScheme::RSA_PSS_SHA512, |
| 112 | SignatureScheme::RSA_PSS_SHA384, |
| 113 | SignatureScheme::RSA_PSS_SHA256, |
| 114 | SignatureScheme::RSA_PKCS1_SHA512, |
| 115 | SignatureScheme::RSA_PKCS1_SHA384, |
| 116 | SignatureScheme::RSA_PKCS1_SHA256, |
| 117 | ]; |
| 118 | |
| 119 | pub(crate) static AES128_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_128_GCM); |
| 120 | pub(crate) static AES256_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_256_GCM); |
| 121 | |
| 122 | pub(crate) struct GcmAlgorithm(&'static aead::Algorithm); |
| 123 | |
| 124 | impl Tls12AeadAlgorithm for GcmAlgorithm { |
| 125 | fn decrypter(&self, dec_key: AeadKey, dec_iv: &[u8]) -> Box<dyn MessageDecrypter> { |
| 126 | let dec_key = |
| 127 | aead::LessSafeKey::new(aead::UnboundKey::new(self.0, dec_key.as_ref()).unwrap()); |
| 128 | |
| 129 | let mut ret = GcmMessageDecrypter { |
| 130 | dec_key, |
| 131 | dec_salt: [0u8; 4], |
| 132 | }; |
| 133 | |
| 134 | debug_assert_eq!(dec_iv.len(), 4); |
| 135 | ret.dec_salt.copy_from_slice(dec_iv); |
| 136 | Box::new(ret) |
| 137 | } |
| 138 | |
| 139 | fn encrypter( |
| 140 | &self, |
| 141 | enc_key: AeadKey, |
| 142 | write_iv: &[u8], |
| 143 | explicit: &[u8], |
| 144 | ) -> Box<dyn MessageEncrypter> { |
| 145 | let enc_key = |
| 146 | aead::LessSafeKey::new(aead::UnboundKey::new(self.0, enc_key.as_ref()).unwrap()); |
| 147 | let iv = gcm_iv(write_iv, explicit); |
| 148 | Box::new(GcmMessageEncrypter { enc_key, iv }) |
| 149 | } |
| 150 | |
| 151 | fn key_block_shape(&self) -> KeyBlockShape { |
| 152 | KeyBlockShape { |
| 153 | enc_key_len: self.0.key_len(), |
| 154 | fixed_iv_len: 4, |
| 155 | explicit_nonce_len: 8, |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | fn extract_keys( |
| 160 | &self, |
| 161 | key: AeadKey, |
| 162 | write_iv: &[u8], |
| 163 | explicit: &[u8], |
| 164 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { |
| 165 | let iv = gcm_iv(write_iv, explicit); |
| 166 | Ok(match self.0.key_len() { |
| 167 | 16 => ConnectionTrafficSecrets::Aes128Gcm { key, iv }, |
| 168 | 32 => ConnectionTrafficSecrets::Aes256Gcm { key, iv }, |
| 169 | _ => unreachable!(), |
| 170 | }) |
| 171 | } |
| 172 | |
| 173 | fn fips(&self) -> bool { |
| 174 | super::fips() |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | pub(crate) struct ChaCha20Poly1305; |
| 179 | |
| 180 | impl Tls12AeadAlgorithm for ChaCha20Poly1305 { |
| 181 | fn decrypter(&self, dec_key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter> { |
| 182 | let dec_key = aead::LessSafeKey::new( |
| 183 | aead::UnboundKey::new(&aead::CHACHA20_POLY1305, dec_key.as_ref()).unwrap(), |
| 184 | ); |
| 185 | Box::new(ChaCha20Poly1305MessageDecrypter { |
| 186 | dec_key, |
| 187 | dec_offset: Iv::copy(iv), |
| 188 | }) |
| 189 | } |
| 190 | |
| 191 | fn encrypter(&self, enc_key: AeadKey, enc_iv: &[u8], _: &[u8]) -> Box<dyn MessageEncrypter> { |
| 192 | let enc_key = aead::LessSafeKey::new( |
| 193 | aead::UnboundKey::new(&aead::CHACHA20_POLY1305, enc_key.as_ref()).unwrap(), |
| 194 | ); |
| 195 | Box::new(ChaCha20Poly1305MessageEncrypter { |
| 196 | enc_key, |
| 197 | enc_offset: Iv::copy(enc_iv), |
| 198 | }) |
| 199 | } |
| 200 | |
| 201 | fn key_block_shape(&self) -> KeyBlockShape { |
| 202 | KeyBlockShape { |
| 203 | enc_key_len: 32, |
| 204 | fixed_iv_len: 12, |
| 205 | explicit_nonce_len: 0, |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | fn extract_keys( |
| 210 | &self, |
| 211 | key: AeadKey, |
| 212 | iv: &[u8], |
| 213 | _explicit: &[u8], |
| 214 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { |
| 215 | // This should always be true because KeyBlockShape and the Iv nonce len are in agreement. |
| 216 | debug_assert_eq!(aead::NONCE_LEN, iv.len()); |
| 217 | Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { |
| 218 | key, |
| 219 | iv: Iv::new(iv[..].try_into().unwrap()), |
| 220 | }) |
| 221 | } |
| 222 | |
| 223 | fn fips(&self) -> bool { |
| 224 | false // not fips approved |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | /// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only. |
| 229 | struct GcmMessageEncrypter { |
| 230 | enc_key: aead::LessSafeKey, |
| 231 | iv: Iv, |
| 232 | } |
| 233 | |
| 234 | /// A `MessageDecrypter` for AES-GCM AEAD ciphersuites. TLS1.2 only. |
| 235 | struct GcmMessageDecrypter { |
| 236 | dec_key: aead::LessSafeKey, |
| 237 | dec_salt: [u8; 4], |
| 238 | } |
| 239 | |
| 240 | const GCM_EXPLICIT_NONCE_LEN: usize = 8; |
| 241 | const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16; |
| 242 | |
| 243 | impl MessageDecrypter for GcmMessageDecrypter { |
| 244 | fn decrypt<'a>( |
| 245 | &mut self, |
| 246 | mut msg: InboundOpaqueMessage<'a>, |
| 247 | seq: u64, |
| 248 | ) -> Result<InboundPlainMessage<'a>, Error> { |
| 249 | let payload = &msg.payload; |
| 250 | if payload.len() < GCM_OVERHEAD { |
| 251 | return Err(Error::DecryptError); |
| 252 | } |
| 253 | |
| 254 | let nonce = { |
| 255 | let mut nonce = [0u8; 12]; |
| 256 | nonce[..4].copy_from_slice(&self.dec_salt); |
| 257 | nonce[4..].copy_from_slice(&payload[..8]); |
| 258 | aead::Nonce::assume_unique_for_key(nonce) |
| 259 | }; |
| 260 | |
| 261 | let aad = aead::Aad::from(make_tls12_aad( |
| 262 | seq, |
| 263 | msg.typ, |
| 264 | msg.version, |
| 265 | payload.len() - GCM_OVERHEAD, |
| 266 | )); |
| 267 | |
| 268 | let payload = &mut msg.payload; |
| 269 | let plain_len = self |
| 270 | .dec_key |
| 271 | .open_within(nonce, aad, payload, GCM_EXPLICIT_NONCE_LEN..) |
| 272 | .map_err(|_| Error::DecryptError)? |
| 273 | .len(); |
| 274 | |
| 275 | if plain_len > MAX_FRAGMENT_LEN { |
| 276 | return Err(Error::PeerSentOversizedRecord); |
| 277 | } |
| 278 | |
| 279 | payload.truncate(plain_len); |
| 280 | Ok(msg.into_plain_message()) |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | impl MessageEncrypter for GcmMessageEncrypter { |
| 285 | fn encrypt( |
| 286 | &mut self, |
| 287 | msg: OutboundPlainMessage<'_>, |
| 288 | seq: u64, |
| 289 | ) -> Result<OutboundOpaqueMessage, Error> { |
| 290 | let total_len = self.encrypted_payload_len(msg.payload.len()); |
| 291 | let mut payload = PrefixedPayload::with_capacity(total_len); |
| 292 | |
| 293 | let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); |
| 294 | let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len())); |
| 295 | payload.extend_from_slice(&nonce.as_ref()[4..]); |
| 296 | payload.extend_from_chunks(&msg.payload); |
| 297 | |
| 298 | self.enc_key |
| 299 | .seal_in_place_separate_tag(nonce, aad, &mut payload.as_mut()[GCM_EXPLICIT_NONCE_LEN..]) |
| 300 | .map(|tag| payload.extend_from_slice(tag.as_ref())) |
| 301 | .map_err(|_| Error::EncryptError)?; |
| 302 | |
| 303 | Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload)) |
| 304 | } |
| 305 | |
| 306 | fn encrypted_payload_len(&self, payload_len: usize) -> usize { |
| 307 | payload_len + GCM_EXPLICIT_NONCE_LEN + self.enc_key.algorithm().tag_len() |
| 308 | } |
| 309 | } |
| 310 | |
| 311 | /// The RFC7905/RFC7539 ChaCha20Poly1305 construction. |
| 312 | /// This implementation does the AAD construction required in TLS1.2. |
| 313 | /// TLS1.3 uses `TLS13MessageEncrypter`. |
| 314 | struct ChaCha20Poly1305MessageEncrypter { |
| 315 | enc_key: aead::LessSafeKey, |
| 316 | enc_offset: Iv, |
| 317 | } |
| 318 | |
| 319 | /// The RFC7905/RFC7539 ChaCha20Poly1305 construction. |
| 320 | /// This implementation does the AAD construction required in TLS1.2. |
| 321 | /// TLS1.3 uses `TLS13MessageDecrypter`. |
| 322 | struct ChaCha20Poly1305MessageDecrypter { |
| 323 | dec_key: aead::LessSafeKey, |
| 324 | dec_offset: Iv, |
| 325 | } |
| 326 | |
| 327 | const CHACHAPOLY1305_OVERHEAD: usize = 16; |
| 328 | |
| 329 | impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter { |
| 330 | fn decrypt<'a>( |
| 331 | &mut self, |
| 332 | mut msg: InboundOpaqueMessage<'a>, |
| 333 | seq: u64, |
| 334 | ) -> Result<InboundPlainMessage<'a>, Error> { |
| 335 | let payload = &msg.payload; |
| 336 | |
| 337 | if payload.len() < CHACHAPOLY1305_OVERHEAD { |
| 338 | return Err(Error::DecryptError); |
| 339 | } |
| 340 | |
| 341 | let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.dec_offset, seq).0); |
| 342 | let aad = aead::Aad::from(make_tls12_aad( |
| 343 | seq, |
| 344 | msg.typ, |
| 345 | msg.version, |
| 346 | payload.len() - CHACHAPOLY1305_OVERHEAD, |
| 347 | )); |
| 348 | |
| 349 | let payload = &mut msg.payload; |
| 350 | let plain_len = self |
| 351 | .dec_key |
| 352 | .open_in_place(nonce, aad, payload) |
| 353 | .map_err(|_| Error::DecryptError)? |
| 354 | .len(); |
| 355 | |
| 356 | if plain_len > MAX_FRAGMENT_LEN { |
| 357 | return Err(Error::PeerSentOversizedRecord); |
| 358 | } |
| 359 | |
| 360 | payload.truncate(plain_len); |
| 361 | Ok(msg.into_plain_message()) |
| 362 | } |
| 363 | } |
| 364 | |
| 365 | impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter { |
| 366 | fn encrypt( |
| 367 | &mut self, |
| 368 | msg: OutboundPlainMessage<'_>, |
| 369 | seq: u64, |
| 370 | ) -> Result<OutboundOpaqueMessage, Error> { |
| 371 | let total_len: usize = self.encrypted_payload_len(msg.payload.len()); |
| 372 | let mut payload: PrefixedPayload = PrefixedPayload::with_capacity(total_len); |
| 373 | |
| 374 | let nonce: Nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.enc_offset, seq).0); |
| 375 | let aad: Aad<[u8; 13]> = aead::Aad::from(make_tls12_aad(seq, msg.typ, vers:msg.version, msg.payload.len())); |
| 376 | payload.extend_from_chunks(&msg.payload); |
| 377 | |
| 378 | self.enc_key |
| 379 | .seal_in_place_append_tag(nonce, aad, &mut payload) |
| 380 | .map_err(|_| Error::EncryptError)?; |
| 381 | |
| 382 | Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload)) |
| 383 | } |
| 384 | |
| 385 | fn encrypted_payload_len(&self, payload_len: usize) -> usize { |
| 386 | payload_len + self.enc_key.algorithm().tag_len() |
| 387 | } |
| 388 | } |
| 389 | |
| 390 | fn gcm_iv(write_iv: &[u8], explicit: &[u8]) -> Iv { |
| 391 | debug_assert_eq!(write_iv.len(), 4); |
| 392 | debug_assert_eq!(explicit.len(), 8); |
| 393 | |
| 394 | // The GCM nonce is constructed from a 32-bit 'salt' derived |
| 395 | // from the master-secret, and a 64-bit explicit part, |
| 396 | // with no specified construction. Thanks for that. |
| 397 | // |
| 398 | // We use the same construction as TLS1.3/ChaCha20Poly1305: |
| 399 | // a starting point extracted from the key block, xored with |
| 400 | // the sequence number. |
| 401 | let mut iv: [u8; 12] = [0; NONCE_LEN]; |
| 402 | iv[..4].copy_from_slice(src:write_iv); |
| 403 | iv[4..].copy_from_slice(src:explicit); |
| 404 | |
| 405 | Iv::new(iv) |
| 406 | } |
| 407 | |