/src/boringssl/ssl/t1_enc.cc
Line | Count | Source |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // Copyright 2005 Nokia. All rights reserved. |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | // you may not use this file except in compliance with the License. |
6 | | // You may obtain a copy of the License at |
7 | | // |
8 | | // https://www.apache.org/licenses/LICENSE-2.0 |
9 | | // |
10 | | // Unless required by applicable law or agreed to in writing, software |
11 | | // distributed under the License is distributed on an "AS IS" BASIS, |
12 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | // See the License for the specific language governing permissions and |
14 | | // limitations under the License. |
15 | | |
16 | | #include <openssl/ssl.h> |
17 | | |
18 | | #include <assert.h> |
19 | | #include <string.h> |
20 | | |
21 | | #include <string_view> |
22 | | #include <utility> |
23 | | |
24 | | #include <openssl/err.h> |
25 | | #include <openssl/evp.h> |
26 | | #include <openssl/hmac.h> |
27 | | #include <openssl/md5.h> |
28 | | #include <openssl/mem.h> |
29 | | #include <openssl/nid.h> |
30 | | #include <openssl/rand.h> |
31 | | #include <openssl/span.h> |
32 | | #include <openssl/tls_prf.h> |
33 | | |
34 | | #include "../crypto/internal.h" |
35 | | #include "internal.h" |
36 | | |
37 | | |
38 | | BSSL_NAMESPACE_BEGIN |
39 | | |
40 | | bool tls1_prf(const EVP_MD *digest, Span<uint8_t> out, |
41 | | Span<const uint8_t> secret, std::string_view label, |
42 | 166k | Span<const uint8_t> seed1, Span<const uint8_t> seed2) { |
43 | 166k | auto label_bytes = StringAsBytes(label); |
44 | 166k | return 1 == CRYPTO_tls1_prf(digest, out.data(), out.size(), secret.data(), |
45 | 166k | secret.size(), label_bytes.data(), |
46 | 166k | label_bytes.size(), seed1.data(), seed1.size(), |
47 | 166k | seed2.data(), seed2.size()); |
48 | 166k | } |
49 | | |
50 | | static bool get_key_block_lengths(const SSLImpl *ssl, |
51 | | size_t *out_mac_secret_len, |
52 | | size_t *out_key_len, size_t *out_iv_len, |
53 | 81.6k | const SSL_CIPHER *cipher) { |
54 | 81.6k | const EVP_AEAD *aead = nullptr; |
55 | 81.6k | if (!ssl_cipher_get_evp_aead(&aead, out_mac_secret_len, out_iv_len, cipher, |
56 | 81.6k | ssl_protocol_version(ssl))) { |
57 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); |
58 | 0 | return false; |
59 | 0 | } |
60 | | |
61 | 81.6k | *out_key_len = EVP_AEAD_key_length(aead); |
62 | 81.6k | if (*out_mac_secret_len > 0) { |
63 | | // For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the |
64 | | // key length reported by `EVP_AEAD_key_length` will include the MAC key |
65 | | // bytes and initial implicit IV. |
66 | 26.4k | if (*out_key_len < *out_mac_secret_len + *out_iv_len) { |
67 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
68 | 0 | return false; |
69 | 0 | } |
70 | 26.4k | *out_key_len -= *out_mac_secret_len + *out_iv_len; |
71 | 26.4k | } |
72 | | |
73 | 81.6k | return true; |
74 | 81.6k | } |
75 | | |
76 | | static bool generate_key_block(const SSLImpl *ssl, Span<uint8_t> out, |
77 | 42.0k | const SSLSession *session) { |
78 | 42.0k | const EVP_MD *digest = ssl_session_get_digest(session); |
79 | | // Note this function assumes that `session`'s key material corresponds to |
80 | | // `ssl->s3->client_random` and `ssl->s3->server_random`. |
81 | 42.0k | return tls1_prf(digest, out, session->secret, "key expansion", |
82 | 42.0k | ssl->s3->server_random, ssl->s3->client_random); |
83 | 42.0k | } |
84 | | |
85 | | bool tls1_configure_aead(SSLImpl *ssl, evp_aead_direction_t direction, |
86 | | Array<uint8_t> *key_block_cache, |
87 | | const SSLSession *session, |
88 | 81.6k | Span<const uint8_t> iv_override) { |
89 | 81.6k | size_t mac_secret_len, key_len, iv_len; |
90 | 81.6k | if (!get_key_block_lengths(ssl, &mac_secret_len, &key_len, &iv_len, |
91 | 81.6k | session->cipher)) { |
92 | 0 | return false; |
93 | 0 | } |
94 | | |
95 | | // Ensure that `key_block_cache` is set up. |
96 | 81.6k | const size_t key_block_size = 2 * (mac_secret_len + key_len + iv_len); |
97 | 81.6k | if (key_block_cache->empty()) { |
98 | 42.0k | if (!key_block_cache->InitForOverwrite(key_block_size) || |
99 | 42.0k | !generate_key_block(ssl, Span(*key_block_cache), session)) { |
100 | 0 | return false; |
101 | 0 | } |
102 | 42.0k | } |
103 | 81.6k | assert(key_block_cache->size() == key_block_size); |
104 | | |
105 | 81.6k | Span<const uint8_t> key_block = *key_block_cache; |
106 | 81.6k | Span<const uint8_t> mac_secret, key, iv; |
107 | 81.6k | if (direction == (ssl->server ? evp_aead_open : evp_aead_seal)) { |
108 | | // Use the client write (server read) keys. |
109 | 41.7k | mac_secret = key_block.subspan(0, mac_secret_len); |
110 | 41.7k | key = key_block.subspan(2 * mac_secret_len, key_len); |
111 | 41.7k | iv = key_block.subspan(2 * mac_secret_len + 2 * key_len, iv_len); |
112 | 41.7k | } else { |
113 | | // Use the server write (client read) keys. |
114 | 39.8k | mac_secret = key_block.subspan(mac_secret_len, mac_secret_len); |
115 | 39.8k | key = key_block.subspan(2 * mac_secret_len + key_len, key_len); |
116 | 39.8k | iv = key_block.subspan(2 * mac_secret_len + 2 * key_len + iv_len, iv_len); |
117 | 39.8k | } |
118 | | |
119 | 81.6k | if (!iv_override.empty()) { |
120 | 0 | if (iv_override.size() != iv_len) { |
121 | 0 | return false; |
122 | 0 | } |
123 | 0 | iv = iv_override; |
124 | 0 | } |
125 | | |
126 | 81.6k | UniquePtr<SSLAEADContext> aead_ctx = SSLAEADContext::Create( |
127 | 81.6k | direction, ssl->s3->version, session->cipher, key, mac_secret, iv); |
128 | 81.6k | if (!aead_ctx) { |
129 | 0 | return false; |
130 | 0 | } |
131 | | |
132 | 81.6k | if (direction == evp_aead_open) { |
133 | 40.1k | return ssl->method->set_read_state(ssl, ssl_encryption_application, |
134 | 40.1k | std::move(aead_ctx), |
135 | 40.1k | /*traffic_secret=*/{}); |
136 | 40.1k | } |
137 | | |
138 | 41.4k | return ssl->method->set_write_state(ssl, ssl_encryption_application, |
139 | 41.4k | std::move(aead_ctx), |
140 | 41.4k | /*traffic_secret=*/{}); |
141 | 81.6k | } |
142 | | |
143 | | bool tls1_change_cipher_state(SSL_HANDSHAKE *hs, |
144 | 81.6k | evp_aead_direction_t direction) { |
145 | 81.6k | return tls1_configure_aead(hs->ssl, direction, &hs->key_block, |
146 | 81.6k | ssl_handshake_session(hs), {}); |
147 | 81.6k | } |
148 | | |
149 | | bool tls1_generate_master_secret(SSL_HANDSHAKE *hs, Span<uint8_t> out, |
150 | 43.8k | Span<const uint8_t> premaster) { |
151 | 43.8k | BSSL_CHECK(out.size() == SSL3_MASTER_SECRET_SIZE); |
152 | | |
153 | 43.8k | const SSLImpl *ssl = hs->ssl; |
154 | 43.8k | if (hs->extended_master_secret) { |
155 | 41.2k | uint8_t digests[EVP_MAX_MD_SIZE]; |
156 | 41.2k | size_t digests_len; |
157 | 41.2k | if (!hs->transcript.GetHash(digests, &digests_len) || |
158 | 41.2k | !tls1_prf(hs->transcript.Digest(), out, premaster, |
159 | 41.2k | "extended master secret", Span(digests, digests_len), {})) { |
160 | 0 | return false; |
161 | 0 | } |
162 | 41.2k | } else { |
163 | 2.68k | if (!tls1_prf(hs->transcript.Digest(), out, premaster, "master secret", |
164 | 2.68k | ssl->s3->client_random, ssl->s3->server_random)) { |
165 | 0 | return false; |
166 | 0 | } |
167 | 2.68k | } |
168 | | |
169 | 43.8k | return true; |
170 | 43.8k | } |
171 | | |
172 | | BSSL_NAMESPACE_END |
173 | | |
174 | | using namespace bssl; |
175 | | |
176 | 0 | size_t SSL_get_key_block_len(const SSL *ssl) { |
177 | 0 | const auto *ssl_impl = FromOpaque(ssl); |
178 | | // See `SSL_generate_key_block`. |
179 | 0 | if (SSL_in_init(ssl_impl) || |
180 | 0 | ssl_protocol_version(ssl_impl) > TLS1_2_VERSION) { |
181 | 0 | return 0; |
182 | 0 | } |
183 | | |
184 | 0 | size_t mac_secret_len, key_len, fixed_iv_len; |
185 | 0 | if (!get_key_block_lengths(ssl_impl, &mac_secret_len, &key_len, &fixed_iv_len, |
186 | 0 | SSL_get_current_cipher(ssl_impl))) { |
187 | 0 | ERR_clear_error(); |
188 | 0 | return 0; |
189 | 0 | } |
190 | | |
191 | 0 | return 2 * (mac_secret_len + key_len + fixed_iv_len); |
192 | 0 | } |
193 | | |
194 | 0 | int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) { |
195 | 0 | const auto *ssl_impl = FromOpaque(ssl); |
196 | | // Which cipher state to use is ambiguous during a handshake. In particular, |
197 | | // there are points where read and write states are from different epochs. |
198 | | // During a handshake, before ChangeCipherSpec, the encryption states may not |
199 | | // match |ssl->s3->client_random| and |ssl->s3->server_random|. |
200 | 0 | if (SSL_in_init(ssl_impl) || |
201 | 0 | ssl_protocol_version(ssl_impl) > TLS1_2_VERSION) { |
202 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
203 | 0 | return 0; |
204 | 0 | } |
205 | | |
206 | 0 | return generate_key_block(ssl_impl, Span(out, out_len), |
207 | 0 | ssl_get_session(ssl_impl)); |
208 | 0 | } |
209 | | |
210 | | int SSL_export_keying_material(const SSL *ssl, uint8_t *out, size_t out_len, |
211 | | const char *label, size_t label_len, |
212 | | const uint8_t *context, size_t context_len, |
213 | 0 | int use_context) { |
214 | 0 | const auto *ssl_impl = FromOpaque(ssl); |
215 | 0 | auto out_span = Span(out, out_len); |
216 | 0 | std::string_view label_sv(label, label_len); |
217 | | // In TLS 1.3, the exporter may be used whenever the secret has been derived. |
218 | 0 | if (ssl_impl->s3->version != 0 && |
219 | 0 | ssl_protocol_version(ssl_impl) >= TLS1_3_VERSION) { |
220 | 0 | if (ssl_impl->s3->exporter_secret.empty()) { |
221 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_NOT_COMPLETE); |
222 | 0 | return 0; |
223 | 0 | } |
224 | 0 | if (!use_context) { |
225 | 0 | context = nullptr; |
226 | 0 | context_len = 0; |
227 | 0 | } |
228 | 0 | return tls13_export_keying_material(ssl_impl, out_span, |
229 | 0 | ssl_impl->s3->exporter_secret, label_sv, |
230 | 0 | Span(context, context_len)); |
231 | 0 | } |
232 | | |
233 | | // Exporters may be used in False Start, where the handshake has progressed |
234 | | // enough. Otherwise, they may not be used during a handshake. |
235 | 0 | if (SSL_in_init(ssl_impl) && !SSL_in_false_start(ssl_impl)) { |
236 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_NOT_COMPLETE); |
237 | 0 | return 0; |
238 | 0 | } |
239 | | |
240 | 0 | size_t seed_len = 2 * SSL3_RANDOM_SIZE; |
241 | 0 | if (use_context) { |
242 | 0 | if (context_len >= 1u << 16) { |
243 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); |
244 | 0 | return 0; |
245 | 0 | } |
246 | 0 | seed_len += 2 + context_len; |
247 | 0 | } |
248 | 0 | Array<uint8_t> seed; |
249 | 0 | if (!seed.InitForOverwrite(seed_len)) { |
250 | 0 | return 0; |
251 | 0 | } |
252 | | |
253 | 0 | OPENSSL_memcpy(seed.data(), ssl_impl->s3->client_random, SSL3_RANDOM_SIZE); |
254 | 0 | OPENSSL_memcpy(seed.data() + SSL3_RANDOM_SIZE, ssl_impl->s3->server_random, |
255 | 0 | SSL3_RANDOM_SIZE); |
256 | 0 | if (use_context) { |
257 | 0 | seed[2 * SSL3_RANDOM_SIZE] = static_cast<uint8_t>(context_len >> 8); |
258 | 0 | seed[2 * SSL3_RANDOM_SIZE + 1] = static_cast<uint8_t>(context_len); |
259 | 0 | OPENSSL_memcpy(seed.data() + 2 * SSL3_RANDOM_SIZE + 2, context, |
260 | 0 | context_len); |
261 | 0 | } |
262 | |
|
263 | 0 | const SSLSession *session = ssl_get_session(ssl_impl); |
264 | 0 | const EVP_MD *digest = ssl_session_get_digest(session); |
265 | 0 | return tls1_prf(digest, out_span, session->secret, label_sv, seed, {}); |
266 | 0 | } |