Mercurial > hg > nginx
comparison src/event/ngx_event_openssl.c @ 8182:b28ea685a56e quic
Moved all QUIC code into ngx_event_quic.c
Introduced ngx_quic_input() and ngx_quic_output() as interface between
nginx and protocol. They are the only functions that are exported.
While there, added copyrights.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Fri, 28 Feb 2020 16:23:25 +0300 |
parents | 3cb4f16426a5 |
children | 253cf267f95a |
comparison
equal
deleted
inserted
replaced
8181:3cb4f16426a5 | 8182:b28ea685a56e |
---|---|
88 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); | 88 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); |
89 static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | 89 static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); |
90 static void ngx_openssl_exit(ngx_cycle_t *cycle); | 90 static void ngx_openssl_exit(ngx_cycle_t *cycle); |
91 | 91 |
92 | 92 |
93 #if NGX_OPENSSL_QUIC | |
94 | |
95 static int | |
96 quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, | |
97 enum ssl_encryption_level_t level, const uint8_t *read_secret, | |
98 const uint8_t *write_secret, size_t secret_len) | |
99 { | |
100 u_char *name; | |
101 ngx_uint_t i; | |
102 const EVP_MD *digest; | |
103 const EVP_CIPHER *cipher; | |
104 ngx_connection_t *c; | |
105 ngx_quic_secret_t *client, *server; | |
106 | |
107 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
108 | |
109 ngx_ssl_handshake_log(c); | |
110 | |
111 #if (NGX_DEBUG) | |
112 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { | |
113 u_char buf[64]; | |
114 size_t m; | |
115 | |
116 m = ngx_hex_dump(buf, (u_char *) read_secret, secret_len) - buf; | |
117 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
118 "set_encryption_secrets: read %*s, len: %uz, level:%d", | |
119 m, buf, secret_len, (int) level); | |
120 | |
121 m = ngx_hex_dump(buf, (u_char *) write_secret, secret_len) - buf; | |
122 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
123 "set_encryption_secrets: write %*s, len: %uz, level:%d", | |
124 m, buf, secret_len, (int) level); | |
125 } | |
126 #endif | |
127 | |
128 name = (u_char *) SSL_get_cipher(ssl_conn); | |
129 | |
130 if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0 | |
131 || ngx_strcasecmp(name, (u_char *) "(NONE)") == 0) | |
132 { | |
133 cipher = EVP_aes_128_gcm(); | |
134 digest = EVP_sha256(); | |
135 | |
136 } else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) { | |
137 cipher = EVP_aes_256_gcm(); | |
138 digest = EVP_sha384(); | |
139 | |
140 } else { | |
141 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher"); | |
142 return 0; | |
143 } | |
144 | |
145 switch (level) { | |
146 | |
147 case ssl_encryption_handshake: | |
148 client = &c->quic->client_hs; | |
149 server = &c->quic->server_hs; | |
150 | |
151 break; | |
152 | |
153 case ssl_encryption_application: | |
154 client = &c->quic->client_ad; | |
155 server = &c->quic->server_ad; | |
156 | |
157 break; | |
158 | |
159 default: | |
160 return 0; | |
161 } | |
162 | |
163 client->key.len = EVP_CIPHER_key_length(cipher); | |
164 server->key.len = EVP_CIPHER_key_length(cipher); | |
165 | |
166 client->iv.len = EVP_CIPHER_iv_length(cipher); | |
167 server->iv.len = EVP_CIPHER_iv_length(cipher); | |
168 | |
169 client->hp.len = EVP_CIPHER_key_length(cipher); | |
170 server->hp.len = EVP_CIPHER_key_length(cipher); | |
171 | |
172 struct { | |
173 ngx_str_t label; | |
174 ngx_str_t *key; | |
175 const uint8_t *secret; | |
176 } seq[] = { | |
177 { ngx_string("tls13 quic key"), &client->key, read_secret }, | |
178 { ngx_string("tls13 quic iv"), &client->iv, read_secret }, | |
179 { ngx_string("tls13 quic hp"), &client->hp, read_secret }, | |
180 { ngx_string("tls13 quic key"), &server->key, write_secret }, | |
181 { ngx_string("tls13 quic iv"), &server->iv, write_secret }, | |
182 { ngx_string("tls13 quic hp"), &server->hp, write_secret }, | |
183 }; | |
184 | |
185 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { | |
186 | |
187 if (ngx_quic_hkdf_expand(c, digest, seq[i].key, &seq[i].label, | |
188 seq[i].secret, secret_len) | |
189 != NGX_OK) | |
190 { | |
191 return 0; | |
192 } | |
193 } | |
194 | |
195 return 1; | |
196 } | |
197 | |
198 | |
199 static int | |
200 quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | |
201 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) | |
202 { | |
203 u_char *p, *pnp, *name, *nonce, *sample; | |
204 ngx_int_t m; | |
205 ngx_str_t in, out, ad; | |
206 static int pn; | |
207 const EVP_CIPHER *cipher; | |
208 ngx_connection_t *c; | |
209 ngx_quic_secret_t *secret; | |
210 ngx_quic_connection_t *qc; | |
211 u_char buf[2048], mask[16]; | |
212 | |
213 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
214 qc = c->quic; | |
215 | |
216 ngx_ssl_handshake_log(c); | |
217 | |
218 switch (level) { | |
219 | |
220 case ssl_encryption_initial: | |
221 secret = &qc->server_in; | |
222 break; | |
223 | |
224 case ssl_encryption_handshake: | |
225 secret = &qc->server_hs; | |
226 break; | |
227 | |
228 default: | |
229 return 0; | |
230 } | |
231 | |
232 m = ngx_hex_dump(buf, (u_char *) data, ngx_min(len, 1024)) - buf; | |
233 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
234 "quic_add_handshake_data: %*s%s, len: %uz, level:%d", | |
235 m, buf, len < 2048 ? "" : "...", len, (int) level); | |
236 | |
237 in.data = ngx_alloc(4 + len + 5 /*minimal ACK*/, c->log); | |
238 if (in.data == 0) { | |
239 return 0; | |
240 } | |
241 | |
242 p = in.data; | |
243 ngx_quic_build_int(&p, 6); // crypto frame | |
244 ngx_quic_build_int(&p, 0); | |
245 ngx_quic_build_int(&p, len); | |
246 p = ngx_cpymem(p, data, len); | |
247 | |
248 if (level == ssl_encryption_initial) { | |
249 ngx_quic_build_int(&p, 2); // ack frame | |
250 ngx_quic_build_int(&p, 0); | |
251 ngx_quic_build_int(&p, 0); | |
252 ngx_quic_build_int(&p, 0); | |
253 ngx_quic_build_int(&p, 0); | |
254 } | |
255 | |
256 in.len = p - in.data; | |
257 out.len = in.len + EVP_GCM_TLS_TAG_LEN; | |
258 | |
259 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
260 "quic_add_handshake_data: clear_len:%uz, ciphertext_len:%uz", | |
261 in.len, out.len); | |
262 | |
263 ad.data = ngx_alloc(346 /*max header*/, c->log); | |
264 if (ad.data == 0) { | |
265 return 0; | |
266 } | |
267 | |
268 p = ad.data; | |
269 if (level == ssl_encryption_initial) { | |
270 *p++ = 0xc0; // initial, packet number len | |
271 } else if (level == ssl_encryption_handshake) { | |
272 *p++ = 0xe0; // handshake, packet number len | |
273 } | |
274 p = ngx_quic_write_uint32(p, quic_version); | |
275 *p++ = qc->scid.len; | |
276 p = ngx_cpymem(p, qc->scid.data, qc->scid.len); | |
277 *p++ = qc->dcid.len; | |
278 p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len); | |
279 if (level == ssl_encryption_initial) { | |
280 ngx_quic_build_int(&p, 0); // token length | |
281 } | |
282 ngx_quic_build_int(&p, out.len + 1); // length (inc. pnl) | |
283 pnp = p; | |
284 | |
285 if (level == ssl_encryption_initial) { | |
286 *p++ = 0; // packet number 0 | |
287 | |
288 } else if (level == ssl_encryption_handshake) { | |
289 *p++ = pn++; | |
290 } | |
291 | |
292 ad.len = p - ad.data; | |
293 | |
294 m = ngx_hex_dump(buf, ad.data, ad.len) - buf; | |
295 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
296 "quic_add_handshake_data ad: %*s, len: %uz", | |
297 m, buf, ad.len); | |
298 | |
299 | |
300 name = (u_char *) SSL_get_cipher(ssl_conn); | |
301 | |
302 if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0 | |
303 || ngx_strcasecmp(name, (u_char *) "(NONE)") == 0) | |
304 { | |
305 cipher = EVP_aes_128_gcm(); | |
306 | |
307 } else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) { | |
308 cipher = EVP_aes_256_gcm(); | |
309 | |
310 } else { | |
311 return 0; | |
312 } | |
313 | |
314 nonce = ngx_pstrdup(c->pool, &secret->iv); | |
315 if (level == ssl_encryption_handshake) { | |
316 nonce[11] ^= (pn - 1); | |
317 } | |
318 | |
319 m = ngx_hex_dump(buf, (u_char *) secret->iv.data, 12) - buf; | |
320 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
321 "quic_add_handshake_data sample: server_iv %*s", | |
322 m, buf); | |
323 m = ngx_hex_dump(buf, (u_char *) nonce, 12) - buf; | |
324 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
325 "quic_add_handshake_data sample: n=%d nonce %*s", | |
326 pn - 1, m, buf); | |
327 | |
328 if (ngx_quic_tls_seal(c, cipher, secret, &out, nonce, &in, &ad) != NGX_OK) | |
329 { | |
330 return 0; | |
331 } | |
332 | |
333 sample = &out.data[3]; // pnl=0 | |
334 if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), secret, mask, sample) != NGX_OK) { | |
335 return 0; | |
336 } | |
337 | |
338 m = ngx_hex_dump(buf, (u_char *) sample, 16) - buf; | |
339 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
340 "quic_add_handshake_data sample: %*s, len: %uz", | |
341 m, buf, 16); | |
342 | |
343 m = ngx_hex_dump(buf, (u_char *) mask, 16) - buf; | |
344 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
345 "quic_add_handshake_data mask: %*s, len: %uz", | |
346 m, buf, 16); | |
347 | |
348 m = ngx_hex_dump(buf, (u_char *) secret->hp.data, 16) - buf; | |
349 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
350 "quic_add_handshake_data hp_key: %*s, len: %uz", | |
351 m, buf, 16); | |
352 | |
353 // header protection, pnl = 0 | |
354 ad.data[0] ^= mask[0] & 0x0f; | |
355 *pnp ^= mask[1]; | |
356 | |
357 u_char *packet = ngx_alloc(ad.len + out.len, c->log); | |
358 if (packet == 0) { | |
359 return 0; | |
360 } | |
361 | |
362 p = ngx_cpymem(packet, ad.data, ad.len); | |
363 p = ngx_cpymem(p, out.data, out.len); | |
364 | |
365 m = ngx_hex_dump(buf, (u_char *) packet, ngx_min(1024, p - packet)) - buf; | |
366 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
367 "quic_add_handshake_data packet: %*s%s, len: %uz", | |
368 m, buf, len < 2048 ? "" : "...", p - packet); | |
369 | |
370 c->send(c, packet, p - packet); | |
371 | |
372 return 1; | |
373 } | |
374 | |
375 | |
376 static int | |
377 quic_flush_flight(ngx_ssl_conn_t *ssl_conn) | |
378 { | |
379 ngx_connection_t *c; | |
380 | |
381 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
382 | |
383 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic_flush_flight()"); | |
384 | |
385 return 1; | |
386 } | |
387 | |
388 | |
389 static int | |
390 quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, | |
391 uint8_t alert) | |
392 { | |
393 ngx_connection_t *c; | |
394 | |
395 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
396 | |
397 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
398 "quic_send_alert(), lvl=%d, alert=%d", | |
399 (int) level, (int) alert); | |
400 | |
401 return 1; | |
402 } | |
403 | |
404 | |
405 static SSL_QUIC_METHOD quic_method = { | |
406 quic_set_encryption_secrets, | |
407 quic_add_handshake_data, | |
408 quic_flush_flight, | |
409 quic_send_alert, | |
410 }; | |
411 | |
412 #endif | |
413 | |
414 | |
415 static ngx_command_t ngx_openssl_commands[] = { | 93 static ngx_command_t ngx_openssl_commands[] = { |
416 | 94 |
417 { ngx_string("ssl_engine"), | 95 { ngx_string("ssl_engine"), |
418 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, | 96 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, |
419 ngx_openssl_engine, | 97 ngx_openssl_engine, |
1788 return NGX_OK; | 1466 return NGX_OK; |
1789 } | 1467 } |
1790 | 1468 |
1791 #if NGX_OPENSSL_QUIC | 1469 #if NGX_OPENSSL_QUIC |
1792 | 1470 |
1793 SSL_CTX_set_quic_method(ssl->ctx, &quic_method); | 1471 ngx_quic_init_ssl_methods(ssl->ctx); |
1794 return NGX_OK; | 1472 return NGX_OK; |
1795 | 1473 |
1796 #else | 1474 #else |
1797 | 1475 |
1798 ngx_log_error(NGX_LOG_WARN, ssl->log, 0, | 1476 ngx_log_error(NGX_LOG_WARN, ssl->log, 0, |