| 1 | use alloc::boxed::Box; |
| 2 | |
| 3 | use super::ring_like::hkdf::KeyType; |
| 4 | use super::ring_like::{aead, hkdf, hmac}; |
| 5 | use crate::crypto; |
| 6 | use crate::crypto::cipher::{ |
| 7 | AeadKey, InboundOpaqueMessage, Iv, MessageDecrypter, MessageEncrypter, Nonce, |
| 8 | Tls13AeadAlgorithm, UnsupportedOperationError, make_tls13_aad, |
| 9 | }; |
| 10 | use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock, OutputLengthError}; |
| 11 | use crate::enums::{CipherSuite, ContentType, ProtocolVersion}; |
| 12 | use crate::error::Error; |
| 13 | use crate::msgs::message::{ |
| 14 | InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, |
| 15 | }; |
| 16 | use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite}; |
| 17 | use crate::tls13::Tls13CipherSuite; |
| 18 | |
| 19 | /// The TLS1.3 ciphersuite TLS_CHACHA20_POLY1305_SHA256 |
| 20 | pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = |
| 21 | SupportedCipherSuite::Tls13(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); |
| 22 | |
| 23 | pub(crate) static TLS13_CHACHA20_POLY1305_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { |
| 24 | common: CipherSuiteCommon { |
| 25 | suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, |
| 26 | hash_provider: &super::hash::SHA256, |
| 27 | // ref: <https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.2.1> |
| 28 | confidentiality_limit: u64::MAX, |
| 29 | }, |
| 30 | hkdf_provider: &RingHkdf(hkdf::HKDF_SHA256, hmac::HMAC_SHA256), |
| 31 | aead_alg: &Chacha20Poly1305Aead(AeadAlgorithm(&aead::CHACHA20_POLY1305)), |
| 32 | quic: Some(&super::quic::KeyBuilder { |
| 33 | packet_alg: &aead::CHACHA20_POLY1305, |
| 34 | header_alg: &aead::quic::CHACHA20, |
| 35 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6> |
| 36 | confidentiality_limit: u64::MAX, |
| 37 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6> |
| 38 | integrity_limit: 1 << 36, |
| 39 | }), |
| 40 | }; |
| 41 | |
| 42 | /// The TLS1.3 ciphersuite TLS_AES_256_GCM_SHA384 |
| 43 | pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = |
| 44 | SupportedCipherSuite::Tls13(&Tls13CipherSuite { |
| 45 | common: CipherSuiteCommon { |
| 46 | suite: CipherSuite::TLS13_AES_256_GCM_SHA384, |
| 47 | hash_provider: &super::hash::SHA384, |
| 48 | confidentiality_limit: 1 << 24, |
| 49 | }, |
| 50 | hkdf_provider: &RingHkdf(hkdf::HKDF_SHA384, hmac::HMAC_SHA384), |
| 51 | aead_alg: &Aes256GcmAead(AeadAlgorithm(&aead::AES_256_GCM)), |
| 52 | quic: Some(&super::quic::KeyBuilder { |
| 53 | packet_alg: &aead::AES_256_GCM, |
| 54 | header_alg: &aead::quic::AES_256, |
| 55 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1> |
| 56 | confidentiality_limit: 1 << 23, |
| 57 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2> |
| 58 | integrity_limit: 1 << 52, |
| 59 | }), |
| 60 | }); |
| 61 | |
| 62 | /// The TLS1.3 ciphersuite TLS_AES_128_GCM_SHA256 |
| 63 | pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = |
| 64 | SupportedCipherSuite::Tls13(TLS13_AES_128_GCM_SHA256_INTERNAL); |
| 65 | |
| 66 | pub(crate) static TLS13_AES_128_GCM_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { |
| 67 | common: CipherSuiteCommon { |
| 68 | suite: CipherSuite::TLS13_AES_128_GCM_SHA256, |
| 69 | hash_provider: &super::hash::SHA256, |
| 70 | confidentiality_limit: 1 << 24, |
| 71 | }, |
| 72 | hkdf_provider: &RingHkdf(hkdf::HKDF_SHA256, hmac::HMAC_SHA256), |
| 73 | aead_alg: &Aes128GcmAead(AeadAlgorithm(&aead::AES_128_GCM)), |
| 74 | quic: Some(&super::quic::KeyBuilder { |
| 75 | packet_alg: &aead::AES_128_GCM, |
| 76 | header_alg: &aead::quic::AES_128, |
| 77 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1> |
| 78 | confidentiality_limit: 1 << 23, |
| 79 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2> |
| 80 | integrity_limit: 1 << 52, |
| 81 | }), |
| 82 | }; |
| 83 | |
| 84 | struct Chacha20Poly1305Aead(AeadAlgorithm); |
| 85 | |
| 86 | impl Tls13AeadAlgorithm for Chacha20Poly1305Aead { |
| 87 | fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { |
| 88 | self.0.encrypter(key, iv) |
| 89 | } |
| 90 | |
| 91 | fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { |
| 92 | self.0.decrypter(key, iv) |
| 93 | } |
| 94 | |
| 95 | fn key_len(&self) -> usize { |
| 96 | self.0.key_len() |
| 97 | } |
| 98 | |
| 99 | fn extract_keys( |
| 100 | &self, |
| 101 | key: AeadKey, |
| 102 | iv: Iv, |
| 103 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { |
| 104 | Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }) |
| 105 | } |
| 106 | |
| 107 | fn fips(&self) -> bool { |
| 108 | false // chacha20poly1305 not FIPS approved |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | struct Aes256GcmAead(AeadAlgorithm); |
| 113 | |
| 114 | impl Tls13AeadAlgorithm for Aes256GcmAead { |
| 115 | fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { |
| 116 | self.0.encrypter(key, iv) |
| 117 | } |
| 118 | |
| 119 | fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { |
| 120 | self.0.decrypter(key, iv) |
| 121 | } |
| 122 | |
| 123 | fn key_len(&self) -> usize { |
| 124 | self.0.key_len() |
| 125 | } |
| 126 | |
| 127 | fn extract_keys( |
| 128 | &self, |
| 129 | key: AeadKey, |
| 130 | iv: Iv, |
| 131 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { |
| 132 | Ok(ConnectionTrafficSecrets::Aes256Gcm { key, iv }) |
| 133 | } |
| 134 | |
| 135 | fn fips(&self) -> bool { |
| 136 | super::fips() |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | struct Aes128GcmAead(AeadAlgorithm); |
| 141 | |
| 142 | impl Tls13AeadAlgorithm for Aes128GcmAead { |
| 143 | fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { |
| 144 | self.0.encrypter(key, iv) |
| 145 | } |
| 146 | |
| 147 | fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { |
| 148 | self.0.decrypter(key, iv) |
| 149 | } |
| 150 | |
| 151 | fn key_len(&self) -> usize { |
| 152 | self.0.key_len() |
| 153 | } |
| 154 | |
| 155 | fn extract_keys( |
| 156 | &self, |
| 157 | key: AeadKey, |
| 158 | iv: Iv, |
| 159 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { |
| 160 | Ok(ConnectionTrafficSecrets::Aes128Gcm { key, iv }) |
| 161 | } |
| 162 | |
| 163 | fn fips(&self) -> bool { |
| 164 | super::fips() |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | // common encrypter/decrypter/key_len items for above Tls13AeadAlgorithm impls |
| 169 | struct AeadAlgorithm(&'static aead::Algorithm); |
| 170 | |
| 171 | impl AeadAlgorithm { |
| 172 | fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { |
| 173 | // safety: the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. |
| 174 | Box::new(Tls13MessageEncrypter { |
| 175 | enc_key: aead::LessSafeKey::new(key:aead::UnboundKey::new(self.0, key.as_ref()).unwrap()), |
| 176 | iv, |
| 177 | }) |
| 178 | } |
| 179 | |
| 180 | fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { |
| 181 | // safety: the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. |
| 182 | Box::new(Tls13MessageDecrypter { |
| 183 | dec_key: aead::LessSafeKey::new(key:aead::UnboundKey::new(self.0, key.as_ref()).unwrap()), |
| 184 | iv, |
| 185 | }) |
| 186 | } |
| 187 | |
| 188 | fn key_len(&self) -> usize { |
| 189 | self.0.key_len() |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | struct Tls13MessageEncrypter { |
| 194 | enc_key: aead::LessSafeKey, |
| 195 | iv: Iv, |
| 196 | } |
| 197 | |
| 198 | struct Tls13MessageDecrypter { |
| 199 | dec_key: aead::LessSafeKey, |
| 200 | iv: Iv, |
| 201 | } |
| 202 | |
| 203 | impl MessageEncrypter for Tls13MessageEncrypter { |
| 204 | fn encrypt( |
| 205 | &mut self, |
| 206 | msg: OutboundPlainMessage<'_>, |
| 207 | seq: u64, |
| 208 | ) -> Result<OutboundOpaqueMessage, Error> { |
| 209 | let total_len = self.encrypted_payload_len(msg.payload.len()); |
| 210 | let mut payload = PrefixedPayload::with_capacity(total_len); |
| 211 | |
| 212 | let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); |
| 213 | let aad = aead::Aad::from(make_tls13_aad(total_len)); |
| 214 | payload.extend_from_chunks(&msg.payload); |
| 215 | payload.extend_from_slice(&msg.typ.to_array()); |
| 216 | |
| 217 | self.enc_key |
| 218 | .seal_in_place_append_tag(nonce, aad, &mut payload) |
| 219 | .map_err(|_| Error::EncryptError)?; |
| 220 | |
| 221 | Ok(OutboundOpaqueMessage::new( |
| 222 | ContentType::ApplicationData, |
| 223 | // Note: all TLS 1.3 application data records use TLSv1_2 (0x0303) as the legacy record |
| 224 | // protocol version, see https://www.rfc-editor.org/rfc/rfc8446#section-5.1 |
| 225 | ProtocolVersion::TLSv1_2, |
| 226 | payload, |
| 227 | )) |
| 228 | } |
| 229 | |
| 230 | fn encrypted_payload_len(&self, payload_len: usize) -> usize { |
| 231 | payload_len + 1 + self.enc_key.algorithm().tag_len() |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | impl MessageDecrypter for Tls13MessageDecrypter { |
| 236 | fn decrypt<'a>( |
| 237 | &mut self, |
| 238 | mut msg: InboundOpaqueMessage<'a>, |
| 239 | seq: u64, |
| 240 | ) -> Result<InboundPlainMessage<'a>, Error> { |
| 241 | let payload: &mut BorrowedPayload<'a> = &mut msg.payload; |
| 242 | if payload.len() < self.dec_key.algorithm().tag_len() { |
| 243 | return Err(Error::DecryptError); |
| 244 | } |
| 245 | |
| 246 | let nonce: Nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); |
| 247 | let aad: Aad<[u8; 5]> = aead::Aad::from(make_tls13_aad(payload.len())); |
| 248 | let plain_len: usize = self |
| 249 | .dec_key |
| 250 | .open_in_place(nonce, aad, payload) |
| 251 | .map_err(|_| Error::DecryptError)? |
| 252 | .len(); |
| 253 | |
| 254 | payload.truncate(plain_len); |
| 255 | msg.into_tls13_unpadded_message() |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | struct RingHkdf(hkdf::Algorithm, hmac::Algorithm); |
| 260 | |
| 261 | impl Hkdf for RingHkdf { |
| 262 | fn extract_from_zero_ikm(&self, salt: Option<&[u8]>) -> Box<dyn HkdfExpander> { |
| 263 | let zeroes = [0u8; OkmBlock::MAX_LEN]; |
| 264 | let salt = match salt { |
| 265 | Some(salt) => salt, |
| 266 | None => &zeroes[..self.0.len()], |
| 267 | }; |
| 268 | Box::new(RingHkdfExpander { |
| 269 | alg: self.0, |
| 270 | prk: hkdf::Salt::new(self.0, salt).extract(&zeroes[..self.0.len()]), |
| 271 | }) |
| 272 | } |
| 273 | |
| 274 | fn extract_from_secret(&self, salt: Option<&[u8]>, secret: &[u8]) -> Box<dyn HkdfExpander> { |
| 275 | let zeroes = [0u8; OkmBlock::MAX_LEN]; |
| 276 | let salt = match salt { |
| 277 | Some(salt) => salt, |
| 278 | None => &zeroes[..self.0.len()], |
| 279 | }; |
| 280 | Box::new(RingHkdfExpander { |
| 281 | alg: self.0, |
| 282 | prk: hkdf::Salt::new(self.0, salt).extract(secret), |
| 283 | }) |
| 284 | } |
| 285 | |
| 286 | fn expander_for_okm(&self, okm: &OkmBlock) -> Box<dyn HkdfExpander> { |
| 287 | Box::new(RingHkdfExpander { |
| 288 | alg: self.0, |
| 289 | prk: hkdf::Prk::new_less_safe(self.0, okm.as_ref()), |
| 290 | }) |
| 291 | } |
| 292 | |
| 293 | fn hmac_sign(&self, key: &OkmBlock, message: &[u8]) -> crypto::hmac::Tag { |
| 294 | crypto::hmac::Tag::new(hmac::sign(&hmac::Key::new(self.1, key.as_ref()), message).as_ref()) |
| 295 | } |
| 296 | |
| 297 | fn fips(&self) -> bool { |
| 298 | super::fips() |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | struct RingHkdfExpander { |
| 303 | alg: hkdf::Algorithm, |
| 304 | prk: hkdf::Prk, |
| 305 | } |
| 306 | |
| 307 | impl HkdfExpander for RingHkdfExpander { |
| 308 | fn expand_slice(&self, info: &[&[u8]], output: &mut [u8]) -> Result<(), OutputLengthError> { |
| 309 | self.prk |
| 310 | .expand(info, Len(output.len())) |
| 311 | .and_then(|okm| okm.fill(output)) |
| 312 | .map_err(|_| OutputLengthError) |
| 313 | } |
| 314 | |
| 315 | fn expand_block(&self, info: &[&[u8]]) -> OkmBlock { |
| 316 | let mut buf: [u8; 64] = [0u8; OkmBlock::MAX_LEN]; |
| 317 | let output: &mut [u8] = &mut buf[..self.hash_len()]; |
| 318 | self.prk |
| 319 | .expand(info, Len(output.len())) |
| 320 | .and_then(|okm: Okm<'_, Len>| okm.fill(out:output)) |
| 321 | .unwrap(); |
| 322 | OkmBlock::new(bytes:output) |
| 323 | } |
| 324 | |
| 325 | fn hash_len(&self) -> usize { |
| 326 | self.alg.len() |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | struct Len(usize); |
| 331 | |
| 332 | impl KeyType for Len { |
| 333 | fn len(&self) -> usize { |
| 334 | self.0 |
| 335 | } |
| 336 | } |
| 337 | |