xref: /webrtc/dtls/src/prf/mod.rs (revision 5d8fe953)
1 #[cfg(test)]
2 mod prf_test;
3 
4 use std::convert::TryInto;
5 use std::fmt;
6 
7 use hmac::{Hmac, Mac};
8 use sha1::Sha1;
9 use sha2::Digest;
10 use sha2::Sha256;
11 
12 type HmacSha256 = Hmac<Sha256>;
13 type HmacSha1 = Hmac<Sha1>;
14 
15 use crate::cipher_suite::CipherSuiteHash;
16 use crate::content::ContentType;
17 use crate::curve::named_curve::*;
18 use crate::error::*;
19 use crate::record_layer::record_layer_header::ProtocolVersion;
20 
21 pub(crate) const PRF_MASTER_SECRET_LABEL: &str = "master secret";
22 pub(crate) const PRF_EXTENDED_MASTER_SECRET_LABEL: &str = "extended master secret";
23 pub(crate) const PRF_KEY_EXPANSION_LABEL: &str = "key expansion";
24 pub(crate) const PRF_VERIFY_DATA_CLIENT_LABEL: &str = "client finished";
25 pub(crate) const PRF_VERIFY_DATA_SERVER_LABEL: &str = "server finished";
26 
27 #[derive(PartialEq, Debug, Clone)]
28 pub(crate) struct EncryptionKeys {
29     pub(crate) master_secret: Vec<u8>,
30     pub(crate) client_mac_key: Vec<u8>,
31     pub(crate) server_mac_key: Vec<u8>,
32     pub(crate) client_write_key: Vec<u8>,
33     pub(crate) server_write_key: Vec<u8>,
34     pub(crate) client_write_iv: Vec<u8>,
35     pub(crate) server_write_iv: Vec<u8>,
36 }
37 
38 impl fmt::Display for EncryptionKeys {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result39     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40         let mut out = "EncryptionKeys:\n".to_string();
41 
42         out += format!("- master_secret: {:?}\n", self.master_secret).as_str();
43         out += format!("- client_mackey: {:?}\n", self.client_mac_key).as_str();
44         out += format!("- server_mackey: {:?}\n", self.server_mac_key).as_str();
45         out += format!("- client_write_key: {:?}\n", self.client_write_key).as_str();
46         out += format!("- server_write_key: {:?}\n", self.server_write_key).as_str();
47         out += format!("- client_write_iv: {:?}\n", self.client_write_iv).as_str();
48         out += format!("- server_write_iv: {:?}\n", self.server_write_iv).as_str();
49 
50         write!(f, "{out}")
51     }
52 }
53 
54 // The premaster secret is formed as follows: if the PSK is N octets
55 // long, concatenate a uint16 with the value N, N zero octets, a second
56 // uint16 with the value N, and the PSK itself.
57 //
58 // https://tools.ietf.org/html/rfc4279#section-2
prf_psk_pre_master_secret(psk: &[u8]) -> Vec<u8>59 pub(crate) fn prf_psk_pre_master_secret(psk: &[u8]) -> Vec<u8> {
60     let psk_len = psk.len();
61 
62     let mut out = vec![0u8; 2 + psk_len + 2];
63 
64     out.extend_from_slice(psk);
65     let be = (psk_len as u16).to_be_bytes();
66     out[..2].copy_from_slice(&be);
67     out[2 + psk_len..2 + psk_len + 2].copy_from_slice(&be);
68 
69     out
70 }
71 
prf_pre_master_secret( public_key: &[u8], private_key: &NamedCurvePrivateKey, curve: NamedCurve, ) -> Result<Vec<u8>>72 pub(crate) fn prf_pre_master_secret(
73     public_key: &[u8],
74     private_key: &NamedCurvePrivateKey,
75     curve: NamedCurve,
76 ) -> Result<Vec<u8>> {
77     match curve {
78         NamedCurve::P256 => elliptic_curve_pre_master_secret(public_key, private_key, curve),
79         NamedCurve::P384 => elliptic_curve_pre_master_secret(public_key, private_key, curve),
80         NamedCurve::X25519 => elliptic_curve_pre_master_secret(public_key, private_key, curve),
81         _ => Err(Error::ErrInvalidNamedCurve),
82     }
83 }
84 
elliptic_curve_pre_master_secret( public_key: &[u8], private_key: &NamedCurvePrivateKey, curve: NamedCurve, ) -> Result<Vec<u8>>85 fn elliptic_curve_pre_master_secret(
86     public_key: &[u8],
87     private_key: &NamedCurvePrivateKey,
88     curve: NamedCurve,
89 ) -> Result<Vec<u8>> {
90     match curve {
91         NamedCurve::P256 => {
92             let pub_key = p256::EncodedPoint::from_bytes(public_key)?;
93             let public = p256::PublicKey::from_sec1_bytes(pub_key.as_ref())?;
94             if let NamedCurvePrivateKey::EphemeralSecretP256(secret) = private_key {
95                 return Ok(secret.diffie_hellman(&public).raw_secret_bytes().to_vec());
96             }
97         }
98         NamedCurve::P384 => {
99             let pub_key = p384::EncodedPoint::from_bytes(public_key)?;
100             let public = p384::PublicKey::from_sec1_bytes(pub_key.as_ref())?;
101             if let NamedCurvePrivateKey::EphemeralSecretP384(secret) = private_key {
102                 return Ok(secret.diffie_hellman(&public).raw_secret_bytes().to_vec());
103             }
104         }
105         NamedCurve::X25519 => {
106             if public_key.len() != 32 {
107                 return Err(Error::Other("Public key is not 32 len".into()));
108             }
109             let pub_key: [u8; 32] = public_key.try_into().unwrap();
110             let public = x25519_dalek::PublicKey::from(pub_key);
111             if let NamedCurvePrivateKey::StaticSecretX25519(secret) = private_key {
112                 return Ok(secret.diffie_hellman(&public).as_bytes().to_vec());
113             }
114         }
115         _ => return Err(Error::ErrInvalidNamedCurve),
116     }
117     Err(Error::ErrNamedCurveAndPrivateKeyMismatch)
118 }
119 
120 //  This PRF with the SHA-256 hash function is used for all cipher suites
121 //  defined in this document and in TLS documents published prior to this
122 //  document when TLS 1.2 is negotiated.  New cipher suites MUST explicitly
123 //  specify a PRF and, in general, SHOULD use the TLS PRF with SHA-256 or a
124 //  stronger standard hash function.
125 //
126 //     P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
127 //                            HMAC_hash(secret, A(2) + seed) +
128 //                            HMAC_hash(secret, A(3) + seed) + ...
129 //
130 //  A() is defined as:
131 //
132 //     A(0) = seed
133 //     A(i) = HMAC_hash(secret, A(i-1))
134 //
135 //  P_hash can be iterated as many times as necessary to produce the
136 //  required quantity of data.  For example, if P_SHA256 is being used to
137 //  create 80 bytes of data, it will have to be iterated three times
138 //  (through A(3)), creating 96 bytes of output data; the last 16 bytes
139 //  of the final iteration will then be discarded, leaving 80 bytes of
140 //  output data.
141 //
142 // https://tools.ietf.org/html/rfc4346w
hmac_sha(h: CipherSuiteHash, key: &[u8], data: &[u8]) -> Result<Vec<u8>>143 fn hmac_sha(h: CipherSuiteHash, key: &[u8], data: &[u8]) -> Result<Vec<u8>> {
144     let mut mac = match h {
145         CipherSuiteHash::Sha256 => {
146             HmacSha256::new_from_slice(key).map_err(|e| Error::Other(e.to_string()))?
147         }
148     };
149     mac.update(data);
150     let result = mac.finalize();
151     let code_bytes = result.into_bytes();
152     Ok(code_bytes.to_vec())
153 }
154 
prf_p_hash( secret: &[u8], seed: &[u8], requested_length: usize, h: CipherSuiteHash, ) -> Result<Vec<u8>>155 pub(crate) fn prf_p_hash(
156     secret: &[u8],
157     seed: &[u8],
158     requested_length: usize,
159     h: CipherSuiteHash,
160 ) -> Result<Vec<u8>> {
161     let mut last_round = seed.to_vec();
162     let mut out = vec![];
163 
164     let iterations = ((requested_length as f64) / (h.size() as f64)).ceil() as usize;
165     for _ in 0..iterations {
166         last_round = hmac_sha(h, secret, &last_round)?;
167 
168         let mut last_round_seed = last_round.clone();
169         last_round_seed.extend_from_slice(seed);
170         let with_secret = hmac_sha(h, secret, &last_round_seed)?;
171 
172         out.extend_from_slice(&with_secret);
173     }
174 
175     Ok(out[..requested_length].to_vec())
176 }
177 
prf_extended_master_secret( pre_master_secret: &[u8], session_hash: &[u8], h: CipherSuiteHash, ) -> Result<Vec<u8>>178 pub(crate) fn prf_extended_master_secret(
179     pre_master_secret: &[u8],
180     session_hash: &[u8],
181     h: CipherSuiteHash,
182 ) -> Result<Vec<u8>> {
183     let mut seed = PRF_EXTENDED_MASTER_SECRET_LABEL.as_bytes().to_vec();
184     seed.extend_from_slice(session_hash);
185     prf_p_hash(pre_master_secret, &seed, 48, h)
186 }
187 
prf_master_secret( pre_master_secret: &[u8], client_random: &[u8], server_random: &[u8], h: CipherSuiteHash, ) -> Result<Vec<u8>>188 pub(crate) fn prf_master_secret(
189     pre_master_secret: &[u8],
190     client_random: &[u8],
191     server_random: &[u8],
192     h: CipherSuiteHash,
193 ) -> Result<Vec<u8>> {
194     let mut seed = PRF_MASTER_SECRET_LABEL.as_bytes().to_vec();
195     seed.extend_from_slice(client_random);
196     seed.extend_from_slice(server_random);
197     prf_p_hash(pre_master_secret, &seed, 48, h)
198 }
199 
prf_encryption_keys( master_secret: &[u8], client_random: &[u8], server_random: &[u8], prf_mac_len: usize, prf_key_len: usize, prf_iv_len: usize, h: CipherSuiteHash, ) -> Result<EncryptionKeys>200 pub(crate) fn prf_encryption_keys(
201     master_secret: &[u8],
202     client_random: &[u8],
203     server_random: &[u8],
204     prf_mac_len: usize,
205     prf_key_len: usize,
206     prf_iv_len: usize,
207     h: CipherSuiteHash,
208 ) -> Result<EncryptionKeys> {
209     let mut seed = PRF_KEY_EXPANSION_LABEL.as_bytes().to_vec();
210     seed.extend_from_slice(server_random);
211     seed.extend_from_slice(client_random);
212 
213     let material = prf_p_hash(
214         master_secret,
215         &seed,
216         (2 * prf_mac_len) + (2 * prf_key_len) + (2 * prf_iv_len),
217         h,
218     )?;
219     let mut key_material = &material[..];
220 
221     let client_mac_key = key_material[..prf_mac_len].to_vec();
222     key_material = &key_material[prf_mac_len..];
223 
224     let server_mac_key = key_material[..prf_mac_len].to_vec();
225     key_material = &key_material[prf_mac_len..];
226 
227     let client_write_key = key_material[..prf_key_len].to_vec();
228     key_material = &key_material[prf_key_len..];
229 
230     let server_write_key = key_material[..prf_key_len].to_vec();
231     key_material = &key_material[prf_key_len..];
232 
233     let client_write_iv = key_material[..prf_iv_len].to_vec();
234     key_material = &key_material[prf_iv_len..];
235 
236     let server_write_iv = key_material[..prf_iv_len].to_vec();
237 
238     Ok(EncryptionKeys {
239         master_secret: master_secret.to_vec(),
240         client_mac_key,
241         server_mac_key,
242         client_write_key,
243         server_write_key,
244         client_write_iv,
245         server_write_iv,
246     })
247 }
248 
prf_verify_data( master_secret: &[u8], handshake_bodies: &[u8], label: &str, h: CipherSuiteHash, ) -> Result<Vec<u8>>249 pub(crate) fn prf_verify_data(
250     master_secret: &[u8],
251     handshake_bodies: &[u8],
252     label: &str,
253     h: CipherSuiteHash,
254 ) -> Result<Vec<u8>> {
255     let mut hasher = match h {
256         CipherSuiteHash::Sha256 => Sha256::new(),
257     };
258     hasher.update(handshake_bodies);
259     let result = hasher.finalize();
260     let mut seed = label.as_bytes().to_vec();
261     seed.extend_from_slice(&result);
262 
263     prf_p_hash(master_secret, &seed, 12, h)
264 }
265 
prf_verify_data_client( master_secret: &[u8], handshake_bodies: &[u8], h: CipherSuiteHash, ) -> Result<Vec<u8>>266 pub(crate) fn prf_verify_data_client(
267     master_secret: &[u8],
268     handshake_bodies: &[u8],
269     h: CipherSuiteHash,
270 ) -> Result<Vec<u8>> {
271     prf_verify_data(
272         master_secret,
273         handshake_bodies,
274         PRF_VERIFY_DATA_CLIENT_LABEL,
275         h,
276     )
277 }
278 
prf_verify_data_server( master_secret: &[u8], handshake_bodies: &[u8], h: CipherSuiteHash, ) -> Result<Vec<u8>>279 pub(crate) fn prf_verify_data_server(
280     master_secret: &[u8],
281     handshake_bodies: &[u8],
282     h: CipherSuiteHash,
283 ) -> Result<Vec<u8>> {
284     prf_verify_data(
285         master_secret,
286         handshake_bodies,
287         PRF_VERIFY_DATA_SERVER_LABEL,
288         h,
289     )
290 }
291 
292 // compute the MAC using HMAC-SHA1
prf_mac( epoch: u16, sequence_number: u64, content_type: ContentType, protocol_version: ProtocolVersion, payload: &[u8], key: &[u8], ) -> Result<Vec<u8>>293 pub(crate) fn prf_mac(
294     epoch: u16,
295     sequence_number: u64,
296     content_type: ContentType,
297     protocol_version: ProtocolVersion,
298     payload: &[u8],
299     key: &[u8],
300 ) -> Result<Vec<u8>> {
301     let mut hmac = HmacSha1::new_from_slice(key).map_err(|e| Error::Other(e.to_string()))?;
302 
303     let mut msg = vec![0u8; 13];
304     msg[..2].copy_from_slice(&epoch.to_be_bytes());
305     msg[2..8].copy_from_slice(&sequence_number.to_be_bytes()[2..]);
306     msg[8] = content_type as u8;
307     msg[9] = protocol_version.major;
308     msg[10] = protocol_version.minor;
309     msg[11..].copy_from_slice(&(payload.len() as u16).to_be_bytes());
310 
311     hmac.update(&msg);
312     hmac.update(payload);
313     let result = hmac.finalize();
314 
315     Ok(result.into_bytes().to_vec())
316 }
317