comparison src/http/ngx_http_request.c @ 7643:76e29ff31cd3 quic

AEAD routines, introduced ngx_quic_tls_open()/ngx_quic_tls_seal().
author Sergey Kandaurov <pluknet@nginx.com>
date Fri, 28 Feb 2020 13:09:52 +0300
parents 8964cc6ecc4a
children a9ff4392ecde
comparison
equal deleted inserted replaced
7642:8964cc6ecc4a 7643:76e29ff31cd3
781 } 781 }
782 #endif 782 #endif
783 783
784 // initial secret 784 // initial secret
785 785
786 size_t is_len; 786 size_t is_len;
787 uint8_t is[SHA256_DIGEST_LENGTH]; 787 uint8_t is[SHA256_DIGEST_LENGTH];
788 const EVP_MD *digest; 788 const EVP_MD *digest;
789 #ifdef OPENSSL_IS_BORINGSSL 789 const ngx_aead_cipher_t *cipher;
790 const EVP_AEAD *cipher;
791 #else
792 const EVP_CIPHER *cipher;
793 #endif
794 static const uint8_t salt[20] = 790 static const uint8_t salt[20] =
795 "\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7" 791 "\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7"
796 "\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02"; 792 "\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02";
797 793
794 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
795
796 cipher = NGX_QUIC_INITIAL_CIPHER;
798 digest = EVP_sha256(); 797 digest = EVP_sha256();
799
800 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
801
802 #ifdef OPENSSL_IS_BORINGSSL
803 cipher = EVP_aead_aes_128_gcm();
804 #else
805 cipher = EVP_aes_128_gcm();
806 #endif
807 798
808 if (ngx_hkdf_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len, 799 if (ngx_hkdf_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len,
809 salt, sizeof(salt)) 800 salt, sizeof(salt))
810 != NGX_OK) 801 != NGX_OK)
811 { 802 {
1177 } 1168 }
1178 #endif 1169 #endif
1179 1170
1180 // packet protection 1171 // packet protection
1181 1172
1182 ngx_str_t ciphertext; 1173 ngx_str_t in;
1183 ciphertext.data = b->pos; 1174 in.data = b->pos;
1184 ciphertext.len = plen - pnl; 1175 in.len = plen - pnl;
1185 1176
1186 ngx_str_t ad; 1177 ngx_str_t ad;
1187 ad.len = b->pos - b->start; 1178 ad.len = b->pos - b->start;
1188 ad.data = ngx_pnalloc(c->pool, ad.len); 1179 ad.data = ngx_pnalloc(c->pool, ad.len);
1189 if (ad.data == NULL) { 1180 if (ad.data == NULL) {
1208 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, 1199 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1209 "quic ad: %*s, len: %uz", m, buf, ad.len); 1200 "quic ad: %*s, len: %uz", m, buf, ad.len);
1210 } 1201 }
1211 #endif 1202 #endif
1212 1203
1213 uint8_t cleartext[1600]; 1204 ngx_str_t out;
1214 size_t cleartext_len; 1205
1215 1206 if (ngx_quic_tls_open(c, cipher, &qc->client_in, &out, nonce, &in, &ad)
1216 #ifdef OPENSSL_IS_BORINGSSL 1207 != NGX_OK)
1217 EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher,
1218 qc->client_in.key.data,
1219 qc->client_in.key.len,
1220 EVP_AEAD_DEFAULT_TAG_LENGTH);
1221 if (aead == NULL) {
1222 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_AEAD_CTX_new() failed");
1223 ngx_http_close_connection(c);
1224 return;
1225 }
1226
1227 if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext),
1228 nonce, qc->client_in.iv.len, ciphertext.data,
1229 ciphertext.len, ad.data, ad.len)
1230 != 1)
1231 { 1208 {
1232 EVP_AEAD_CTX_free(aead); 1209 ngx_http_close_connection(c);
1233 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, 1210 return;
1234 "EVP_AEAD_CTX_open() failed"); 1211 }
1235 ngx_http_close_connection(c);
1236 return;
1237 }
1238
1239 EVP_AEAD_CTX_free(aead);
1240 #else
1241 int len;
1242 u_char *tag;
1243 EVP_CIPHER_CTX *aead;
1244
1245 aead = EVP_CIPHER_CTX_new();
1246 if (aead == NULL) {
1247 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_CIPHER_CTX_new() failed");
1248 ngx_http_close_connection(c);
1249 return;
1250 }
1251
1252 if (EVP_DecryptInit_ex(aead, cipher, NULL, NULL, NULL) != 1) {
1253 EVP_CIPHER_CTX_free(aead);
1254 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed");
1255 ngx_http_close_connection(c);
1256 return;
1257 }
1258
1259 if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_in.iv.len,
1260 NULL)
1261 == 0)
1262 {
1263 EVP_CIPHER_CTX_free(aead);
1264 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1265 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed");
1266 ngx_http_close_connection(c);
1267 return;
1268 }
1269
1270 if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_in.key.data, nonce)
1271 != 1)
1272 {
1273 EVP_CIPHER_CTX_free(aead);
1274 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed");
1275 ngx_http_close_connection(c);
1276 return;
1277 }
1278
1279 if (EVP_DecryptUpdate(aead, NULL, &len, ad.data, ad.len) != 1) {
1280 EVP_CIPHER_CTX_free(aead);
1281 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed");
1282 ngx_http_close_connection(c);
1283 return;
1284 }
1285
1286 if (EVP_DecryptUpdate(aead, cleartext, &len, ciphertext.data,
1287 ciphertext.len - EVP_GCM_TLS_TAG_LEN)
1288 != 1)
1289 {
1290 EVP_CIPHER_CTX_free(aead);
1291 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed");
1292 ngx_http_close_connection(c);
1293 return;
1294 }
1295
1296 cleartext_len = len;
1297 tag = ciphertext.data + ciphertext.len - EVP_GCM_TLS_TAG_LEN;
1298
1299 if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN,
1300 tag)
1301 == 0)
1302 {
1303 EVP_CIPHER_CTX_free(aead);
1304 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1305 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed");
1306 ngx_http_close_connection(c);
1307 return;
1308 }
1309
1310 if (EVP_DecryptFinal_ex(aead, cleartext + len, &len) <= 0) {
1311 EVP_CIPHER_CTX_free(aead);
1312 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptFinal_ex failed");
1313 ngx_http_close_connection(c);
1314 return;
1315 }
1316
1317 cleartext_len += len;
1318
1319 EVP_CIPHER_CTX_free(aead);
1320 #endif
1321 1212
1322 #if (NGX_DEBUG) 1213 #if (NGX_DEBUG)
1323 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { 1214 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
1324 m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf; 1215 m = ngx_hex_dump(buf, out.data, ngx_min(out.len, 256)) - buf;
1325 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0, 1216 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1326 "quic packet payload: %*s%s, len: %uz", 1217 "quic packet payload: %*s%s, len: %uz",
1327 m, buf, m < 512 ? "" : "...", cleartext_len); 1218 m, buf, m < 512 ? "" : "...", out.len);
1328 } 1219 }
1329 #endif 1220 #endif
1330 1221
1331 if (cleartext[0] != 0x06) { 1222 if (out.data[0] != 0x06) {
1332 ngx_log_error(NGX_LOG_INFO, rev->log, 0, 1223 ngx_log_error(NGX_LOG_INFO, rev->log, 0,
1333 "unexpected frame in initial packet"); 1224 "unexpected frame in initial packet");
1334 ngx_http_close_connection(c); 1225 ngx_http_close_connection(c);
1335 return; 1226 return;
1336 } 1227 }
1337 1228
1338 if (cleartext[1] != 0x00) { 1229 if (out.data[1] != 0x00) {
1339 ngx_log_error(NGX_LOG_INFO, rev->log, 0, 1230 ngx_log_error(NGX_LOG_INFO, rev->log, 0,
1340 "unexpected CRYPTO offset in initial packet"); 1231 "unexpected CRYPTO offset in initial packet");
1341 ngx_http_close_connection(c); 1232 ngx_http_close_connection(c);
1342 return; 1233 return;
1343 } 1234 }
1344 1235
1345 uint8_t *crypto = &cleartext[2]; 1236 uint8_t *crypto = &out.data[2];
1346 uint64_t crypto_len = ngx_quic_parse_int(&crypto); 1237 uint64_t crypto_len = ngx_quic_parse_int(&crypto);
1347 1238
1348 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, 1239 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1349 "quic initial packet CRYPTO length: %uL pp:%p:%p", 1240 "quic initial packet CRYPTO length: %uL pp:%p:%p",
1350 crypto_len, cleartext, crypto); 1241 crypto_len, out.data, crypto);
1351 1242
1352 sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); 1243 sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
1353 1244
1354 if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER) 1245 if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)
1355 != NGX_OK) 1246 != NGX_OK)
1463 } 1354 }
1464 1355
1465 m = ngx_hex_dump(buf, b, n) - buf; 1356 m = ngx_hex_dump(buf, b, n) - buf;
1466 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, 1357 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1467 "quic handshake handler: %*s, len: %uz", m, buf, n); 1358 "quic handshake handler: %*s, len: %uz", m, buf, n);
1468
1469 /* XXX bug-for-bug compat - assuming initial ack in handshake pkt */
1470 1359
1471 if ((p[0] & 0xf0) != 0xe0) { 1360 if ((p[0] & 0xf0) != 0xe0) {
1472 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid packet type"); 1361 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid packet type");
1473 ngx_http_close_connection(c); 1362 ngx_http_close_connection(c);
1474 return; 1363 return;
1574 } 1463 }
1575 #endif 1464 #endif
1576 1465
1577 // packet protection 1466 // packet protection
1578 1467
1579 ngx_str_t ciphertext; 1468 ngx_str_t in;
1580 ciphertext.data = p; 1469 in.data = p;
1581 ciphertext.len = plen - pnl; 1470 in.len = plen - pnl;
1582 1471
1583 ngx_str_t ad; 1472 ngx_str_t ad;
1584 ad.len = p - b; 1473 ad.len = p - b;
1585 ad.data = ngx_pnalloc(c->pool, ad.len); 1474 ad.data = ngx_pnalloc(c->pool, ad.len);
1586 if (ad.data == NULL) { 1475 if (ad.data == NULL) {
1605 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0, 1494 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1606 "quic ad: %*s, len: %uz", m, buf, ad.len); 1495 "quic ad: %*s, len: %uz", m, buf, ad.len);
1607 } 1496 }
1608 #endif 1497 #endif
1609 1498
1610 #ifdef OPENSSL_IS_BORINGSSL 1499 const ngx_aead_cipher_t *cipher;
1611 const EVP_AEAD *cipher;
1612 #else
1613 const EVP_CIPHER *cipher;
1614 #endif
1615 1500
1616 u_char *name = (u_char *) SSL_get_cipher(c->ssl->connection); 1501 u_char *name = (u_char *) SSL_get_cipher(c->ssl->connection);
1617 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, 1502 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1618 "quic ssl cipher: %s", name); 1503 "quic ssl cipher: %s", name);
1619 1504
1637 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "unexpected cipher"); 1522 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "unexpected cipher");
1638 ngx_http_close_connection(c); 1523 ngx_http_close_connection(c);
1639 return; 1524 return;
1640 } 1525 }
1641 1526
1642 1527 ngx_str_t out;
1643 uint8_t cleartext[1600]; 1528
1644 size_t cleartext_len; 1529 if (ngx_quic_tls_open(c, cipher, &qc->client_hs, &out, nonce, &in, &ad)
1645 1530 != NGX_OK)
1646 #ifdef OPENSSL_IS_BORINGSSL
1647 EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher,
1648 qc->client_hs.key.data,
1649 qc->client_hs.key.len,
1650 EVP_AEAD_DEFAULT_TAG_LENGTH);
1651 if (aead == NULL) {
1652 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_AEAD_CTX_new() failed");
1653 ngx_http_close_connection(c);
1654 return;
1655 }
1656
1657 if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext),
1658 nonce, qc->client_hs.iv.len, ciphertext.data,
1659 ciphertext.len, ad.data, ad.len)
1660 != 1)
1661 { 1531 {
1662 EVP_AEAD_CTX_free(aead); 1532 ngx_http_close_connection(c);
1663 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, 1533 return;
1664 "EVP_AEAD_CTX_open() failed"); 1534 }
1665 ngx_http_close_connection(c);
1666 return;
1667 }
1668
1669 EVP_AEAD_CTX_free(aead);
1670 #else
1671 int len;
1672 u_char *tag;
1673 EVP_CIPHER_CTX *aead;
1674
1675 aead = EVP_CIPHER_CTX_new();
1676 if (aead == NULL) {
1677 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_CIPHER_CTX_new() failed");
1678 ngx_http_close_connection(c);
1679 return;
1680 }
1681
1682 if (EVP_DecryptInit_ex(aead, cipher, NULL, NULL, NULL) != 1) {
1683 EVP_CIPHER_CTX_free(aead);
1684 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed");
1685 ngx_http_close_connection(c);
1686 return;
1687 }
1688
1689 if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_hs.iv.len,
1690 NULL)
1691 == 0)
1692 {
1693 EVP_CIPHER_CTX_free(aead);
1694 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1695 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed");
1696 ngx_http_close_connection(c);
1697 return;
1698 }
1699
1700 if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_hs.key.data, nonce)
1701 != 1)
1702 {
1703 EVP_CIPHER_CTX_free(aead);
1704 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed");
1705 ngx_http_close_connection(c);
1706 return;
1707 }
1708
1709 if (EVP_DecryptUpdate(aead, NULL, &len, ad.data, ad.len) != 1) {
1710 EVP_CIPHER_CTX_free(aead);
1711 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed");
1712 ngx_http_close_connection(c);
1713 return;
1714 }
1715
1716 if (EVP_DecryptUpdate(aead, cleartext, &len, ciphertext.data,
1717 ciphertext.len - EVP_GCM_TLS_TAG_LEN)
1718 != 1)
1719 {
1720 EVP_CIPHER_CTX_free(aead);
1721 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed");
1722 ngx_http_close_connection(c);
1723 return;
1724 }
1725
1726 cleartext_len = len;
1727 tag = ciphertext.data + ciphertext.len - EVP_GCM_TLS_TAG_LEN;
1728
1729 if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN,
1730 tag)
1731 == 0)
1732 {
1733 EVP_CIPHER_CTX_free(aead);
1734 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1735 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed");
1736 ngx_http_close_connection(c);
1737 return;
1738 }
1739
1740 if (EVP_DecryptFinal_ex(aead, cleartext + len, &len) <= 0) {
1741 EVP_CIPHER_CTX_free(aead);
1742 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptFinal_ex failed");
1743 ngx_http_close_connection(c);
1744 return;
1745 }
1746
1747 cleartext_len += len;
1748
1749 EVP_CIPHER_CTX_free(aead);
1750 #endif
1751 1535
1752 #if (NGX_DEBUG) 1536 #if (NGX_DEBUG)
1753 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { 1537 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
1754 m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf; 1538 m = ngx_hex_dump(buf, out.data, ngx_min(out.len, 256)) - buf;
1755 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0, 1539 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1756 "quic packet payload: %*s%s, len: %uz", 1540 "quic packet payload: %*s%s, len: %uz",
1757 m, buf, m < 512 ? "" : "...", cleartext_len); 1541 m, buf, m < 512 ? "" : "...", out.len);
1758 } 1542 }
1759 #endif 1543 #endif
1760 1544
1761 } 1545 }
1762 1546