comparison src/http/ngx_http_request.c @ 8174:b7bbfea7a6c3 quic

QUIC handshake handler, draft 24 bump.
author Sergey Kandaurov <pluknet@nginx.com>
date Fri, 28 Feb 2020 13:09:52 +0300
parents 02f331613232
children 72f632f90a17
comparison
equal deleted inserted replaced
8173:02f331613232 8174:b7bbfea7a6c3
62 #if (NGX_HTTP_SSL) 62 #if (NGX_HTTP_SSL)
63 static void ngx_http_ssl_handshake(ngx_event_t *rev); 63 static void ngx_http_ssl_handshake(ngx_event_t *rev);
64 static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); 64 static void ngx_http_ssl_handshake_handler(ngx_connection_t *c);
65 65
66 static void ngx_http_quic_handshake(ngx_event_t *rev); 66 static void ngx_http_quic_handshake(ngx_event_t *rev);
67 static void ngx_http_quic_handshake_handler(ngx_event_t *rev);
67 #endif 68 #endif
68 69
69 70
70 static char *ngx_http_client_errors[] = { 71 static char *ngx_http_client_errors[] = {
71 72
704 b->pos += 4; 705 b->pos += 4;
705 706
706 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0, 707 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
707 "quic flags:%xi version:%xD", flags, version); 708 "quic flags:%xi version:%xD", flags, version);
708 709
709 if (version != 0xff000017) { 710 if (version != 0xff000018) {
710 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version"); 711 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version");
711 ngx_http_close_connection(c); 712 ngx_http_close_connection(c);
712 return; 713 return;
713 } 714 }
714 715
740 } 741 }
741 742
742 ngx_memcpy(qc->token.data, b->pos, qc->token.len); 743 ngx_memcpy(qc->token.data, b->pos, qc->token.len);
743 b->pos += qc->token.len; 744 b->pos += qc->token.len;
744 745
745 uint64_t plen = ngx_quic_parse_int(&b->pos); 746 ngx_int_t plen = ngx_quic_parse_int(&b->pos);
747
748 if (plen > b->last - b->pos) {
749 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "truncated initial packet");
750 ngx_http_close_connection(c);
751 return;
752 }
753
746 /* draft-ietf-quic-tls-23#section-5.4.2: 754 /* draft-ietf-quic-tls-23#section-5.4.2:
747 * the Packet Number field is assumed to be 4 bytes long 755 * the Packet Number field is assumed to be 4 bytes long
748 * draft-ietf-quic-tls-23#section-5.4.[34]: 756 * draft-ietf-quic-tls-23#section-5.4.[34]:
749 * AES-Based and ChaCha20-Based header protections sample 16 bytes 757 * AES-Based and ChaCha20-Based header protections sample 16 bytes
750 */ 758 */
1394 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, 1402 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1395 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", 1403 "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
1396 (int) SSL_quic_read_level(c->ssl->connection), 1404 (int) SSL_quic_read_level(c->ssl->connection),
1397 (int) SSL_quic_write_level(c->ssl->connection)); 1405 (int) SSL_quic_write_level(c->ssl->connection));
1398 1406
1407 if (!rev->timer_set) {
1408 ngx_add_timer(rev, c->listening->post_accept_timeout);
1409 }
1410
1411 rev->handler = ngx_http_quic_handshake_handler;
1412 return;
1413 }
1414
1415
1416 static void
1417 ngx_http_quic_handshake_handler(ngx_event_t *rev)
1418 {
1419 size_t m;
1420 ssize_t n;
1421 ngx_connection_t *c;
1422 ngx_quic_connection_t *qc;
1423 u_char buf[4096], b[512], *p;
1424
1425 c = rev->data;
1426 qc = c->quic;
1427 p = b;
1428
1429 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic handshake handler");
1430
1431 if (rev->timedout) {
1432 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
1433 ngx_http_close_connection(c);
1434 return;
1435 }
1436
1437 if (c->close) {
1438 ngx_http_close_connection(c);
1439 return;
1440 }
1441
1442 n = c->recv(c, b, sizeof(b));
1443
1444 if (n == NGX_AGAIN) {
1445 return;
1446 }
1447
1448 if (n == NGX_ERROR) {
1449 c->read->eof = 1;
1450 ngx_http_close_connection(c);
1451 return;
1452 }
1453
1454 m = ngx_hex_dump(buf, b, n) - buf;
1455 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1456 "quic handshake handler: %*s, len: %uz", m, buf, n);
1457
1458 /* XXX bug-for-bug compat - assuming initial ack in handshake pkt */
1459
1460 if ((p[0] & 0xf0) != 0xe0) {
1461 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid packet type");
1462 ngx_http_close_connection(c);
1463 return;
1464 }
1465
1466 ngx_int_t flags = *p++;
1467 uint32_t version = ngx_http_v2_parse_uint32(p);
1468 p += 4;
1469
1470 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1471 "quic flags:%xi version:%xD", flags, version);
1472
1473 if (version != 0xff000018) {
1474 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version");
1475 ngx_http_close_connection(c);
1476 return;
1477 }
1478
1479 if (*p++ != qc->dcid.len) {
1480 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic dcidl");
1481 ngx_http_close_connection(c);
1482 return;
1483 }
1484
1485 if (ngx_memcmp(p, qc->dcid.data, qc->dcid.len) != 0) {
1486 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic dcid");
1487 ngx_http_close_connection(c);
1488 return;
1489 }
1490
1491 p += qc->dcid.len;
1492
1493 if (*p++ != qc->scid.len) {
1494 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic scidl");
1495 ngx_http_close_connection(c);
1496 return;
1497 }
1498
1499 if (ngx_memcmp(p, qc->scid.data, qc->scid.len) != 0) {
1500 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic scid");
1501 ngx_http_close_connection(c);
1502 return;
1503 }
1504
1505 p += qc->scid.len;
1506
1507 ngx_int_t plen = ngx_quic_parse_int(&p);
1508
1509 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1510 "quic packet length: %d", plen);
1511
1512 if (plen > b + n - p) {
1513 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "truncated handshake packet");
1514 ngx_http_close_connection(c);
1515 return;
1516 }
1517
1518 u_char *sample = p + 4;
1519
1520 m = ngx_hex_dump(buf, sample, 16) - buf;
1521 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic sample: %*s", m, buf);
1522
1523 // header protection
1524
1525 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
1526 uint8_t mask[16];
1527 int outlen;
1528
1529 if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL,
1530 qc->client_hs_hp.data, NULL)
1531 != 1)
1532 {
1533 EVP_CIPHER_CTX_free(ctx);
1534 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1535 "EVP_EncryptInit_ex() failed");
1536 ngx_http_close_connection(c);
1537 return;
1538 }
1539
1540 if (!EVP_EncryptUpdate(ctx, mask, &outlen, sample, 16)) {
1541 EVP_CIPHER_CTX_free(ctx);
1542 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1543 "EVP_EncryptUpdate() failed");
1544 ngx_http_close_connection(c);
1545 return;
1546 }
1547
1548 EVP_CIPHER_CTX_free(ctx);
1549
1550 u_char clearflags = flags ^ (mask[0] & 0x0f);
1551 ngx_int_t pnl = (clearflags & 0x03) + 1;
1552 uint64_t pn = ngx_quic_parse_pn(&p, pnl, &mask[1]);
1553
1554 #if (NGX_DEBUG)
1555 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
1556 m = ngx_hex_dump(buf, mask, 5) - buf;
1557 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1558 "quic mask: %*s", m, buf);
1559 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1560 "quic clear flags: %xi", clearflags);
1561 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1562 "quic packet number: %uL, len: %xi", pn, pnl);
1563 }
1564 #endif
1565
1566 // packet protection
1567
1568 ngx_str_t ciphertext;
1569 ciphertext.data = p;
1570 ciphertext.len = plen - pnl;
1571
1572 ngx_str_t ad;
1573 ad.len = p - b;
1574 ad.data = ngx_pnalloc(c->pool, ad.len);
1575 if (ad.data == NULL) {
1576 ngx_http_close_connection(c);
1577 return;
1578 }
1579
1580 ngx_memcpy(ad.data, b, ad.len);
1581 ad.data[0] = clearflags;
1582 ad.data[ad.len - pnl] = (u_char)pn;
1583
1584 uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_hs_iv);
1585 nonce[11] ^= pn;
1586
1587 #if (NGX_DEBUG)
1588 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
1589 m = ngx_hex_dump(buf, nonce, 12) - buf;
1590 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1591 "quic nonce: %*s, len: %uz", m, buf, 12);
1592
1593 m = ngx_hex_dump(buf, ad.data, ad.len) - buf;
1594 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1595 "quic ad: %*s, len: %uz", m, buf, ad.len);
1596 }
1597 #endif
1598
1599 #ifdef OPENSSL_IS_BORINGSSL
1600 const EVP_AEAD *cipher;
1601 #else
1602 const EVP_CIPHER *cipher;
1603 #endif
1604
1605 u_char *name = (u_char *) SSL_get_cipher(c->ssl->connection);
1606 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1607 "quic ssl cipher: %s", name);
1608
1609 if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0
1610 || ngx_strcasecmp(name, (u_char *) "(NONE)") == 0)
1611 {
1612 #ifdef OPENSSL_IS_BORINGSSL
1613 cipher = EVP_aead_aes_128_gcm();
1614 #else
1615 cipher = EVP_aes_128_gcm();
1616 #endif
1617
1618 } else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) {
1619 #ifdef OPENSSL_IS_BORINGSSL
1620 cipher = EVP_aead_aes_256_gcm();
1621 #else
1622 cipher = EVP_aes_256_gcm();
1623 #endif
1624
1625 } else {
1626 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "unexpected cipher");
1627 ngx_http_close_connection(c);
1628 return;
1629 }
1630
1631
1632 uint8_t cleartext[1600];
1633 size_t cleartext_len;
1634
1635 #ifdef OPENSSL_IS_BORINGSSL
1636 EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher,
1637 qc->client_hs_key.data,
1638 qc->client_hs_key.len,
1639 EVP_AEAD_DEFAULT_TAG_LENGTH);
1640 if (aead == NULL) {
1641 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_AEAD_CTX_new() failed");
1642 ngx_http_close_connection(c);
1643 return;
1644 }
1645
1646 if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext),
1647 nonce, qc->client_hs_iv.len, ciphertext.data,
1648 ciphertext.len, ad.data, ad.len)
1649 != 1)
1650 {
1651 EVP_AEAD_CTX_free(aead);
1652 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1653 "EVP_AEAD_CTX_open() failed");
1654 ngx_http_close_connection(c);
1655 return;
1656 }
1657
1658 EVP_AEAD_CTX_free(aead);
1659 #else
1660 int len;
1661 u_char *tag;
1662 EVP_CIPHER_CTX *aead;
1663
1664 aead = EVP_CIPHER_CTX_new();
1665 if (aead == NULL) {
1666 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_CIPHER_CTX_new() failed");
1667 ngx_http_close_connection(c);
1668 return;
1669 }
1670
1671 if (EVP_DecryptInit_ex(aead, cipher, NULL, NULL, NULL) != 1) {
1672 EVP_CIPHER_CTX_free(aead);
1673 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed");
1674 ngx_http_close_connection(c);
1675 return;
1676 }
1677
1678 if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, qc->client_hs_iv.len,
1679 NULL)
1680 == 0)
1681 {
1682 EVP_CIPHER_CTX_free(aead);
1683 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1684 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed");
1685 ngx_http_close_connection(c);
1686 return;
1687 }
1688
1689 if (EVP_DecryptInit_ex(aead, NULL, NULL, qc->client_hs_key.data, nonce)
1690 != 1)
1691 {
1692 EVP_CIPHER_CTX_free(aead);
1693 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptInit_ex() failed");
1694 ngx_http_close_connection(c);
1695 return;
1696 }
1697
1698 if (EVP_DecryptUpdate(aead, NULL, &len, ad.data, ad.len) != 1) {
1699 EVP_CIPHER_CTX_free(aead);
1700 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed");
1701 ngx_http_close_connection(c);
1702 return;
1703 }
1704
1705 if (EVP_DecryptUpdate(aead, cleartext, &len, ciphertext.data,
1706 ciphertext.len - EVP_GCM_TLS_TAG_LEN)
1707 != 1)
1708 {
1709 EVP_CIPHER_CTX_free(aead);
1710 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptUpdate() failed");
1711 ngx_http_close_connection(c);
1712 return;
1713 }
1714
1715 cleartext_len = len;
1716 tag = ciphertext.data + ciphertext.len - EVP_GCM_TLS_TAG_LEN;
1717
1718 if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN,
1719 tag)
1720 == 0)
1721 {
1722 EVP_CIPHER_CTX_free(aead);
1723 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1724 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed");
1725 ngx_http_close_connection(c);
1726 return;
1727 }
1728
1729 if (EVP_DecryptFinal_ex(aead, cleartext + len, &len) <= 0) {
1730 EVP_CIPHER_CTX_free(aead);
1731 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "EVP_DecryptFinal_ex failed");
1732 ngx_http_close_connection(c);
1733 return;
1734 }
1735
1736 cleartext_len += len;
1737
1738 EVP_CIPHER_CTX_free(aead);
1739 #endif
1740
1741 #if (NGX_DEBUG)
1742 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
1743 m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf;
1744 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1745 "quic packet payload: %*s%s, len: %uz",
1746 m, buf, m < 512 ? "" : "...", cleartext_len);
1747 }
1748 #endif
1749
1399 ngx_http_close_connection(c); 1750 ngx_http_close_connection(c);
1400 return;
1401 } 1751 }
1402 1752
1403 1753
1404 static void 1754 static void
1405 ngx_http_ssl_handshake(ngx_event_t *rev) 1755 ngx_http_ssl_handshake(ngx_event_t *rev)