comparison lib/Test/Nginx/HTTP3.pm @ 1908:1baf5fe1d86c

Tests: TLS_AES_256_GCM_SHA384 support in QUIC handshake.
author Sergey Kandaurov <pluknet@nginx.com>
date Tue, 13 Jun 2023 03:27:02 +0400
parents f35824e75b66
children 46bb1ffbb960
comparison
equal deleted inserted replaced
1907:034c9121b9d1 1908:1baf5fe1d86c
38 $self->{repeat} = 0; 38 $self->{repeat} = 0;
39 $self->{token} = ''; 39 $self->{token} = '';
40 $self->{psk_list} = $extra{psk_list} || []; 40 $self->{psk_list} = $extra{psk_list} || [];
41 41
42 $self->{sni} = exists $extra{sni} ? $extra{sni} : 'localhost'; 42 $self->{sni} = exists $extra{sni} ? $extra{sni} : 'localhost';
43 $self->{cipher} = 0x1301;
44 $self->{ciphers} = $extra{ciphers} || "\x13\x01";
43 $self->{opts} = $extra{opts}; 45 $self->{opts} = $extra{opts};
44 46
45 $self->{zero} = pack("x5"); 47 $self->{zero} = pack("x5");
46 48
47 $self->{static_encode} = [ static_table() ]; 49 $self->{static_encode} = [ static_table() ];
105 107
106 Test::Nginx::log_core('||', "scid = " . unpack("H*", $self->{scid})); 108 Test::Nginx::log_core('||', "scid = " . unpack("H*", $self->{scid}));
107 Test::Nginx::log_core('||', "dcid = " . unpack("H*", $self->{dcid})); 109 Test::Nginx::log_core('||', "dcid = " . unpack("H*", $self->{dcid}));
108 Test::Nginx::log_core('||', "prk = " . unpack("H*", $prk)); 110 Test::Nginx::log_core('||', "prk = " . unpack("H*", $prk));
109 111
110 $self->set_traffic_keys('tls13 client in', 0, 'w', $prk); 112 $self->set_traffic_keys('tls13 client in', 'SHA256', 32, 0, 'w', $prk);
111 $self->set_traffic_keys('tls13 server in', 0, 'r', $prk); 113 $self->set_traffic_keys('tls13 server in', 'SHA256', 32, 0, 'r', $prk);
112 } 114 }
113 115
114 sub init_key_schedule { 116 sub init_key_schedule {
115 my ($self) = @_; 117 my ($self) = @_;
116 $self->{psk} = $self->{psk_list}[0]; 118 $self->{psk} = $self->{psk_list}[0];
119 my ($hash, $hlen) = $self->{psk} && $self->{psk}{cipher} == 0x1302 ?
120 ('SHA384', 48) : ('SHA256', 32);
117 $self->{es_prk} = Crypt::KeyDerivation::hkdf_extract( 121 $self->{es_prk} = Crypt::KeyDerivation::hkdf_extract(
118 $self->{psk}->{secret} || pack("x32"), pack("x32"), 'SHA256'); 122 $self->{psk}->{secret} || pack("x$hlen"), pack("x$hlen"),
123 $hash);
124 Test::Nginx::log_core('||', "es = " . unpack("H*", $self->{es_prk}));
119 $self->{sk} = Crypt::PK::X25519->new->generate_key; 125 $self->{sk} = Crypt::PK::X25519->new->generate_key;
120 } 126 }
121 127
122 sub initial { 128 sub initial {
123 my ($self, $ed) = @_; 129 my ($self, $ed) = @_;
128 $padding = 0 if $padding < 0 || $self->{psk}->{ed}; 134 $padding = 0 if $padding < 0 || $self->{psk}->{ed};
129 my $payload = $crypto . pack("x$padding"); 135 my $payload = $crypto . pack("x$padding");
130 my $initial = $self->encrypt_aead($payload, 0); 136 my $initial = $self->encrypt_aead($payload, 0);
131 137
132 if ($ed && $self->{psk}->{ed}) { 138 if ($ed && $self->{psk}->{ed}) {
133 $self->set_traffic_keys('tls13 c e traffic', 1, 'w', 139 my ($hash, $hlen) = $self->{psk}{cipher} == 0x1302 ?
134 $self->{es_prk}, Crypt::Digest::digest_data('SHA256', 140 ('SHA384', 48) : ('SHA256', 32);
141 $self->set_traffic_keys('tls13 c e traffic', $hash, $hlen, 1,
142 'w', $self->{es_prk}, Crypt::Digest::digest_data($hash,
135 $self->{tlsm}{ch})); 143 $self->{tlsm}{ch}));
136 144
137 # my $ed = "\x0a\x02\x08\x00\x04\x02\x06\x1f\x0d\x00\x0a" 145 # my $ed = "\x0a\x02\x08\x00\x04\x02\x06\x1f\x0d\x00\x0a"
138 # . $self->build_stream("\x01\x06\x00\x00\xc0"); 146 # . $self->build_stream("\x01\x06\x00\x00\xc0");
139 $payload = $ed; 147 $payload = $ed;
151 my $buf = ''; 159 my $buf = '';
152 160
153 $self->read_tls_message(\$buf, \&parse_tls_server_hello) or return; 161 $self->read_tls_message(\$buf, \&parse_tls_server_hello) or return;
154 162
155 my $sh = $self->{tlsm}{sh}; 163 my $sh = $self->{tlsm}{sh};
164 $self->{cipher} = unpack("n", substr($sh, 6 + 32 + 1, 2));
165
156 my $extens_len = unpack("C*", substr($sh, 6 + 32 + 4, 2)) * 8 166 my $extens_len = unpack("C*", substr($sh, 6 + 32 + 4, 2)) * 8
157 + unpack("C*", substr($sh, 6 + 32 + 5, 1)); 167 + unpack("C*", substr($sh, 6 + 32 + 5, 1));
158 my $extens = substr($sh, 6 + 32 + 4 + 2, $extens_len); 168 my $extens = substr($sh, 6 + 32 + 4 + 2, $extens_len);
159 my $pub = key_share($extens); 169 my $pub = key_share($extens);
160 Test::Nginx::log_core('||', "pub = " . unpack("H*", $pub)); 170 Test::Nginx::log_core('||', "pub = " . unpack("H*", $pub));
164 my $shared_secret = $self->{sk}->shared_secret($pk); 174 my $shared_secret = $self->{sk}->shared_secret($pk);
165 Test::Nginx::log_core('||', "shared = " . unpack("H*", $shared_secret)); 175 Test::Nginx::log_core('||', "shared = " . unpack("H*", $shared_secret));
166 176
167 # tls13_advance_key_schedule 177 # tls13_advance_key_schedule
168 178
179 my ($hash, $hlen) = $self->{cipher} == 0x1302 ?
180 ('SHA384', 48) : ('SHA256', 32);
181
169 my $psk = pre_shared_key($extens); 182 my $psk = pre_shared_key($extens);
170 $self->{psk} = (defined $psk && $self->{psk_list}[$psk]) || undef; 183 $self->{psk} = (defined $psk && $self->{psk_list}[$psk]) || undef;
171 $self->{es_prk} = Crypt::KeyDerivation::hkdf_extract( 184 $self->{es_prk} = Crypt::KeyDerivation::hkdf_extract(
172 $self->{psk}->{secret} || pack("x32"), pack("x32"), 'SHA256'); 185 $self->{psk}->{secret} || pack("x$hlen"), pack("x$hlen"),
173 186 $hash);
174 $self->{hs_prk} = hkdf_advance($shared_secret, $self->{es_prk}); 187
188 $self->{hs_prk} = hkdf_advance($hash, $hlen, $shared_secret,
189 $self->{es_prk});
190 Test::Nginx::log_core('||', "es = " . unpack("H*", $self->{es_prk}));
175 Test::Nginx::log_core('||', "hs = " . unpack("H*", $self->{hs_prk})); 191 Test::Nginx::log_core('||', "hs = " . unpack("H*", $self->{hs_prk}));
176 192
177 # derive_secret_with_transcript 193 # derive_secret_with_transcript
178 194
179 my $digest = Crypt::Digest::digest_data('SHA256', $self->{tlsm}{ch} 195 my $digest = Crypt::Digest::digest_data($hash, $self->{tlsm}{ch}
180 . $self->{tlsm}{sh}); 196 . $self->{tlsm}{sh});
181 $self->set_traffic_keys('tls13 c hs traffic', 2, 'w', 197 $self->set_traffic_keys('tls13 c hs traffic', $hash, $hlen, 2, 'w',
182 $self->{hs_prk}, $digest); 198 $self->{hs_prk}, $digest);
183 $self->set_traffic_keys('tls13 s hs traffic', 2, 'r', 199 $self->set_traffic_keys('tls13 s hs traffic', $hash, $hlen, 2, 'r',
184 $self->{hs_prk}, $digest); 200 $self->{hs_prk}, $digest);
185 201
186 $self->read_tls_message(\$buf, \&parse_tls_encrypted_extensions); 202 $self->read_tls_message(\$buf, \&parse_tls_encrypted_extensions);
187 203
188 unless (keys %{$self->{psk}}) { 204 unless (keys %{$self->{psk}}) {
192 208
193 $self->read_tls_message(\$buf, \&parse_tls_finished); 209 $self->read_tls_message(\$buf, \&parse_tls_finished);
194 210
195 # tls13_advance_key_schedule(application) 211 # tls13_advance_key_schedule(application)
196 212
197 $self->{ms_prk} = hkdf_advance(pack("x32"), $self->{hs_prk}); 213 $self->{ms_prk} = hkdf_advance($hash, $hlen, pack("x$hlen"),
214 $self->{hs_prk});
198 Test::Nginx::log_core('||', 215 Test::Nginx::log_core('||',
199 "master = " . unpack("H*", $self->{ms_prk})); 216 "master = " . unpack("H*", $self->{ms_prk}));
200 217
201 # derive_secret_with_transcript(application) 218 # derive_secret_with_transcript(application)
202 219
203 $digest = Crypt::Digest::digest_data('SHA256', $self->{tlsm}{ch} 220 $digest = Crypt::Digest::digest_data($hash, $self->{tlsm}{ch}
204 . $self->{tlsm}{sh} . $self->{tlsm}{ee} . $self->{tlsm}{cert} 221 . $self->{tlsm}{sh} . $self->{tlsm}{ee} . $self->{tlsm}{cert}
205 . $self->{tlsm}{cv} . $self->{tlsm}{sf}); 222 . $self->{tlsm}{cv} . $self->{tlsm}{sf});
206 $self->set_traffic_keys('tls13 c ap traffic', 3, 'w', 223 $self->set_traffic_keys('tls13 c ap traffic', $hash, $hlen, 3, 'w',
207 $self->{ms_prk}, $digest); 224 $self->{ms_prk}, $digest);
208 $self->set_traffic_keys('tls13 s ap traffic', 3, 'r', 225 $self->set_traffic_keys('tls13 s ap traffic', $hash, $hlen, 3, 'r',
209 $self->{ms_prk}, $digest); 226 $self->{ms_prk}, $digest);
210 227
211 # client finished 228 # client finished
212 229
213 my $finished = tls13_finished($self->{keys}[2]{w}{prk}, $digest); 230 my $finished = tls13_finished($hash, $hlen, $self->{keys}[2]{w}{prk},
231 $digest);
214 Test::Nginx::log_core('||', "finished = " . unpack("H*", $finished)); 232 Test::Nginx::log_core('||', "finished = " . unpack("H*", $finished));
215 233
216 $self->{tlsm}{cf} = $finished; 234 $self->{tlsm}{cf} = $finished;
217 235
218 $digest = Crypt::Digest::digest_data('SHA256', $self->{tlsm}{ch} 236 $digest = Crypt::Digest::digest_data($hash, $self->{tlsm}{ch}
219 . $self->{tlsm}{sh} . $self->{tlsm}{ee} . $self->{tlsm}{cert} 237 . $self->{tlsm}{sh} . $self->{tlsm}{ee} . $self->{tlsm}{cert}
220 . $self->{tlsm}{cv} . $self->{tlsm}{sf} . $self->{tlsm}{cf}); 238 . $self->{tlsm}{cv} . $self->{tlsm}{sf} . $self->{tlsm}{cf});
221 $self->{rms_prk} = hkdf_expand_label("tls13 res master", 32, 239 $self->{rms_prk} = hkdf_expand_label("tls13 res master", $hash, $hlen,
222 $self->{ms_prk}, $digest); 240 $self->{ms_prk}, $digest);
223 Test::Nginx::log_core('||', 241 Test::Nginx::log_core('||',
224 "resumption = " . unpack("H*", $self->{rms_prk})); 242 "resumption = " . unpack("H*", $self->{rms_prk}));
225 243
226 my $crypto = build_crypto($finished); 244 my $crypto = build_crypto($finished);
1595 ############################################################################### 1613 ###############################################################################
1596 1614
1597 sub save_session_tickets { 1615 sub save_session_tickets {
1598 my ($self, $content) = @_; 1616 my ($self, $content) = @_;
1599 1617
1618 my ($hash, $hlen) = $self->{cipher} == 0x1302 ?
1619 ('SHA384', 48) : ('SHA256', 32);
1620
1600 my $nst_len = unpack("n", substr($content, 2, 2)); 1621 my $nst_len = unpack("n", substr($content, 2, 2));
1601 my $nst = substr($content, 4, $nst_len); 1622 my $nst = substr($content, 4, $nst_len);
1602 1623
1603 my $psk = {}; 1624 my $psk = { cipher => $self->{cipher} };
1604 my $lifetime = substr($nst, 0, 4); 1625 my $lifetime = substr($nst, 0, 4);
1605 $psk->{age_add} = substr($nst, 4, 4); 1626 $psk->{age_add} = substr($nst, 4, 4);
1606 my $nonce_len = unpack("C", substr($nst, 8, 1)); 1627 my $nonce_len = unpack("C", substr($nst, 8, 1));
1607 my $nonce = substr($nst, 9, $nonce_len); 1628 my $nonce = substr($nst, 9, $nonce_len);
1608 my $len = unpack("n", substr($nst, 8 + 1 + $nonce_len, 2)); 1629 my $len = unpack("n", substr($nst, 8 + 1 + $nonce_len, 2));
1610 1631
1611 my $extens_len = unpack("n", substr($nst, 11 + $nonce_len + $len, 2)); 1632 my $extens_len = unpack("n", substr($nst, 11 + $nonce_len + $len, 2));
1612 my $extens = substr($nst, 11 + $nonce_len + $len + 2, $extens_len); 1633 my $extens = substr($nst, 11 + $nonce_len + $len + 2, $extens_len);
1613 1634
1614 $psk->{ed} = early_data($extens); 1635 $psk->{ed} = early_data($extens);
1615 $psk->{secret} = hkdf_expand_label("tls13 resumption", 32, 1636 $psk->{secret} = hkdf_expand_label("tls13 resumption", $hash, $hlen,
1616 $self->{rms_prk}, $nonce); 1637 $self->{rms_prk}, $nonce);
1617 push @{$self->{psk_list}}, $psk; 1638 push @{$self->{psk_list}}, $psk;
1618 } 1639 }
1619 1640
1620 sub decode_pn { 1641 sub decode_pn {
1745 $key, $nonce, shift, ''); 1766 $key, $nonce, shift, '');
1746 return $tag; 1767 return $tag;
1747 } 1768 }
1748 1769
1749 sub set_traffic_keys { 1770 sub set_traffic_keys {
1750 my ($self, $label, $level, $direction, $secret, $digest) = @_; 1771 my ($self, $label, $hash, $hlen, $level, $direction, $secret, $digest)
1751 my $prk = hkdf_expand_label($label, 32, $secret, $digest); 1772 = @_;
1752 my $key = hkdf_expand_label("tls13 quic key", 16, $prk); 1773 my $prk = hkdf_expand_label($label, $hash, $hlen, $secret, $digest);
1753 my $iv = hkdf_expand_label("tls13 quic iv", 12, $prk); 1774 my $klen = $self->{cipher} == 0x1301 ? 16 : 32;
1754 my $hp = hkdf_expand_label("tls13 quic hp", 16, $prk); 1775 my $key = hkdf_expand_label("tls13 quic key", $hash, $klen, $prk);
1776 my $iv = hkdf_expand_label("tls13 quic iv", $hash, 12, $prk);
1777 my $hp = hkdf_expand_label("tls13 quic hp", $hash, $klen, $prk);
1755 $self->{keys}[$level]{$direction}{prk} = $prk; 1778 $self->{keys}[$level]{$direction}{prk} = $prk;
1756 $self->{keys}[$level]{$direction}{key} = $key; 1779 $self->{keys}[$level]{$direction}{key} = $key;
1757 $self->{keys}[$level]{$direction}{iv} = $iv; 1780 $self->{keys}[$level]{$direction}{iv} = $iv;
1758 $self->{keys}[$level]{$direction}{hp} = $hp; 1781 $self->{keys}[$level]{$direction}{hp} = $hp;
1759 } 1782 }
1760 1783
1761 sub hmac_finished { 1784 sub hmac_finished {
1762 my ($key, $digest) = @_; 1785 my ($hash, $hlen, $key, $digest) = @_;
1763 my $finished_key = hkdf_expand_label("tls13 finished", 32, $key); 1786 my $expand = hkdf_expand_label("tls13 finished", $hash, $hlen, $key);
1764 Crypt::Mac::HMAC::hmac('SHA256', $finished_key, $digest); 1787 Crypt::Mac::HMAC::hmac($hash, $expand, $digest);
1765 } 1788 }
1766 1789
1767 sub tls13_finished { 1790 sub tls13_finished {
1768 my ($key, $digest) = @_; 1791 my $hmac = hmac_finished(@_);
1769 my $hmac = hmac_finished($key, $digest);
1770 "\x14\x00" . pack('n', length($hmac)) . $hmac; 1792 "\x14\x00" . pack('n', length($hmac)) . $hmac;
1771 } 1793 }
1772 1794
1773 sub binders { 1795 sub binders {
1774 my ($key, $digest) = @_; 1796 my $hmac = hmac_finished(@_);
1775 my $hmac = hmac_finished($key, $digest);
1776 pack('n', length($hmac) + 1) . pack('C', length($hmac)) . $hmac; 1797 pack('n', length($hmac) + 1) . pack('C', length($hmac)) . $hmac;
1777 } 1798 }
1778 1799
1779 sub hkdf_advance { 1800 sub hkdf_advance {
1780 my ($secret, $prk) = @_; 1801 my ($hash, $hlen, $secret, $prk) = @_;
1781 my $digest0 = Crypt::Digest::digest_data('SHA256', ''); 1802 my $expand = hkdf_expand_label("tls13 derived", $hash, $hlen, $prk,
1782 my $expand = hkdf_expand_label("tls13 derived", 32, $prk, $digest0); 1803 Crypt::Digest::digest_data($hash, ''));
1783 Crypt::KeyDerivation::hkdf_extract($secret, $expand, 'SHA256'); 1804 Crypt::KeyDerivation::hkdf_extract($secret, $expand, $hash);
1784 } 1805 }
1785 1806
1786 sub hkdf_expand_label { 1807 sub hkdf_expand_label {
1787 my ($label, $len, $prk, $context) = @_; 1808 my ($label, $hash, $len, $prk, $context) = @_;
1788 $context = '' if !defined $context; 1809 $context = '' if !defined $context;
1789 my $info = pack("C3", 0, $len, length($label)) . $label 1810 my $info = pack("C3", 0, $len, length($label)) . $label
1790 . pack("C", length($context)) . $context; 1811 . pack("C", length($context)) . $context;
1791 return Crypt::KeyDerivation::hkdf_expand($prk, 'SHA256', $len, $info); 1812 Crypt::KeyDerivation::hkdf_expand($prk, $hash, $len, $info);
1792 } 1813 }
1793 1814
1794 sub key_share { 1815 sub key_share {
1795 my ($extens) = @_; 1816 my ($extens) = @_;
1796 my $offset = 0; 1817 my $offset = 0;
2156 my $key_share = $self->{sk}->export_key_raw('public'); 2177 my $key_share = $self->{sk}->export_key_raw('public');
2157 2178
2158 my $version = "\x03\x03"; 2179 my $version = "\x03\x03";
2159 my $random = Crypt::PRNG::random_bytes(32); 2180 my $random = Crypt::PRNG::random_bytes(32);
2160 my $session = "\x00"; 2181 my $session = "\x00";
2161 my $cipher = "\x00\x02\x13\x01"; 2182 my $cipher = pack('n', length($self->{ciphers})) . $self->{ciphers};
2162 my $compr = "\x01\x00"; 2183 my $compr = "\x01\x00";
2163 my $ext = build_tlsext_server_name($self->{sni}) 2184 my $ext = build_tlsext_server_name($self->{sni})
2164 . build_tlsext_supported_groups(29) 2185 . build_tlsext_supported_groups(29)
2165 . build_tlsext_alpn("h3", "hq-interop") 2186 . build_tlsext_alpn("h3", "hq-interop")
2166 . build_tlsext_sigalgs(0x0804, 0x0805, 0x0806) 2187 . build_tlsext_sigalgs(0x0804, 0x0805, 0x0806)
2173 . build_tlsext_psk($self->{psk}) if keys %{$self->{psk}}; 2194 . build_tlsext_psk($self->{psk}) if keys %{$self->{psk}};
2174 2195
2175 my $len = pack('n', length($ext)); 2196 my $len = pack('n', length($ext));
2176 my $ch = $version . $random . $session . $cipher . $compr . $len . $ext; 2197 my $ch = $version . $random . $session . $cipher . $compr . $len . $ext;
2177 $ch = "\x01\x00" . pack('n', length($ch)) . $ch; 2198 $ch = "\x01\x00" . pack('n', length($ch)) . $ch;
2178 $ch = build_tls_ch_with_binder($ch, $self->{es_prk}) 2199 $ch = build_tls_ch_with_binder($ch, $self->{psk}, $self->{es_prk})
2179 if keys %{$self->{psk}}; 2200 if keys %{$self->{psk}};
2180 return $ch; 2201 return $ch;
2181 } 2202 }
2182 2203
2183 sub build_tlsext_server_name { 2204 sub build_tlsext_server_name {
2247 sub build_tlsext_psk { 2268 sub build_tlsext_psk {
2248 my ($psk) = @_; 2269 my ($psk) = @_;
2249 my $identity = pack('n', length($psk->{ticket})) . $psk->{ticket} 2270 my $identity = pack('n', length($psk->{ticket})) . $psk->{ticket}
2250 . $psk->{age_add}; 2271 . $psk->{age_add};
2251 my $identities = pack('n', length($identity)) . $identity; 2272 my $identities = pack('n', length($identity)) . $identity;
2252 my $hash = pack('x32'); # SHA256 2273 my $hash = $psk->{cipher} == 0x1302 ? pack('x48') : pack('x32');
2253 my $binder = pack('C', length($hash)) . $hash; 2274 my $binder = pack('C', length($hash)) . $hash;
2254 my $binders = pack('n', length($binder)) . $binder; 2275 my $binders = pack('n', length($binder)) . $binder;
2255 pack('n2', 41, length($identities . $binders)) . $identities . $binders; 2276 pack('n2', 41, length($identities . $binders)) . $identities . $binders;
2256 } 2277 }
2257 2278
2258 sub build_tls_ch_with_binder { 2279 sub build_tls_ch_with_binder {
2259 my ($ch, $prk) = @_; 2280 my ($ch, $psk, $prk) = @_;
2260 my $digest0 = Crypt::Digest::digest_data('SHA256', ''); 2281 my ($hash, $hlen) = $psk->{cipher} == 0x1302 ?
2261 my $key = hkdf_expand_label("tls13 res binder", 32, $prk, $digest0); 2282 ('SHA384', 48) : ('SHA256', 32);
2262 my $truncated = substr($ch, 0, -35); 2283 my $key = hkdf_expand_label("tls13 res binder", $hash, $hlen, $prk,
2263 my $context = Crypt::Digest::digest_data('SHA256', $truncated); 2284 Crypt::Digest::digest_data($hash, ''));
2264 $truncated . binders($key, $context); 2285 my $truncated = substr($ch, 0, -3 - $hlen);
2286 my $context = Crypt::Digest::digest_data($hash, $truncated);
2287 $truncated . binders($hash, $hlen, $key, $context);
2265 } 2288 }
2266 2289
2267 ############################################################################### 2290 ###############################################################################
2268 2291
2269 1; 2292 1;