Mercurial > hg > nginx-tests
comparison lib/Test/Nginx/HTTP3.pm @ 1909:46bb1ffbb960
Tests: TLS_CHACHA20_POLY1305_SHA256 support in QUIC handshake.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Tue, 13 Jun 2023 17:58:30 +0400 |
parents | 1baf5fe1d86c |
children | e0b53fbdb5cf |
comparison
equal
deleted
inserted
replaced
1908:1baf5fe1d86c | 1909:46bb1ffbb960 |
---|---|
24 | 24 |
25 require Crypt::KeyDerivation; | 25 require Crypt::KeyDerivation; |
26 require Crypt::PK::X25519; | 26 require Crypt::PK::X25519; |
27 require Crypt::PRNG; | 27 require Crypt::PRNG; |
28 require Crypt::AuthEnc::GCM; | 28 require Crypt::AuthEnc::GCM; |
29 require Crypt::AuthEnc::ChaCha20Poly1305; | |
29 require Crypt::Mode::CTR; | 30 require Crypt::Mode::CTR; |
31 require Crypt::Stream::ChaCha; | |
30 require Crypt::Digest; | 32 require Crypt::Digest; |
31 require Crypt::Mac::HMAC; | 33 require Crypt::Mac::HMAC; |
32 | 34 |
33 $self->{socket} = IO::Socket::INET->new( | 35 $self->{socket} = IO::Socket::INET->new( |
34 Proto => "udp", | 36 Proto => "udp", |
1654 } | 1656 } |
1655 | 1657 |
1656 return $pn; | 1658 return $pn; |
1657 } | 1659 } |
1658 | 1660 |
1661 sub decrypt_aead_f { | |
1662 my ($level, $cipher) = @_; | |
1663 if ($level == 0 || $cipher == 0x1301 || $cipher == 0x1302) { | |
1664 return \&Crypt::AuthEnc::GCM::gcm_decrypt_verify, 'AES'; | |
1665 } | |
1666 \&Crypt::AuthEnc::ChaCha20Poly1305::chacha20poly1305_decrypt_verify; | |
1667 } | |
1668 | |
1659 sub decrypt_aead { | 1669 sub decrypt_aead { |
1660 my ($self, $buf) = @_; | 1670 my ($self, $buf) = @_; |
1661 my $flags = unpack("C", substr($buf, 0, 1)); | 1671 my $flags = unpack("C", substr($buf, 0, 1)); |
1662 return 0, $self->decrypt_retry($buf) if ($flags & 0xf0) == 0xf0; | 1672 return 0, $self->decrypt_retry($buf) if ($flags & 0xf0) == 0xf0; |
1663 my $level = $flags & 0x80 ? $flags - 0xc0 >> 4 : 3; | 1673 my $level = $flags & 0x80 ? $flags - 0xc0 >> 4 : 3; |
1675 : (0, length($buf) - $offpn); | 1685 : (0, length($buf) - $offpn); |
1676 $offpn += $len; | 1686 $offpn += $len; |
1677 | 1687 |
1678 my $sample = substr($buf, $offpn + 4, 16); | 1688 my $sample = substr($buf, $offpn + 4, 16); |
1679 my ($ad, $pnl, $pn) = $self->decrypt_ad($buf, | 1689 my ($ad, $pnl, $pn) = $self->decrypt_ad($buf, |
1680 $self->{keys}[$level]{r}{hp}, $sample, $offpn, $level == 3); | 1690 $self->{keys}[$level]{r}{hp}, $sample, $offpn, $level); |
1681 Test::Nginx::log_core('||', "ad = " . unpack("H*", $ad)); | 1691 Test::Nginx::log_core('||', "ad = " . unpack("H*", $ad)); |
1682 $pn = $self->decode_pn($pn, $pnl, $level); | 1692 $pn = $self->decode_pn($pn, $pnl, $level); |
1683 my $nonce = substr(pack("x12") . pack("N", $pn), -12) | 1693 my $nonce = substr(pack("x12") . pack("N", $pn), -12) |
1684 ^ $self->{keys}[$level]{r}{iv}; | 1694 ^ $self->{keys}[$level]{r}{iv}; |
1685 my $ciphertext = substr($buf, $offpn + $pnl, $val - 16 - $pnl); | 1695 my $ciphertext = substr($buf, $offpn + $pnl, $val - 16 - $pnl); |
1686 my $tag = substr($buf, $offpn + $val - 16, 16); | 1696 my $tag = substr($buf, $offpn + $val - 16, 16); |
1687 my $plaintext = Crypt::AuthEnc::GCM::gcm_decrypt_verify('AES', | 1697 my ($f, @args) = decrypt_aead_f($level, $self->{cipher}); |
1698 my $plaintext = $f->(@args, | |
1688 $self->{keys}[$level]{r}{key}, $nonce, $ad, $ciphertext, $tag); | 1699 $self->{keys}[$level]{r}{key}, $nonce, $ad, $ciphertext, $tag); |
1689 return if !defined $plaintext; | 1700 return if !defined $plaintext; |
1690 Test::Nginx::log_core('||', | 1701 Test::Nginx::log_core('||', |
1691 "pn = $pn, level = $level, length = " . length($plaintext)); | 1702 "pn = $pn, level = $level, length = " . length($plaintext)); |
1692 | 1703 |
1697 return ($level, $plaintext, | 1708 return ($level, $plaintext, |
1698 substr($buf, length($ad . $ciphertext . $tag)), ''); | 1709 substr($buf, length($ad . $ciphertext . $tag)), ''); |
1699 } | 1710 } |
1700 | 1711 |
1701 sub decrypt_ad { | 1712 sub decrypt_ad { |
1702 my ($self, $buf, $hp, $sample, $offset, $short) = @_; | 1713 my ($self, $buf, $hp, $sample, $offset, $level) = @_; |
1714 | |
1715 goto aes if $level == 0 || $self->{cipher} != 0x1303; | |
1716 | |
1717 my $counter = unpack("V", substr($sample, 0, 4)); | |
1718 my $nonce = substr($sample, 4, 12); | |
1719 my $stream = Crypt::Stream::ChaCha->new($hp, $nonce, $counter); | |
1720 my $mask = $stream->crypt($self->{zero}); | |
1721 goto mask; | |
1722 aes: | |
1703 my $m = Crypt::Mode::CTR->new('AES'); | 1723 my $m = Crypt::Mode::CTR->new('AES'); |
1704 my $mask = $m->encrypt($self->{zero}, $hp, $sample); | 1724 $mask = $m->encrypt($self->{zero}, $hp, $sample); |
1705 substr($buf, 0, 1) ^= substr($mask, 0, 1) & ($short ? "\x1f" : "\x0f"); | 1725 mask: |
1726 substr($buf, 0, 1) ^= substr($mask, 0, 1) | |
1727 & ($level == 3 ? "\x1f" : "\x0f"); | |
1706 my $pnl = unpack("C", substr($buf, 0, 1) & "\x03") + 1; | 1728 my $pnl = unpack("C", substr($buf, 0, 1) & "\x03") + 1; |
1707 for (my $i = 0; $i < $pnl; $i++) { | 1729 substr($buf, $offset, $pnl) ^= substr($mask, 1); |
1708 substr($buf, $offset + $i, 1) ^= substr($mask, $i + 1, 1); | |
1709 } | |
1710 my $pn = unpack("C", substr($buf, $offset, $pnl)); | 1730 my $pn = unpack("C", substr($buf, $offset, $pnl)); |
1711 my $ad = substr($buf, 0, $offset + $pnl); | 1731 my $ad = substr($buf, 0, $offset + $pnl); |
1712 return ($ad, $pnl, $pn); | 1732 return ($ad, $pnl, $pn); |
1733 } | |
1734 | |
1735 sub encrypt_aead_f { | |
1736 my ($level, $cipher) = @_; | |
1737 if ($level == 0 || $cipher == 0x1301 || $cipher == 0x1302) { | |
1738 return \&Crypt::AuthEnc::GCM::gcm_encrypt_authenticate, 'AES'; | |
1739 } | |
1740 \&Crypt::AuthEnc::ChaCha20Poly1305::chacha20poly1305_encrypt_authenticate; | |
1713 } | 1741 } |
1714 | 1742 |
1715 sub encrypt_aead { | 1743 sub encrypt_aead { |
1716 my ($self, $payload, $level) = @_; | 1744 my ($self, $payload, $level) = @_; |
1717 my $pn = ++$self->{pn}[0][$level]; | 1745 my $pn = ++$self->{pn}[0][$level]; |
1724 if $level == 0; | 1752 if $level == 0; |
1725 $ad .= build_int(length($payload) + 16 + 4) unless $level == 3; | 1753 $ad .= build_int(length($payload) + 16 + 4) unless $level == 3; |
1726 $ad .= pack("N", $pn); | 1754 $ad .= pack("N", $pn); |
1727 my $nonce = substr(pack("x12") . pack("N", $pn), -12) | 1755 my $nonce = substr(pack("x12") . pack("N", $pn), -12) |
1728 ^ $self->{keys}[$level]{w}{iv}; | 1756 ^ $self->{keys}[$level]{w}{iv}; |
1729 my ($ciphertext, $tag) = Crypt::AuthEnc::GCM::gcm_encrypt_authenticate( | 1757 my ($f, @args) = encrypt_aead_f($level, $self->{cipher}); |
1730 'AES', $self->{keys}[$level]{w}{key}, $nonce, $ad, $payload); | 1758 my ($ciphertext, $tag) = $f->(@args, |
1759 $self->{keys}[$level]{w}{key}, $nonce, $ad, $payload); | |
1731 my $sample = substr($ciphertext . $tag, 0, 16); | 1760 my $sample = substr($ciphertext . $tag, 0, 16); |
1732 | 1761 |
1733 $ad = $self->encrypt_ad($ad, $self->{keys}[$level]{w}{hp}, | 1762 $ad = $self->encrypt_ad($ad, $self->{keys}[$level]{w}{hp}, |
1734 $sample, $level == 3); | 1763 $sample, $level); |
1735 return $ad . $ciphertext . $tag; | 1764 return $ad . $ciphertext . $tag; |
1736 } | 1765 } |
1737 | 1766 |
1738 sub encrypt_ad { | 1767 sub encrypt_ad { |
1739 my ($self, $ad, $hp, $sample, $short) = @_; | 1768 my ($self, $ad, $hp, $sample, $level) = @_; |
1769 | |
1770 goto aes if $level == 0 || $self->{cipher} != 0x1303; | |
1771 | |
1772 my $counter = unpack("V", substr($sample, 0, 4)); | |
1773 my $nonce = substr($sample, 4, 12); | |
1774 my $stream = Crypt::Stream::ChaCha->new($hp, $nonce, $counter); | |
1775 my $mask = $stream->crypt($self->{zero}); | |
1776 goto mask; | |
1777 aes: | |
1740 my $m = Crypt::Mode::CTR->new('AES'); | 1778 my $m = Crypt::Mode::CTR->new('AES'); |
1741 my $mask = $m->encrypt($self->{zero}, $hp, $sample); | 1779 $mask = $m->encrypt($self->{zero}, $hp, $sample); |
1742 substr($ad, 0, 1) ^= substr($mask, 0, 1) & ($short ? "\x1f" : "\x0f"); | 1780 mask: |
1781 substr($ad, 0, 1) ^= substr($mask, 0, 1) | |
1782 & ($level == 3 ? "\x1f" : "\x0f"); | |
1743 substr($ad, -4) ^= substr($mask, 1); | 1783 substr($ad, -4) ^= substr($mask, 1); |
1744 return $ad; | 1784 return $ad; |
1745 } | 1785 } |
1746 | 1786 |
1747 sub decrypt_retry { | 1787 sub decrypt_retry { |