aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Yu <yumike@google.com>2022-12-08 18:43:58 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-12-08 18:43:58 +0000
commit747fd9a206e17c313cc1b117943305eced93f22b (patch)
treea680c8c7b840bfec949292f9785d1d085efeaa8b
parent4ee1fc18fea8cc01a8c13ae165d830ac1659db55 (diff)
parent21aebcb8b95c5c6d5d8f6b210af7aa420c28b59a (diff)
downloadquiche-747fd9a206e17c313cc1b117943305eced93f22b.tar.gz
Upgrade quiche to 0.14.0 am: 21aebcb8b9main-16k-with-phones
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/quiche/+/2299706 Change-Id: Ifb0da6667b8e3b0d944cae96d86cb64d542f9ccf Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--Android.bp2
-rw-r--r--Cargo.lock553
-rw-r--r--Cargo.toml90
-rw-r--r--Cargo.toml.orig33
-rw-r--r--METADATA12
-rw-r--r--OWNERS2
-rw-r--r--README.md113
-rw-r--r--deps/boringssl/CMakeLists.txt48
-rw-r--r--deps/boringssl/err_data.c954
-rw-r--r--deps/boringssl/ios-aarch64/crypto/fipsmodule/ghashv8-armx64.S326
-rw-r--r--deps/boringssl/ios-arm/crypto/fipsmodule/ghashv8-armx32.S5
-rw-r--r--deps/boringssl/linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S326
-rw-r--r--deps/boringssl/linux-arm/crypto/fipsmodule/ghashv8-armx32.S5
-rw-r--r--deps/boringssl/src/CMakeLists.txt54
-rw-r--r--deps/boringssl/src/crypto/CMakeLists.txt29
-rw-r--r--deps/boringssl/src/crypto/asn1/a_bitstr.c99
-rw-r--r--deps/boringssl/src/crypto/asn1/a_bool.c2
-rw-r--r--deps/boringssl/src/crypto/asn1/a_d2i_fp.c2
-rw-r--r--deps/boringssl/src/crypto/asn1/a_gentm.c7
-rw-r--r--deps/boringssl/src/crypto/asn1/a_mbstr.c39
-rw-r--r--deps/boringssl/src/crypto/asn1/a_object.c17
-rw-r--r--deps/boringssl/src/crypto/asn1/a_print.c48
-rw-r--r--deps/boringssl/src/crypto/asn1/a_strex.c (renamed from deps/boringssl/src/crypto/x509/a_strex.c)541
-rw-r--r--deps/boringssl/src/crypto/asn1/a_strnid.c49
-rw-r--r--deps/boringssl/src/crypto/asn1/a_time.c6
-rw-r--r--deps/boringssl/src/crypto/asn1/a_type.c28
-rw-r--r--deps/boringssl/src/crypto/asn1/a_utctm.c41
-rw-r--r--deps/boringssl/src/crypto/asn1/a_utf8.c2
-rw-r--r--deps/boringssl/src/crypto/asn1/asn1_lib.c3
-rw-r--r--deps/boringssl/src/crypto/asn1/asn1_par.c2
-rw-r--r--deps/boringssl/src/crypto/asn1/asn1_test.cc959
-rw-r--r--deps/boringssl/src/crypto/asn1/charmap.h (renamed from deps/boringssl/src/crypto/x509/charmap.h)0
-rw-r--r--deps/boringssl/src/crypto/asn1/internal.h (renamed from deps/boringssl/src/crypto/asn1/asn1_locl.h)30
-rw-r--r--deps/boringssl/src/crypto/asn1/tasn_dec.c2
-rw-r--r--deps/boringssl/src/crypto/asn1/tasn_enc.c34
-rw-r--r--deps/boringssl/src/crypto/asn1/tasn_fre.c4
-rw-r--r--deps/boringssl/src/crypto/asn1/tasn_new.c8
-rw-r--r--deps/boringssl/src/crypto/asn1/tasn_utl.c2
-rw-r--r--deps/boringssl/src/crypto/asn1/time_support.c2
-rw-r--r--deps/boringssl/src/crypto/bio/bio_mem.c8
-rw-r--r--deps/boringssl/src/crypto/bio/connect.c6
-rw-r--r--deps/boringssl/src/crypto/bio/fd.c4
-rw-r--r--deps/boringssl/src/crypto/bio/file.c8
-rw-r--r--deps/boringssl/src/crypto/bio/pair.c7
-rw-r--r--deps/boringssl/src/crypto/bio/socket.c20
-rw-r--r--deps/boringssl/src/crypto/bytestring/bytestring_test.cc34
-rw-r--r--deps/boringssl/src/crypto/bytestring/cbb.c9
-rw-r--r--deps/boringssl/src/crypto/bytestring/cbs.c8
-rw-r--r--deps/boringssl/src/crypto/cipher_extra/aead_test.cc13
-rw-r--r--deps/boringssl/src/crypto/cipher_extra/cipher_extra.c4
-rw-r--r--deps/boringssl/src/crypto/cipher_extra/cipher_test.cc50
-rw-r--r--deps/boringssl/src/crypto/cipher_extra/e_tls.c89
-rw-r--r--deps/boringssl/src/crypto/cipher_extra/internal.h17
-rw-r--r--deps/boringssl/src/crypto/cipher_extra/tls_cbc.c392
-rw-r--r--deps/boringssl/src/crypto/conf/conf.c17
-rw-r--r--deps/boringssl/src/crypto/conf/conf_test.cc44
-rw-r--r--deps/boringssl/src/crypto/cpu-arm-linux.c13
-rw-r--r--deps/boringssl/src/crypto/cpu-arm.c6
-rw-r--r--deps/boringssl/src/crypto/crypto_test.cc46
-rw-r--r--deps/boringssl/src/crypto/curve25519/curve25519.c2
-rw-r--r--deps/boringssl/src/crypto/curve25519/internal.h2
-rw-r--r--deps/boringssl/src/crypto/digest_extra/digest_extra.c9
-rw-r--r--deps/boringssl/src/crypto/digest_extra/digest_test.cc31
-rw-r--r--deps/boringssl/src/crypto/err/err.c167
-rw-r--r--deps/boringssl/src/crypto/err/err_test.cc10
-rw-r--r--deps/boringssl/src/crypto/evp/evp.c9
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/CMakeLists.txt22
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/bcm.c1
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/bn/bn_test.cc23
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/bn/div.c35
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/bn/gcd_extra.c5
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/bn/internal.h9
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/bn/prime.c4
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/cipher/cipher.c48
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/cipher/e_aes.c27
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/digest/digest.c9
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/digest/digests.c12
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/digest/md32_common.h247
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/ec/ec.c4
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/ec/ec_key.c1
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/ec/internal.h4
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa.c197
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc19
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/ecdsa/internal.h39
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/is_fips.c29
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/md4/md4.c119
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/md5/md5.c118
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/modes/cbc.c55
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/modes/cfb.c17
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/modes/ctr.c17
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/modes/gcm.c30
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/modes/gcm_nohw.c2
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/modes/gcm_test.cc2
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/modes/internal.h23
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/modes/ofb.c3
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/rand/internal.h19
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/rand/rand.c27
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/rand/urandom.c43
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/rsa/rsa.c77
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.c23
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/self_check/fips.c79
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/self_check/self_check.c23
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/sha/sha1.c136
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/sha/sha256.c183
-rw-r--r--deps/boringssl/src/crypto/fipsmodule/sha/sha512.c89
-rw-r--r--deps/boringssl/src/crypto/hpke/hpke.c708
-rw-r--r--deps/boringssl/src/crypto/hpke/hpke_test.cc407
-rw-r--r--deps/boringssl/src/crypto/hpke/internal.h246
-rw-r--r--deps/boringssl/src/crypto/hrss/asm/poly_rq_mul.S2820
-rw-r--r--deps/boringssl/src/crypto/hrss/hrss.c340
-rw-r--r--deps/boringssl/src/crypto/hrss/hrss_test.cc43
-rw-r--r--deps/boringssl/src/crypto/hrss/internal.h11
-rw-r--r--deps/boringssl/src/crypto/internal.h86
-rw-r--r--deps/boringssl/src/crypto/lhash/internal.h253
-rw-r--r--deps/boringssl/src/crypto/lhash/lhash.c51
-rw-r--r--deps/boringssl/src/crypto/lhash/lhash_test.cc17
-rw-r--r--deps/boringssl/src/crypto/mem.c55
-rw-r--r--deps/boringssl/src/crypto/obj/obj.c16
-rw-r--r--deps/boringssl/src/crypto/obj/obj_test.cc49
-rw-r--r--deps/boringssl/src/crypto/pem/pem_all.c9
-rw-r--r--deps/boringssl/src/crypto/pem/pem_info.c2
-rw-r--r--deps/boringssl/src/crypto/pem/pem_lib.c8
-rw-r--r--deps/boringssl/src/crypto/pem/pem_pk8.c2
-rw-r--r--deps/boringssl/src/crypto/pem/pem_pkey.c4
-rw-r--r--deps/boringssl/src/crypto/pkcs7/pkcs7_test.cc119
-rw-r--r--deps/boringssl/src/crypto/pkcs7/pkcs7_x509.c8
-rw-r--r--deps/boringssl/src/crypto/pkcs8/pkcs12_test.cc1544
-rw-r--r--deps/boringssl/src/crypto/pkcs8/pkcs8_x509.c143
-rw-r--r--deps/boringssl/src/crypto/poly1305/poly1305.c2
-rw-r--r--deps/boringssl/src/crypto/pool/pool.c1
-rw-r--r--deps/boringssl/src/crypto/rand_extra/deterministic.c4
-rw-r--r--deps/boringssl/src/crypto/rand_extra/fuchsia.c4
-rw-r--r--deps/boringssl/src/crypto/rand_extra/passive.c4
-rw-r--r--deps/boringssl/src/crypto/rand_extra/rand_extra.c2
-rw-r--r--deps/boringssl/src/crypto/rand_extra/windows.c4
-rw-r--r--deps/boringssl/src/crypto/rsa_extra/rsa_asn1.c3
-rw-r--r--deps/boringssl/src/crypto/thread_pthread.c28
-rw-r--r--deps/boringssl/src/crypto/x509/a_verify.c26
-rw-r--r--deps/boringssl/src/crypto/x509/algorithm.c2
-rw-r--r--deps/boringssl/src/crypto/x509/by_dir.c1
-rw-r--r--deps/boringssl/src/crypto/x509/by_file.c2
-rw-r--r--deps/boringssl/src/crypto/x509/internal.h359
-rw-r--r--deps/boringssl/src/crypto/x509/name_print.c246
-rw-r--r--deps/boringssl/src/crypto/x509/rsa_pss.c6
-rw-r--r--deps/boringssl/src/crypto/x509/t_crl.c15
-rw-r--r--deps/boringssl/src/crypto/x509/t_req.c2
-rw-r--r--deps/boringssl/src/crypto/x509/t_x509.c179
-rw-r--r--deps/boringssl/src/crypto/x509/t_x509a.c9
-rw-r--r--deps/boringssl/src/crypto/x509/vpm_int.h71
-rw-r--r--deps/boringssl/src/crypto/x509/x509_att.c71
-rw-r--r--deps/boringssl/src/crypto/x509/x509_cmp.c33
-rw-r--r--deps/boringssl/src/crypto/x509/x509_ext.c4
-rw-r--r--deps/boringssl/src/crypto/x509/x509_lu.c1
-rw-r--r--deps/boringssl/src/crypto/x509/x509_obj.c1
-rw-r--r--deps/boringssl/src/crypto/x509/x509_req.c131
-rw-r--r--deps/boringssl/src/crypto/x509/x509_set.c25
-rw-r--r--deps/boringssl/src/crypto/x509/x509_test.cc498
-rw-r--r--deps/boringssl/src/crypto/x509/x509_trs.c2
-rw-r--r--deps/boringssl/src/crypto/x509/x509_v3.c47
-rw-r--r--deps/boringssl/src/crypto/x509/x509_vfy.c58
-rw-r--r--deps/boringssl/src/crypto/x509/x509_vpm.c126
-rw-r--r--deps/boringssl/src/crypto/x509/x509cset.c32
-rw-r--r--deps/boringssl/src/crypto/x509/x509name.c6
-rw-r--r--deps/boringssl/src/crypto/x509/x509rset.c3
-rw-r--r--deps/boringssl/src/crypto/x509/x_algor.c40
-rw-r--r--deps/boringssl/src/crypto/x509/x_all.c19
-rw-r--r--deps/boringssl/src/crypto/x509/x_attrib.c55
-rw-r--r--deps/boringssl/src/crypto/x509/x_crl.c25
-rw-r--r--deps/boringssl/src/crypto/x509/x_exten.c2
-rw-r--r--deps/boringssl/src/crypto/x509/x_name.c5
-rw-r--r--deps/boringssl/src/crypto/x509/x_pubkey.c47
-rw-r--r--deps/boringssl/src/crypto/x509/x_req.c13
-rw-r--r--deps/boringssl/src/crypto/x509/x_sig.c5
-rw-r--r--deps/boringssl/src/crypto/x509/x_val.c2
-rw-r--r--deps/boringssl/src/crypto/x509/x_x509.c5
-rw-r--r--deps/boringssl/src/crypto/x509/x_x509a.c3
-rw-r--r--deps/boringssl/src/crypto/x509v3/internal.h23
-rw-r--r--deps/boringssl/src/crypto/x509v3/pcy_cache.c1
-rw-r--r--deps/boringssl/src/crypto/x509v3/pcy_data.c2
-rw-r--r--deps/boringssl/src/crypto/x509v3/pcy_int.h2
-rw-r--r--deps/boringssl/src/crypto/x509v3/pcy_map.c1
-rw-r--r--deps/boringssl/src/crypto/x509v3/pcy_tree.c7
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_akey.c29
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_alt.c25
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_bitst.c3
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_conf.c1
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_cpols.c18
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_crld.c6
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_enum.c5
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_lib.c2
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_ncons.c167
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_pci.c3
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_prn.c27
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_purp.c3
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_skey.c1
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3_utl.c118
-rw-r--r--deps/boringssl/src/crypto/x509v3/v3name_test.cc2
-rw-r--r--deps/boringssl/src/decrepit/evp/evp_do_all.c8
-rw-r--r--deps/boringssl/src/decrepit/ripemd/internal.h494
-rw-r--r--deps/boringssl/src/decrepit/ripemd/ripemd.c488
-rw-r--r--deps/boringssl/src/fuzz/CMakeLists.txt1
-rw-r--r--deps/boringssl/src/fuzz/cert.cc4
-rw-r--r--deps/boringssl/src/fuzz/decode_client_hello_inner.cc52
-rw-r--r--deps/boringssl/src/fuzz/ssl_ctx_api.cc23
-rw-r--r--deps/boringssl/src/include/openssl/aead.h5
-rw-r--r--deps/boringssl/src/include/openssl/arm_arch.h67
-rw-r--r--deps/boringssl/src/include/openssl/asn1.h863
-rw-r--r--deps/boringssl/src/include/openssl/asn1t.h7
-rw-r--r--deps/boringssl/src/include/openssl/base.h58
-rw-r--r--deps/boringssl/src/include/openssl/bio.h4
-rw-r--r--deps/boringssl/src/include/openssl/bytestring.h10
-rw-r--r--deps/boringssl/src/include/openssl/chacha.h2
-rw-r--r--deps/boringssl/src/include/openssl/cipher.h4
-rw-r--r--deps/boringssl/src/include/openssl/conf.h13
-rw-r--r--deps/boringssl/src/include/openssl/cpu.h54
-rw-r--r--deps/boringssl/src/include/openssl/crypto.h28
-rw-r--r--deps/boringssl/src/include/openssl/digest.h11
-rw-r--r--deps/boringssl/src/include/openssl/ec.h7
-rw-r--r--deps/boringssl/src/include/openssl/ecdsa.h33
-rw-r--r--deps/boringssl/src/include/openssl/err.h5
-rw-r--r--deps/boringssl/src/include/openssl/evp.h75
-rw-r--r--deps/boringssl/src/include/openssl/evp_errors.h (renamed from deps/boringssl/src/crypto/x509/x509_r2x.c)99
-rw-r--r--deps/boringssl/src/include/openssl/hkdf.h4
-rw-r--r--deps/boringssl/src/include/openssl/hpke.h350
-rw-r--r--deps/boringssl/src/include/openssl/hrss.h26
-rw-r--r--deps/boringssl/src/include/openssl/lhash.h209
-rw-r--r--deps/boringssl/src/include/openssl/mem.h3
-rw-r--r--deps/boringssl/src/include/openssl/obj.h32
-rw-r--r--deps/boringssl/src/include/openssl/pem.h20
-rw-r--r--deps/boringssl/src/include/openssl/pkcs7.h32
-rw-r--r--deps/boringssl/src/include/openssl/pkcs8.h10
-rw-r--r--deps/boringssl/src/include/openssl/rand.h4
-rw-r--r--deps/boringssl/src/include/openssl/rsa.h162
-rw-r--r--deps/boringssl/src/include/openssl/span.h52
-rw-r--r--deps/boringssl/src/include/openssl/ssl.h462
-rw-r--r--deps/boringssl/src/include/openssl/tls1.h89
-rw-r--r--deps/boringssl/src/include/openssl/x509.h949
-rw-r--r--deps/boringssl/src/include/openssl/x509_vfy.h768
-rw-r--r--deps/boringssl/src/include/openssl/x509v3.h64
-rw-r--r--deps/boringssl/src/sources.cmake12
-rw-r--r--deps/boringssl/src/ssl/CMakeLists.txt3
-rw-r--r--deps/boringssl/src/ssl/d1_both.cc34
-rw-r--r--deps/boringssl/src/ssl/d1_srtp.cc2
-rw-r--r--deps/boringssl/src/ssl/encrypted_client_hello.cc1126
-rw-r--r--deps/boringssl/src/ssl/extensions.cc (renamed from deps/boringssl/src/ssl/t1_lib.cc)1462
-rw-r--r--deps/boringssl/src/ssl/handoff.cc320
-rw-r--r--deps/boringssl/src/ssl/handshake.cc133
-rw-r--r--deps/boringssl/src/ssl/handshake_client.cc508
-rw-r--r--deps/boringssl/src/ssl/handshake_server.cc209
-rw-r--r--deps/boringssl/src/ssl/internal.h626
-rw-r--r--deps/boringssl/src/ssl/s3_both.cc12
-rw-r--r--deps/boringssl/src/ssl/s3_lib.cc1
-rw-r--r--deps/boringssl/src/ssl/s3_pkt.cc33
-rw-r--r--deps/boringssl/src/ssl/ssl_cert.cc10
-rw-r--r--deps/boringssl/src/ssl/ssl_cipher.cc4
-rw-r--r--deps/boringssl/src/ssl/ssl_key_share.cc65
-rw-r--r--deps/boringssl/src/ssl/ssl_lib.cc162
-rw-r--r--deps/boringssl/src/ssl/ssl_privkey.cc2
-rw-r--r--deps/boringssl/src/ssl/ssl_session.cc225
-rw-r--r--deps/boringssl/src/ssl/ssl_stat.cc3
-rw-r--r--deps/boringssl/src/ssl/ssl_test.cc1923
-rw-r--r--deps/boringssl/src/ssl/ssl_transcript.cc25
-rw-r--r--deps/boringssl/src/ssl/ssl_versions.cc10
-rw-r--r--deps/boringssl/src/ssl/ssl_x509.cc50
-rw-r--r--deps/boringssl/src/ssl/test/bssl_shim.cc152
-rw-r--r--deps/boringssl/src/ssl/test/fuzzer.h54
-rw-r--r--deps/boringssl/src/ssl/test/fuzzer_tags.h5
-rw-r--r--deps/boringssl/src/ssl/test/handshake_util.cc386
-rw-r--r--deps/boringssl/src/ssl/test/handshake_util.h24
-rw-r--r--deps/boringssl/src/ssl/test/handshaker.cc158
-rw-r--r--deps/boringssl/src/ssl/test/mock_quic_transport.cc2
-rw-r--r--deps/boringssl/src/ssl/test/settings_writer.cc25
-rw-r--r--deps/boringssl/src/ssl/test/settings_writer.h5
-rw-r--r--deps/boringssl/src/ssl/test/test_config.cc442
-rw-r--r--deps/boringssl/src/ssl/test/test_config.h21
-rw-r--r--deps/boringssl/src/ssl/test/test_state.h7
-rw-r--r--deps/boringssl/src/ssl/tls13_both.cc113
-rw-r--r--deps/boringssl/src/ssl/tls13_client.cc413
-rw-r--r--deps/boringssl/src/ssl/tls13_enc.cc256
-rw-r--r--deps/boringssl/src/ssl/tls13_server.cc373
-rw-r--r--deps/boringssl/src/ssl/tls_method.cc6
-rw-r--r--deps/boringssl/src/tool/CMakeLists.txt1
-rw-r--r--deps/boringssl/src/tool/args.cc10
-rw-r--r--deps/boringssl/src/tool/client.cc54
-rw-r--r--deps/boringssl/src/tool/file.cc18
-rw-r--r--deps/boringssl/src/tool/generate_ech.cc133
-rw-r--r--deps/boringssl/src/tool/generate_ed25519.cc20
-rw-r--r--deps/boringssl/src/tool/internal.h3
-rw-r--r--deps/boringssl/src/tool/server.cc52
-rw-r--r--deps/boringssl/src/tool/speed.cc63
-rw-r--r--deps/boringssl/src/tool/tool.cc1
-rw-r--r--deps/boringssl/src/tool/transport_common.cc3
-rw-r--r--deps/boringssl/src/util/fipstools/acvp/modulewrapper/CMakeLists.txt1
-rw-r--r--deps/boringssl/src/util/fipstools/acvp/modulewrapper/main.cc75
-rw-r--r--deps/boringssl/src/util/fipstools/acvp/modulewrapper/modulewrapper.cc543
-rw-r--r--deps/boringssl/src/util/fipstools/acvp/modulewrapper/modulewrapper.h69
-rw-r--r--deps/boringssl/win-aarch64/crypto/fipsmodule/ghashv8-armx64.S328
-rw-r--r--examples/Makefile2
-rw-r--r--examples/client.rs23
-rw-r--r--examples/http3-client.c30
-rw-r--r--examples/http3-client.rs48
-rw-r--r--examples/http3-server.c8
-rw-r--r--examples/http3-server.rs47
-rw-r--r--examples/server.c2
-rw-r--r--examples/server.rs27
-rw-r--r--include/quiche.h248
-rw-r--r--patches/Android.bp.patch75
-rw-r--r--patches/lib.rs-app-proto.patch47
-rw-r--r--src/build.rs61
-rw-r--r--src/crypto.rs242
-rw-r--r--src/dgram.rs5
-rw-r--r--src/ffi.rs120
-rw-r--r--src/flowcontrol.rs220
-rw-r--r--src/frame.rs505
-rw-r--r--src/h3/ffi.rs86
-rw-r--r--src/h3/frame.rs406
-rw-r--r--src/h3/mod.rs1477
-rw-r--r--src/h3/qpack/decoder.rs11
-rw-r--r--src/h3/qpack/encoder.rs11
-rw-r--r--src/h3/qpack/huffman/mod.rs2
-rw-r--r--src/h3/qpack/huffman/table.rs2
-rw-r--r--src/h3/qpack/mod.rs4
-rw-r--r--src/h3/stream.rs114
-rw-r--r--src/lib.rs2045
-rw-r--r--src/minmax.rs10
-rw-r--r--src/octets.rs1277
-rw-r--r--src/packet.rs114
-rw-r--r--src/ranges.rs1
-rw-r--r--src/recovery/cubic.rs501
-rw-r--r--src/recovery/delivery_rate.rs452
-rw-r--r--src/recovery/hystart.rs158
-rw-r--r--src/recovery/mod.rs476
-rw-r--r--src/recovery/prr.rs238
-rw-r--r--src/recovery/reno.rs110
-rw-r--r--src/stream.rs453
-rw-r--r--src/tls.rs388
337 files changed, 27375 insertions, 16045 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 3186f7e..615faf7 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
{
"git": {
- "sha1": "ad9d9330cf77b212915c2b175e90063c2cc3ac78"
- }
-}
+ "sha1": "4d411c22413835f2d57f993d1c90c07813f803cd"
+ },
+ "path_in_vcs": "quiche"
+} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 109b229..135c2dc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -61,6 +61,7 @@ rust_defaults {
"liblibc",
"liblibm",
"liblog_rust",
+ "liboctets",
"libring",
],
prefer_rlib: true,
@@ -129,6 +130,7 @@ rust_defaults {
"liblibm",
"liblog_rust",
"libmio",
+ "liboctets",
"libring",
"liburl",
],
diff --git a/Cargo.lock b/Cargo.lock
index de30126..563148c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,74 +1,62 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-[[package]]
-name = "aho-corasick"
-version = "0.7.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
-dependencies = [
- "memchr",
-]
+version = 3
[[package]]
-name = "ansi_term"
-version = "0.11.0"
+name = "arrayvec"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
-dependencies = [
- "winapi 0.3.9",
-]
-
-[[package]]
-name = "atty"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
-dependencies = [
- "hermit-abi",
- "libc",
- "winapi 0.3.9",
-]
+checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]]
name = "autocfg"
-version = "1.0.1"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bindgen"
-version = "0.57.0"
+version = "0.59.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd4865004a46a0aafb2a0a5eb19d3c9fc46ee5f063a6cfc605c69ac9ecf5263d"
+checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
- "clap",
- "env_logger",
"lazy_static",
"lazycell",
- "log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
- "which",
]
[[package]]
name = "bitflags"
-version = "1.2.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "boring"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6953f3fea6f9f20c15e81b3f4ef2217ea06cc05652a0db49c0abb35626b0fad1"
+dependencies = [
+ "bitflags",
+ "boring-sys",
+ "foreign-types",
+ "lazy_static",
+ "libc",
+]
[[package]]
name = "boring-sys"
-version = "1.1.1"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2416bce1bcabf0d7995ce0338ec2425b8766a4d5a39d758a3638008911642fc"
+checksum = "9e43b1d5c3524929bc64d56e604f7362e357d509ff8b29903605fd72f4f41eae"
dependencies = [
"bindgen",
"cmake",
@@ -76,42 +64,36 @@ dependencies = [
[[package]]
name = "bumpalo"
-version = "3.7.0"
+version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631"
+checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]]
name = "cc"
-version = "1.0.68"
+version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
+checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cexpr"
-version = "0.4.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-
-[[package]]
-name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
-version = "1.2.0"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c"
+checksum = "bf6b561dcf059c85bbe388e0a7b0a1469acb3934cc0cfa148613a830629e3049"
dependencies = [
"glob",
"libc",
@@ -119,34 +101,19 @@ dependencies = [
]
[[package]]
-name = "clap"
-version = "2.33.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
-dependencies = [
- "ansi_term",
- "atty",
- "bitflags",
- "strsim 0.8.0",
- "textwrap",
- "unicode-width",
- "vec_map",
-]
-
-[[package]]
name = "cmake"
-version = "0.1.45"
+version = "0.1.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855"
+checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a"
dependencies = [
"cc",
]
[[package]]
name = "darling"
-version = "0.13.0"
+version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12"
+checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
dependencies = [
"darling_core",
"darling_macro",
@@ -154,23 +121,23 @@ dependencies = [
[[package]]
name = "darling_core"
-version = "0.13.0"
+version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3"
+checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
- "strsim 0.10.0",
+ "strsim",
"syn",
]
[[package]]
name = "darling_macro"
-version = "0.13.0"
+version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc"
+checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [
"darling_core",
"quote",
@@ -178,17 +145,10 @@ dependencies = [
]
[[package]]
-name = "env_logger"
-version = "0.8.3"
+name = "data-encoding"
+version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f"
-dependencies = [
- "atty",
- "humantime",
- "log",
- "regex",
- "termcolor",
-]
+checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
[[package]]
name = "fnv"
@@ -197,20 +157,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
-name = "fuchsia-zircon"
-version = "0.3.3"
+name = "foreign-types"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
dependencies = [
- "bitflags",
- "fuchsia-zircon-sys",
+ "foreign-types-macros",
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-macros"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
-name = "fuchsia-zircon-sys"
-version = "0.3.3"
+name = "foreign-types-shared"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]]
name = "glob"
@@ -220,24 +191,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "hashbrown"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
-
-[[package]]
-name = "hermit-abi"
-version = "0.1.18"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "ident_case"
@@ -258,49 +214,30 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "1.6.2"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
+checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
-name = "iovec"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
-dependencies = [
- "libc",
-]
-
-[[package]]
name = "itoa"
-version = "0.4.7"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
[[package]]
name = "js-sys"
-version = "0.3.51"
+version = "0.3.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
+checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397"
dependencies = [
"wasm-bindgen",
]
[[package]]
-name = "kernel32-sys"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-dependencies = [
- "winapi 0.2.8",
- "winapi-build",
-]
-
-[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -314,104 +251,95 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
-version = "0.2.95"
+version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "libloading"
-version = "0.7.0"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
+checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
dependencies = [
- "cfg-if 1.0.0",
- "winapi 0.3.9",
+ "cfg-if",
+ "winapi",
]
[[package]]
name = "libm"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
+checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db"
[[package]]
name = "log"
-version = "0.4.14"
+version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
]
[[package]]
name = "matches"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
+checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "memchr"
-version = "2.4.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "mio"
-version = "0.6.23"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
+checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799"
dependencies = [
- "cfg-if 0.1.10",
- "fuchsia-zircon",
- "fuchsia-zircon-sys",
- "iovec",
- "kernel32-sys",
"libc",
"log",
- "miow",
- "net2",
- "slab",
- "winapi 0.2.8",
+ "wasi",
+ "windows-sys",
]
[[package]]
-name = "miow"
-version = "0.2.2"
+name = "nom"
+version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
+checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [
- "kernel32-sys",
- "net2",
- "winapi 0.2.8",
- "ws2_32-sys",
+ "memchr",
+ "minimal-lexical",
]
[[package]]
-name = "net2"
-version = "0.2.37"
+name = "num-traits"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
- "cfg-if 0.1.10",
- "libc",
- "winapi 0.3.9",
+ "autocfg",
]
[[package]]
-name = "nom"
-version = "5.1.2"
+name = "octets"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
-dependencies = [
- "memchr",
- "version_check",
-]
+checksum = "3fa906ec83d76442cc421a362fa8c131caa513ca19af87dc5736b6679b43240d"
[[package]]
name = "once_cell"
-version = "1.7.2"
+version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
+checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca"
[[package]]
name = "peeking_take_while"
@@ -427,18 +355,18 @@ checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
[[package]]
name = "proc-macro2"
-version = "1.0.27"
+version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
dependencies = [
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
name = "qlog"
-version = "0.4.0"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8777d5490145d6907198d48b3a907447689ce80e071b3d8a16a9d9fb3df02bc1"
+checksum = "8d439010ca75633cd1a13f0ebc31e8fe982541d1db4ecd84a4d7280adc01d296"
dependencies = [
"serde",
"serde_derive",
@@ -448,46 +376,47 @@ dependencies = [
[[package]]
name = "quiche"
-version = "0.9.0"
+version = "0.14.0"
dependencies = [
- "boring-sys",
+ "boring",
"cmake",
+ "foreign-types-shared",
"lazy_static",
"libc",
"libm",
"log",
"mio",
+ "octets",
"qlog",
"ring",
+ "sfv",
"url",
- "winapi 0.3.9",
+ "winapi",
]
[[package]]
name = "quote"
-version = "1.0.9"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
-version = "1.5.4"
+version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
dependencies = [
- "aho-corasick",
- "memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
-version = "0.6.25"
+version = "0.6.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
[[package]]
name = "ring"
@@ -501,7 +430,18 @@ dependencies = [
"spin",
"untrusted",
"web-sys",
- "winapi 0.3.9",
+ "winapi",
+]
+
+[[package]]
+name = "rust_decimal"
+version = "1.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22dc69eadbf0ee2110b8d20418c0c6edbaefec2811c4963dc17b6344e11fe0f8"
+dependencies = [
+ "arrayvec",
+ "num-traits",
+ "serde",
]
[[package]]
@@ -512,30 +452,30 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustversion"
-version = "1.0.5"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
+checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]]
name = "ryu"
-version = "1.0.5"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
[[package]]
name = "serde"
-version = "1.0.126"
+version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
+checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.126"
+version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
+checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
dependencies = [
"proc-macro2",
"quote",
@@ -544,9 +484,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.64"
+version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
+checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
dependencies = [
"indexmap",
"itoa",
@@ -556,9 +496,9 @@ dependencies = [
[[package]]
name = "serde_with"
-version = "1.9.2"
+version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e3132bd01cfb74aac8b1b10083ad1f38dbf756df3176d5e63dd91e3f62a87f5"
+checksum = "b827f2113224f3f19a665136f006709194bdfdcb1fdc1e4b2b5cbac8e0cced54"
dependencies = [
"rustversion",
"serde",
@@ -567,9 +507,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "1.4.2"
+version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1569374bd54623ec8bd592cf22ba6e03c0f177ff55fbc8c29a49e296e7adecf"
+checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
dependencies = [
"darling",
"proc-macro2",
@@ -578,16 +518,21 @@ dependencies = [
]
[[package]]
-name = "shlex"
-version = "0.1.1"
+name = "sfv"
+version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
+checksum = "5082e028484c60920c1b0dc8ab6bd4663f075e15095c5a9009fae779c01f6364"
+dependencies = [
+ "data-encoding",
+ "indexmap",
+ "rust_decimal",
+]
[[package]]
-name = "slab"
-version = "0.4.3"
+name = "shlex"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
+checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]]
name = "spin"
@@ -597,50 +542,26 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "strsim"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
-
-[[package]]
-name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
-version = "1.0.72"
+version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
+checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
dependencies = [
"proc-macro2",
"quote",
- "unicode-xid",
-]
-
-[[package]]
-name = "termcolor"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
-name = "textwrap"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
-dependencies = [
- "unicode-width",
+ "unicode-ident",
]
[[package]]
name = "tinyvec"
-version = "1.2.0"
+version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
"tinyvec_macros",
]
@@ -653,12 +574,15 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "unicode-bidi"
-version = "0.3.5"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
-dependencies = [
- "matches",
-]
+checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
[[package]]
name = "unicode-normalization"
@@ -670,18 +594,6 @@ dependencies = [
]
[[package]]
-name = "unicode-width"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
-
-[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -699,32 +611,26 @@ dependencies = [
]
[[package]]
-name = "vec_map"
-version = "0.8.2"
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
-
-[[package]]
-name = "version_check"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.74"
+version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
+checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.74"
+version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
+checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
dependencies = [
"bumpalo",
"lazy_static",
@@ -737,9 +643,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.74"
+version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
+checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -747,9 +653,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.74"
+version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
+checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
dependencies = [
"proc-macro2",
"quote",
@@ -760,36 +666,21 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.74"
+version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
+checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
[[package]]
name = "web-sys"
-version = "0.3.51"
+version = "0.3.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
+checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
-name = "which"
-version = "3.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "winapi"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
-
-[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -800,38 +691,56 @@ dependencies = [
]
[[package]]
-name = "winapi-build"
-version = "0.1.1"
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
-name = "winapi-i686-pc-windows-gnu"
+name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
-name = "winapi-util"
-version = "0.1.5"
+name = "windows-sys"
+version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
- "winapi 0.3.9",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_msvc",
]
[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
+name = "windows_aarch64_msvc"
+version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
-name = "ws2_32-sys"
-version = "0.2.1"
+name = "windows_i686_gnu"
+version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
-dependencies = [
- "winapi 0.2.8",
- "winapi-build",
-]
+checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
diff --git a/Cargo.toml b/Cargo.toml
index 62b856a..ad466c8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,38 +3,67 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "quiche"
-version = "0.9.0"
+version = "0.14.0"
authors = ["Alessandro Ghedini <alessandro@ghedini.me>"]
build = "src/build.rs"
-include = ["/*.md", "/*.toml", "/CODEOWNERS", "/COPYING", "/benches", "/deps/boringssl/**/*.[chS]", "/deps/boringssl/**/*.asm", "/deps/boringssl/src/**/*.cc", "/deps/boringssl/**/CMakeLists.txt", "/deps/boringssl/**/sources.cmake", "/deps/boringssl/LICENSE", "/examples", "/include", "/quiche.svg", "/src"]
+include = [
+ "/*.md",
+ "/*.toml",
+ "/COPYING",
+ "/deps/boringssl/**/*.[chS]",
+ "/deps/boringssl/**/*.asm",
+ "/deps/boringssl/src/**/*.cc",
+ "/deps/boringssl/**/CMakeLists.txt",
+ "/deps/boringssl/**/sources.cmake",
+ "/deps/boringssl/LICENSE",
+ "/examples",
+ "/include",
+ "/quiche.svg",
+ "/src",
+]
description = "🥧 Savoury implementation of the QUIC transport protocol and HTTP/3"
readme = "README.md"
-keywords = ["quic", "http3"]
+keywords = [
+ "quic",
+ "http3",
+]
categories = ["network-programming"]
license = "BSD-2-Clause"
repository = "https://github.com/cloudflare/quiche"
+
[package.metadata.docs.rs]
no-default-features = true
-[profile.bench]
-debug = true
-
-[profile.release]
-debug = true
+features = [
+ "boringssl-boring-crate",
+ "qlog",
+]
+rustdoc-args = [
+ "--cfg",
+ "docsrs",
+]
[lib]
-crate-type = ["lib", "staticlib", "cdylib"]
-[dependencies.boring-sys]
-version = "1.0.2"
+crate-type = [
+ "lib",
+ "staticlib",
+ "cdylib",
+]
+
+[dependencies.boring]
+version = "2.0.0"
+optional = true
+
+[dependencies.foreign-types-shared]
+version = "0.3.0"
optional = true
[dependencies.lazy_static]
@@ -50,27 +79,48 @@ version = "0.2"
version = "0.4"
features = ["std"]
+[dependencies.octets]
+version = "0.1"
+
[dependencies.qlog]
-version = "0.4"
+version = "0.7"
optional = true
[dependencies.ring]
version = "0.16"
+
+[dependencies.sfv]
+version = "0.9"
+optional = true
+
[dev-dependencies.mio]
-version = "0.6"
+version = "0.8"
+features = [
+ "net",
+ "os-poll",
+]
[dev-dependencies.url]
version = "1"
+
[build-dependencies.cmake]
version = "0.1"
[features]
+boringssl-boring-crate = [
+ "boring",
+ "foreign-types-shared",
+]
boringssl-vendored = []
default = ["boringssl-vendored"]
ffi = []
fuzzing = []
-ndk-old-gcc = []
pkg-config-meta = []
+
[target."cfg(windows)".dependencies.winapi]
version = "0.3"
-features = ["wincrypt"]
+features = [
+ "wincrypt",
+ "ws2def",
+ "ws2ipdef",
+]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 12bddf8..b217d2a 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "quiche"
-version = "0.9.0"
+version = "0.14.0"
authors = ["Alessandro Ghedini <alessandro@ghedini.me>"]
edition = "2018"
build = "src/build.rs"
@@ -13,9 +13,7 @@ license = "BSD-2-Clause"
include = [
"/*.md",
"/*.toml",
- "/CODEOWNERS",
"/COPYING",
- "/benches",
"/deps/boringssl/**/*.[chS]",
"/deps/boringssl/**/*.asm",
"/deps/boringssl/src/**/*.cc",
@@ -31,23 +29,25 @@ include = [
[features]
default = ["boringssl-vendored"]
-# Build vendored BoringSSL library.
+# Build the vendored BoringSSL library.
boringssl-vendored = []
+# Use the BoringSSL library provided by the boring crate.
+boringssl-boring-crate = ["boring", "foreign-types-shared"]
+
# Generate pkg-config metadata file for libquiche.
pkg-config-meta = []
# Equivalent to "--cfg fuzzing", but can also be checked in build.rs.
fuzzing = []
-# For building with Android NDK < 18 and GCC.
-ndk-old-gcc = []
-
-# Expose the FFI API.
+# Build and expose the FFI API.
ffi = []
[package.metadata.docs.rs]
no-default-features = true
+features = ["boringssl-boring-crate", "qlog"]
+rustdoc-args = ["--cfg", "docsrs"]
[build-dependencies]
cmake = "0.1"
@@ -58,21 +58,18 @@ libc = "0.2"
libm = "0.2"
ring = "0.16"
lazy_static = "1"
-boring-sys = { version = "1.0.2", optional = true }
-qlog = { version = "0.4", path = "tools/qlog", optional = true }
+octets = { version = "0.1", path = "../octets" }
+boring = { version = "2.0.0", optional = true }
+foreign-types-shared = { version = "0.3.0", optional = true }
+qlog = { version = "0.7", path = "../qlog", optional = true }
+sfv = { version = "0.9", optional = true }
[target."cfg(windows)".dependencies]
-winapi = { version = "0.3", features = ["wincrypt"] }
+winapi = { version = "0.3", features = ["wincrypt", "ws2def", "ws2ipdef"] }
[dev-dependencies]
-mio = "0.6"
+mio = { version = "0.8", features = ["net", "os-poll"] }
url = "1"
-[profile.bench]
-debug = true
-
-[profile.release]
-debug = true
-
[lib]
crate-type = ["lib", "staticlib", "cdylib"]
diff --git a/METADATA b/METADATA
index 218f6f3..96b080d 100644
--- a/METADATA
+++ b/METADATA
@@ -1,5 +1,5 @@
name: "quiche"
-description: "\360\237\245\247 Savoury implementation of the QUIC transport protocol and HTTP/3"
+description: "\ud83e\udd67 Savoury implementation of the QUIC transport protocol and HTTP/3"
third_party {
url {
type: HOMEPAGE
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/quiche/quiche-0.9.0.crate"
+ value: "https://static.crates.io/crates/quiche/quiche-0.14.0.crate"
}
- version: "0.9.0"
+ version: "0.14.0"
license_type: NOTICE
last_upgrade_date {
- year: 2021
- month: 6
- day: 8
+ year: 2022
+ month: 9
+ day: 20
}
}
diff --git a/OWNERS b/OWNERS
index 46fc303..45dc4dd 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1 +1 @@
-include platform/prebuilts/rust:/OWNERS
+include platform/prebuilts/rust:master:/OWNERS
diff --git a/README.md b/README.md
index 2be56f2..65e5810 100644
--- a/README.md
+++ b/README.md
@@ -32,12 +32,11 @@ quiche can be [integrated into curl][curl-http3] to provide support for HTTP/3.
### NGINX (unofficial)
-quiche can be [integrated into NGINX][nginx-http3] using an unofficial patch to
+quiche can be [integrated into NGINX](nginx/) using an unofficial patch to
provide support for HTTP/3.
[cloudflare-http3]: https://blog.cloudflare.com/http3-the-past-present-and-future/
[curl-http3]: https://github.com/curl/curl/blob/master/docs/HTTP3.md#quiche-version
-[nginx-http3]: https://github.com/cloudflare/quiche/tree/master/extras/nginx
Getting Started
---------------
@@ -45,20 +44,18 @@ Getting Started
### Command-line apps
Before diving into the quiche API, here are a few examples on how to use the
-quiche tools provided as part of the [quiche-apps](tools/apps/) crate.
+quiche tools provided as part of the [quiche-apps](apps/) crate.
After cloning the project according to the command mentioned in the [building](#building) section, the client can be run as follows:
```bash
- $ cargo run --manifest-path=tools/apps/Cargo.toml --bin quiche-client -- https://cloudflare-quic.com/
+ $ cargo run --bin quiche-client -- https://cloudflare-quic.com/
```
while the server can be run as follows:
```bash
- $ cargo run --manifest-path=tools/apps/Cargo.toml --bin quiche-server -- \
- --cert tools/apps/src/bin/cert.crt \
- --key tools/apps/src/bin/cert.key
+ $ cargo run --bin quiche-server -- --cert apps/src/bin/cert.crt --key apps/src/bin/cert.key
```
(note that the certificate provided is self-signed and should not be used in
@@ -97,9 +94,11 @@ incoming packets that belong to that connection from the network:
```rust
loop {
- let read = socket.recv(&mut buf).unwrap();
+ let (read, from) = socket.recv_from(&mut buf).unwrap();
- let read = match conn.recv(&mut buf[..read]) {
+ let recv_info = quiche::RecvInfo { from };
+
+ let read = match conn.recv(&mut buf[..read], recv_info) {
Ok(v) => v,
Err(e) => {
@@ -117,7 +116,7 @@ instead:
```rust
loop {
- let write = match conn.send(&mut out) {
+ let (write, send_info) = match conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -131,7 +130,7 @@ loop {
},
};
- socket.send(&out[..write]).unwrap();
+ socket.send_to(&out[..write], &send_info.to).unwrap();
}
```
@@ -154,7 +153,7 @@ conn.on_timeout();
// Send more packets as needed after timeout.
loop {
- let write = match conn.send(&mut out) {
+ let (write, send_info) = match conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -168,10 +167,29 @@ loop {
},
};
- socket.send(&out[..write]).unwrap();
+ socket.send_to(&out[..write], &send_info.to).unwrap();
}
```
+#### Pacing
+
+It is recommended that applications [pace] sending of outgoing packets to
+avoid creating packet bursts that could cause short-term congestion and
+losses in the network.
+
+quiche exposes pacing hints for outgoing packets through the [`at`] field
+of the [`SendInfo`] structure that is returned by the [`send()`] method.
+This field represents the time when a specific packet should be sent into
+the network.
+
+Applications can use these hints by artificially delaying the sending of
+packets through platform-specific mechanisms (such as the [`SO_TXTIME`]
+socket option on Linux), or custom methods (for example by using user-space
+timers).
+
+[pace]: https://datatracker.ietf.org/doc/html/rfc9002#section-7.7
+[`SO_TXTIME`]: https://man7.org/linux/man-pages/man8/tc-etf.8.html
+
### Sending and receiving stream data
After some back and forth, the connection will complete its handshake and
@@ -221,11 +239,11 @@ receiving HTTP requests and responses on top of the QUIC transport protocol.
[`stream_recv()`]: https://docs.quic.tech/quiche/struct.Connection.html#method.stream_recv
[HTTP/3 module]: https://docs.quic.tech/quiche/h3/index.html
-Have a look at the [examples/] directory for more complete examples on how to use
-the quiche API, including examples on how to use quiche in C/C++ applications
-(see below for more information).
+Have a look at the [quiche/examples/] directory for more complete examples on
+how to use the quiche API, including examples on how to use quiche in C/C++
+applications (see below for more information).
-[examples/]: examples/
+[examples/]: quiche/examples/
Calling quiche from C/C++
-------------------------
@@ -242,12 +260,12 @@ be linked directly into C/C++ applications.
Note that in order to enable the FFI API, the ``ffi`` feature must be enabled (it
is disabled by default), by passing ``--features ffi`` to ``cargo``.
-[thin C API]: https://github.com/cloudflare/quiche/blob/master/include/quiche.h
+[thin C API]: https://github.com/cloudflare/quiche/blob/master/quiche/include/quiche.h
Building
--------
-quiche requires Rust 1.50 or later to build. The latest stable Rust release can
+quiche requires Rust 1.54 or later to build. The latest stable Rust release can
be installed using [rustup](https://rustup.rs/).
Once the Rust build environment is setup, the quiche source code can be fetched
@@ -288,38 +306,34 @@ the BoringSSL directory with the ``QUICHE_BSSL_PATH`` environment variable:
### Building for Android
-To build quiche for Android, you need the following:
+Building quiche for Android (NDK version 19 or higher, 21 recommended), can be
+done using [cargo-ndk] (v2.0 or later).
-- Install the [Android NDK] (13b or higher), using Android Studio or directly.
-- Set `ANDROID_NDK_HOME` environment variable to NDK path, e.g.
+First the [Android NDK] needs to be installed, either using Android Studio or
+directly, and the `ANDROID_NDK_HOME` environment variable needs to be set to the
+NDK installation path, e.g.:
```bash
$ export ANDROID_NDK_HOME=/usr/local/share/android-ndk
```
-- Install the Rust toolchain for Android architectures needed:
+Then the Rust toolchain for the Android architectures needed can be installed as
+follows:
```bash
- $ rustup target add aarch64-linux-android arm-linux-androideabi armv7-linux-androideabi i686-linux-android x86_64-linux-android
+ $ rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
```
Note that the minimum API level is 21 for all target architectures.
-Depending on the NDK version used, you can take one of the following procedures:
-
-[Android NDK]: https://developer.android.com/ndk
-
-#### NDK version >= 19
-
-For NDK version 19 or higher (21 recommended), you can build in a simpler
-way using [cargo-ndk]. You need to install [cargo-ndk] (v2.0 or later) first.
+[cargo-ndk] (v2.0 or later) also needs to be installed:
```bash
$ cargo install cargo-ndk
```
-You can build the quiche library using the following procedure. Note that
-`-t <architecture>` and `-p <NDK version>` are mandatory.
+Finally the quiche library can be built using the following procedure. Note that
+the `-t <architecture>` and `-p <NDK version>` options are mandatory.
```bash
$ cargo ndk -t arm64-v8a -p 21 -- build --features ffi
@@ -327,39 +341,10 @@ You can build the quiche library using the following procedure. Note that
See [build_android_ndk19.sh] for more information.
-Note that building with NDK version 18 appears to be broken.
-
+[Android NDK]: https://developer.android.com/ndk
[cargo-ndk]: https://docs.rs/crate/cargo-ndk
[build_android_ndk19.sh]: https://github.com/cloudflare/quiche/blob/master/tools/android/build_android_ndk19.sh
-#### NDK version < 18
-
-If you need to use NDK version < 18 (gcc), you can build quiche in the following way.
-
-To prepare the cross-compiling toolchain, run the following command:
-
-```bash
- $ tools/android/setup_android.sh
-```
-
-It will create a standalone toolchain for arm64/arm/x86 architectures under the
-`$TOOLCHAIN_DIR/arch` directory. If you didn't set `TOOLCHAIN_DIR` environment
-variable, the current directory will be used.
-
-After it run successfully, run the following script to build libquiche:
-
-```bash
- $ tools/android/build_android.sh --features ndk-old-gcc
-```
-
-It will build binaries for aarch64, armv7 and i686. You can pass parameters to
-this script for cargo build. For example if you want to build a release binary
-with verbose logs, do the following:
-
-```bash
- $ tools/android/build_android.sh --features ndk-old-gcc --release -vv
-```
-
### Building for iOS
To build quiche for iOS, you need the following:
diff --git a/deps/boringssl/CMakeLists.txt b/deps/boringssl/CMakeLists.txt
index 1645a26..3795e7b 100644
--- a/deps/boringssl/CMakeLists.txt
+++ b/deps/boringssl/CMakeLists.txt
@@ -4,7 +4,7 @@
# This file is created by generate_build_files.py. Do not edit manually.
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.5)
project(BoringSSL LANGUAGES C CXX)
@@ -18,12 +18,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fno-common")
- if((CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR CLANG)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
- else()
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
- endif()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fno-common -std=c11")
endif()
# pthread_rwlock_t requires a feature flag.
@@ -53,7 +48,7 @@ add_definitions(-DBORINGSSL_IMPLEMENTATION)
# builds.
if(NOT OPENSSL_NO_ASM AND CMAKE_OSX_ARCHITECTURES)
list(LENGTH CMAKE_OSX_ARCHITECTURES NUM_ARCHES)
- if(NOT ${NUM_ARCHES} EQUAL 1)
+ if(NOT NUM_ARCHES EQUAL 1)
message(FATAL_ERROR "Universal binaries not supported.")
endif()
list(GET CMAKE_OSX_ARCHITECTURES 0 CMAKE_SYSTEM_PROCESSOR)
@@ -62,36 +57,36 @@ endif()
if(OPENSSL_NO_ASM)
add_definitions(-DOPENSSL_NO_ASM)
set(ARCH "generic")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(ARCH "x86_64")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64")
set(ARCH "x86_64")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")
# cmake reports AMD64 on Windows, but we might be building for 32-bit.
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(ARCH "x86_64")
else()
set(ARCH "x86")
endif()
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
set(ARCH "x86")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i386")
set(ARCH "x86")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686")
set(ARCH "x86")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
set(ARCH "aarch64")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(ARCH "aarch64")
# Apple A12 Bionic chipset which is added in iPhone XS/XS Max/XR uses arm64e architecture.
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64e")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64e")
set(ARCH "aarch64")
-elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*")
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm*")
set(ARCH "arm")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "mips")
# Just to avoid the “unknown processor” error.
set(ARCH "generic")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
set(ARCH "ppc64le")
else()
message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR})
@@ -344,9 +339,9 @@ set(
win-x86_64/crypto/test/trampoline-x86_64.asm
)
-if(APPLE AND ${ARCH} STREQUAL "aarch64")
+if(APPLE AND ARCH STREQUAL "aarch64")
set(CRYPTO_ARCH_SOURCES ${CRYPTO_ios_aarch64_SOURCES})
-elseif(APPLE AND ${ARCH} STREQUAL "arm")
+elseif(APPLE AND ARCH STREQUAL "arm")
set(CRYPTO_ARCH_SOURCES ${CRYPTO_ios_arm_SOURCES})
elseif(APPLE)
set(CRYPTO_ARCH_SOURCES ${CRYPTO_mac_${ARCH}_SOURCES})
@@ -373,6 +368,7 @@ add_library(
src/crypto/asn1/a_object.c
src/crypto/asn1/a_octet.c
src/crypto/asn1/a_print.c
+ src/crypto/asn1/a_strex.c
src/crypto/asn1/a_strnid.c
src/crypto/asn1/a_time.c
src/crypto/asn1/a_type.c
@@ -467,7 +463,6 @@ add_library(
src/crypto/ex_data.c
src/crypto/fipsmodule/bcm.c
src/crypto/fipsmodule/fips_shared_support.c
- src/crypto/fipsmodule/is_fips.c
src/crypto/hkdf/hkdf.c
src/crypto/hpke/hpke.c
src/crypto/hrss/hrss.c
@@ -514,13 +509,13 @@ add_library(
src/crypto/trust_token/voprf.c
src/crypto/x509/a_digest.c
src/crypto/x509/a_sign.c
- src/crypto/x509/a_strex.c
src/crypto/x509/a_verify.c
src/crypto/x509/algorithm.c
src/crypto/x509/asn1_gen.c
src/crypto/x509/by_dir.c
src/crypto/x509/by_file.c
src/crypto/x509/i2d_pr.c
+ src/crypto/x509/name_print.c
src/crypto/x509/rsa_pss.c
src/crypto/x509/t_crl.c
src/crypto/x509/t_req.c
@@ -534,7 +529,6 @@ add_library(
src/crypto/x509/x509_ext.c
src/crypto/x509/x509_lu.c
src/crypto/x509/x509_obj.c
- src/crypto/x509/x509_r2x.c
src/crypto/x509/x509_req.c
src/crypto/x509/x509_set.c
src/crypto/x509/x509_trs.c
@@ -604,6 +598,8 @@ add_library(
src/ssl/d1_srtp.cc
src/ssl/dtls_method.cc
src/ssl/dtls_record.cc
+ src/ssl/encrypted_client_hello.cc
+ src/ssl/extensions.cc
src/ssl/handoff.cc
src/ssl/handshake.cc
src/ssl/handshake_client.cc
@@ -626,7 +622,6 @@ add_library(
src/ssl/ssl_versions.cc
src/ssl/ssl_x509.cc
src/ssl/t1_enc.cc
- src/ssl/t1_lib.cc
src/ssl/tls13_both.cc
src/ssl/tls13_client.cc
src/ssl/tls13_enc.cc
@@ -645,6 +640,7 @@ add_executable(
src/tool/digest.cc
src/tool/fd.cc
src/tool/file.cc
+ src/tool/generate_ech.cc
src/tool/generate_ed25519.cc
src/tool/genrsa.cc
src/tool/pkcs12.cc
diff --git a/deps/boringssl/err_data.c b/deps/boringssl/err_data.c
index 7103cb1..4f4e973 100644
--- a/deps/boringssl/err_data.c
+++ b/deps/boringssl/err_data.c
@@ -76,54 +76,54 @@ const uint32_t kOpenSSLReasonValues[] = {
0xc3b00f7,
0xc3b88e3,
0x10320854,
- 0x103295b6,
- 0x103315c2,
- 0x103395db,
- 0x103415ee,
+ 0x103295ca,
+ 0x103315d6,
+ 0x103395ef,
+ 0x10341602,
0x10348f34,
0x10350c6d,
- 0x10359601,
- 0x1036162b,
- 0x1036963e,
- 0x1037165d,
- 0x10379676,
- 0x1038168b,
- 0x103896a9,
- 0x103916b8,
- 0x103996d4,
- 0x103a16ef,
- 0x103a96fe,
- 0x103b171a,
- 0x103b9735,
- 0x103c175b,
+ 0x10359615,
+ 0x1036163f,
+ 0x10369652,
+ 0x10371671,
+ 0x1037968a,
+ 0x1038169f,
+ 0x103896bd,
+ 0x103916cc,
+ 0x103996e8,
+ 0x103a1703,
+ 0x103a9712,
+ 0x103b172e,
+ 0x103b9749,
+ 0x103c176f,
0x103c80f7,
- 0x103d176c,
- 0x103d9780,
- 0x103e179f,
- 0x103e97ae,
- 0x103f17c5,
- 0x103f97d8,
+ 0x103d1780,
+ 0x103d9794,
+ 0x103e17b3,
+ 0x103e97c2,
+ 0x103f17d9,
+ 0x103f97ec,
0x10400c31,
- 0x104097eb,
- 0x10411809,
- 0x1041981c,
- 0x10421836,
- 0x10429846,
- 0x1043185a,
- 0x10439870,
- 0x10441888,
- 0x1044989d,
- 0x104518b1,
- 0x104598c3,
+ 0x104097ff,
+ 0x1041181d,
+ 0x10419830,
+ 0x1042184a,
+ 0x1042985a,
+ 0x1043186e,
+ 0x10439884,
+ 0x1044189c,
+ 0x104498b1,
+ 0x104518c5,
+ 0x104598d7,
0x1046060a,
0x1046895c,
- 0x104718d8,
- 0x104798ef,
- 0x10481904,
- 0x10489912,
+ 0x104718ec,
+ 0x10479903,
+ 0x10481918,
+ 0x10489926,
0x10490e80,
- 0x1049974c,
- 0x104a1616,
+ 0x10499760,
+ 0x104a162a,
0x14320c14,
0x14328c22,
0x14330c31,
@@ -140,50 +140,51 @@ const uint32_t kOpenSSLReasonValues[] = {
0x18358feb,
0x18361000,
0x18369014,
- 0x18371038,
- 0x1837904e,
- 0x18381062,
- 0x18389072,
+ 0x1837104c,
+ 0x18379062,
+ 0x18381076,
+ 0x18389086,
0x18390a82,
- 0x18399082,
- 0x183a10a8,
- 0x183a90ce,
+ 0x18399096,
+ 0x183a10bc,
+ 0x183a90e2,
0x183b0c8c,
- 0x183b911d,
- 0x183c112f,
- 0x183c913a,
- 0x183d114a,
- 0x183d915b,
- 0x183e116c,
- 0x183e917e,
- 0x183f11a7,
- 0x183f91c0,
- 0x184011d8,
+ 0x183b9131,
+ 0x183c1143,
+ 0x183c914e,
+ 0x183d115e,
+ 0x183d916f,
+ 0x183e1180,
+ 0x183e9192,
+ 0x183f11bb,
+ 0x183f91d4,
+ 0x184011ec,
0x184086e2,
- 0x184110f1,
- 0x184190bc,
- 0x184210db,
+ 0x18411105,
+ 0x184190d0,
+ 0x184210ef,
0x18428c79,
- 0x18431097,
- 0x18439103,
+ 0x184310ab,
+ 0x18439117,
0x18440fc9,
- 0x20321212,
- 0x203291ff,
- 0x2432121e,
+ 0x18449038,
+ 0x20321226,
+ 0x20329213,
+ 0x24321232,
0x243289a2,
- 0x24331230,
- 0x2433923d,
- 0x2434124a,
- 0x2434925c,
- 0x2435126b,
- 0x24359288,
- 0x24361295,
- 0x243692a3,
- 0x243712b1,
- 0x243792bf,
- 0x243812c8,
- 0x243892d5,
- 0x243912e8,
+ 0x24331244,
+ 0x24339251,
+ 0x2434125e,
+ 0x24349270,
+ 0x2435127f,
+ 0x2435929c,
+ 0x243612a9,
+ 0x243692b7,
+ 0x243712c5,
+ 0x243792d3,
+ 0x243812dc,
+ 0x243892e9,
+ 0x243912fc,
0x28320c61,
0x28328c8c,
0x28330c31,
@@ -192,47 +193,47 @@ const uint32_t kOpenSSLReasonValues[] = {
0x283480b9,
0x283500f7,
0x28358c79,
- 0x2c3230db,
- 0x2c3292ff,
- 0x2c3330e9,
- 0x2c33b0fb,
- 0x2c34310f,
- 0x2c34b121,
- 0x2c35313c,
- 0x2c35b14e,
- 0x2c36317e,
+ 0x2c32326b,
+ 0x2c329313,
+ 0x2c333279,
+ 0x2c33b28b,
+ 0x2c34329f,
+ 0x2c34b2b1,
+ 0x2c3532cc,
+ 0x2c35b2de,
+ 0x2c36330e,
0x2c36833a,
- 0x2c37318b,
- 0x2c37b1b7,
- 0x2c3831dc,
- 0x2c38b1f3,
- 0x2c393211,
- 0x2c39b221,
- 0x2c3a3233,
- 0x2c3ab247,
- 0x2c3b3258,
- 0x2c3bb277,
- 0x2c3c1311,
- 0x2c3c9327,
- 0x2c3d328b,
- 0x2c3d9340,
- 0x2c3e32a8,
- 0x2c3eb2b6,
- 0x2c3f32ce,
- 0x2c3fb2e6,
- 0x2c403310,
- 0x2c409212,
- 0x2c413321,
- 0x2c41b334,
- 0x2c4211d8,
- 0x2c42b345,
+ 0x2c37331b,
+ 0x2c37b347,
+ 0x2c38336c,
+ 0x2c38b383,
+ 0x2c3933a1,
+ 0x2c39b3b1,
+ 0x2c3a33c3,
+ 0x2c3ab3d7,
+ 0x2c3b33e8,
+ 0x2c3bb407,
+ 0x2c3c1325,
+ 0x2c3c933b,
+ 0x2c3d341b,
+ 0x2c3d9354,
+ 0x2c3e3438,
+ 0x2c3eb446,
+ 0x2c3f345e,
+ 0x2c3fb476,
+ 0x2c4034a0,
+ 0x2c409226,
+ 0x2c4134b1,
+ 0x2c41b4c4,
+ 0x2c4211ec,
+ 0x2c42b4d5,
0x2c43072f,
- 0x2c43b269,
- 0x2c4431ca,
- 0x2c44b2f3,
- 0x2c453161,
- 0x2c45b19d,
- 0x2c463201,
+ 0x2c43b3f9,
+ 0x2c44335a,
+ 0x2c44b483,
+ 0x2c4532f1,
+ 0x2c45b32d,
+ 0x2c463391,
0x30320000,
0x30328015,
0x3033001f,
@@ -368,248 +369,261 @@ const uint32_t kOpenSSLReasonValues[] = {
0x3c418d74,
0x3c420e80,
0x3c428e0a,
- 0x403219a4,
- 0x403299ba,
- 0x403319e8,
- 0x403399f2,
- 0x40341a09,
- 0x40349a27,
- 0x40351a37,
- 0x40359a49,
- 0x40361a56,
- 0x40369a62,
- 0x40371a77,
- 0x40379a89,
- 0x40381a94,
- 0x40389aa6,
+ 0x403219b8,
+ 0x403299ce,
+ 0x403319fc,
+ 0x40339a06,
+ 0x40341a1d,
+ 0x40349a3b,
+ 0x40351a4b,
+ 0x40359a5d,
+ 0x40361a6a,
+ 0x40369a76,
+ 0x40371a8b,
+ 0x40379a9d,
+ 0x40381aa8,
+ 0x40389aba,
0x40390f34,
- 0x40399ab6,
- 0x403a1ac9,
- 0x403a9aea,
- 0x403b1afb,
- 0x403b9b0b,
+ 0x40399aca,
+ 0x403a1add,
+ 0x403a9afe,
+ 0x403b1b0f,
+ 0x403b9b1f,
0x403c0071,
0x403c8090,
- 0x403d1b6c,
- 0x403d9b82,
- 0x403e1b91,
- 0x403e9bc9,
- 0x403f1be3,
- 0x403f9c0b,
- 0x40401c20,
- 0x40409c34,
- 0x40411c6f,
- 0x40419c8a,
- 0x40421ca3,
- 0x40429cb6,
- 0x40431cca,
- 0x40439ce2,
- 0x40441cf9,
+ 0x403d1b80,
+ 0x403d9b96,
+ 0x403e1ba5,
+ 0x403e9bdd,
+ 0x403f1bf7,
+ 0x403f9c1f,
+ 0x40401c34,
+ 0x40409c48,
+ 0x40411c83,
+ 0x40419c9e,
+ 0x40421cb7,
+ 0x40429cca,
+ 0x40431cde,
+ 0x40439d0c,
+ 0x40441d23,
0x404480b9,
- 0x40451d0e,
- 0x40459d20,
- 0x40461d44,
- 0x40469d64,
- 0x40471d72,
- 0x40479d99,
- 0x40481e0a,
- 0x40489e3d,
- 0x40491e54,
- 0x40499e6e,
- 0x404a1e85,
- 0x404a9ea3,
- 0x404b1ebb,
- 0x404b9ee8,
- 0x404c1efe,
- 0x404c9f10,
- 0x404d1f31,
- 0x404d9f6a,
- 0x404e1f7e,
- 0x404e9f8b,
- 0x404f1fd2,
- 0x404fa018,
- 0x4050206f,
- 0x4050a083,
- 0x405120b6,
- 0x405220d3,
- 0x4052a0f7,
- 0x4053210f,
- 0x4053a122,
- 0x40542137,
- 0x4054a15a,
- 0x40552185,
- 0x4055a1c2,
- 0x405621cf,
- 0x4056a1e8,
- 0x40572200,
- 0x4057a213,
- 0x40582228,
- 0x4058a24f,
- 0x4059227e,
- 0x4059a2ab,
- 0x405a22bf,
- 0x405aa2cf,
- 0x405b22e7,
- 0x405ba2f8,
- 0x405c230b,
- 0x405ca34a,
- 0x405d2357,
- 0x405da37c,
- 0x405e23ba,
+ 0x40451d38,
+ 0x40459d4a,
+ 0x40461d6e,
+ 0x40469d8e,
+ 0x40471d9c,
+ 0x40479dc3,
+ 0x40481e34,
+ 0x40489eee,
+ 0x40491f05,
+ 0x40499f1f,
+ 0x404a1f36,
+ 0x404a9f54,
+ 0x404b1f6c,
+ 0x404b9f99,
+ 0x404c1faf,
+ 0x404c9fc1,
+ 0x404d1fe2,
+ 0x404da01b,
+ 0x404e202f,
+ 0x404ea03c,
+ 0x404f20d6,
+ 0x404fa14c,
+ 0x405021a3,
+ 0x4050a1b7,
+ 0x405121ea,
+ 0x405221fa,
+ 0x4052a21e,
+ 0x40532236,
+ 0x4053a249,
+ 0x4054225e,
+ 0x4054a281,
+ 0x405522ac,
+ 0x4055a2e9,
+ 0x4056230e,
+ 0x4056a327,
+ 0x4057233f,
+ 0x4057a352,
+ 0x40582367,
+ 0x4058a38e,
+ 0x405923bd,
+ 0x4059a3ea,
+ 0x405a23fe,
+ 0x405aa40e,
+ 0x405b2426,
+ 0x405ba437,
+ 0x405c244a,
+ 0x405ca489,
+ 0x405d2496,
+ 0x405da4bb,
+ 0x405e24f9,
0x405e8ac0,
- 0x405f23db,
- 0x405fa3e8,
- 0x406023f6,
- 0x4060a418,
- 0x40612479,
- 0x4061a4b1,
- 0x406224c8,
- 0x4062a4d9,
- 0x40632526,
- 0x4063a53b,
- 0x40642552,
- 0x4064a57e,
- 0x40652599,
- 0x4065a5b0,
- 0x406625c8,
- 0x4066a5f2,
- 0x4067261d,
- 0x4067a662,
- 0x406826aa,
- 0x4068a6cb,
- 0x406926fd,
- 0x4069a72b,
- 0x406a274c,
- 0x406aa76c,
- 0x406b28f4,
- 0x406ba917,
- 0x406c292d,
- 0x406cac1e,
- 0x406d2c4d,
- 0x406dac75,
- 0x406e2ca3,
- 0x406eacf0,
- 0x406f2d49,
- 0x406fad81,
- 0x40702d94,
- 0x4070adb1,
+ 0x405f2534,
+ 0x405fa541,
+ 0x4060254f,
+ 0x4060a571,
+ 0x406125d2,
+ 0x4061a60a,
+ 0x40622621,
+ 0x4062a632,
+ 0x4063267f,
+ 0x4063a694,
+ 0x406426ab,
+ 0x4064a6d7,
+ 0x406526f2,
+ 0x4065a709,
+ 0x40662721,
+ 0x4066a74b,
+ 0x40672776,
+ 0x4067a7bb,
+ 0x40682803,
+ 0x4068a824,
+ 0x40692856,
+ 0x4069a884,
+ 0x406a28a5,
+ 0x406aa8c5,
+ 0x406b2a4d,
+ 0x406baa70,
+ 0x406c2a86,
+ 0x406cad90,
+ 0x406d2dbf,
+ 0x406dade7,
+ 0x406e2e15,
+ 0x406eae62,
+ 0x406f2ebb,
+ 0x406faef3,
+ 0x40702f06,
+ 0x4070af23,
0x4071080f,
- 0x4071adc3,
- 0x40722dd6,
- 0x4072ae0c,
- 0x40732e24,
- 0x40739511,
- 0x40742e38,
- 0x4074ae52,
- 0x40752e63,
- 0x4075ae77,
- 0x40762e85,
- 0x407692d5,
- 0x40772eaa,
- 0x4077aecc,
- 0x40782ee7,
- 0x4078af20,
- 0x40792f37,
- 0x4079af4d,
- 0x407a2f79,
- 0x407aaf8c,
- 0x407b2fa1,
- 0x407bafb3,
- 0x407c2fe4,
- 0x407cafed,
- 0x407d26e6,
- 0x407da028,
- 0x407e2efc,
- 0x407ea25f,
- 0x407f1d86,
- 0x407f9ed2,
- 0x40801fe2,
- 0x40809dae,
- 0x408120e5,
- 0x40819fbc,
- 0x40822c8e,
- 0x40829b17,
- 0x4083223a,
- 0x4083a563,
- 0x40841dc2,
- 0x4084a297,
- 0x4085231c,
- 0x4085a440,
- 0x4086239c,
- 0x4086a042,
- 0x40872cd4,
- 0x4087a48e,
- 0x40881b55,
- 0x4088a675,
- 0x40891ba4,
- 0x40899b31,
- 0x408a2965,
- 0x408a9929,
- 0x408b2fc8,
- 0x408bad5e,
- 0x408c232c,
- 0x408c9961,
- 0x408d1e23,
- 0x408d9df4,
- 0x408e1f53,
- 0x408ea1a2,
- 0x408f2689,
- 0x408fa45c,
- 0x4090263e,
- 0x4090a36e,
- 0x4091294d,
- 0x40919987,
- 0x40921bf1,
- 0x4092ad0f,
- 0x40932def,
- 0x4093a053,
- 0x40941dd6,
- 0x4094a97e,
- 0x409524ea,
- 0x4095af59,
- 0x40962cbb,
- 0x40969ffb,
- 0x4097209e,
- 0x40979fa2,
- 0x40981c51,
- 0x4098a4fe,
- 0x40992d2b,
- 0x4099a0c6,
- 0x409a2168,
- 0x409a9945,
- 0x41f4281f,
- 0x41f928b1,
- 0x41fe27a4,
- 0x41feaa5a,
- 0x41ff2b6f,
- 0x42032838,
- 0x4208285a,
- 0x4208a896,
- 0x42092788,
- 0x4209a8d0,
- 0x420a27df,
- 0x420aa7bf,
- 0x420b27ff,
- 0x420ba878,
- 0x420c2b8b,
- 0x420ca98e,
- 0x420d2a41,
- 0x420daa78,
- 0x42122a92,
- 0x42172b52,
- 0x4217aad4,
- 0x421c2af6,
- 0x421f2ab1,
- 0x42212c03,
- 0x42262b35,
- 0x422b2be1,
- 0x422baa1c,
- 0x422c2bc3,
- 0x422ca9cf,
- 0x422d29a8,
- 0x422daba2,
- 0x422e29fb,
- 0x42302b11,
+ 0x4071af35,
+ 0x40722f48,
+ 0x4072af7e,
+ 0x40732f96,
+ 0x40739525,
+ 0x40742faa,
+ 0x4074afc4,
+ 0x40752fd5,
+ 0x4075afe9,
+ 0x40762ff7,
+ 0x407692e9,
+ 0x4077301c,
+ 0x4077b05c,
+ 0x40783077,
+ 0x4078b0b0,
+ 0x407930c7,
+ 0x4079b0dd,
+ 0x407a3109,
+ 0x407ab11c,
+ 0x407b3131,
+ 0x407bb143,
+ 0x407c3174,
+ 0x407cb17d,
+ 0x407d283f,
+ 0x407da15c,
+ 0x407e308c,
+ 0x407ea39e,
+ 0x407f1db0,
+ 0x407f9f83,
+ 0x408020e6,
+ 0x40809dd8,
+ 0x4081220c,
+ 0x4081a08a,
+ 0x40822e00,
+ 0x40829b2b,
+ 0x40832379,
+ 0x4083a6bc,
+ 0x40841dec,
+ 0x4084a3d6,
+ 0x4085245b,
+ 0x4085a599,
+ 0x408624db,
+ 0x4086a176,
+ 0x40872e46,
+ 0x4087a5e7,
+ 0x40881b69,
+ 0x4088a7ce,
+ 0x40891bb8,
+ 0x40899b45,
+ 0x408a2abe,
+ 0x408a993d,
+ 0x408b3158,
+ 0x408baed0,
+ 0x408c246b,
+ 0x408c9975,
+ 0x408d1ed4,
+ 0x408d9e1e,
+ 0x408e2004,
+ 0x408ea2c9,
+ 0x408f27e2,
+ 0x408fa5b5,
+ 0x40902797,
+ 0x4090a4ad,
+ 0x40912aa6,
+ 0x4091999b,
+ 0x40921c05,
+ 0x4092ae81,
+ 0x40932f61,
+ 0x4093a187,
+ 0x40941e00,
+ 0x4094aad7,
+ 0x40952643,
+ 0x4095b0e9,
+ 0x40962e2d,
+ 0x4096a0ff,
+ 0x409721d2,
+ 0x4097a053,
+ 0x40981c65,
+ 0x4098a657,
+ 0x40992e9d,
+ 0x4099a2f6,
+ 0x409a228f,
+ 0x409a9959,
+ 0x409b1e5a,
+ 0x409b9e85,
+ 0x409c303e,
+ 0x409c9ead,
+ 0x409d20bb,
+ 0x409da0a0,
+ 0x409e1cf6,
+ 0x409ea134,
+ 0x409f211c,
+ 0x409f9e4d,
+ 0x40a0251a,
+ 0x40a0a06d,
+ 0x41f42978,
+ 0x41f92a0a,
+ 0x41fe28fd,
+ 0x41feabb3,
+ 0x41ff2ce1,
+ 0x42032991,
+ 0x420829b3,
+ 0x4208a9ef,
+ 0x420928e1,
+ 0x4209aa29,
+ 0x420a2938,
+ 0x420aa918,
+ 0x420b2958,
+ 0x420ba9d1,
+ 0x420c2cfd,
+ 0x420caae7,
+ 0x420d2b9a,
+ 0x420dabd1,
+ 0x42122c04,
+ 0x42172cc4,
+ 0x4217ac46,
+ 0x421c2c68,
+ 0x421f2c23,
+ 0x42212d75,
+ 0x42262ca7,
+ 0x422b2d53,
+ 0x422bab75,
+ 0x422c2d35,
+ 0x422cab28,
+ 0x422d2b01,
+ 0x422dad14,
+ 0x422e2b54,
+ 0x42302c83,
+ 0x4230abeb,
0x4432073a,
0x44328749,
0x44330755,
@@ -627,106 +641,107 @@ const uint32_t kOpenSSLReasonValues[] = {
0x4439080f,
0x4439881d,
0x443a0830,
- 0x483212ff,
- 0x48329311,
- 0x48331327,
- 0x48339340,
- 0x4c321365,
- 0x4c329375,
- 0x4c331388,
- 0x4c3393a8,
+ 0x48321313,
+ 0x48329325,
+ 0x4833133b,
+ 0x48339354,
+ 0x4c321379,
+ 0x4c329389,
+ 0x4c33139c,
+ 0x4c3393bc,
0x4c3400b9,
0x4c3480f7,
- 0x4c3513b4,
- 0x4c3593c2,
- 0x4c3613de,
- 0x4c369404,
- 0x4c371413,
- 0x4c379421,
- 0x4c381436,
- 0x4c389442,
- 0x4c391462,
- 0x4c39948c,
- 0x4c3a14a5,
- 0x4c3a94be,
+ 0x4c3513c8,
+ 0x4c3593d6,
+ 0x4c3613f2,
+ 0x4c369418,
+ 0x4c371427,
+ 0x4c379435,
+ 0x4c38144a,
+ 0x4c389456,
+ 0x4c391476,
+ 0x4c3994a0,
+ 0x4c3a14b9,
+ 0x4c3a94d2,
0x4c3b060a,
- 0x4c3b94d7,
- 0x4c3c14e9,
- 0x4c3c94f8,
- 0x4c3d1511,
+ 0x4c3b94eb,
+ 0x4c3c14fd,
+ 0x4c3c950c,
+ 0x4c3d1525,
0x4c3d8c54,
- 0x4c3e157e,
- 0x4c3e9520,
- 0x4c3f15a0,
- 0x4c3f92d5,
- 0x4c401536,
- 0x4c409351,
- 0x4c41156e,
- 0x4c4193f1,
- 0x4c42155a,
- 0x50323357,
- 0x5032b366,
- 0x50333371,
- 0x5033b381,
- 0x5034339a,
- 0x5034b3b4,
- 0x503533c2,
- 0x5035b3d8,
- 0x503633ea,
- 0x5036b400,
- 0x50373419,
- 0x5037b42c,
- 0x50383444,
- 0x5038b455,
- 0x5039346a,
- 0x5039b47e,
- 0x503a349e,
- 0x503ab4b4,
- 0x503b34cc,
- 0x503bb4de,
- 0x503c34fa,
- 0x503cb511,
- 0x503d352a,
- 0x503db540,
- 0x503e354d,
- 0x503eb563,
- 0x503f3575,
+ 0x4c3e1592,
+ 0x4c3e9534,
+ 0x4c3f15b4,
+ 0x4c3f92e9,
+ 0x4c40154a,
+ 0x4c409365,
+ 0x4c411582,
+ 0x4c419405,
+ 0x4c42156e,
+ 0x503234e7,
+ 0x5032b4f6,
+ 0x50333501,
+ 0x5033b511,
+ 0x5034352a,
+ 0x5034b544,
+ 0x50353552,
+ 0x5035b568,
+ 0x5036357a,
+ 0x5036b590,
+ 0x503735a9,
+ 0x5037b5bc,
+ 0x503835d4,
+ 0x5038b5e5,
+ 0x503935fa,
+ 0x5039b60e,
+ 0x503a362e,
+ 0x503ab644,
+ 0x503b365c,
+ 0x503bb66e,
+ 0x503c368a,
+ 0x503cb6a1,
+ 0x503d36ba,
+ 0x503db6d0,
+ 0x503e36dd,
+ 0x503eb6f3,
+ 0x503f3705,
0x503f8388,
- 0x50403588,
- 0x5040b598,
- 0x504135b2,
- 0x5041b5c1,
- 0x504235db,
- 0x5042b5f8,
- 0x50433608,
- 0x5043b618,
- 0x50443627,
+ 0x50403718,
+ 0x5040b728,
+ 0x50413742,
+ 0x5041b751,
+ 0x5042376b,
+ 0x5042b788,
+ 0x50433798,
+ 0x5043b7a8,
+ 0x504437c5,
0x5044843e,
- 0x5045363b,
- 0x5045b659,
- 0x5046366c,
- 0x5046b682,
- 0x50473694,
- 0x5047b6a9,
- 0x504836cf,
- 0x5048b6dd,
- 0x504936f0,
- 0x5049b705,
- 0x504a371b,
- 0x504ab72b,
- 0x504b374b,
- 0x504bb75e,
- 0x504c3781,
- 0x504cb7af,
- 0x504d37c1,
- 0x504db7de,
- 0x504e37f9,
- 0x504eb815,
- 0x504f3827,
- 0x504fb83e,
- 0x5050384d,
+ 0x504537d9,
+ 0x5045b7f7,
+ 0x5046380a,
+ 0x5046b820,
+ 0x50473832,
+ 0x5047b847,
+ 0x5048386d,
+ 0x5048b87b,
+ 0x5049388e,
+ 0x5049b8a3,
+ 0x504a38b9,
+ 0x504ab8c9,
+ 0x504b38e9,
+ 0x504bb8fc,
+ 0x504c391f,
+ 0x504cb94d,
+ 0x504d395f,
+ 0x504db97c,
+ 0x504e3997,
+ 0x504eb9b3,
+ 0x504f39c5,
+ 0x504fb9dc,
+ 0x505039eb,
0x505086fe,
- 0x50513860,
+ 0x505139fe,
+ 0x5051b7b7,
0x58320f72,
0x68320f34,
0x68328c8c,
@@ -767,22 +782,22 @@ const uint32_t kOpenSSLReasonValues[] = {
0x783d8b59,
0x783e0aaf,
0x783e8a61,
- 0x7c3211ee,
- 0x80321404,
+ 0x7c321202,
+ 0x80321418,
0x80328090,
- 0x803330aa,
+ 0x8033323a,
0x803380b9,
- 0x803430b9,
- 0x8034b021,
- 0x8035303f,
- 0x8035b0cd,
- 0x80363081,
- 0x8036b030,
- 0x80373073,
- 0x8037b00e,
- 0x80383094,
- 0x8038b050,
- 0x80393065,
+ 0x80343249,
+ 0x8034b1b1,
+ 0x803531cf,
+ 0x8035b25d,
+ 0x80363211,
+ 0x8036b1c0,
+ 0x80373203,
+ 0x8037b19e,
+ 0x80383224,
+ 0x8038b1e0,
+ 0x803931f5,
};
const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]);
@@ -1004,6 +1019,7 @@ const char kOpenSSLReasonStringData[] =
"EXPECTING_AN_RSA_KEY\0"
"EXPECTING_A_DSA_KEY\0"
"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE\0"
+ "INVALID_BUFFER_SIZE\0"
"INVALID_DIGEST_LENGTH\0"
"INVALID_DIGEST_TYPE\0"
"INVALID_KEYBITS\0"
@@ -1158,6 +1174,7 @@ const char kOpenSSLReasonStringData[] =
"CLIENTHELLO_TLSEXT\0"
"CONNECTION_REJECTED\0"
"CONNECTION_TYPE_NOT_SET\0"
+ "COULD_NOT_PARSE_HINTS\0"
"CUSTOM_EXTENSION_ERROR\0"
"DATA_LENGTH_TOO_LONG\0"
"DECRYPTION_FAILED\0"
@@ -1172,6 +1189,10 @@ const char kOpenSSLReasonStringData[] =
"DUPLICATE_SIGNATURE_ALGORITHM\0"
"EARLY_DATA_NOT_IN_USE\0"
"ECC_CERT_NOT_FOR_SIGNING\0"
+ "ECH_REJECTED\0"
+ "ECH_SERVER_CONFIG_AND_PRIVATE_KEY_MISMATCH\0"
+ "ECH_SERVER_CONFIG_UNSUPPORTED_EXTENSION\0"
+ "ECH_SERVER_WOULD_HAVE_NO_RETRY_CONFIGS\0"
"EMPTY_HELLO_RETRY_REQUEST\0"
"EMS_STATE_INCONSISTENT\0"
"ENCRYPTED_LENGTH_TOO_LONG\0"
@@ -1189,10 +1210,15 @@ const char kOpenSSLReasonStringData[] =
"HTTP_REQUEST\0"
"INAPPROPRIATE_FALLBACK\0"
"INCONSISTENT_CLIENT_HELLO\0"
+ "INCONSISTENT_ECH_NEGOTIATION\0"
"INVALID_ALPN_PROTOCOL\0"
+ "INVALID_ALPN_PROTOCOL_LIST\0"
+ "INVALID_CLIENT_HELLO_INNER\0"
"INVALID_COMMAND\0"
"INVALID_COMPRESSION_LIST\0"
"INVALID_DELEGATED_CREDENTIAL\0"
+ "INVALID_ECH_CONFIG_LIST\0"
+ "INVALID_ECH_PUBLIC_NAME\0"
"INVALID_MESSAGE\0"
"INVALID_OUTER_RECORD_TYPE\0"
"INVALID_SCT_LIST\0"
@@ -1201,7 +1227,6 @@ const char kOpenSSLReasonStringData[] =
"INVALID_TICKET_KEYS_LENGTH\0"
"KEY_USAGE_BIT_INCORRECT\0"
"LENGTH_MISMATCH\0"
- "MISSING_ALPN\0"
"MISSING_EXTENSION\0"
"MISSING_KEY_SHARE\0"
"MISSING_RSA_CERTIFICATE\0"
@@ -1213,6 +1238,7 @@ const char kOpenSSLReasonStringData[] =
"NEGOTIATED_BOTH_NPN_AND_ALPN\0"
"NEGOTIATED_TB_WITHOUT_EMS_OR_RI\0"
"NESTED_GROUP\0"
+ "NO_APPLICATION_PROTOCOL\0"
"NO_CERTIFICATES_RETURNED\0"
"NO_CERTIFICATE_ASSIGNED\0"
"NO_CERTIFICATE_SET\0"
@@ -1237,6 +1263,7 @@ const char kOpenSSLReasonStringData[] =
"OLD_SESSION_CIPHER_NOT_RETURNED\0"
"OLD_SESSION_PRF_HASH_MISMATCH\0"
"OLD_SESSION_VERSION_NOT_RETURNED\0"
+ "OUTER_EXTENSION_NOT_FOUND\0"
"PARSE_TLSEXT\0"
"PATH_TOO_LONG\0"
"PEER_DID_NOT_RETURN_A_CERTIFICATE\0"
@@ -1297,6 +1324,7 @@ const char kOpenSSLReasonStringData[] =
"TLSV1_ALERT_DECODE_ERROR\0"
"TLSV1_ALERT_DECRYPTION_FAILED\0"
"TLSV1_ALERT_DECRYPT_ERROR\0"
+ "TLSV1_ALERT_ECH_REQUIRED\0"
"TLSV1_ALERT_EXPORT_RESTRICTION\0"
"TLSV1_ALERT_INAPPROPRIATE_FALLBACK\0"
"TLSV1_ALERT_INSUFFICIENT_SECURITY\0"
@@ -1336,6 +1364,7 @@ const char kOpenSSLReasonStringData[] =
"UNKNOWN_STATE\0"
"UNSAFE_LEGACY_RENEGOTIATION_DISABLED\0"
"UNSUPPORTED_COMPRESSION_ALGORITHM\0"
+ "UNSUPPORTED_ECH_SERVER_CONFIG\0"
"UNSUPPORTED_ELLIPTIC_CURVE\0"
"UNSUPPORTED_PROTOCOL\0"
"UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY\0"
@@ -1430,6 +1459,7 @@ const char kOpenSSLReasonStringData[] =
"INVALID_PURPOSE\0"
"INVALID_SECTION\0"
"INVALID_SYNTAX\0"
+ "INVALID_VALUE\0"
"ISSUER_DECODE_ERROR\0"
"NEED_ORGANIZATION_AND_NUMBERS\0"
"NO_CONFIG_DATABASE\0"
diff --git a/deps/boringssl/ios-aarch64/crypto/fipsmodule/ghashv8-armx64.S b/deps/boringssl/ios-aarch64/crypto/fipsmodule/ghashv8-armx64.S
index 566330f..dcef3c5 100644
--- a/deps/boringssl/ios-aarch64/crypto/fipsmodule/ghashv8-armx64.S
+++ b/deps/boringssl/ios-aarch64/crypto/fipsmodule/ghashv8-armx64.S
@@ -14,6 +14,7 @@
#endif
#include <openssl/arm_arch.h>
+#if __ARM_MAX_ARCH__>=7
.text
.globl _gcm_init_v8
@@ -64,8 +65,48 @@ _gcm_init_v8:
ext v17.16b,v22.16b,v22.16b,#8 //Karatsuba pre-processing
eor v17.16b,v17.16b,v22.16b
ext v21.16b,v16.16b,v17.16b,#8 //pack Karatsuba pre-processed
- st1 {v21.2d,v22.2d},[x0] //store Htable[1..2]
+ st1 {v21.2d,v22.2d},[x0],#32 //store Htable[1..2]
+ //calculate H^3 and H^4
+ pmull v0.1q,v20.1d, v22.1d
+ pmull v5.1q,v22.1d,v22.1d
+ pmull2 v2.1q,v20.2d, v22.2d
+ pmull2 v7.1q,v22.2d,v22.2d
+ pmull v1.1q,v16.1d,v17.1d
+ pmull v6.1q,v17.1d,v17.1d
+
+ ext v16.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ ext v17.16b,v5.16b,v7.16b,#8
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v16.16b
+ eor v4.16b,v5.16b,v7.16b
+ eor v6.16b,v6.16b,v17.16b
+ eor v1.16b,v1.16b,v18.16b
+ pmull v18.1q,v0.1d,v19.1d //1st phase
+ eor v6.16b,v6.16b,v4.16b
+ pmull v4.1q,v5.1d,v19.1d
+
+ ins v2.d[0],v1.d[1]
+ ins v7.d[0],v6.d[1]
+ ins v1.d[1],v0.d[0]
+ ins v6.d[1],v5.d[0]
+ eor v0.16b,v1.16b,v18.16b
+ eor v5.16b,v6.16b,v4.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase
+ ext v4.16b,v5.16b,v5.16b,#8
+ pmull v0.1q,v0.1d,v19.1d
+ pmull v5.1q,v5.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v4.16b,v4.16b,v7.16b
+ eor v20.16b, v0.16b,v18.16b //H^3
+ eor v22.16b,v5.16b,v4.16b //H^4
+ ext v16.16b,v20.16b, v20.16b,#8 //Karatsuba pre-processing
+ ext v17.16b,v22.16b,v22.16b,#8
+ eor v16.16b,v16.16b,v20.16b
+ eor v17.16b,v17.16b,v22.16b
+ ext v21.16b,v16.16b,v17.16b,#8 //pack Karatsuba pre-processed
+ st1 {v20.2d,v21.2d,v22.2d},[x0] //store Htable[3..5]
ret
.globl _gcm_gmult_v8
@@ -117,6 +158,8 @@ _gcm_gmult_v8:
.align 4
_gcm_ghash_v8:
AARCH64_VALID_CALL_TARGET
+ cmp x3,#64
+ b.hs Lgcm_ghash_v8_4x
ld1 {v0.2d},[x0] //load [rotated] Xi
//"[rotated]" means that
//loaded value would have
@@ -243,7 +286,288 @@ Ldone_v8:
ret
+
+.align 4
+gcm_ghash_v8_4x:
+Lgcm_ghash_v8_4x:
+ ld1 {v0.2d},[x0] //load [rotated] Xi
+ ld1 {v20.2d,v21.2d,v22.2d},[x1],#48 //load twisted H, ..., H^2
+ movi v19.16b,#0xe1
+ ld1 {v26.2d,v27.2d,v28.2d},[x1] //load twisted H^3, ..., H^4
+ shl v19.2d,v19.2d,#57 //compose 0xc2.0 constant
+
+ ld1 {v4.2d,v5.2d,v6.2d,v7.2d},[x2],#64
+#ifndef __ARMEB__
+ rev64 v0.16b,v0.16b
+ rev64 v5.16b,v5.16b
+ rev64 v6.16b,v6.16b
+ rev64 v7.16b,v7.16b
+ rev64 v4.16b,v4.16b
+#endif
+ ext v25.16b,v7.16b,v7.16b,#8
+ ext v24.16b,v6.16b,v6.16b,#8
+ ext v23.16b,v5.16b,v5.16b,#8
+
+ pmull v29.1q,v20.1d,v25.1d //H·Ii+3
+ eor v7.16b,v7.16b,v25.16b
+ pmull2 v31.1q,v20.2d,v25.2d
+ pmull v30.1q,v21.1d,v7.1d
+
+ pmull v16.1q,v22.1d,v24.1d //H^2·Ii+2
+ eor v6.16b,v6.16b,v24.16b
+ pmull2 v24.1q,v22.2d,v24.2d
+ pmull2 v6.1q,v21.2d,v6.2d
+
+ eor v29.16b,v29.16b,v16.16b
+ eor v31.16b,v31.16b,v24.16b
+ eor v30.16b,v30.16b,v6.16b
+
+ pmull v7.1q,v26.1d,v23.1d //H^3·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+ pmull2 v23.1q,v26.2d,v23.2d
+ pmull v5.1q,v27.1d,v5.1d
+
+ eor v29.16b,v29.16b,v7.16b
+ eor v31.16b,v31.16b,v23.16b
+ eor v30.16b,v30.16b,v5.16b
+
+ subs x3,x3,#128
+ b.lo Ltail4x
+
+ b Loop4x
+
+.align 4
+Loop4x:
+ eor v16.16b,v4.16b,v0.16b
+ ld1 {v4.2d,v5.2d,v6.2d,v7.2d},[x2],#64
+ ext v3.16b,v16.16b,v16.16b,#8
+#ifndef __ARMEB__
+ rev64 v5.16b,v5.16b
+ rev64 v6.16b,v6.16b
+ rev64 v7.16b,v7.16b
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v0.1q,v28.1d,v3.1d //H^4·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v28.2d,v3.2d
+ ext v25.16b,v7.16b,v7.16b,#8
+ pmull2 v1.1q,v27.2d,v16.2d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ ext v24.16b,v6.16b,v6.16b,#8
+ eor v1.16b,v1.16b,v30.16b
+ ext v23.16b,v5.16b,v5.16b,#8
+
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ pmull v29.1q,v20.1d,v25.1d //H·Ii+3
+ eor v7.16b,v7.16b,v25.16b
+ eor v1.16b,v1.16b,v17.16b
+ pmull2 v31.1q,v20.2d,v25.2d
+ eor v1.16b,v1.16b,v18.16b
+ pmull v30.1q,v21.1d,v7.1d
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ pmull v16.1q,v22.1d,v24.1d //H^2·Ii+2
+ eor v6.16b,v6.16b,v24.16b
+ pmull2 v24.1q,v22.2d,v24.2d
+ eor v0.16b,v1.16b,v18.16b
+ pmull2 v6.1q,v21.2d,v6.2d
+
+ eor v29.16b,v29.16b,v16.16b
+ eor v31.16b,v31.16b,v24.16b
+ eor v30.16b,v30.16b,v6.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ pmull v7.1q,v26.1d,v23.1d //H^3·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+ eor v18.16b,v18.16b,v2.16b
+ pmull2 v23.1q,v26.2d,v23.2d
+ pmull v5.1q,v27.1d,v5.1d
+
+ eor v0.16b,v0.16b,v18.16b
+ eor v29.16b,v29.16b,v7.16b
+ eor v31.16b,v31.16b,v23.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+ eor v30.16b,v30.16b,v5.16b
+
+ subs x3,x3,#64
+ b.hs Loop4x
+
+Ltail4x:
+ eor v16.16b,v4.16b,v0.16b
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ pmull v0.1q,v28.1d,v3.1d //H^4·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v28.2d,v3.2d
+ pmull2 v1.1q,v27.2d,v16.2d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ eor v1.16b,v1.16b,v30.16b
+
+ adds x3,x3,#64
+ b.eq Ldone4x
+
+ cmp x3,#32
+ b.lo Lone
+ b.eq Ltwo
+Lthree:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ ld1 {v4.2d,v5.2d,v6.2d},[x2]
+ eor v1.16b,v1.16b,v18.16b
+#ifndef __ARMEB__
+ rev64 v5.16b,v5.16b
+ rev64 v6.16b,v6.16b
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ ext v24.16b,v6.16b,v6.16b,#8
+ ext v23.16b,v5.16b,v5.16b,#8
+ eor v0.16b,v1.16b,v18.16b
+
+ pmull v29.1q,v20.1d,v24.1d //H·Ii+2
+ eor v6.16b,v6.16b,v24.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ pmull2 v31.1q,v20.2d,v24.2d
+ pmull v30.1q,v21.1d,v6.1d
+ eor v0.16b,v0.16b,v18.16b
+ pmull v7.1q,v22.1d,v23.1d //H^2·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+ pmull2 v23.1q,v22.2d,v23.2d
+ eor v16.16b,v4.16b,v0.16b
+ pmull2 v5.1q,v21.2d,v5.2d
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ eor v29.16b,v29.16b,v7.16b
+ eor v31.16b,v31.16b,v23.16b
+ eor v30.16b,v30.16b,v5.16b
+
+ pmull v0.1q,v26.1d,v3.1d //H^3·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v26.2d,v3.2d
+ pmull v1.1q,v27.1d,v16.1d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ eor v1.16b,v1.16b,v30.16b
+ b Ldone4x
+
+.align 4
+Ltwo:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ ld1 {v4.2d,v5.2d},[x2]
+ eor v1.16b,v1.16b,v18.16b
+#ifndef __ARMEB__
+ rev64 v5.16b,v5.16b
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ ext v23.16b,v5.16b,v5.16b,#8
+ eor v0.16b,v1.16b,v18.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v0.16b,v0.16b,v18.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+ pmull v29.1q,v20.1d,v23.1d //H·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+
+ eor v16.16b,v4.16b,v0.16b
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ pmull2 v31.1q,v20.2d,v23.2d
+ pmull v30.1q,v21.1d,v5.1d
+
+ pmull v0.1q,v22.1d,v3.1d //H^2·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v22.2d,v3.2d
+ pmull2 v1.1q,v21.2d,v16.2d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ eor v1.16b,v1.16b,v30.16b
+ b Ldone4x
+
+.align 4
+Lone:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ ld1 {v4.2d},[x2]
+ eor v1.16b,v1.16b,v18.16b
+#ifndef __ARMEB__
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ eor v0.16b,v1.16b,v18.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v0.16b,v0.16b,v18.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+ eor v16.16b,v4.16b,v0.16b
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ pmull v0.1q,v20.1d,v3.1d
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v20.2d,v3.2d
+ pmull v1.1q,v21.1d,v16.1d
+
+Ldone4x:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ eor v1.16b,v1.16b,v18.16b
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ eor v0.16b,v1.16b,v18.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v0.16b,v0.16b,v18.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+#ifndef __ARMEB__
+ rev64 v0.16b,v0.16b
+#endif
+ st1 {v0.2d},[x0] //write out Xi
+
+ ret
+
.byte 71,72,65,83,72,32,102,111,114,32,65,82,77,118,56,44,32,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0
.align 2
.align 2
+#endif
#endif // !OPENSSL_NO_ASM
diff --git a/deps/boringssl/ios-arm/crypto/fipsmodule/ghashv8-armx32.S b/deps/boringssl/ios-arm/crypto/fipsmodule/ghashv8-armx32.S
index 4a7497f..dcac580 100644
--- a/deps/boringssl/ios-arm/crypto/fipsmodule/ghashv8-armx32.S
+++ b/deps/boringssl/ios-arm/crypto/fipsmodule/ghashv8-armx32.S
@@ -14,6 +14,7 @@
#endif
#include <openssl/arm_arch.h>
+#if __ARM_MAX_ARCH__>=7
.text
.code 32
@@ -68,8 +69,7 @@ _gcm_init_v8:
vext.8 q9,q14,q14,#8 @ Karatsuba pre-processing
veor q9,q9,q14
vext.8 q13,q8,q9,#8 @ pack Karatsuba pre-processed
- vst1.64 {q13,q14},[r0] @ store Htable[1..2]
-
+ vst1.64 {q13,q14},[r0]! @ store Htable[1..2]
bx lr
.globl _gcm_gmult_v8
@@ -256,4 +256,5 @@ Ldone_v8:
.byte 71,72,65,83,72,32,102,111,114,32,65,82,77,118,56,44,32,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0
.align 2
.align 2
+#endif
#endif // !OPENSSL_NO_ASM
diff --git a/deps/boringssl/linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S b/deps/boringssl/linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S
index 62e5884..9480a38 100644
--- a/deps/boringssl/linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S
+++ b/deps/boringssl/linux-aarch64/crypto/fipsmodule/ghashv8-armx64.S
@@ -15,6 +15,7 @@
#endif
#include <openssl/arm_arch.h>
+#if __ARM_MAX_ARCH__>=7
.text
.arch armv8-a+crypto
.globl gcm_init_v8
@@ -65,8 +66,48 @@ gcm_init_v8:
ext v17.16b,v22.16b,v22.16b,#8 //Karatsuba pre-processing
eor v17.16b,v17.16b,v22.16b
ext v21.16b,v16.16b,v17.16b,#8 //pack Karatsuba pre-processed
- st1 {v21.2d,v22.2d},[x0] //store Htable[1..2]
+ st1 {v21.2d,v22.2d},[x0],#32 //store Htable[1..2]
+ //calculate H^3 and H^4
+ pmull v0.1q,v20.1d, v22.1d
+ pmull v5.1q,v22.1d,v22.1d
+ pmull2 v2.1q,v20.2d, v22.2d
+ pmull2 v7.1q,v22.2d,v22.2d
+ pmull v1.1q,v16.1d,v17.1d
+ pmull v6.1q,v17.1d,v17.1d
+ ext v16.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ ext v17.16b,v5.16b,v7.16b,#8
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v16.16b
+ eor v4.16b,v5.16b,v7.16b
+ eor v6.16b,v6.16b,v17.16b
+ eor v1.16b,v1.16b,v18.16b
+ pmull v18.1q,v0.1d,v19.1d //1st phase
+ eor v6.16b,v6.16b,v4.16b
+ pmull v4.1q,v5.1d,v19.1d
+
+ ins v2.d[0],v1.d[1]
+ ins v7.d[0],v6.d[1]
+ ins v1.d[1],v0.d[0]
+ ins v6.d[1],v5.d[0]
+ eor v0.16b,v1.16b,v18.16b
+ eor v5.16b,v6.16b,v4.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase
+ ext v4.16b,v5.16b,v5.16b,#8
+ pmull v0.1q,v0.1d,v19.1d
+ pmull v5.1q,v5.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v4.16b,v4.16b,v7.16b
+ eor v20.16b, v0.16b,v18.16b //H^3
+ eor v22.16b,v5.16b,v4.16b //H^4
+
+ ext v16.16b,v20.16b, v20.16b,#8 //Karatsuba pre-processing
+ ext v17.16b,v22.16b,v22.16b,#8
+ eor v16.16b,v16.16b,v20.16b
+ eor v17.16b,v17.16b,v22.16b
+ ext v21.16b,v16.16b,v17.16b,#8 //pack Karatsuba pre-processed
+ st1 {v20.2d,v21.2d,v22.2d},[x0] //store Htable[3..5]
ret
.size gcm_init_v8,.-gcm_init_v8
.globl gcm_gmult_v8
@@ -118,6 +159,8 @@ gcm_gmult_v8:
.align 4
gcm_ghash_v8:
AARCH64_VALID_CALL_TARGET
+ cmp x3,#64
+ b.hs .Lgcm_ghash_v8_4x
ld1 {v0.2d},[x0] //load [rotated] Xi
//"[rotated]" means that
//loaded value would have
@@ -244,9 +287,290 @@ gcm_ghash_v8:
ret
.size gcm_ghash_v8,.-gcm_ghash_v8
+.type gcm_ghash_v8_4x,%function
+.align 4
+gcm_ghash_v8_4x:
+.Lgcm_ghash_v8_4x:
+ ld1 {v0.2d},[x0] //load [rotated] Xi
+ ld1 {v20.2d,v21.2d,v22.2d},[x1],#48 //load twisted H, ..., H^2
+ movi v19.16b,#0xe1
+ ld1 {v26.2d,v27.2d,v28.2d},[x1] //load twisted H^3, ..., H^4
+ shl v19.2d,v19.2d,#57 //compose 0xc2.0 constant
+
+ ld1 {v4.2d,v5.2d,v6.2d,v7.2d},[x2],#64
+#ifndef __ARMEB__
+ rev64 v0.16b,v0.16b
+ rev64 v5.16b,v5.16b
+ rev64 v6.16b,v6.16b
+ rev64 v7.16b,v7.16b
+ rev64 v4.16b,v4.16b
+#endif
+ ext v25.16b,v7.16b,v7.16b,#8
+ ext v24.16b,v6.16b,v6.16b,#8
+ ext v23.16b,v5.16b,v5.16b,#8
+
+ pmull v29.1q,v20.1d,v25.1d //H·Ii+3
+ eor v7.16b,v7.16b,v25.16b
+ pmull2 v31.1q,v20.2d,v25.2d
+ pmull v30.1q,v21.1d,v7.1d
+
+ pmull v16.1q,v22.1d,v24.1d //H^2·Ii+2
+ eor v6.16b,v6.16b,v24.16b
+ pmull2 v24.1q,v22.2d,v24.2d
+ pmull2 v6.1q,v21.2d,v6.2d
+
+ eor v29.16b,v29.16b,v16.16b
+ eor v31.16b,v31.16b,v24.16b
+ eor v30.16b,v30.16b,v6.16b
+
+ pmull v7.1q,v26.1d,v23.1d //H^3·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+ pmull2 v23.1q,v26.2d,v23.2d
+ pmull v5.1q,v27.1d,v5.1d
+
+ eor v29.16b,v29.16b,v7.16b
+ eor v31.16b,v31.16b,v23.16b
+ eor v30.16b,v30.16b,v5.16b
+
+ subs x3,x3,#128
+ b.lo .Ltail4x
+
+ b .Loop4x
+
+.align 4
+.Loop4x:
+ eor v16.16b,v4.16b,v0.16b
+ ld1 {v4.2d,v5.2d,v6.2d,v7.2d},[x2],#64
+ ext v3.16b,v16.16b,v16.16b,#8
+#ifndef __ARMEB__
+ rev64 v5.16b,v5.16b
+ rev64 v6.16b,v6.16b
+ rev64 v7.16b,v7.16b
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v0.1q,v28.1d,v3.1d //H^4·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v28.2d,v3.2d
+ ext v25.16b,v7.16b,v7.16b,#8
+ pmull2 v1.1q,v27.2d,v16.2d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ ext v24.16b,v6.16b,v6.16b,#8
+ eor v1.16b,v1.16b,v30.16b
+ ext v23.16b,v5.16b,v5.16b,#8
+
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ pmull v29.1q,v20.1d,v25.1d //H·Ii+3
+ eor v7.16b,v7.16b,v25.16b
+ eor v1.16b,v1.16b,v17.16b
+ pmull2 v31.1q,v20.2d,v25.2d
+ eor v1.16b,v1.16b,v18.16b
+ pmull v30.1q,v21.1d,v7.1d
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ pmull v16.1q,v22.1d,v24.1d //H^2·Ii+2
+ eor v6.16b,v6.16b,v24.16b
+ pmull2 v24.1q,v22.2d,v24.2d
+ eor v0.16b,v1.16b,v18.16b
+ pmull2 v6.1q,v21.2d,v6.2d
+
+ eor v29.16b,v29.16b,v16.16b
+ eor v31.16b,v31.16b,v24.16b
+ eor v30.16b,v30.16b,v6.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ pmull v7.1q,v26.1d,v23.1d //H^3·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+ eor v18.16b,v18.16b,v2.16b
+ pmull2 v23.1q,v26.2d,v23.2d
+ pmull v5.1q,v27.1d,v5.1d
+
+ eor v0.16b,v0.16b,v18.16b
+ eor v29.16b,v29.16b,v7.16b
+ eor v31.16b,v31.16b,v23.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+ eor v30.16b,v30.16b,v5.16b
+
+ subs x3,x3,#64
+ b.hs .Loop4x
+
+.Ltail4x:
+ eor v16.16b,v4.16b,v0.16b
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ pmull v0.1q,v28.1d,v3.1d //H^4·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v28.2d,v3.2d
+ pmull2 v1.1q,v27.2d,v16.2d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ eor v1.16b,v1.16b,v30.16b
+
+ adds x3,x3,#64
+ b.eq .Ldone4x
+
+ cmp x3,#32
+ b.lo .Lone
+ b.eq .Ltwo
+.Lthree:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ ld1 {v4.2d,v5.2d,v6.2d},[x2]
+ eor v1.16b,v1.16b,v18.16b
+#ifndef __ARMEB__
+ rev64 v5.16b,v5.16b
+ rev64 v6.16b,v6.16b
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ ext v24.16b,v6.16b,v6.16b,#8
+ ext v23.16b,v5.16b,v5.16b,#8
+ eor v0.16b,v1.16b,v18.16b
+
+ pmull v29.1q,v20.1d,v24.1d //H·Ii+2
+ eor v6.16b,v6.16b,v24.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ pmull2 v31.1q,v20.2d,v24.2d
+ pmull v30.1q,v21.1d,v6.1d
+ eor v0.16b,v0.16b,v18.16b
+ pmull v7.1q,v22.1d,v23.1d //H^2·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+ pmull2 v23.1q,v22.2d,v23.2d
+ eor v16.16b,v4.16b,v0.16b
+ pmull2 v5.1q,v21.2d,v5.2d
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ eor v29.16b,v29.16b,v7.16b
+ eor v31.16b,v31.16b,v23.16b
+ eor v30.16b,v30.16b,v5.16b
+
+ pmull v0.1q,v26.1d,v3.1d //H^3·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v26.2d,v3.2d
+ pmull v1.1q,v27.1d,v16.1d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ eor v1.16b,v1.16b,v30.16b
+ b .Ldone4x
+
+.align 4
+.Ltwo:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ ld1 {v4.2d,v5.2d},[x2]
+ eor v1.16b,v1.16b,v18.16b
+#ifndef __ARMEB__
+ rev64 v5.16b,v5.16b
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ ext v23.16b,v5.16b,v5.16b,#8
+ eor v0.16b,v1.16b,v18.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v0.16b,v0.16b,v18.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+ pmull v29.1q,v20.1d,v23.1d //H·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+
+ eor v16.16b,v4.16b,v0.16b
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ pmull2 v31.1q,v20.2d,v23.2d
+ pmull v30.1q,v21.1d,v5.1d
+
+ pmull v0.1q,v22.1d,v3.1d //H^2·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v22.2d,v3.2d
+ pmull2 v1.1q,v21.2d,v16.2d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ eor v1.16b,v1.16b,v30.16b
+ b .Ldone4x
+
+.align 4
+.Lone:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ ld1 {v4.2d},[x2]
+ eor v1.16b,v1.16b,v18.16b
+#ifndef __ARMEB__
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ eor v0.16b,v1.16b,v18.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v0.16b,v0.16b,v18.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+ eor v16.16b,v4.16b,v0.16b
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ pmull v0.1q,v20.1d,v3.1d
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v20.2d,v3.2d
+ pmull v1.1q,v21.1d,v16.1d
+
+.Ldone4x:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ eor v1.16b,v1.16b,v18.16b
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ eor v0.16b,v1.16b,v18.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v0.16b,v0.16b,v18.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+#ifndef __ARMEB__
+ rev64 v0.16b,v0.16b
+#endif
+ st1 {v0.2d},[x0] //write out Xi
+
+ ret
+.size gcm_ghash_v8_4x,.-gcm_ghash_v8_4x
.byte 71,72,65,83,72,32,102,111,114,32,65,82,77,118,56,44,32,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0
.align 2
.align 2
#endif
+#endif
#endif // !OPENSSL_NO_ASM
.section .note.GNU-stack,"",%progbits
diff --git a/deps/boringssl/linux-arm/crypto/fipsmodule/ghashv8-armx32.S b/deps/boringssl/linux-arm/crypto/fipsmodule/ghashv8-armx32.S
index b97457b..096dfb7 100644
--- a/deps/boringssl/linux-arm/crypto/fipsmodule/ghashv8-armx32.S
+++ b/deps/boringssl/linux-arm/crypto/fipsmodule/ghashv8-armx32.S
@@ -15,6 +15,7 @@
#endif
#include <openssl/arm_arch.h>
+#if __ARM_MAX_ARCH__>=7
.text
.fpu neon
.code 32
@@ -67,8 +68,7 @@ gcm_init_v8:
vext.8 q9,q14,q14,#8 @ Karatsuba pre-processing
veor q9,q9,q14
vext.8 q13,q8,q9,#8 @ pack Karatsuba pre-processed
- vst1.64 {q13,q14},[r0] @ store Htable[1..2]
-
+ vst1.64 {q13,q14},[r0]! @ store Htable[1..2]
bx lr
.size gcm_init_v8,.-gcm_init_v8
.globl gcm_gmult_v8
@@ -252,5 +252,6 @@ gcm_ghash_v8:
.align 2
.align 2
#endif
+#endif
#endif // !OPENSSL_NO_ASM
.section .note.GNU-stack,"",%progbits
diff --git a/deps/boringssl/src/CMakeLists.txt b/deps/boringssl/src/CMakeLists.txt
index f58e853..6a5a6aa 100644
--- a/deps/boringssl/src/CMakeLists.txt
+++ b/deps/boringssl/src/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.3)
+cmake_minimum_required(VERSION 3.5)
# Defer enabling C and CXX languages.
project(BoringSSL NONE)
@@ -117,7 +117,7 @@ endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
# Note clang-cl is odd and sets both CLANG and MSVC. We base our configuration
# primarily on our normal Clang one.
- set(C_CXX_FLAGS "-Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings -Wvla")
+ set(C_CXX_FLAGS "-Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings -Wvla -Wshadow")
if(MSVC)
# clang-cl sets different default warnings than clang. It also treats -Wall
# as -Weverything, to match MSVC. Instead -W3 is the alias for -Wall.
@@ -172,11 +172,6 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
if(CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-prototypes")
endif()
-
- if(CMAKE_COMPILER_IS_GNUCXX AND "4.8" VERSION_GREATER CMAKE_C_COMPILER_VERSION)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-array-bounds")
- endif()
-
elseif(MSVC)
set(MSVC_DISABLED_WARNINGS_LIST
"C4061" # enumerator 'identifier' in switch of enum 'enumeration' is not
@@ -254,18 +249,8 @@ if(WIN32)
add_definitions("-D_STL_EXTRA_DISABLED_WARNINGS=4774 4987")
endif()
-if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.7.99") OR
- CLANG)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
-endif()
-
if(CMAKE_COMPILER_IS_GNUCXX)
- if((CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR CLANG)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
- else()
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
- endif()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
endif()
# pthread_rwlock_t requires a feature flag.
@@ -409,8 +394,7 @@ endif()
function(go_executable dest package)
set(godeps "${CMAKE_SOURCE_DIR}/util/godeps.go")
- if(${CMAKE_VERSION} VERSION_LESS "3.7" OR
- NOT ${CMAKE_GENERATOR} STREQUAL "Ninja")
+ if(CMAKE_VERSION VERSION_LESS "3.7" OR NOT CMAKE_GENERATOR STREQUAL "Ninja")
# The DEPFILE parameter to add_custom_command is new as of CMake 3.7 and
# only works with Ninja. Query the sources at configure time. Additionally,
# everything depends on go.mod. That affects what external packages to use.
@@ -452,7 +436,7 @@ endfunction()
# builds.
if(NOT OPENSSL_NO_ASM AND CMAKE_OSX_ARCHITECTURES)
list(LENGTH CMAKE_OSX_ARCHITECTURES NUM_ARCHES)
- if(NOT ${NUM_ARCHES} EQUAL 1)
+ if(NOT NUM_ARCHES EQUAL 1)
message(FATAL_ERROR "Universal binaries not supported.")
endif()
list(GET CMAKE_OSX_ARCHITECTURES 0 CMAKE_SYSTEM_PROCESSOR)
@@ -465,44 +449,44 @@ endif()
if(OPENSSL_NO_ASM)
add_definitions(-DOPENSSL_NO_ASM)
set(ARCH "generic")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(ARCH "x86_64")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64")
set(ARCH "x86_64")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")
# cmake reports AMD64 on Windows, but we might be building for 32-bit.
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(ARCH "x86_64")
else()
set(ARCH "x86")
endif()
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
set(ARCH "x86")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i386")
set(ARCH "x86")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686")
set(ARCH "x86")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
set(ARCH "aarch64")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ARM64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
set(ARCH "aarch64")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(ARCH "aarch64")
# Apple A12 Bionic chipset which is added in iPhone XS/XS Max/XR uses arm64e architecture.
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64e")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64e")
set(ARCH "aarch64")
-elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*")
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm*")
set(ARCH "arm")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "mips")
# Just to avoid the “unknown processor” error.
set(ARCH "generic")
-elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
set(ARCH "ppc64le")
else()
message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR})
endif()
-if(ANDROID AND NOT ANDROID_NDK_REVISION AND ${ARCH} STREQUAL "arm")
+if(ANDROID AND NOT ANDROID_NDK_REVISION AND ARCH STREQUAL "arm")
# The third-party Android-NDK CMake files somehow fail to set the -march flag
# for assembly files. Without this flag, the compiler believes that it's
# building for ARMv5.
diff --git a/deps/boringssl/src/crypto/CMakeLists.txt b/deps/boringssl/src/crypto/CMakeLists.txt
index cde92b5..990df00 100644
--- a/deps/boringssl/src/crypto/CMakeLists.txt
+++ b/deps/boringssl/src/crypto/CMakeLists.txt
@@ -2,7 +2,7 @@ include_directories(../include)
if(NOT OPENSSL_NO_ASM)
if(UNIX)
- if(${ARCH} STREQUAL "aarch64")
+ if(ARCH STREQUAL "aarch64")
# The "armx" Perl scripts look for "64" in the style argument
# in order to decide whether to generate 32- or 64-bit asm.
if(APPLE)
@@ -10,16 +10,16 @@ if(NOT OPENSSL_NO_ASM)
else()
set(PERLASM_STYLE linux64)
endif()
- elseif(${ARCH} STREQUAL "arm")
+ elseif(ARCH STREQUAL "arm")
if(APPLE)
set(PERLASM_STYLE ios32)
else()
set(PERLASM_STYLE linux32)
endif()
- elseif(${ARCH} STREQUAL "ppc64le")
+ elseif(ARCH STREQUAL "ppc64le")
set(PERLASM_STYLE linux64le)
else()
- if(${ARCH} STREQUAL "x86")
+ if(ARCH STREQUAL "x86")
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2")
endif()
if(APPLE)
@@ -47,12 +47,12 @@ if(NOT OPENSSL_NO_ASM)
endforeach()
endif()
else()
- if(${ARCH} STREQUAL "aarch64")
+ if(ARCH STREQUAL "aarch64")
set(PERLASM_STYLE win64)
set(ASM_EXT S)
enable_language(ASM)
else()
- if(${ARCH} STREQUAL "x86_64")
+ if(ARCH STREQUAL "x86_64")
set(PERLASM_STYLE nasm)
else()
set(PERLASM_STYLE win32n)
@@ -69,7 +69,7 @@ endif()
function(perlasm dest src)
get_filename_component(dir ${dest} DIRECTORY)
- if ("${dir}" STREQUAL "")
+ if(dir STREQUAL "")
set(dir ".")
endif()
@@ -104,7 +104,7 @@ if(FIPS_DELOCATE OR FIPS_SHARED)
)
endif()
-if(${ARCH} STREQUAL "arm")
+if(ARCH STREQUAL "arm")
set(
CRYPTO_ARCH_SOURCES
@@ -115,7 +115,7 @@ if(${ARCH} STREQUAL "arm")
)
endif()
-if(${ARCH} STREQUAL "aarch64")
+if(ARCH STREQUAL "aarch64")
set(
CRYPTO_ARCH_SOURCES
@@ -124,7 +124,7 @@ if(${ARCH} STREQUAL "aarch64")
)
endif()
-if(${ARCH} STREQUAL "ppc64le")
+if(ARCH STREQUAL "ppc64le")
set(
CRYPTO_ARCH_SOURCES
@@ -132,7 +132,7 @@ if(${ARCH} STREQUAL "ppc64le")
)
endif()
-if(${ARCH} STREQUAL "x86")
+if(ARCH STREQUAL "x86")
set(
CRYPTO_ARCH_SOURCES
@@ -141,7 +141,7 @@ if(${ARCH} STREQUAL "x86")
)
endif()
-if(${ARCH} STREQUAL "x86_64")
+if(ARCH STREQUAL "x86_64")
set(
CRYPTO_ARCH_SOURCES
@@ -211,6 +211,7 @@ add_library(
asn1/a_object.c
asn1/a_octet.c
asn1/a_print.c
+ asn1/a_strex.c
asn1/a_strnid.c
asn1/a_time.c
asn1/a_type.c
@@ -350,13 +351,13 @@ add_library(
trust_token/voprf.c
x509/a_digest.c
x509/a_sign.c
- x509/a_strex.c
x509/a_verify.c
x509/algorithm.c
x509/asn1_gen.c
x509/by_dir.c
x509/by_file.c
x509/i2d_pr.c
+ x509/name_print.c
x509/rsa_pss.c
x509/t_crl.c
x509/t_req.c
@@ -370,7 +371,6 @@ add_library(
x509/x509_ext.c
x509/x509_lu.c
x509/x509_obj.c
- x509/x509_r2x.c
x509/x509_req.c
x509/x509_set.c
x509/x509_trs.c
@@ -502,6 +502,7 @@ add_executable(
cipher_extra/cipher_test.cc
cmac/cmac_test.cc
compiler_test.cc
+ conf/conf_test.cc
constant_time_test.cc
cpu-arm-linux_test.cc
crypto_test.cc
diff --git a/deps/boringssl/src/crypto/asn1/a_bitstr.c b/deps/boringssl/src/crypto/asn1/a_bitstr.c
index b945cb1..d45a73e 100644
--- a/deps/boringssl/src/crypto/asn1/a_bitstr.c
+++ b/deps/boringssl/src/crypto/asn1/a_bitstr.c
@@ -65,64 +65,69 @@
#include "../internal.h"
-int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len)
+int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, const unsigned char *d, int len)
{
return ASN1_STRING_set(x, d, len);
}
-int i2c_ASN1_BIT_STRING(const ASN1_BIT_STRING *a, unsigned char **pp)
-{
- int ret, j, bits, len;
- unsigned char *p, *d;
-
- if (a == NULL)
- return (0);
-
- len = a->length;
+static int asn1_bit_string_length(const ASN1_BIT_STRING *str,
+ uint8_t *out_padding_bits) {
+ int len = str->length;
+ if (str->flags & ASN1_STRING_FLAG_BITS_LEFT) {
+ // If the string is already empty, it cannot have padding bits.
+ *out_padding_bits = len == 0 ? 0 : str->flags & 0x07;
+ return len;
+ }
+ // TODO(davidben): If we move this logic to |ASN1_BIT_STRING_set_bit|, can
+ // we remove this representation?
+ while (len > 0 && str->data[len - 1] == 0) {
+ len--;
+ }
+ uint8_t padding_bits = 0;
if (len > 0) {
- if (a->flags & ASN1_STRING_FLAG_BITS_LEFT) {
- bits = (int)a->flags & 0x07;
- } else {
- for (; len > 0; len--) {
- if (a->data[len - 1])
- break;
+ uint8_t last = str->data[len - 1];
+ assert(last != 0);
+ for (; padding_bits < 7; padding_bits++) {
+ if (last & (1 << padding_bits)) {
+ break;
}
- j = a->data[len - 1];
- if (j & 0x01)
- bits = 0;
- else if (j & 0x02)
- bits = 1;
- else if (j & 0x04)
- bits = 2;
- else if (j & 0x08)
- bits = 3;
- else if (j & 0x10)
- bits = 4;
- else if (j & 0x20)
- bits = 5;
- else if (j & 0x40)
- bits = 6;
- else if (j & 0x80)
- bits = 7;
- else
- bits = 0; /* should not happen */
}
- } else
- bits = 0;
+ }
+ *out_padding_bits = padding_bits;
+ return len;
+}
- ret = 1 + len;
- if (pp == NULL)
- return (ret);
+int ASN1_BIT_STRING_num_bytes(const ASN1_BIT_STRING *str, size_t *out) {
+ uint8_t padding_bits;
+ int len = asn1_bit_string_length(str, &padding_bits);
+ if (padding_bits != 0) {
+ return 0;
+ }
+ *out = len;
+ return 1;
+}
- p = *pp;
+int i2c_ASN1_BIT_STRING(const ASN1_BIT_STRING *a, unsigned char **pp)
+{
+ if (a == NULL) {
+ return 0;
+ }
+
+ uint8_t bits;
+ int len = asn1_bit_string_length(a, &bits);
+ int ret = 1 + len;
+ if (pp == NULL) {
+ return ret;
+ }
- *(p++) = (unsigned char)bits;
- d = a->data;
- OPENSSL_memcpy(p, d, len);
+ uint8_t *p = *pp;
+ *(p++) = bits;
+ OPENSSL_memcpy(p, a->data, len);
+ if (len > 0) {
+ p[len - 1] &= (0xff << bits);
+ }
p += len;
- if (len > 0)
- p[-1] &= (0xff << bits);
*pp = p;
return (ret);
}
@@ -251,7 +256,7 @@ int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n)
* 'len' is the length of 'flags'.
*/
int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *a,
- unsigned char *flags, int flags_len)
+ const unsigned char *flags, int flags_len)
{
int i, ok;
/* Check if there is one bit set at all. */
diff --git a/deps/boringssl/src/crypto/asn1/a_bool.c b/deps/boringssl/src/crypto/asn1/a_bool.c
index 34bbd15..64ae9e5 100644
--- a/deps/boringssl/src/crypto/asn1/a_bool.c
+++ b/deps/boringssl/src/crypto/asn1/a_bool.c
@@ -78,7 +78,7 @@ int i2d_ASN1_BOOLEAN(int a, unsigned char **pp)
}
ASN1_put_object(&p, 0, 1, V_ASN1_BOOLEAN, V_ASN1_UNIVERSAL);
- *p = (unsigned char)a;
+ *p = a ? 0xff : 0x00;
/*
* If a new buffer was allocated, just return it back.
diff --git a/deps/boringssl/src/crypto/asn1/a_d2i_fp.c b/deps/boringssl/src/crypto/asn1/a_d2i_fp.c
index fd423e2..d0d6d03 100644
--- a/deps/boringssl/src/crypto/asn1/a_d2i_fp.c
+++ b/deps/boringssl/src/crypto/asn1/a_d2i_fp.c
@@ -78,7 +78,6 @@ void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
return ret;
}
-#ifndef OPENSSL_NO_FP_API
void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
{
BIO *b = BIO_new_fp(in, BIO_NOCLOSE);
@@ -90,4 +89,3 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
BIO_free(b);
return ret;
}
-#endif
diff --git a/deps/boringssl/src/crypto/asn1/a_gentm.c b/deps/boringssl/src/crypto/asn1/a_gentm.c
index 5fcb65b..3e6f14e 100644
--- a/deps/boringssl/src/crypto/asn1/a_gentm.c
+++ b/deps/boringssl/src/crypto/asn1/a_gentm.c
@@ -62,7 +62,7 @@
#include <openssl/err.h>
#include <openssl/mem.h>
-#include "asn1_locl.h"
+#include "internal.h"
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d)
{
@@ -237,6 +237,11 @@ ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
goto err;
}
+ if (ts->tm_year < 0 - 1900 || ts->tm_year > 9999 - 1900) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_TIME_VALUE);
+ goto err;
+ }
+
p = (char *)tmps->data;
if ((p == NULL) || ((size_t)tmps->length < len)) {
p = OPENSSL_malloc(len);
diff --git a/deps/boringssl/src/crypto/asn1/a_mbstr.c b/deps/boringssl/src/crypto/asn1/a_mbstr.c
index 1bbcd1b..5853b72 100644
--- a/deps/boringssl/src/crypto/asn1/a_mbstr.c
+++ b/deps/boringssl/src/crypto/asn1/a_mbstr.c
@@ -63,11 +63,9 @@
#include <openssl/err.h>
#include <openssl/mem.h>
-#include "asn1_locl.h"
+#include "internal.h"
#include "../bytestring/internal.h"
-static int is_printable(uint32_t value);
-
/*
* These functions take a string in UTF8, ASCII or multibyte form and a mask
* of permissible ASN1 string types. It then works out the minimal type
@@ -153,7 +151,7 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
}
/* Update which output formats are still possible. */
- if ((mask & B_ASN1_PRINTABLESTRING) && !is_printable(c)) {
+ if ((mask & B_ASN1_PRINTABLESTRING) && !asn1_is_printable(c)) {
mask &= ~B_ASN1_PRINTABLESTRING;
}
if ((mask & B_ASN1_IA5STRING) && (c > 127)) {
@@ -208,11 +206,14 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
encode_func = cbb_add_utf32_be;
size_estimate = 4 * nchar;
outform = MBSTRING_UNIV;
- } else {
+ } else if (mask & B_ASN1_UTF8STRING) {
str_type = V_ASN1_UTF8STRING;
outform = MBSTRING_UTF8;
encode_func = cbb_add_utf8;
size_estimate = utf8_len;
+ } else {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
+ return -1;
}
if (!out)
@@ -282,24 +283,16 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
return -1;
}
-/* Return 1 if the character is permitted in a PrintableString */
-static int is_printable(uint32_t value)
+int asn1_is_printable(uint32_t value)
{
- int ch;
- if (value > 0x7f)
+ if (value > 0x7f) {
return 0;
- ch = (int)value;
- /*
- * Note: we can't use 'isalnum' because certain accented characters may
- * count as alphanumeric in some environments.
- */
- if ((ch >= 'a') && (ch <= 'z'))
- return 1;
- if ((ch >= 'A') && (ch <= 'Z'))
- return 1;
- if ((ch >= '0') && (ch <= '9'))
- return 1;
- if ((ch == ' ') || strchr("'()+,-./:=?", ch))
- return 1;
- return 0;
+ }
+ /* Note we cannot use |isalnum| because it is locale-dependent. */
+ return ('a' <= value && value <= 'z') || //
+ ('A' <= value && value <= 'Z') || //
+ ('0' <= value && value <= '9') || //
+ value == ' ' || value == '\'' || value == '(' || value == ')' ||
+ value == '+' || value == ',' || value == '-' || value == '.' ||
+ value == '/' || value == ':' || value == '=' || value == '?';
}
diff --git a/deps/boringssl/src/crypto/asn1/a_object.c b/deps/boringssl/src/crypto/asn1/a_object.c
index bf386dd..de27e87 100644
--- a/deps/boringssl/src/crypto/asn1/a_object.c
+++ b/deps/boringssl/src/crypto/asn1/a_object.c
@@ -64,6 +64,7 @@
#include <openssl/obj.h>
#include "../internal.h"
+#include "internal.h"
int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp)
@@ -180,16 +181,13 @@ ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
}
}
- /*
- * only the ASN1_OBJECTs from the 'table' will have values for ->sn or
- * ->ln
- */
if ((a == NULL) || ((*a) == NULL) ||
!((*a)->flags & ASN1_OBJECT_FLAG_DYNAMIC)) {
if ((ret = ASN1_OBJECT_new()) == NULL)
return (NULL);
- } else
+ } else {
ret = (*a);
+ }
p = *pp;
/* detach data from object */
@@ -208,12 +206,17 @@ ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
ret->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA;
}
OPENSSL_memcpy(data, p, length);
+ /* If there are dynamic strings, free them here, and clear the flag */
+ if ((ret->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS) != 0) {
+ OPENSSL_free((char *)ret->sn);
+ OPENSSL_free((char *)ret->ln);
+ ret->flags &= ~ASN1_OBJECT_FLAG_DYNAMIC_STRINGS;
+ }
/* reattach data to object, after which it remains const */
ret->data = data;
ret->length = length;
ret->sn = NULL;
ret->ln = NULL;
- /* ret->flags=ASN1_OBJECT_FLAG_DYNAMIC; we know it is dynamic */
p += length;
if (a != NULL)
@@ -263,7 +266,7 @@ void ASN1_OBJECT_free(ASN1_OBJECT *a)
OPENSSL_free(a);
}
-ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data, int len,
+ASN1_OBJECT *ASN1_OBJECT_create(int nid, const unsigned char *data, int len,
const char *sn, const char *ln)
{
ASN1_OBJECT o;
diff --git a/deps/boringssl/src/crypto/asn1/a_print.c b/deps/boringssl/src/crypto/asn1/a_print.c
index 2104521..c7efede 100644
--- a/deps/boringssl/src/crypto/asn1/a_print.c
+++ b/deps/boringssl/src/crypto/asn1/a_print.c
@@ -56,38 +56,28 @@
#include <openssl/asn1.h>
-#include <openssl/err.h>
-#include <openssl/mem.h>
+#include <string.h>
+
+#include "internal.h"
+
int ASN1_PRINTABLE_type(const unsigned char *s, int len)
{
- int c;
- int ia5 = 0;
- int t61 = 0;
-
- if (len <= 0)
- len = -1;
- if (s == NULL)
- return (V_ASN1_PRINTABLESTRING);
+ if (len < 0) {
+ len = strlen((const char *)s);
+ }
- while ((*s) && (len-- != 0)) {
- c = *(s++);
- if (!(((c >= 'a') && (c <= 'z')) ||
- ((c >= 'A') && (c <= 'Z')) ||
- (c == ' ') ||
- ((c >= '0') && (c <= '9')) ||
- (c == ' ') || (c == '\'') ||
- (c == '(') || (c == ')') ||
- (c == '+') || (c == ',') ||
- (c == '-') || (c == '.') ||
- (c == '/') || (c == ':') || (c == '=') || (c == '?')))
- ia5 = 1;
- if (c & 0x80)
- t61 = 1;
+ int printable = 1;
+ for (int i = 0; i < len; i++) {
+ unsigned char c = s[i];
+ if (c & 0x80) {
+ /* No need to continue iterating. */
+ return V_ASN1_T61STRING;
+ }
+ if (!asn1_is_printable(c)) {
+ printable = 0;
+ }
}
- if (t61)
- return (V_ASN1_T61STRING);
- if (ia5)
- return (V_ASN1_IA5STRING);
- return (V_ASN1_PRINTABLESTRING);
+
+ return printable ? V_ASN1_PRINTABLESTRING : V_ASN1_IA5STRING;
}
diff --git a/deps/boringssl/src/crypto/x509/a_strex.c b/deps/boringssl/src/crypto/asn1/a_strex.c
index 2c4824e..7829d67 100644
--- a/deps/boringssl/src/crypto/x509/a_strex.c
+++ b/deps/boringssl/src/crypto/asn1/a_strex.c
@@ -54,23 +54,27 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
-#include <openssl/x509.h>
+#include <openssl/asn1.h>
+#include <ctype.h>
#include <inttypes.h>
#include <string.h>
-#include <openssl/asn1.h>
+#include <openssl/bio.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include "charmap.h"
-#include "../asn1/asn1_locl.h"
+#include "internal.h"
-/*
- * ASN1_STRING_print_ex() and X509_NAME_print_ex(). Enhanced string and name
- * printing routines handling multibyte characters, RFC2253 and a host of
- * other options.
- */
+
+// These flags must be distinct from |ESC_FLAGS| and fit in a byte.
+
+// Character is a valid PrintableString character
+#define CHARTYPE_PRINTABLESTRING 0x10
+// Character needs escaping if it is the first character
+#define CHARTYPE_FIRST_ESC_2253 0x20
+// Character needs escaping if it is the last character
+#define CHARTYPE_LAST_ESC_2253 0x40
#define CHARTYPE_BS_ESC (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253)
@@ -79,26 +83,12 @@
ASN1_STRFLGS_ESC_CTRL | \
ASN1_STRFLGS_ESC_MSB)
-static int send_bio_chars(void *arg, const void *buf, int len)
+static int maybe_write(BIO *out, const void *buf, int len)
{
- if (!arg)
- return 1;
- if (BIO_write(arg, buf, len) != len)
- return 0;
- return 1;
+ /* If |out| is NULL, ignore the output but report the length. */
+ return out == NULL || BIO_write(out, buf, len) == len;
}
-static int send_fp_chars(void *arg, const void *buf, int len)
-{
- if (!arg)
- return 1;
- if (fwrite(buf, 1, len, arg) != (unsigned int)len)
- return 0;
- return 1;
-}
-
-typedef int char_io (void *arg, const void *buf, int len);
-
/*
* This function handles display of strings, one character at a time. It is
* passed an unsigned long for each character because it could come from 2 or
@@ -108,20 +98,20 @@ typedef int char_io (void *arg, const void *buf, int len);
#define HEX_SIZE(type) (sizeof(type)*2)
static int do_esc_char(uint32_t c, unsigned char flags, char *do_quotes,
- char_io *io_ch, void *arg)
+ BIO *out)
{
unsigned char chflgs, chtmp;
char tmphex[HEX_SIZE(uint32_t) + 3];
if (c > 0xffff) {
BIO_snprintf(tmphex, sizeof tmphex, "\\W%08" PRIX32, c);
- if (!io_ch(arg, tmphex, 10))
+ if (!maybe_write(out, tmphex, 10))
return -1;
return 10;
}
if (c > 0xff) {
BIO_snprintf(tmphex, sizeof tmphex, "\\U%04" PRIX32, c);
- if (!io_ch(arg, tmphex, 6))
+ if (!maybe_write(out, tmphex, 6))
return -1;
return 6;
}
@@ -135,19 +125,19 @@ static int do_esc_char(uint32_t c, unsigned char flags, char *do_quotes,
if (chflgs & ASN1_STRFLGS_ESC_QUOTE) {
if (do_quotes)
*do_quotes = 1;
- if (!io_ch(arg, &chtmp, 1))
+ if (!maybe_write(out, &chtmp, 1))
return -1;
return 1;
}
- if (!io_ch(arg, "\\", 1))
+ if (!maybe_write(out, "\\", 1))
return -1;
- if (!io_ch(arg, &chtmp, 1))
+ if (!maybe_write(out, &chtmp, 1))
return -1;
return 2;
}
if (chflgs & (ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB)) {
BIO_snprintf(tmphex, 11, "\\%02X", chtmp);
- if (!io_ch(arg, tmphex, 3))
+ if (!maybe_write(out, tmphex, 3))
return -1;
return 3;
}
@@ -156,11 +146,11 @@ static int do_esc_char(uint32_t c, unsigned char flags, char *do_quotes,
* character itself: backslash.
*/
if (chtmp == '\\' && flags & ESC_FLAGS) {
- if (!io_ch(arg, "\\\\", 2))
+ if (!maybe_write(out, "\\\\", 2))
return -1;
return 2;
}
- if (!io_ch(arg, &chtmp, 1))
+ if (!maybe_write(out, &chtmp, 1))
return -1;
return 1;
}
@@ -175,8 +165,7 @@ static int do_esc_char(uint32_t c, unsigned char flags, char *do_quotes,
*/
static int do_buf(unsigned char *buf, int buflen,
- int type, unsigned char flags, char *quotes, char_io *io_ch,
- void *arg)
+ int type, unsigned char flags, char *quotes, BIO *out)
{
int i, outlen, len, charwidth;
unsigned char orflags, *p, *q;
@@ -208,6 +197,8 @@ static int do_buf(unsigned char *buf, int buflen,
orflags = CHARTYPE_FIRST_ESC_2253;
else
orflags = 0;
+ /* TODO(davidben): Replace this with |cbs_get_ucs2_be|, etc., to check
+ * for invalid codepoints. */
switch (charwidth) {
case 4:
c = ((uint32_t)*p++) << 24;
@@ -248,17 +239,14 @@ static int do_buf(unsigned char *buf, int buflen,
* otherwise each character will be > 0x7f and so the
* character will never be escaped on first and last.
*/
- len =
- do_esc_char(utfbuf[i], (unsigned char)(flags | orflags),
- quotes, io_ch, arg);
+ len = do_esc_char(utfbuf[i], (unsigned char)(flags | orflags),
+ quotes, out);
if (len < 0)
return -1;
outlen += len;
}
} else {
- len =
- do_esc_char(c, (unsigned char)(flags | orflags), quotes,
- io_ch, arg);
+ len = do_esc_char(c, (unsigned char)(flags | orflags), quotes, out);
if (len < 0)
return -1;
outlen += len;
@@ -269,19 +257,18 @@ static int do_buf(unsigned char *buf, int buflen,
/* This function hex dumps a buffer of characters */
-static int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf,
- int buflen)
+static int do_hex_dump(BIO *out, unsigned char *buf, int buflen)
{
static const char hexdig[] = "0123456789ABCDEF";
unsigned char *p, *q;
char hextmp[2];
- if (arg) {
+ if (out) {
p = buf;
q = buf + buflen;
while (p != q) {
hextmp[0] = hexdig[*p >> 4];
hextmp[1] = hexdig[*p & 0xf];
- if (!io_ch(arg, hextmp, 2))
+ if (!maybe_write(out, hextmp, 2))
return -1;
p++;
}
@@ -292,41 +279,55 @@ static int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf,
/*
* "dump" a string. This is done when the type is unknown, or the flags
* request it. We can either dump the content octets or the entire DER
- * encoding. This uses the RFC2253 #01234 format.
+ * encoding. This uses the RFC 2253 #01234 format.
*/
-static int do_dump(unsigned long lflags, char_io *io_ch, void *arg,
- const ASN1_STRING *str)
+static int do_dump(unsigned long lflags, BIO *out, const ASN1_STRING *str)
{
- /*
- * Placing the ASN1_STRING in a temp ASN1_TYPE allows the DER encoding to
- * readily obtained
- */
- ASN1_TYPE t;
- unsigned char *der_buf, *p;
- int outlen, der_len;
-
- if (!io_ch(arg, "#", 1))
+ if (!maybe_write(out, "#", 1)) {
return -1;
+ }
+
/* If we don't dump DER encoding just dump content octets */
if (!(lflags & ASN1_STRFLGS_DUMP_DER)) {
- outlen = do_hex_dump(io_ch, arg, str->data, str->length);
- if (outlen < 0)
+ int outlen = do_hex_dump(out, str->data, str->length);
+ if (outlen < 0) {
return -1;
+ }
return outlen + 1;
}
+
+ /*
+ * Placing the ASN1_STRING in a temporary ASN1_TYPE allows the DER encoding
+ * to readily obtained.
+ */
+ ASN1_TYPE t;
t.type = str->type;
- t.value.ptr = (char *)str;
- der_len = i2d_ASN1_TYPE(&t, NULL);
- der_buf = OPENSSL_malloc(der_len);
- if (!der_buf)
+ /* Negative INTEGER and ENUMERATED values are the only case where
+ * |ASN1_STRING| and |ASN1_TYPE| types do not match.
+ *
+ * TODO(davidben): There are also some type fields which, in |ASN1_TYPE|, do
+ * not correspond to |ASN1_STRING|. It is unclear whether those are allowed
+ * in |ASN1_STRING| at all, or what the space of allowed types is.
+ * |ASN1_item_ex_d2i| will never produce such a value so, for now, we say
+ * this is an invalid input. But this corner of the library in general
+ * should be more robust. */
+ if (t.type == V_ASN1_NEG_INTEGER) {
+ t.type = V_ASN1_INTEGER;
+ } else if (t.type == V_ASN1_NEG_ENUMERATED) {
+ t.type = V_ASN1_ENUMERATED;
+ }
+ t.value.asn1_string = (ASN1_STRING *)str;
+ unsigned char *der_buf = NULL;
+ int der_len = i2d_ASN1_TYPE(&t, &der_buf);
+ if (der_len < 0) {
return -1;
- p = der_buf;
- i2d_ASN1_TYPE(&t, &p);
- outlen = do_hex_dump(io_ch, arg, der_buf, der_len);
+ }
+ int outlen = do_hex_dump(out, der_buf, der_len);
OPENSSL_free(der_buf);
- if (outlen < 0)
+ if (outlen < 0) {
return -1;
+ }
return outlen + 1;
}
@@ -353,8 +354,7 @@ static const signed char tag2nbyte[] = {
* an error occurred.
*/
-static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags,
- const ASN1_STRING *str)
+int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, unsigned long lflags)
{
int outlen, len;
int type;
@@ -372,7 +372,7 @@ static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags,
const char *tagname;
tagname = ASN1_tag2str(type);
outlen += strlen(tagname);
- if (!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1))
+ if (!maybe_write(out, tagname, outlen) || !maybe_write(out, ":", 1))
return -1;
outlen++;
}
@@ -396,7 +396,7 @@ static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags,
}
if (type == -1) {
- len = do_dump(lflags, io_ch, arg, str);
+ len = do_dump(lflags, out, str);
if (len < 0)
return -1;
outlen += len;
@@ -415,219 +415,41 @@ static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags,
type |= BUF_TYPE_CONVUTF8;
}
- len = do_buf(str->data, str->length, type, flags, &quotes, io_ch, NULL);
+ len = do_buf(str->data, str->length, type, flags, &quotes, NULL);
if (len < 0)
return -1;
outlen += len;
if (quotes)
outlen += 2;
- if (!arg)
+ if (!out)
return outlen;
- if (quotes && !io_ch(arg, "\"", 1))
+ if (quotes && !maybe_write(out, "\"", 1))
return -1;
- if (do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0)
+ if (do_buf(str->data, str->length, type, flags, NULL, out) < 0)
return -1;
- if (quotes && !io_ch(arg, "\"", 1))
+ if (quotes && !maybe_write(out, "\"", 1))
return -1;
return outlen;
}
-/* Used for line indenting: print 'indent' spaces */
-
-static int do_indent(char_io *io_ch, void *arg, int indent)
-{
- int i;
- for (i = 0; i < indent; i++)
- if (!io_ch(arg, " ", 1))
- return 0;
- return 1;
-}
-
-#define FN_WIDTH_LN 25
-#define FN_WIDTH_SN 10
-
-static int do_name_ex(char_io *io_ch, void *arg, const X509_NAME *n,
- int indent, unsigned long flags)
+int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str,
+ unsigned long flags)
{
- int i, prev = -1, orflags, cnt;
- int fn_opt, fn_nid;
- ASN1_OBJECT *fn;
- ASN1_STRING *val;
- X509_NAME_ENTRY *ent;
- char objtmp[80];
- const char *objbuf;
- int outlen, len;
- const char *sep_dn, *sep_mv, *sep_eq;
- int sep_dn_len, sep_mv_len, sep_eq_len;
- if (indent < 0)
- indent = 0;
- outlen = indent;
- if (!do_indent(io_ch, arg, indent))
- return -1;
- switch (flags & XN_FLAG_SEP_MASK) {
- case XN_FLAG_SEP_MULTILINE:
- sep_dn = "\n";
- sep_dn_len = 1;
- sep_mv = " + ";
- sep_mv_len = 3;
- break;
-
- case XN_FLAG_SEP_COMMA_PLUS:
- sep_dn = ",";
- sep_dn_len = 1;
- sep_mv = "+";
- sep_mv_len = 1;
- indent = 0;
- break;
-
- case XN_FLAG_SEP_CPLUS_SPC:
- sep_dn = ", ";
- sep_dn_len = 2;
- sep_mv = " + ";
- sep_mv_len = 3;
- indent = 0;
- break;
-
- case XN_FLAG_SEP_SPLUS_SPC:
- sep_dn = "; ";
- sep_dn_len = 2;
- sep_mv = " + ";
- sep_mv_len = 3;
- indent = 0;
- break;
-
- default:
- return -1;
- }
-
- if (flags & XN_FLAG_SPC_EQ) {
- sep_eq = " = ";
- sep_eq_len = 3;
- } else {
- sep_eq = "=";
- sep_eq_len = 1;
- }
-
- fn_opt = flags & XN_FLAG_FN_MASK;
-
- cnt = X509_NAME_entry_count(n);
- for (i = 0; i < cnt; i++) {
- if (flags & XN_FLAG_DN_REV)
- ent = X509_NAME_get_entry(n, cnt - i - 1);
- else
- ent = X509_NAME_get_entry(n, i);
- if (prev != -1) {
- if (prev == ent->set) {
- if (!io_ch(arg, sep_mv, sep_mv_len))
- return -1;
- outlen += sep_mv_len;
- } else {
- if (!io_ch(arg, sep_dn, sep_dn_len))
- return -1;
- outlen += sep_dn_len;
- if (!do_indent(io_ch, arg, indent))
- return -1;
- outlen += indent;
- }
- }
- prev = ent->set;
- fn = X509_NAME_ENTRY_get_object(ent);
- val = X509_NAME_ENTRY_get_data(ent);
- fn_nid = OBJ_obj2nid(fn);
- if (fn_opt != XN_FLAG_FN_NONE) {
- int objlen, fld_len;
- if ((fn_opt == XN_FLAG_FN_OID) || (fn_nid == NID_undef)) {
- OBJ_obj2txt(objtmp, sizeof objtmp, fn, 1);
- fld_len = 0; /* XXX: what should this be? */
- objbuf = objtmp;
- } else {
- if (fn_opt == XN_FLAG_FN_SN) {
- fld_len = FN_WIDTH_SN;
- objbuf = OBJ_nid2sn(fn_nid);
- } else if (fn_opt == XN_FLAG_FN_LN) {
- fld_len = FN_WIDTH_LN;
- objbuf = OBJ_nid2ln(fn_nid);
- } else {
- fld_len = 0; /* XXX: what should this be? */
- objbuf = "";
- }
- }
- objlen = strlen(objbuf);
- if (!io_ch(arg, objbuf, objlen))
- return -1;
- if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
- if (!do_indent(io_ch, arg, fld_len - objlen))
- return -1;
- outlen += fld_len - objlen;
- }
- if (!io_ch(arg, sep_eq, sep_eq_len))
- return -1;
- outlen += objlen + sep_eq_len;
- }
- /*
- * If the field name is unknown then fix up the DER dump flag. We
- * might want to limit this further so it will DER dump on anything
- * other than a few 'standard' fields.
- */
- if ((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS))
- orflags = ASN1_STRFLGS_DUMP_ALL;
- else
- orflags = 0;
-
- len = do_print_ex(io_ch, arg, flags | orflags, val);
- if (len < 0)
+ BIO *bio = NULL;
+ if (fp != NULL) {
+ /* If |fp| is NULL, this function returns the number of bytes without
+ * writing. */
+ bio = BIO_new_fp(fp, BIO_NOCLOSE);
+ if (bio == NULL) {
return -1;
- outlen += len;
- }
- return outlen;
-}
-
-/* Wrappers round the main functions */
-
-int X509_NAME_print_ex(BIO *out, const X509_NAME *nm, int indent,
- unsigned long flags)
-{
- if (flags == XN_FLAG_COMPAT)
- return X509_NAME_print(out, nm, indent);
- return do_name_ex(send_bio_chars, out, nm, indent, flags);
-}
-
-#ifndef OPENSSL_NO_FP_API
-int X509_NAME_print_ex_fp(FILE *fp, const X509_NAME *nm, int indent,
- unsigned long flags)
-{
- if (flags == XN_FLAG_COMPAT) {
- BIO *btmp;
- int ret;
- btmp = BIO_new_fp(fp, BIO_NOCLOSE);
- if (!btmp)
- return -1;
- ret = X509_NAME_print(btmp, nm, indent);
- BIO_free(btmp);
- return ret;
+ }
}
- return do_name_ex(send_fp_chars, fp, nm, indent, flags);
-}
-#endif
-
-int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, unsigned long flags)
-{
- return do_print_ex(send_bio_chars, out, flags, str);
+ int ret = ASN1_STRING_print_ex(bio, str, flags);
+ BIO_free(bio);
+ return ret;
}
-#ifndef OPENSSL_NO_FP_API
-int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str, unsigned long flags)
-{
- return do_print_ex(send_fp_chars, fp, flags, str);
-}
-#endif
-
-/*
- * Utility function: convert any string type to UTF8, returns number of bytes
- * in output string or a negative error code
- */
-
-int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in)
+int ASN1_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in)
{
ASN1_STRING stmp, *str = &stmp;
int mbflag, type, ret;
@@ -643,11 +465,186 @@ int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in)
stmp.data = NULL;
stmp.length = 0;
stmp.flags = 0;
- ret =
- ASN1_mbstring_copy(&str, in->data, in->length, mbflag,
- B_ASN1_UTF8STRING);
+ ret = ASN1_mbstring_copy(&str, in->data, in->length, mbflag,
+ B_ASN1_UTF8STRING);
if (ret < 0)
return ret;
*out = stmp.data;
return stmp.length;
}
+
+int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v)
+{
+ int i, n;
+ char buf[80];
+ const char *p;
+
+ if (v == NULL)
+ return (0);
+ n = 0;
+ p = (const char *)v->data;
+ for (i = 0; i < v->length; i++) {
+ if ((p[i] > '~') || ((p[i] < ' ') &&
+ (p[i] != '\n') && (p[i] != '\r')))
+ buf[n] = '.';
+ else
+ buf[n] = p[i];
+ n++;
+ if (n >= 80) {
+ if (BIO_write(bp, buf, n) <= 0)
+ return (0);
+ n = 0;
+ }
+ }
+ if (n > 0)
+ if (BIO_write(bp, buf, n) <= 0)
+ return (0);
+ return (1);
+}
+
+int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
+{
+ if (tm->type == V_ASN1_UTCTIME)
+ return ASN1_UTCTIME_print(bp, tm);
+ if (tm->type == V_ASN1_GENERALIZEDTIME)
+ return ASN1_GENERALIZEDTIME_print(bp, tm);
+ BIO_write(bp, "Bad time value", 14);
+ return (0);
+}
+
+static const char *const mon[12] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm)
+{
+ char *v;
+ int gmt = 0;
+ int i;
+ int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0;
+ char *f = NULL;
+ int f_len = 0;
+
+ i = tm->length;
+ v = (char *)tm->data;
+
+ if (i < 12)
+ goto err;
+ if (v[i - 1] == 'Z')
+ gmt = 1;
+ for (i = 0; i < 12; i++)
+ if ((v[i] > '9') || (v[i] < '0'))
+ goto err;
+ y = (v[0] - '0') * 1000 + (v[1] - '0') * 100 + (v[2] - '0') * 10 + (v[3] -
+ '0');
+ M = (v[4] - '0') * 10 + (v[5] - '0');
+ if ((M > 12) || (M < 1))
+ goto err;
+ d = (v[6] - '0') * 10 + (v[7] - '0');
+ h = (v[8] - '0') * 10 + (v[9] - '0');
+ m = (v[10] - '0') * 10 + (v[11] - '0');
+ if (tm->length >= 14 &&
+ (v[12] >= '0') && (v[12] <= '9') &&
+ (v[13] >= '0') && (v[13] <= '9')) {
+ s = (v[12] - '0') * 10 + (v[13] - '0');
+ /* Check for fractions of seconds. */
+ if (tm->length >= 15 && v[14] == '.') {
+ int l = tm->length;
+ f = &v[14]; /* The decimal point. */
+ f_len = 1;
+ while (14 + f_len < l && f[f_len] >= '0' && f[f_len] <= '9')
+ ++f_len;
+ }
+ }
+
+ if (BIO_printf(bp, "%s %2d %02d:%02d:%02d%.*s %d%s",
+ mon[M - 1], d, h, m, s, f_len, f, y,
+ (gmt) ? " GMT" : "") <= 0)
+ return (0);
+ else
+ return (1);
+ err:
+ BIO_write(bp, "Bad time value", 14);
+ return (0);
+}
+
+// consume_two_digits is a helper function for ASN1_UTCTIME_print. If |*v|,
+// assumed to be |*len| bytes long, has two leading digits, updates |*out| with
+// their value, updates |v| and |len|, and returns one. Otherwise, returns
+// zero.
+static int consume_two_digits(int* out, const char **v, int *len) {
+ if (*len < 2|| !isdigit((*v)[0]) || !isdigit((*v)[1])) {
+ return 0;
+ }
+ *out = ((*v)[0] - '0') * 10 + ((*v)[1] - '0');
+ *len -= 2;
+ *v += 2;
+ return 1;
+}
+
+// consume_zulu_timezone is a helper function for ASN1_UTCTIME_print. If |*v|,
+// assumed to be |*len| bytes long, starts with "Z" then it updates |*v| and
+// |*len| and returns one. Otherwise returns zero.
+static int consume_zulu_timezone(const char **v, int *len) {
+ if (*len == 0 || (*v)[0] != 'Z') {
+ return 0;
+ }
+
+ *len -= 1;
+ *v += 1;
+ return 1;
+}
+
+int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) {
+ const char *v = (const char *)tm->data;
+ int len = tm->length;
+ int Y = 0, M = 0, D = 0, h = 0, m = 0, s = 0;
+
+ // YYMMDDhhmm are required to be present.
+ if (!consume_two_digits(&Y, &v, &len) ||
+ !consume_two_digits(&M, &v, &len) ||
+ !consume_two_digits(&D, &v, &len) ||
+ !consume_two_digits(&h, &v, &len) ||
+ !consume_two_digits(&m, &v, &len)) {
+ goto err;
+ }
+ // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires seconds
+ // to be present, but historically this code has forgiven its absence.
+ consume_two_digits(&s, &v, &len);
+
+ // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, specifies this
+ // interpretation of the year.
+ if (Y < 50) {
+ Y += 2000;
+ } else {
+ Y += 1900;
+ }
+ if (M > 12 || M == 0) {
+ goto err;
+ }
+ if (D > 31 || D == 0) {
+ goto err;
+ }
+ if (h > 23 || m > 59 || s > 60) {
+ goto err;
+ }
+
+ // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires the "Z"
+ // to be present, but historically this code has forgiven its absence.
+ const int is_gmt = consume_zulu_timezone(&v, &len);
+
+ // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, does not permit
+ // the specification of timezones using the +hhmm / -hhmm syntax, which is
+ // the only other thing that might legitimately be found at the end.
+ if (len) {
+ goto err;
+ }
+
+ return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s", mon[M - 1], D, h, m, s, Y,
+ is_gmt ? " GMT" : "") > 0;
+
+err:
+ BIO_write(bp, "Bad time value", 14);
+ return 0;
+}
diff --git a/deps/boringssl/src/crypto/asn1/a_strnid.c b/deps/boringssl/src/crypto/asn1/a_strnid.c
index efbf0fa..f7ad084 100644
--- a/deps/boringssl/src/crypto/asn1/a_strnid.c
+++ b/deps/boringssl/src/crypto/asn1/a_strnid.c
@@ -69,53 +69,17 @@ DEFINE_STACK_OF(ASN1_STRING_TABLE)
static STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
static void st_free(ASN1_STRING_TABLE *tbl);
-/*
- * This is the global mask for the mbstring functions: this is use to mask
- * out certain types (such as BMPString and UTF8String) because certain
- * software (e.g. Netscape) has problems with them.
- */
-
-static unsigned long global_mask = B_ASN1_UTF8STRING;
-
void ASN1_STRING_set_default_mask(unsigned long mask)
{
- global_mask = mask;
}
unsigned long ASN1_STRING_get_default_mask(void)
{
- return global_mask;
+ return B_ASN1_UTF8STRING;
}
-/*
- * This function sets the default to various "flavours" of configuration.
- * based on an ASCII string. Currently this is: MASK:XXXX : a numerical mask
- * value. nobmp : Don't use BMPStrings (just Printable, T61). pkix : PKIX
- * recommendation in RFC2459. utf8only : only use UTF8Strings (RFC2459
- * recommendation for 2004). default: the default value, Printable, T61, BMP.
- */
-
int ASN1_STRING_set_default_mask_asc(const char *p)
{
- unsigned long mask;
- char *end;
- if (!strncmp(p, "MASK:", 5)) {
- if (!p[5])
- return 0;
- mask = strtoul(p + 5, &end, 0);
- if (*end)
- return 0;
- } else if (!strcmp(p, "nombstr"))
- mask = ~((unsigned long)(B_ASN1_BMPSTRING | B_ASN1_UTF8STRING));
- else if (!strcmp(p, "pkix"))
- mask = ~((unsigned long)B_ASN1_T61STRING);
- else if (!strcmp(p, "utf8only"))
- mask = B_ASN1_UTF8STRING;
- else if (!strcmp(p, "default"))
- mask = 0xFFFFFFFFL;
- else
- return 0;
- ASN1_STRING_set_default_mask(mask);
return 1;
}
@@ -139,13 +103,12 @@ ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out,
if (tbl) {
mask = tbl->mask;
if (!(tbl->flags & STABLE_NO_MASK))
- mask &= global_mask;
+ mask &= B_ASN1_UTF8STRING;
ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask,
tbl->minsize, tbl->maxsize);
- } else
- ret =
- ASN1_mbstring_copy(out, in, inlen, inform,
- DIRSTRING_TYPE & global_mask);
+ } else {
+ ret = ASN1_mbstring_copy(out, in, inlen, inform, B_ASN1_UTF8STRING);
+ }
if (ret <= 0)
return NULL;
return *out;
@@ -155,7 +118,7 @@ ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out,
* Now the tables and helper functions for the string table:
*/
-/* size limits: this stuff is taken straight from RFC3280 */
+/* size limits: this stuff is taken straight from RFC 3280 */
#define ub_name 32768
#define ub_common_name 64
diff --git a/deps/boringssl/src/crypto/asn1/a_time.c b/deps/boringssl/src/crypto/asn1/a_time.c
index 98a9c3e..ad7f784 100644
--- a/deps/boringssl/src/crypto/asn1/a_time.c
+++ b/deps/boringssl/src/crypto/asn1/a_time.c
@@ -63,7 +63,7 @@
#include <openssl/err.h>
#include <openssl/mem.h>
-#include "asn1_locl.h"
+#include "internal.h"
/*
* This is an implementation of the ASN1 Time structure which is: Time ::=
@@ -200,7 +200,7 @@ static int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *t)
return 0;
}
-int ASN1_TIME_diff(int *pday, int *psec,
+int ASN1_TIME_diff(int *out_days, int *out_seconds,
const ASN1_TIME *from, const ASN1_TIME *to)
{
struct tm tm_from, tm_to;
@@ -208,5 +208,5 @@ int ASN1_TIME_diff(int *pday, int *psec,
return 0;
if (!asn1_time_to_tm(&tm_to, to))
return 0;
- return OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to);
+ return OPENSSL_gmtime_diff(out_days, out_seconds, &tm_from, &tm_to);
}
diff --git a/deps/boringssl/src/crypto/asn1/a_type.c b/deps/boringssl/src/crypto/asn1/a_type.c
index f320e49..c63030b 100644
--- a/deps/boringssl/src/crypto/asn1/a_type.c
+++ b/deps/boringssl/src/crypto/asn1/a_type.c
@@ -61,23 +61,33 @@
#include <openssl/mem.h>
#include <openssl/obj.h>
-#include "asn1_locl.h"
+#include "internal.h"
int ASN1_TYPE_get(const ASN1_TYPE *a)
{
- if ((a->value.ptr != NULL) || (a->type == V_ASN1_NULL))
- return (a->type);
- else
- return (0);
+ if (a->type == V_ASN1_BOOLEAN || a->type == V_ASN1_NULL ||
+ a->value.ptr != NULL) {
+ return a->type;
+ }
+ return 0;
}
-void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value)
+const void *asn1_type_value_as_pointer(const ASN1_TYPE *a)
{
- if (a->value.ptr != NULL) {
- ASN1_TYPE **tmp_a = &a;
- ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL);
+ if (a->type == V_ASN1_BOOLEAN) {
+ return a->value.boolean ? (void *)0xff : NULL;
+ }
+ if (a->type == V_ASN1_NULL) {
+ return NULL;
}
+ return a->value.ptr;
+}
+
+void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value)
+{
+ ASN1_TYPE **tmp_a = &a;
+ ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL);
a->type = type;
if (type == V_ASN1_BOOLEAN)
a->value.boolean = value ? 0xff : 0;
diff --git a/deps/boringssl/src/crypto/asn1/a_utctm.c b/deps/boringssl/src/crypto/asn1/a_utctm.c
index d5bd0e4..21ea2cc 100644
--- a/deps/boringssl/src/crypto/asn1/a_utctm.c
+++ b/deps/boringssl/src/crypto/asn1/a_utctm.c
@@ -62,7 +62,7 @@
#include <openssl/err.h>
#include <openssl/mem.h>
-#include "asn1_locl.h"
+#include "internal.h"
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
@@ -262,42 +262,3 @@ int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t)
return -1;
return 0;
}
-
-#if 0
-time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s)
-{
- struct tm tm;
- int offset;
-
- OPENSSL_memset(&tm, '\0', sizeof tm);
-
-# define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
- tm.tm_year = g2(s->data);
- if (tm.tm_year < 50)
- tm.tm_year += 100;
- tm.tm_mon = g2(s->data + 2) - 1;
- tm.tm_mday = g2(s->data + 4);
- tm.tm_hour = g2(s->data + 6);
- tm.tm_min = g2(s->data + 8);
- tm.tm_sec = g2(s->data + 10);
- if (s->data[12] == 'Z')
- offset = 0;
- else {
- offset = g2(s->data + 13) * 60 + g2(s->data + 15);
- if (s->data[12] == '-')
- offset = -offset;
- }
-# undef g2
-
- return mktime(&tm) - offset * 60; /* FIXME: mktime assumes the current
- * timezone instead of UTC, and unless
- * we rewrite OpenSSL in Lisp we cannot
- * locally change the timezone without
- * possibly interfering with other
- * parts of the program. timegm, which
- * uses UTC, is non-standard. Also
- * time_t is inappropriate for general
- * UTC times because it may a 32 bit
- * type. */
-}
-#endif
diff --git a/deps/boringssl/src/crypto/asn1/a_utf8.c b/deps/boringssl/src/crypto/asn1/a_utf8.c
index 119ccf9..922a780 100644
--- a/deps/boringssl/src/crypto/asn1/a_utf8.c
+++ b/deps/boringssl/src/crypto/asn1/a_utf8.c
@@ -59,7 +59,7 @@
#include <openssl/err.h>
#include <openssl/mem.h>
-#include "asn1_locl.h"
+#include "internal.h"
/* UTF8 utilities */
diff --git a/deps/boringssl/src/crypto/asn1/asn1_lib.c b/deps/boringssl/src/crypto/asn1/asn1_lib.c
index db8afac..b13a82a 100644
--- a/deps/boringssl/src/crypto/asn1/asn1_lib.c
+++ b/deps/boringssl/src/crypto/asn1/asn1_lib.c
@@ -370,8 +370,7 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len)
{
- if (str->data)
- OPENSSL_free(str->data);
+ OPENSSL_free(str->data);
str->data = data;
str->length = len;
}
diff --git a/deps/boringssl/src/crypto/asn1/asn1_par.c b/deps/boringssl/src/crypto/asn1/asn1_par.c
index b1a01ed..282ad23 100644
--- a/deps/boringssl/src/crypto/asn1/asn1_par.c
+++ b/deps/boringssl/src/crypto/asn1/asn1_par.c
@@ -72,7 +72,7 @@ const char *ASN1_tag2str(int tag)
};
if ((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED))
- tag &= ~0x100;
+ tag &= ~V_ASN1_NEG;
if (tag < 0 || tag > 30)
return "(unknown)";
diff --git a/deps/boringssl/src/crypto/asn1/asn1_test.cc b/deps/boringssl/src/crypto/asn1/asn1_test.cc
index 7b09ba5..28a5998 100644
--- a/deps/boringssl/src/crypto/asn1/asn1_test.cc
+++ b/deps/boringssl/src/crypto/asn1/asn1_test.cc
@@ -15,6 +15,7 @@
#include <limits.h>
#include <stdio.h>
+#include <string>
#include <vector>
#include <gtest/gtest.h>
@@ -26,6 +27,7 @@
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/span.h>
+#include <openssl/x509v3.h>
#include "../test/test_util.h"
@@ -99,20 +101,23 @@ TEST(ASN1Test, IntegerSetting) {
template <typename T>
void TestSerialize(T obj, int (*i2d_func)(T a, uint8_t **pp),
bssl::Span<const uint8_t> expected) {
- int len = static_cast<int>(expected.size());
- ASSERT_EQ(i2d_func(obj, nullptr), len);
+ // Test the allocating version first. It is easiest to debug.
+ uint8_t *ptr = nullptr;
+ int len = i2d_func(obj, &ptr);
+ ASSERT_GT(len, 0);
+ EXPECT_EQ(Bytes(expected), Bytes(ptr, len));
+ OPENSSL_free(ptr);
+
+ len = i2d_func(obj, nullptr);
+ ASSERT_GT(len, 0);
+ EXPECT_EQ(len, static_cast<int>(expected.size()));
- std::vector<uint8_t> buf(expected.size());
- uint8_t *ptr = buf.data();
- ASSERT_EQ(i2d_func(obj, &ptr), len);
+ std::vector<uint8_t> buf(len);
+ ptr = buf.data();
+ len = i2d_func(obj, &ptr);
+ ASSERT_EQ(len, static_cast<int>(expected.size()));
EXPECT_EQ(ptr, buf.data() + buf.size());
EXPECT_EQ(Bytes(expected), Bytes(buf));
-
- // Test the allocating version.
- ptr = nullptr;
- ASSERT_EQ(i2d_func(obj, &ptr), len);
- EXPECT_EQ(Bytes(expected), Bytes(ptr, expected.size()));
- OPENSSL_free(ptr);
}
TEST(ASN1Test, SerializeObject) {
@@ -125,11 +130,943 @@ TEST(ASN1Test, SerializeObject) {
TEST(ASN1Test, SerializeBoolean) {
static const uint8_t kTrue[] = {0x01, 0x01, 0xff};
TestSerialize(0xff, i2d_ASN1_BOOLEAN, kTrue);
+ // Other constants are also correctly encoded as TRUE.
+ TestSerialize(1, i2d_ASN1_BOOLEAN, kTrue);
+ TestSerialize(0x100, i2d_ASN1_BOOLEAN, kTrue);
static const uint8_t kFalse[] = {0x01, 0x01, 0x00};
TestSerialize(0x00, i2d_ASN1_BOOLEAN, kFalse);
}
+// The templates go through a different codepath, so test them separately.
+TEST(ASN1Test, SerializeEmbeddedBoolean) {
+ bssl::UniquePtr<BASIC_CONSTRAINTS> val(BASIC_CONSTRAINTS_new());
+ ASSERT_TRUE(val);
+
+ // BasicConstraints defaults to FALSE, so the encoding should be empty.
+ static const uint8_t kLeaf[] = {0x30, 0x00};
+ val->ca = 0;
+ TestSerialize(val.get(), i2d_BASIC_CONSTRAINTS, kLeaf);
+
+ // TRUE should always be encoded as 0xff, independent of what value the caller
+ // placed in the |ASN1_BOOLEAN|.
+ static const uint8_t kCA[] = {0x30, 0x03, 0x01, 0x01, 0xff};
+ val->ca = 0xff;
+ TestSerialize(val.get(), i2d_BASIC_CONSTRAINTS, kCA);
+ val->ca = 1;
+ TestSerialize(val.get(), i2d_BASIC_CONSTRAINTS, kCA);
+ val->ca = 0x100;
+ TestSerialize(val.get(), i2d_BASIC_CONSTRAINTS, kCA);
+}
+
+TEST(ASN1Test, ASN1Type) {
+ const struct {
+ int type;
+ std::vector<uint8_t> der;
+ } kTests[] = {
+ // BOOLEAN { TRUE }
+ {V_ASN1_BOOLEAN, {0x01, 0x01, 0xff}},
+ // BOOLEAN { FALSE }
+ {V_ASN1_BOOLEAN, {0x01, 0x01, 0x00}},
+ // OCTET_STRING { "a" }
+ {V_ASN1_OCTET_STRING, {0x04, 0x01, 0x61}},
+ // BIT_STRING { `01` `00` }
+ {V_ASN1_BIT_STRING, {0x03, 0x02, 0x01, 0x00}},
+ // INTEGER { -1 }
+ {V_ASN1_INTEGER, {0x02, 0x01, 0xff}},
+ // OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2 }
+ {V_ASN1_OBJECT,
+ {0x06, 0x0c, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7,
+ 0x09, 0x02}},
+ // NULL {}
+ {V_ASN1_NULL, {0x05, 0x00}},
+ // SEQUENCE {}
+ {V_ASN1_SEQUENCE, {0x30, 0x00}},
+ // SET {}
+ {V_ASN1_SET, {0x31, 0x00}},
+ // [0] { UTF8String { "a" } }
+ {V_ASN1_OTHER, {0xa0, 0x03, 0x0c, 0x01, 0x61}},
+ };
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(Bytes(t.der));
+
+ // The input should successfully parse.
+ const uint8_t *ptr = t.der.data();
+ bssl::UniquePtr<ASN1_TYPE> val(d2i_ASN1_TYPE(nullptr, &ptr, t.der.size()));
+ ASSERT_TRUE(val);
+
+ EXPECT_EQ(ASN1_TYPE_get(val.get()), t.type);
+ EXPECT_EQ(val->type, t.type);
+ TestSerialize(val.get(), i2d_ASN1_TYPE, t.der);
+ }
+}
+
+// Test that reading |value.ptr| from a FALSE |ASN1_TYPE| behaves correctly. The
+// type historically supported this, so maintain the invariant in case external
+// code relies on it.
+TEST(ASN1Test, UnusedBooleanBits) {
+ // OCTET_STRING { "a" }
+ static const uint8_t kDER[] = {0x04, 0x01, 0x61};
+ const uint8_t *ptr = kDER;
+ bssl::UniquePtr<ASN1_TYPE> val(d2i_ASN1_TYPE(nullptr, &ptr, sizeof(kDER)));
+ ASSERT_TRUE(val);
+ EXPECT_EQ(V_ASN1_OCTET_STRING, val->type);
+ EXPECT_TRUE(val->value.ptr);
+
+ // Set |val| to a BOOLEAN containing FALSE.
+ ASN1_TYPE_set(val.get(), V_ASN1_BOOLEAN, NULL);
+ EXPECT_EQ(V_ASN1_BOOLEAN, val->type);
+ EXPECT_FALSE(val->value.ptr);
+}
+
+TEST(ASN1Test, ASN1ObjectReuse) {
+ // 1.2.840.113554.4.1.72585.2, an arbitrary unknown OID.
+ static const uint8_t kOID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12,
+ 0x04, 0x01, 0x84, 0xb7, 0x09, 0x02};
+ ASN1_OBJECT *obj = ASN1_OBJECT_create(NID_undef, kOID, sizeof(kOID),
+ "short name", "long name");
+ ASSERT_TRUE(obj);
+
+ // OBJECT_IDENTIFIER { 1.3.101.112 }
+ static const uint8_t kDER[] = {0x06, 0x03, 0x2b, 0x65, 0x70};
+ const uint8_t *ptr = kDER;
+ EXPECT_TRUE(d2i_ASN1_OBJECT(&obj, &ptr, sizeof(kDER)));
+ EXPECT_EQ(NID_ED25519, OBJ_obj2nid(obj));
+ ASN1_OBJECT_free(obj);
+
+ // Repeat the test, this time overriding a static |ASN1_OBJECT|.
+ obj = OBJ_nid2obj(NID_rsaEncryption);
+ ptr = kDER;
+ EXPECT_TRUE(d2i_ASN1_OBJECT(&obj, &ptr, sizeof(kDER)));
+ EXPECT_EQ(NID_ED25519, OBJ_obj2nid(obj));
+ ASN1_OBJECT_free(obj);
+}
+
+TEST(ASN1Test, BitString) {
+ const size_t kNotWholeBytes = static_cast<size_t>(-1);
+ const struct {
+ std::vector<uint8_t> in;
+ size_t num_bytes;
+ } kValidInputs[] = {
+ // Empty bit string
+ {{0x03, 0x01, 0x00}, 0},
+ // 0b1
+ {{0x03, 0x02, 0x07, 0x80}, kNotWholeBytes},
+ // 0b1010
+ {{0x03, 0x02, 0x04, 0xa0}, kNotWholeBytes},
+ // 0b1010101
+ {{0x03, 0x02, 0x01, 0xaa}, kNotWholeBytes},
+ // 0b10101010
+ {{0x03, 0x02, 0x00, 0xaa}, 1},
+ // Bits 0 and 63 are set
+ {{0x03, 0x09, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 8},
+ // 64 zero bits
+ {{0x03, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8},
+ };
+ for (const auto &test : kValidInputs) {
+ SCOPED_TRACE(Bytes(test.in));
+ // The input should parse and round-trip correctly.
+ const uint8_t *ptr = test.in.data();
+ bssl::UniquePtr<ASN1_BIT_STRING> val(
+ d2i_ASN1_BIT_STRING(nullptr, &ptr, test.in.size()));
+ ASSERT_TRUE(val);
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, test.in);
+
+ // Check the byte count.
+ size_t num_bytes;
+ if (test.num_bytes == kNotWholeBytes) {
+ EXPECT_FALSE(ASN1_BIT_STRING_num_bytes(val.get(), &num_bytes));
+ } else {
+ ASSERT_TRUE(ASN1_BIT_STRING_num_bytes(val.get(), &num_bytes));
+ EXPECT_EQ(num_bytes, test.num_bytes);
+ }
+ }
+
+ const std::vector<uint8_t> kInvalidInputs[] = {
+ // Wrong tag
+ {0x04, 0x01, 0x00},
+ // Missing leading byte
+ {0x03, 0x00},
+ // Leading byte too high
+ {0x03, 0x02, 0x08, 0x00},
+ {0x03, 0x02, 0xff, 0x00},
+ // TODO(https://crbug.com/boringssl/354): Reject these inputs.
+ // Empty bit strings must have a zero leading byte.
+ // {0x03, 0x01, 0x01},
+ // Unused bits must all be zero.
+ // {0x03, 0x02, 0x06, 0xc1 /* 0b11000001 */},
+ };
+ for (const auto &test : kInvalidInputs) {
+ SCOPED_TRACE(Bytes(test));
+ const uint8_t *ptr = test.data();
+ bssl::UniquePtr<ASN1_BIT_STRING> val(
+ d2i_ASN1_BIT_STRING(nullptr, &ptr, test.size()));
+ EXPECT_FALSE(val);
+ }
+}
+
+TEST(ASN1Test, SetBit) {
+ bssl::UniquePtr<ASN1_BIT_STRING> val(ASN1_BIT_STRING_new());
+ ASSERT_TRUE(val);
+ static const uint8_t kBitStringEmpty[] = {0x03, 0x01, 0x00};
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitStringEmpty);
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 0));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 100));
+
+ // Set a few bits via |ASN1_BIT_STRING_set_bit|.
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 0, 1));
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 1, 1));
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 2, 0));
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 3, 1));
+ static const uint8_t kBitString1101[] = {0x03, 0x02, 0x04, 0xd0};
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitString1101);
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 0));
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 1));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 2));
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 3));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 4));
+
+ // Bits that were set may be cleared.
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 1, 0));
+ static const uint8_t kBitString1001[] = {0x03, 0x02, 0x04, 0x90};
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitString1001);
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 0));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 1));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 2));
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 3));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 4));
+
+ // Clearing trailing bits truncates the string.
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 3, 0));
+ static const uint8_t kBitString1[] = {0x03, 0x02, 0x07, 0x80};
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitString1);
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 0));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 1));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 2));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 3));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 4));
+
+ // Bits may be set beyond the end of the string.
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 63, 1));
+ static const uint8_t kBitStringLong[] = {0x03, 0x09, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01};
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitStringLong);
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 0));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 62));
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 63));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 64));
+
+ // The string can be truncated back down again.
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 63, 0));
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitString1);
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 0));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 62));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 63));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 64));
+
+ // |ASN1_BIT_STRING_set_bit| also truncates when starting from a parsed
+ // string.
+ const uint8_t *ptr = kBitStringLong;
+ val.reset(d2i_ASN1_BIT_STRING(nullptr, &ptr, sizeof(kBitStringLong)));
+ ASSERT_TRUE(val);
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitStringLong);
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 63, 0));
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitString1);
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 0));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 62));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 63));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 64));
+
+ // A parsed bit string preserves trailing zero bits.
+ static const uint8_t kBitString10010[] = {0x03, 0x02, 0x03, 0x90};
+ ptr = kBitString10010;
+ val.reset(d2i_ASN1_BIT_STRING(nullptr, &ptr, sizeof(kBitString10010)));
+ ASSERT_TRUE(val);
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitString10010);
+ // But |ASN1_BIT_STRING_set_bit| will truncate it even if otherwise a no-op.
+ ASSERT_TRUE(ASN1_BIT_STRING_set_bit(val.get(), 0, 1));
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitString1001);
+ EXPECT_EQ(1, ASN1_BIT_STRING_get_bit(val.get(), 0));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 62));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 63));
+ EXPECT_EQ(0, ASN1_BIT_STRING_get_bit(val.get(), 64));
+
+ // By default, a BIT STRING implicitly truncates trailing zeros.
+ val.reset(ASN1_BIT_STRING_new());
+ ASSERT_TRUE(val);
+ static const uint8_t kZeros[64] = {0};
+ ASSERT_TRUE(ASN1_STRING_set(val.get(), kZeros, sizeof(kZeros)));
+ TestSerialize(val.get(), i2d_ASN1_BIT_STRING, kBitStringEmpty);
+}
+
+TEST(ASN1Test, StringToUTF8) {
+ static const struct {
+ std::vector<uint8_t> in;
+ int type;
+ const char *expected;
+ } kTests[] = {
+ // Non-minimal, two-byte UTF-8.
+ {{0xc0, 0x81}, V_ASN1_UTF8STRING, nullptr},
+ // Non-minimal, three-byte UTF-8.
+ {{0xe0, 0x80, 0x81}, V_ASN1_UTF8STRING, nullptr},
+ // Non-minimal, four-byte UTF-8.
+ {{0xf0, 0x80, 0x80, 0x81}, V_ASN1_UTF8STRING, nullptr},
+ // Truncated, four-byte UTF-8.
+ {{0xf0, 0x80, 0x80}, V_ASN1_UTF8STRING, nullptr},
+ // Low-surrogate value.
+ {{0xed, 0xa0, 0x80}, V_ASN1_UTF8STRING, nullptr},
+ // High-surrogate value.
+ {{0xed, 0xb0, 0x81}, V_ASN1_UTF8STRING, nullptr},
+ // Initial BOMs should be rejected from UCS-2 and UCS-4.
+ {{0xfe, 0xff, 0, 88}, V_ASN1_BMPSTRING, nullptr},
+ {{0, 0, 0xfe, 0xff, 0, 0, 0, 88}, V_ASN1_UNIVERSALSTRING, nullptr},
+ // Otherwise, BOMs should pass through.
+ {{0, 88, 0xfe, 0xff}, V_ASN1_BMPSTRING, "X\xef\xbb\xbf"},
+ {{0, 0, 0, 88, 0, 0, 0xfe, 0xff}, V_ASN1_UNIVERSALSTRING,
+ "X\xef\xbb\xbf"},
+ // The maximum code-point should pass though.
+ {{0, 16, 0xff, 0xfd}, V_ASN1_UNIVERSALSTRING, "\xf4\x8f\xbf\xbd"},
+ // Values outside the Unicode space should not.
+ {{0, 17, 0, 0}, V_ASN1_UNIVERSALSTRING, nullptr},
+ // Non-characters should be rejected.
+ {{0, 1, 0xff, 0xff}, V_ASN1_UNIVERSALSTRING, nullptr},
+ {{0, 1, 0xff, 0xfe}, V_ASN1_UNIVERSALSTRING, nullptr},
+ {{0, 0, 0xfd, 0xd5}, V_ASN1_UNIVERSALSTRING, nullptr},
+ // BMPString is UCS-2, not UTF-16, so surrogate pairs are invalid.
+ {{0xd8, 0, 0xdc, 1}, V_ASN1_BMPSTRING, nullptr},
+ };
+
+ for (const auto &test : kTests) {
+ SCOPED_TRACE(Bytes(test.in));
+ SCOPED_TRACE(test.type);
+ bssl::UniquePtr<ASN1_STRING> s(ASN1_STRING_type_new(test.type));
+ ASSERT_TRUE(s);
+ ASSERT_TRUE(ASN1_STRING_set(s.get(), test.in.data(), test.in.size()));
+
+ uint8_t *utf8;
+ const int utf8_len = ASN1_STRING_to_UTF8(&utf8, s.get());
+ EXPECT_EQ(utf8_len < 0, test.expected == nullptr);
+ if (utf8_len >= 0) {
+ if (test.expected != nullptr) {
+ EXPECT_EQ(Bytes(test.expected), Bytes(utf8, utf8_len));
+ }
+ OPENSSL_free(utf8);
+ } else {
+ ERR_clear_error();
+ }
+ }
+}
+
+static std::string ASN1StringToStdString(const ASN1_STRING *str) {
+ return std::string(ASN1_STRING_get0_data(str),
+ ASN1_STRING_get0_data(str) + ASN1_STRING_length(str));
+}
+
+TEST(ASN1Test, SetTime) {
+ static const struct {
+ time_t time;
+ const char *generalized;
+ const char *utc;
+ } kTests[] = {
+ {-631152001, "19491231235959Z", nullptr},
+ {-631152000, "19500101000000Z", "500101000000Z"},
+ {0, "19700101000000Z", "700101000000Z"},
+ {981173106, "20010203040506Z", "010203040506Z"},
+#if defined(OPENSSL_64_BIT)
+ // TODO(https://crbug.com/boringssl/416): These cases overflow 32-bit
+ // |time_t| and do not consistently work on 32-bit platforms. For now,
+ // disable the tests on 32-bit. Re-enable them once the bug is fixed.
+ {2524607999, "20491231235959Z", "491231235959Z"},
+ {2524608000, "20500101000000Z", nullptr},
+ // Test boundary conditions.
+ {-62167219200, "00000101000000Z", nullptr},
+ {-62167219201, nullptr, nullptr},
+ {253402300799, "99991231235959Z", nullptr},
+ {253402300800, nullptr, nullptr},
+#endif
+ };
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(t.time);
+#if defined(OPENSSL_WINDOWS)
+ // Windows |time_t| functions can only handle 1970 through 3000. See
+ // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/gmtime-s-gmtime32-s-gmtime64-s?view=msvc-160
+ if (t.time < 0 || int64_t{t.time} > 32535215999) {
+ continue;
+ }
+#endif
+
+ bssl::UniquePtr<ASN1_UTCTIME> utc(ASN1_UTCTIME_set(nullptr, t.time));
+ if (t.utc) {
+ ASSERT_TRUE(utc);
+ EXPECT_EQ(V_ASN1_UTCTIME, ASN1_STRING_type(utc.get()));
+ EXPECT_EQ(t.utc, ASN1StringToStdString(utc.get()));
+ } else {
+ EXPECT_FALSE(utc);
+ }
+
+ bssl::UniquePtr<ASN1_GENERALIZEDTIME> generalized(
+ ASN1_GENERALIZEDTIME_set(nullptr, t.time));
+ if (t.generalized) {
+ ASSERT_TRUE(generalized);
+ EXPECT_EQ(V_ASN1_GENERALIZEDTIME, ASN1_STRING_type(generalized.get()));
+ EXPECT_EQ(t.generalized, ASN1StringToStdString(generalized.get()));
+ } else {
+ EXPECT_FALSE(generalized);
+ }
+
+ bssl::UniquePtr<ASN1_TIME> choice(ASN1_TIME_set(nullptr, t.time));
+ if (t.generalized) {
+ ASSERT_TRUE(choice);
+ if (t.utc) {
+ EXPECT_EQ(V_ASN1_UTCTIME, ASN1_STRING_type(choice.get()));
+ EXPECT_EQ(t.utc, ASN1StringToStdString(choice.get()));
+ } else {
+ EXPECT_EQ(V_ASN1_GENERALIZEDTIME, ASN1_STRING_type(choice.get()));
+ EXPECT_EQ(t.generalized, ASN1StringToStdString(choice.get()));
+ }
+ } else {
+ EXPECT_FALSE(choice);
+ }
+ }
+}
+
+static std::vector<uint8_t> StringToVector(const std::string &str) {
+ return std::vector<uint8_t>(str.begin(), str.end());
+}
+
+TEST(ASN1Test, StringPrintEx) {
+ const struct {
+ int type;
+ std::vector<uint8_t> data;
+ int str_flags;
+ unsigned long flags;
+ std::string expected;
+ } kTests[] = {
+ // A string like "hello" is never escaped or quoted.
+ // |ASN1_STRFLGS_ESC_QUOTE| only introduces quotes when needed. Note
+ // OpenSSL interprets T61String as Latin-1.
+ {V_ASN1_T61STRING, StringToVector("hello"), 0, 0, "hello"},
+ {V_ASN1_T61STRING, StringToVector("hello"), 0,
+ ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB,
+ "hello"},
+ {V_ASN1_T61STRING, StringToVector("hello"), 0,
+ ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB |
+ ASN1_STRFLGS_ESC_QUOTE,
+ "hello"},
+
+ // By default, 8-bit characters are printed without escaping.
+ {V_ASN1_T61STRING,
+ {0, '\n', 0x80, 0xff, ',', '+', '"', '\\', '<', '>', ';'},
+ 0,
+ 0,
+ std::string(1, '\0') + "\n\x80\xff,+\"\\<>;"},
+
+ // Flags control different escapes. Note that any escape flag will cause
+ // blackslashes to be escaped.
+ {V_ASN1_T61STRING,
+ {0, '\n', 0x80, 0xff, ',', '+', '"', '\\', '<', '>', ';'},
+ 0,
+ ASN1_STRFLGS_ESC_2253,
+ std::string(1, '\0') + "\n\x80\xff\\,\\+\\\"\\\\\\<\\>\\;"},
+ {V_ASN1_T61STRING,
+ {0, '\n', 0x80, 0xff, ',', '+', '"', '\\', '<', '>', ';'},
+ 0,
+ ASN1_STRFLGS_ESC_CTRL,
+ "\\00\\0A\x80\xff,+\"\\\\<>;"},
+ {V_ASN1_T61STRING,
+ {0, '\n', 0x80, 0xff, ',', '+', '"', '\\', '<', '>', ';'},
+ 0,
+ ASN1_STRFLGS_ESC_MSB,
+ std::string(1, '\0') + "\n\\80\\FF,+\"\\\\<>;"},
+ {V_ASN1_T61STRING,
+ {0, '\n', 0x80, 0xff, ',', '+', '"', '\\', '<', '>', ';'},
+ 0,
+ ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB,
+ "\\00\\0A\\80\\FF\\,\\+\\\"\\\\\\<\\>\\;"},
+
+ // When quoted, fewer characters need to be escaped in RFC 2253.
+ {V_ASN1_T61STRING,
+ {0, '\n', 0x80, 0xff, ',', '+', '"', '\\', '<', '>', ';'},
+ 0,
+ ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB |
+ ASN1_STRFLGS_ESC_QUOTE,
+ "\"\\00\\0A\\80\\FF,+\\\"\\\\<>;\""},
+
+ // If no characters benefit from quotes, no quotes are added.
+ {V_ASN1_T61STRING,
+ {0, '\n', 0x80, 0xff, '"', '\\'},
+ 0,
+ ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB |
+ ASN1_STRFLGS_ESC_QUOTE,
+ "\\00\\0A\\80\\FF\\\"\\\\"},
+
+ // RFC 2253 only escapes spaces at the start and end of a string.
+ {V_ASN1_T61STRING, StringToVector(" "), 0, ASN1_STRFLGS_ESC_2253,
+ "\\ \\ "},
+ {V_ASN1_T61STRING, StringToVector(" "), 0,
+ ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_QUOTE, "\" \""},
+
+ // RFC 2253 only escapes # at the start of a string.
+ {V_ASN1_T61STRING, StringToVector("###"), 0, ASN1_STRFLGS_ESC_2253,
+ "\\###"},
+ {V_ASN1_T61STRING, StringToVector("###"), 0,
+ ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_QUOTE, "\"###\""},
+
+ // By default, strings are decoded and Unicode code points are
+ // individually escaped.
+ {V_ASN1_UTF8STRING, StringToVector("a\xc2\x80\xc4\x80\xf0\x90\x80\x80"),
+ 0, ASN1_STRFLGS_ESC_MSB, "a\\80\\U0100\\W00010000"},
+ {V_ASN1_BMPSTRING,
+ {0x00, 'a', 0x00, 0x80, 0x01, 0x00},
+ 0,
+ ASN1_STRFLGS_ESC_MSB,
+ "a\\80\\U0100"},
+ {V_ASN1_UNIVERSALSTRING,
+ {0x00, 0x00, 0x00, 'a', //
+ 0x00, 0x00, 0x00, 0x80, //
+ 0x00, 0x00, 0x01, 0x00, //
+ 0x00, 0x01, 0x00, 0x00},
+ 0,
+ ASN1_STRFLGS_ESC_MSB,
+ "a\\80\\U0100\\W00010000"},
+
+ // |ASN1_STRFLGS_UTF8_CONVERT| normalizes everything to UTF-8 and then
+ // escapes individual bytes.
+ {V_ASN1_IA5STRING, StringToVector("a\x80"), 0,
+ ASN1_STRFLGS_ESC_MSB | ASN1_STRFLGS_UTF8_CONVERT, "a\\C2\\80"},
+ {V_ASN1_T61STRING, StringToVector("a\x80"), 0,
+ ASN1_STRFLGS_ESC_MSB | ASN1_STRFLGS_UTF8_CONVERT, "a\\C2\\80"},
+ {V_ASN1_UTF8STRING, StringToVector("a\xc2\x80\xc4\x80\xf0\x90\x80\x80"),
+ 0, ASN1_STRFLGS_ESC_MSB | ASN1_STRFLGS_UTF8_CONVERT,
+ "a\\C2\\80\\C4\\80\\F0\\90\\80\\80"},
+ {V_ASN1_BMPSTRING,
+ {0x00, 'a', 0x00, 0x80, 0x01, 0x00},
+ 0,
+ ASN1_STRFLGS_ESC_MSB | ASN1_STRFLGS_UTF8_CONVERT,
+ "a\\C2\\80\\C4\\80"},
+ {V_ASN1_UNIVERSALSTRING,
+ {0x00, 0x00, 0x00, 'a', //
+ 0x00, 0x00, 0x00, 0x80, //
+ 0x00, 0x00, 0x01, 0x00, //
+ 0x00, 0x01, 0x00, 0x00},
+ 0,
+ ASN1_STRFLGS_ESC_MSB | ASN1_STRFLGS_UTF8_CONVERT,
+ "a\\C2\\80\\C4\\80\\F0\\90\\80\\80"},
+
+ // The same as above, but without escaping the UTF-8 encoding.
+ {V_ASN1_IA5STRING, StringToVector("a\x80"), 0, ASN1_STRFLGS_UTF8_CONVERT,
+ "a\xc2\x80"},
+ {V_ASN1_T61STRING, StringToVector("a\x80"), 0, ASN1_STRFLGS_UTF8_CONVERT,
+ "a\xc2\x80"},
+ {V_ASN1_UTF8STRING, StringToVector("a\xc2\x80\xc4\x80\xf0\x90\x80\x80"),
+ 0, ASN1_STRFLGS_UTF8_CONVERT, "a\xc2\x80\xc4\x80\xf0\x90\x80\x80"},
+ {V_ASN1_BMPSTRING,
+ {0x00, 'a', 0x00, 0x80, 0x01, 0x00},
+ 0,
+ ASN1_STRFLGS_UTF8_CONVERT,
+ "a\xc2\x80\xc4\x80"},
+ {V_ASN1_UNIVERSALSTRING,
+ {0x00, 0x00, 0x00, 'a', //
+ 0x00, 0x00, 0x00, 0x80, //
+ 0x00, 0x00, 0x01, 0x00, //
+ 0x00, 0x01, 0x00, 0x00},
+ 0,
+ ASN1_STRFLGS_UTF8_CONVERT,
+ "a\xc2\x80\xc4\x80\xf0\x90\x80\x80"},
+
+ // Types that cannot be decoded are, by default, treated as a byte string.
+ {V_ASN1_OCTET_STRING, {0xff}, 0, 0, "\xff"},
+ {-1, {0xff}, 0, 0, "\xff"},
+ {100, {0xff}, 0, 0, "\xff"},
+
+ // |ASN1_STRFLGS_UTF8_CONVERT| still converts these bytes to UTF-8.
+ //
+ // TODO(davidben): This seems like a bug. Although it's unclear because
+ // the non-RFC-2253 options aren't especially sound. Can we just remove
+ // them?
+ {V_ASN1_OCTET_STRING, {0xff}, 0, ASN1_STRFLGS_UTF8_CONVERT, "\xc3\xbf"},
+ {-1, {0xff}, 0, ASN1_STRFLGS_UTF8_CONVERT, "\xc3\xbf"},
+ {100, {0xff}, 0, ASN1_STRFLGS_UTF8_CONVERT, "\xc3\xbf"},
+
+ // |ASN1_STRFLGS_IGNORE_TYPE| causes the string type to be ignored, so it
+ // is always treated as a byte string, even if it is not a valid encoding.
+ {V_ASN1_UTF8STRING, {0xff}, 0, ASN1_STRFLGS_IGNORE_TYPE, "\xff"},
+ {V_ASN1_BMPSTRING, {0xff}, 0, ASN1_STRFLGS_IGNORE_TYPE, "\xff"},
+ {V_ASN1_UNIVERSALSTRING, {0xff}, 0, ASN1_STRFLGS_IGNORE_TYPE, "\xff"},
+
+ // |ASN1_STRFLGS_SHOW_TYPE| prepends the type name.
+ {V_ASN1_UTF8STRING, {'a'}, 0, ASN1_STRFLGS_SHOW_TYPE, "UTF8STRING:a"},
+ {-1, {'a'}, 0, ASN1_STRFLGS_SHOW_TYPE, "(unknown):a"},
+ {100, {'a'}, 0, ASN1_STRFLGS_SHOW_TYPE, "(unknown):a"},
+
+ // |ASN1_STRFLGS_DUMP_ALL| and |ASN1_STRFLGS_DUMP_UNKNOWN| cause
+ // non-string types to be printed in hex, though without the DER wrapper
+ // by default.
+ {V_ASN1_UTF8STRING, StringToVector("\xe2\x98\x83"), 0,
+ ASN1_STRFLGS_DUMP_UNKNOWN, "\\U2603"},
+ {V_ASN1_UTF8STRING, StringToVector("\xe2\x98\x83"), 0,
+ ASN1_STRFLGS_DUMP_ALL, "#E29883"},
+ {V_ASN1_OCTET_STRING, StringToVector("\xe2\x98\x83"), 0,
+ ASN1_STRFLGS_DUMP_UNKNOWN, "#E29883"},
+ {V_ASN1_OCTET_STRING, StringToVector("\xe2\x98\x83"), 0,
+ ASN1_STRFLGS_DUMP_ALL, "#E29883"},
+
+ // |ASN1_STRFLGS_DUMP_DER| includes the entire element.
+ {V_ASN1_UTF8STRING, StringToVector("\xe2\x98\x83"), 0,
+ ASN1_STRFLGS_DUMP_ALL | ASN1_STRFLGS_DUMP_DER, "#0C03E29883"},
+ {V_ASN1_OCTET_STRING, StringToVector("\xe2\x98\x83"), 0,
+ ASN1_STRFLGS_DUMP_ALL | ASN1_STRFLGS_DUMP_DER, "#0403E29883"},
+ {V_ASN1_BIT_STRING,
+ {0x80},
+ ASN1_STRING_FLAG_BITS_LEFT | 4,
+ ASN1_STRFLGS_DUMP_ALL | ASN1_STRFLGS_DUMP_DER,
+ "#03020480"},
+ // INTEGER { 1 }
+ {V_ASN1_INTEGER,
+ {0x01},
+ 0,
+ ASN1_STRFLGS_DUMP_ALL | ASN1_STRFLGS_DUMP_DER,
+ "#020101"},
+ // INTEGER { -1 }
+ {V_ASN1_NEG_INTEGER,
+ {0x01},
+ 0,
+ ASN1_STRFLGS_DUMP_ALL | ASN1_STRFLGS_DUMP_DER,
+ "#0201FF"},
+ // ENUMERATED { 1 }
+ {V_ASN1_ENUMERATED,
+ {0x01},
+ 0,
+ ASN1_STRFLGS_DUMP_ALL | ASN1_STRFLGS_DUMP_DER,
+ "#0A0101"},
+ // ENUMERATED { -1 }
+ {V_ASN1_NEG_ENUMERATED,
+ {0x01},
+ 0,
+ ASN1_STRFLGS_DUMP_ALL | ASN1_STRFLGS_DUMP_DER,
+ "#0A01FF"},
+ };
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(t.type);
+ SCOPED_TRACE(Bytes(t.data));
+ SCOPED_TRACE(t.str_flags);
+ SCOPED_TRACE(t.flags);
+
+ bssl::UniquePtr<ASN1_STRING> str(ASN1_STRING_type_new(t.type));
+ ASSERT_TRUE(ASN1_STRING_set(str.get(), t.data.data(), t.data.size()));
+ str->flags = t.str_flags;
+
+ // If the |BIO| is null, it should measure the size.
+ int len = ASN1_STRING_print_ex(nullptr, str.get(), t.flags);
+ EXPECT_EQ(len, static_cast<int>(t.expected.size()));
+
+ // Measuring the size should also work for the |FILE| version
+ len = ASN1_STRING_print_ex_fp(nullptr, str.get(), t.flags);
+ EXPECT_EQ(len, static_cast<int>(t.expected.size()));
+
+ // Actually print the string.
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+ ASSERT_TRUE(bio);
+ len = ASN1_STRING_print_ex(bio.get(), str.get(), t.flags);
+ EXPECT_EQ(len, static_cast<int>(t.expected.size()));
+
+ const uint8_t *bio_contents;
+ size_t bio_len;
+ ASSERT_TRUE(BIO_mem_contents(bio.get(), &bio_contents, &bio_len));
+ EXPECT_EQ(t.expected, std::string(bio_contents, bio_contents + bio_len));
+ }
+
+ const struct {
+ int type;
+ std::vector<uint8_t> data;
+ int str_flags;
+ unsigned long flags;
+ } kUnprintableTests[] = {
+ // When decoding strings, invalid codepoints are errors.
+ {V_ASN1_UTF8STRING, {0xff}, 0, ASN1_STRFLGS_ESC_MSB},
+ {V_ASN1_BMPSTRING, {0xff}, 0, ASN1_STRFLGS_ESC_MSB},
+ {V_ASN1_BMPSTRING, {0xff}, 0, ASN1_STRFLGS_ESC_MSB},
+ {V_ASN1_UNIVERSALSTRING, {0xff}, 0, ASN1_STRFLGS_ESC_MSB},
+ };
+ for (const auto &t : kUnprintableTests) {
+ SCOPED_TRACE(t.type);
+ SCOPED_TRACE(Bytes(t.data));
+ SCOPED_TRACE(t.str_flags);
+ SCOPED_TRACE(t.flags);
+
+ bssl::UniquePtr<ASN1_STRING> str(ASN1_STRING_type_new(t.type));
+ ASSERT_TRUE(ASN1_STRING_set(str.get(), t.data.data(), t.data.size()));
+ str->flags = t.str_flags;
+
+ // If the |BIO| is null, it should measure the size.
+ int len = ASN1_STRING_print_ex(nullptr, str.get(), t.flags);
+ EXPECT_EQ(len, -1);
+ ERR_clear_error();
+
+ // Measuring the size should also work for the |FILE| version
+ len = ASN1_STRING_print_ex_fp(nullptr, str.get(), t.flags);
+ EXPECT_EQ(len, -1);
+ ERR_clear_error();
+
+ // Actually print the string.
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+ ASSERT_TRUE(bio);
+ len = ASN1_STRING_print_ex(bio.get(), str.get(), t.flags);
+ EXPECT_EQ(len, -1);
+ ERR_clear_error();
+ }
+}
+
+TEST(ASN1Test, MBString) {
+ const unsigned long kAll = B_ASN1_PRINTABLESTRING | B_ASN1_IA5STRING |
+ B_ASN1_T61STRING | B_ASN1_BMPSTRING |
+ B_ASN1_UNIVERSALSTRING | B_ASN1_UTF8STRING;
+
+ const struct {
+ int format;
+ std::vector<uint8_t> in;
+ unsigned long mask;
+ int expected_type;
+ std::vector<uint8_t> expected_data;
+ int num_codepoints;
+ } kTests[] = {
+ // Given a choice of formats, we pick the smallest that fits.
+ {MBSTRING_UTF8, {}, kAll, V_ASN1_PRINTABLESTRING, {}, 0},
+ {MBSTRING_UTF8, {'a'}, kAll, V_ASN1_PRINTABLESTRING, {'a'}, 1},
+ {MBSTRING_UTF8,
+ {'a', 'A', '0', '\'', '(', ')', '+', ',', '-', '.', '/', ':', '=', '?'},
+ kAll,
+ V_ASN1_PRINTABLESTRING,
+ {'a', 'A', '0', '\'', '(', ')', '+', ',', '-', '.', '/', ':', '=', '?'},
+ 14},
+ {MBSTRING_UTF8, {'*'}, kAll, V_ASN1_IA5STRING, {'*'}, 1},
+ {MBSTRING_UTF8, {'\n'}, kAll, V_ASN1_IA5STRING, {'\n'}, 1},
+ {MBSTRING_UTF8,
+ {0xc2, 0x80 /* U+0080 */},
+ kAll,
+ V_ASN1_T61STRING,
+ {0x80},
+ 1},
+ {MBSTRING_UTF8,
+ {0xc4, 0x80 /* U+0100 */},
+ kAll,
+ V_ASN1_BMPSTRING,
+ {0x01, 0x00},
+ 1},
+ {MBSTRING_UTF8,
+ {0xf0, 0x90, 0x80, 0x80 /* U+10000 */},
+ kAll,
+ V_ASN1_UNIVERSALSTRING,
+ {0x00, 0x01, 0x00, 0x00},
+ 1},
+ {MBSTRING_UTF8,
+ {0xf0, 0x90, 0x80, 0x80 /* U+10000 */},
+ kAll & ~B_ASN1_UNIVERSALSTRING,
+ V_ASN1_UTF8STRING,
+ {0xf0, 0x90, 0x80, 0x80},
+ 1},
+
+ // NUL is not printable. It should also not terminate iteration.
+ {MBSTRING_UTF8, {0}, kAll, V_ASN1_IA5STRING, {0}, 1},
+ {MBSTRING_UTF8, {0, 'a'}, kAll, V_ASN1_IA5STRING, {0, 'a'}, 2},
+
+ // When a particular format is specified, we use it.
+ {MBSTRING_UTF8,
+ {'a'},
+ B_ASN1_PRINTABLESTRING,
+ V_ASN1_PRINTABLESTRING,
+ {'a'},
+ 1},
+ {MBSTRING_UTF8, {'a'}, B_ASN1_IA5STRING, V_ASN1_IA5STRING, {'a'}, 1},
+ {MBSTRING_UTF8, {'a'}, B_ASN1_T61STRING, V_ASN1_T61STRING, {'a'}, 1},
+ {MBSTRING_UTF8, {'a'}, B_ASN1_UTF8STRING, V_ASN1_UTF8STRING, {'a'}, 1},
+ {MBSTRING_UTF8,
+ {'a'},
+ B_ASN1_BMPSTRING,
+ V_ASN1_BMPSTRING,
+ {0x00, 'a'},
+ 1},
+ {MBSTRING_UTF8,
+ {'a'},
+ B_ASN1_UNIVERSALSTRING,
+ V_ASN1_UNIVERSALSTRING,
+ {0x00, 0x00, 0x00, 'a'},
+ 1},
+
+ // A long string with characters of many widths, to test sizes are
+ // measured in code points.
+ {MBSTRING_UTF8,
+ {
+ 'a', //
+ 0xc2, 0x80, // U+0080
+ 0xc4, 0x80, // U+0100
+ 0xf0, 0x90, 0x80, 0x80, // U+10000
+ },
+ B_ASN1_UNIVERSALSTRING,
+ V_ASN1_UNIVERSALSTRING,
+ {
+ 0x00, 0x00, 0x00, 'a', //
+ 0x00, 0x00, 0x00, 0x80, //
+ 0x00, 0x00, 0x01, 0x00, //
+ 0x00, 0x01, 0x00, 0x00, //
+ },
+ 4},
+ };
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(t.format);
+ SCOPED_TRACE(Bytes(t.in));
+ SCOPED_TRACE(t.mask);
+
+ // Passing in nullptr should do a dry run.
+ EXPECT_EQ(t.expected_type,
+ ASN1_mbstring_copy(nullptr, t.in.data(), t.in.size(), t.format,
+ t.mask));
+
+ // Test allocating a new object.
+ ASN1_STRING *str = nullptr;
+ EXPECT_EQ(
+ t.expected_type,
+ ASN1_mbstring_copy(&str, t.in.data(), t.in.size(), t.format, t.mask));
+ ASSERT_TRUE(str);
+ EXPECT_EQ(t.expected_type, ASN1_STRING_type(str));
+ EXPECT_EQ(Bytes(t.expected_data),
+ Bytes(ASN1_STRING_get0_data(str), ASN1_STRING_length(str)));
+
+ // Test writing into an existing object.
+ ASN1_STRING_free(str);
+ str = ASN1_STRING_new();
+ ASSERT_TRUE(str);
+ ASN1_STRING *old_str = str;
+ EXPECT_EQ(
+ t.expected_type,
+ ASN1_mbstring_copy(&str, t.in.data(), t.in.size(), t.format, t.mask));
+ ASSERT_EQ(old_str, str);
+ EXPECT_EQ(t.expected_type, ASN1_STRING_type(str));
+ EXPECT_EQ(Bytes(t.expected_data),
+ Bytes(ASN1_STRING_get0_data(str), ASN1_STRING_length(str)));
+ ASN1_STRING_free(str);
+ str = nullptr;
+
+ // minsize and maxsize should be enforced, even in a dry run.
+ EXPECT_EQ(t.expected_type,
+ ASN1_mbstring_ncopy(nullptr, t.in.data(), t.in.size(), t.format,
+ t.mask, /*minsize=*/t.num_codepoints,
+ /*maxsize=*/t.num_codepoints));
+
+ EXPECT_EQ(t.expected_type,
+ ASN1_mbstring_ncopy(&str, t.in.data(), t.in.size(), t.format,
+ t.mask, /*minsize=*/t.num_codepoints,
+ /*maxsize=*/t.num_codepoints));
+ ASSERT_TRUE(str);
+ EXPECT_EQ(t.expected_type, ASN1_STRING_type(str));
+ EXPECT_EQ(Bytes(t.expected_data),
+ Bytes(ASN1_STRING_get0_data(str), ASN1_STRING_length(str)));
+ ASN1_STRING_free(str);
+ str = nullptr;
+
+ EXPECT_EQ(-1, ASN1_mbstring_ncopy(
+ nullptr, t.in.data(), t.in.size(), t.format, t.mask,
+ /*minsize=*/t.num_codepoints + 1, /*maxsize=*/0));
+ ERR_clear_error();
+ EXPECT_EQ(-1, ASN1_mbstring_ncopy(
+ &str, t.in.data(), t.in.size(), t.format, t.mask,
+ /*minsize=*/t.num_codepoints + 1, /*maxsize=*/0));
+ EXPECT_FALSE(str);
+ ERR_clear_error();
+ if (t.num_codepoints > 1) {
+ EXPECT_EQ(-1, ASN1_mbstring_ncopy(
+ nullptr, t.in.data(), t.in.size(), t.format, t.mask,
+ /*minsize=*/0, /*maxsize=*/t.num_codepoints - 1));
+ ERR_clear_error();
+ EXPECT_EQ(-1, ASN1_mbstring_ncopy(
+ &str, t.in.data(), t.in.size(), t.format, t.mask,
+ /*minsize=*/0, /*maxsize=*/t.num_codepoints - 1));
+ EXPECT_FALSE(str);
+ ERR_clear_error();
+ }
+ }
+
+ const struct {
+ int format;
+ std::vector<uint8_t> in;
+ unsigned long mask;
+ } kInvalidTests[] = {
+ // Invalid encodings are rejected.
+ {MBSTRING_UTF8, {0xff}, B_ASN1_UTF8STRING},
+ {MBSTRING_BMP, {0xff}, B_ASN1_UTF8STRING},
+ {MBSTRING_UNIV, {0xff}, B_ASN1_UTF8STRING},
+
+ // Lone surrogates are not code points.
+ {MBSTRING_UTF8, {0xed, 0xa0, 0x80}, B_ASN1_UTF8STRING},
+ {MBSTRING_BMP, {0xd8, 0x00}, B_ASN1_UTF8STRING},
+ {MBSTRING_UNIV, {0x00, 0x00, 0xd8, 0x00}, B_ASN1_UTF8STRING},
+
+ // The input does not fit in the allowed output types.
+ {MBSTRING_UTF8, {'\n'}, B_ASN1_PRINTABLESTRING},
+ {MBSTRING_UTF8,
+ {0xc2, 0x80 /* U+0080 */},
+ B_ASN1_PRINTABLESTRING | B_ASN1_IA5STRING},
+ {MBSTRING_UTF8,
+ {0xc4, 0x80 /* U+0100 */},
+ B_ASN1_PRINTABLESTRING | B_ASN1_IA5STRING | B_ASN1_T61STRING},
+ {MBSTRING_UTF8,
+ {0xf0, 0x90, 0x80, 0x80 /* U+10000 */},
+ B_ASN1_PRINTABLESTRING | B_ASN1_IA5STRING | B_ASN1_T61STRING |
+ B_ASN1_BMPSTRING},
+
+ // Unrecognized bits are ignored.
+ {MBSTRING_UTF8, {'\n'}, B_ASN1_PRINTABLESTRING | B_ASN1_SEQUENCE},
+ };
+ for (const auto &t : kInvalidTests) {
+ SCOPED_TRACE(t.format);
+ SCOPED_TRACE(Bytes(t.in));
+ SCOPED_TRACE(t.mask);
+
+ EXPECT_EQ(-1, ASN1_mbstring_copy(nullptr, t.in.data(), t.in.size(),
+ t.format, t.mask));
+ ERR_clear_error();
+
+ ASN1_STRING *str = nullptr;
+ EXPECT_EQ(-1, ASN1_mbstring_copy(&str, t.in.data(), t.in.size(),
+ t.format, t.mask));
+ ERR_clear_error();
+ EXPECT_EQ(nullptr, str);
+ }
+}
+
+// Test that multi-string types correctly encode negative ENUMERATED.
+// Multi-string types cannot contain INTEGER, so we only test ENUMERATED.
+TEST(ASN1Test, NegativeEnumeratedMultistring) {
+ static const uint8_t kMinusOne[] = {0x0a, 0x01, 0xff}; // ENUMERATED { -1 }
+ // |ASN1_PRINTABLE| is a multi-string type that allows ENUMERATED.
+ const uint8_t *p = kMinusOne;
+ bssl::UniquePtr<ASN1_STRING> str(
+ d2i_ASN1_PRINTABLE(nullptr, &p, sizeof(kMinusOne)));
+ ASSERT_TRUE(str);
+ TestSerialize(str.get(), i2d_ASN1_PRINTABLE, kMinusOne);
+}
+
+TEST(ASN1Test, PrintableType) {
+ const struct {
+ std::vector<uint8_t> in;
+ int result;
+ } kTests[] = {
+ {{}, V_ASN1_PRINTABLESTRING},
+ {{'a', 'A', '0', '\'', '(', ')', '+', ',', '-', '.', '/', ':', '=', '?'},
+ V_ASN1_PRINTABLESTRING},
+ {{'*'}, V_ASN1_IA5STRING},
+ {{'\0'}, V_ASN1_IA5STRING},
+ {{'\0', 'a'}, V_ASN1_IA5STRING},
+ {{0, 1, 2, 3, 125, 126, 127}, V_ASN1_IA5STRING},
+ {{0, 1, 2, 3, 125, 126, 127, 128}, V_ASN1_T61STRING},
+ {{128, 0, 1, 2, 3, 125, 126, 127}, V_ASN1_T61STRING},
+ };
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(Bytes(t.in));
+ EXPECT_EQ(t.result, ASN1_PRINTABLE_type(t.in.data(), t.in.size()));
+ }
+}
+
// The ASN.1 macros do not work on Windows shared library builds, where usage of
// |OPENSSL_EXPORT| is a bit stricter.
#if !defined(OPENSSL_WINDOWS) || !defined(BORINGSSL_SHARED_LIBRARY)
diff --git a/deps/boringssl/src/crypto/x509/charmap.h b/deps/boringssl/src/crypto/asn1/charmap.h
index 3305ad1..3305ad1 100644
--- a/deps/boringssl/src/crypto/x509/charmap.h
+++ b/deps/boringssl/src/crypto/asn1/charmap.h
diff --git a/deps/boringssl/src/crypto/asn1/asn1_locl.h b/deps/boringssl/src/crypto/asn1/internal.h
index bf90ea2..f40aa86 100644
--- a/deps/boringssl/src/crypto/asn1/asn1_locl.h
+++ b/deps/boringssl/src/crypto/asn1/internal.h
@@ -1,4 +1,3 @@
-/* asn1t.h */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
* 2006.
@@ -87,6 +86,26 @@ int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
/* Internal ASN1 structures and functions: not for application use */
+/* These are used internally in the ASN1_OBJECT to keep track of
+ * whether the names and data need to be free()ed */
+#define ASN1_OBJECT_FLAG_DYNAMIC 0x01 /* internal use */
+#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 /* internal use */
+#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08 /* internal use */
+
+/* An asn1_object_st (aka |ASN1_OBJECT|) represents an ASN.1 OBJECT IDENTIFIER.
+ * Note: Mutating an |ASN1_OBJECT| is only permitted when initializing it. The
+ * library maintains a table of static |ASN1_OBJECT|s, which may be referenced
+ * by non-const |ASN1_OBJECT| pointers. Code which receives an |ASN1_OBJECT|
+ * pointer externally must assume it is immutable, even if the pointer is not
+ * const. */
+struct asn1_object_st {
+ const char *sn, *ln;
+ int nid;
+ int length;
+ const unsigned char *data; /* data remains const after init */
+ int flags; /* Should we free this one */
+};
+
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
@@ -126,6 +145,15 @@ int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval,
int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
const ASN1_ITEM *it);
+/* asn1_type_value_as_pointer returns |a|'s value in pointer form. This is
+ * usually the value object but, for BOOLEAN values, is 0 or 0xff cast to
+ * a pointer. */
+const void *asn1_type_value_as_pointer(const ASN1_TYPE *a);
+
+/* asn1_is_printable returns one if |value| is a valid Unicode codepoint for an
+ * ASN.1 PrintableString, and zero otherwise. */
+int asn1_is_printable(uint32_t value);
+
#if defined(__cplusplus)
} /* extern C */
diff --git a/deps/boringssl/src/crypto/asn1/tasn_dec.c b/deps/boringssl/src/crypto/asn1/tasn_dec.c
index 99a9714..0d123cc 100644
--- a/deps/boringssl/src/crypto/asn1/tasn_dec.c
+++ b/deps/boringssl/src/crypto/asn1/tasn_dec.c
@@ -65,7 +65,7 @@
#include <openssl/mem.h>
#include "../internal.h"
-#include "asn1_locl.h"
+#include "internal.h"
/*
* Constructed types with a recursive definition (such as can be found in PKCS7)
diff --git a/deps/boringssl/src/crypto/asn1/tasn_enc.c b/deps/boringssl/src/crypto/asn1/tasn_enc.c
index 1323439..142de6d 100644
--- a/deps/boringssl/src/crypto/asn1/tasn_enc.c
+++ b/deps/boringssl/src/crypto/asn1/tasn_enc.c
@@ -63,7 +63,7 @@
#include <openssl/mem.h>
#include "../internal.h"
-#include "asn1_locl.h"
+#include "internal.h"
static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
@@ -295,11 +295,12 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
if (flags & ASN1_TFLG_SET_OF) {
isset = 1;
- /* 2 means we reorder */
- if (flags & ASN1_TFLG_SEQUENCE_OF)
- isset = 2;
- } else
+ /* Historically, types with both bits set were mutated when
+ * serialized to apply the sort. We no longer support this. */
+ assert((flags & ASN1_TFLG_SEQUENCE_OF) == 0);
+ } else {
isset = 0;
+ }
/*
* Work out inner tag value: if EXPLICIT or no tagging use underlying
@@ -378,7 +379,6 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
typedef struct {
unsigned char *data;
int length;
- ASN1_VALUE *field;
} DER_ENC;
static int der_cmp(const void *a, const void *b)
@@ -433,7 +433,6 @@ static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
skitem = sk_ASN1_VALUE_value(sk, i);
tder->data = p;
tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass);
- tder->field = skitem;
}
/* Now sort them */
@@ -445,11 +444,6 @@ static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
p += tder->length;
}
*out = p;
- /* If do_sort is 2 then reorder the STACK */
- if (do_sort == 2) {
- for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++)
- (void)sk_ASN1_VALUE_set(sk, i, tder->field);
- }
OPENSSL_free(derlst);
OPENSSL_free(tmpdat);
return 1;
@@ -531,6 +525,20 @@ static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
/* If MSTRING type set the underlying type */
strtmp = (ASN1_STRING *)*pval;
utype = strtmp->type;
+ /* Negative INTEGER and ENUMERATED values use |ASN1_STRING| type values
+ * that do not match their corresponding utype values. INTEGERs cannot
+ * participate in MSTRING types, but ENUMERATEDs can.
+ *
+ * TODO(davidben): Is this a bug? Although arguably one of the MSTRING
+ * types should contain more values, rather than less. See
+ * https://crbug.com/boringssl/412. But it is not possible to fit all
+ * possible ANY values into an |ASN1_STRING|, so matching the spec here
+ * is somewhat hopeless. */
+ if (utype == V_ASN1_NEG_INTEGER) {
+ utype = V_ASN1_INTEGER;
+ } else if (utype == V_ASN1_NEG_ENUMERATED) {
+ utype = V_ASN1_ENUMERATED;
+ }
*putype = utype;
} else if (it->utype == V_ASN1_ANY) {
/* If ANY set type and pointer to value */
@@ -569,7 +577,7 @@ static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
if (!*tbool && !it->size)
return -1;
}
- c = (unsigned char)*tbool;
+ c = *tbool ? 0xff : 0x00;
cont = &c;
len = 1;
break;
diff --git a/deps/boringssl/src/crypto/asn1/tasn_fre.c b/deps/boringssl/src/crypto/asn1/tasn_fre.c
index a1e7315..2f5032d 100644
--- a/deps/boringssl/src/crypto/asn1/tasn_fre.c
+++ b/deps/boringssl/src/crypto/asn1/tasn_fre.c
@@ -61,7 +61,7 @@
#include <openssl/asn1t.h>
#include <openssl/mem.h>
-#include "asn1_locl.h"
+#include "internal.h"
/* Free up an ASN1 structure */
@@ -192,7 +192,7 @@ void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
ASN1_TYPE *typ = (ASN1_TYPE *)*pval;
utype = typ->type;
pval = &typ->value.asn1_value;
- if (!*pval)
+ if (utype != V_ASN1_BOOLEAN && !*pval)
return;
} else if (it->itype == ASN1_ITYPE_MSTRING) {
utype = -1;
diff --git a/deps/boringssl/src/crypto/asn1/tasn_new.c b/deps/boringssl/src/crypto/asn1/tasn_new.c
index dc864da..346887b 100644
--- a/deps/boringssl/src/crypto/asn1/tasn_new.c
+++ b/deps/boringssl/src/crypto/asn1/tasn_new.c
@@ -63,7 +63,7 @@
#include <openssl/mem.h>
#include <openssl/obj.h>
-#include "asn1_locl.h"
+#include "internal.h"
#include "../internal.h"
@@ -271,7 +271,6 @@ static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
static int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
{
ASN1_TYPE *typ;
- ASN1_STRING *str;
int utype;
if (!it)
@@ -308,10 +307,7 @@ static int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
break;
default:
- str = ASN1_STRING_type_new(utype);
- if (it->itype == ASN1_ITYPE_MSTRING && str)
- str->flags |= ASN1_STRING_FLAG_MSTRING;
- *pval = (ASN1_VALUE *)str;
+ *pval = (ASN1_VALUE *)ASN1_STRING_type_new(utype);
break;
}
if (*pval)
diff --git a/deps/boringssl/src/crypto/asn1/tasn_utl.c b/deps/boringssl/src/crypto/asn1/tasn_utl.c
index f0288b4..24ad8c3 100644
--- a/deps/boringssl/src/crypto/asn1/tasn_utl.c
+++ b/deps/boringssl/src/crypto/asn1/tasn_utl.c
@@ -66,7 +66,7 @@
#include <openssl/thread.h>
#include "../internal.h"
-#include "asn1_locl.h"
+#include "internal.h"
/* Utility functions for manipulating fields and offsets */
diff --git a/deps/boringssl/src/crypto/asn1/time_support.c b/deps/boringssl/src/crypto/asn1/time_support.c
index 3efd43e..e748ad7 100644
--- a/deps/boringssl/src/crypto/asn1/time_support.c
+++ b/deps/boringssl/src/crypto/asn1/time_support.c
@@ -59,7 +59,7 @@
#define _POSIX_C_SOURCE 201410L /* for gmtime_r */
#endif
-#include "asn1_locl.h"
+#include "internal.h"
#include <time.h>
diff --git a/deps/boringssl/src/crypto/bio/bio_mem.c b/deps/boringssl/src/crypto/bio/bio_mem.c
index 08dd6e9..f40a9a7 100644
--- a/deps/boringssl/src/crypto/bio/bio_mem.c
+++ b/deps/boringssl/src/crypto/bio/bio_mem.c
@@ -116,17 +116,11 @@ static int mem_new(BIO *bio) {
}
static int mem_free(BIO *bio) {
- BUF_MEM *b;
-
- if (bio == NULL) {
- return 0;
- }
-
if (!bio->shutdown || !bio->init || bio->ptr == NULL) {
return 1;
}
- b = (BUF_MEM *)bio->ptr;
+ BUF_MEM *b = (BUF_MEM *)bio->ptr;
if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
b->data = NULL;
}
diff --git a/deps/boringssl/src/crypto/bio/connect.c b/deps/boringssl/src/crypto/bio/connect.c
index b8afa61..3b65acf 100644
--- a/deps/boringssl/src/crypto/bio/connect.c
+++ b/deps/boringssl/src/crypto/bio/connect.c
@@ -320,7 +320,7 @@ static int conn_new(BIO *bio) {
bio->init = 0;
bio->num = -1;
bio->flags = 0;
- bio->ptr = (char *)BIO_CONNECT_new();
+ bio->ptr = BIO_CONNECT_new();
return bio->ptr != NULL;
}
@@ -340,10 +340,6 @@ static void conn_close_socket(BIO *bio) {
}
static int conn_free(BIO *bio) {
- if (bio == NULL) {
- return 0;
- }
-
if (bio->shutdown) {
conn_close_socket(bio);
}
diff --git a/deps/boringssl/src/crypto/bio/fd.c b/deps/boringssl/src/crypto/bio/fd.c
index d4e6918..349ee9d 100644
--- a/deps/boringssl/src/crypto/bio/fd.c
+++ b/deps/boringssl/src/crypto/bio/fd.c
@@ -146,10 +146,6 @@ static int fd_new(BIO *bio) {
}
static int fd_free(BIO *bio) {
- if (bio == NULL) {
- return 0;
- }
-
if (bio->shutdown) {
if (bio->init) {
BORINGSSL_CLOSE(bio->num);
diff --git a/deps/boringssl/src/crypto/bio/file.c b/deps/boringssl/src/crypto/bio/file.c
index 15feb9d..835d661 100644
--- a/deps/boringssl/src/crypto/bio/file.c
+++ b/deps/boringssl/src/crypto/bio/file.c
@@ -126,13 +126,7 @@ BIO *BIO_new_fp(FILE *stream, int close_flag) {
return ret;
}
-static int file_new(BIO *bio) { return 1; }
-
static int file_free(BIO *bio) {
- if (bio == NULL) {
- return 0;
- }
-
if (!bio->shutdown) {
return 1;
}
@@ -279,7 +273,7 @@ static const BIO_METHOD methods_filep = {
BIO_TYPE_FILE, "FILE pointer",
file_write, file_read,
NULL /* puts */, file_gets,
- file_ctrl, file_new,
+ file_ctrl, NULL /* create */,
file_free, NULL /* callback_ctrl */,
};
diff --git a/deps/boringssl/src/crypto/bio/pair.c b/deps/boringssl/src/crypto/bio/pair.c
index 03f60b7..a1a9c9c 100644
--- a/deps/boringssl/src/crypto/bio/pair.c
+++ b/deps/boringssl/src/crypto/bio/pair.c
@@ -127,12 +127,7 @@ static void bio_destroy_pair(BIO *bio) {
}
static int bio_free(BIO *bio) {
- struct bio_bio_st *b;
-
- if (bio == NULL) {
- return 0;
- }
- b = bio->ptr;
+ struct bio_bio_st *b = bio->ptr;
assert(b != NULL);
diff --git a/deps/boringssl/src/crypto/bio/socket.c b/deps/boringssl/src/crypto/bio/socket.c
index 081ce01..679959e 100644
--- a/deps/boringssl/src/crypto/bio/socket.c
+++ b/deps/boringssl/src/crypto/bio/socket.c
@@ -81,19 +81,7 @@ static int closesocket(int sock) {
}
#endif
-static int sock_new(BIO *bio) {
- bio->init = 0;
- bio->num = 0;
- bio->ptr = NULL;
- bio->flags = 0;
- return 1;
-}
-
static int sock_free(BIO *bio) {
- if (bio == NULL) {
- return 0;
- }
-
if (bio->shutdown) {
if (bio->init) {
closesocket(bio->num);
@@ -105,17 +93,15 @@ static int sock_free(BIO *bio) {
}
static int sock_read(BIO *b, char *out, int outl) {
- int ret = 0;
-
if (out == NULL) {
return 0;
}
bio_clear_socket_error();
#if defined(OPENSSL_WINDOWS)
- ret = recv(b->num, out, outl, 0);
+ int ret = recv(b->num, out, outl, 0);
#else
- ret = read(b->num, out, outl);
+ int ret = read(b->num, out, outl);
#endif
BIO_clear_retry_flags(b);
if (ret <= 0) {
@@ -186,7 +172,7 @@ static const BIO_METHOD methods_sockp = {
BIO_TYPE_SOCKET, "socket",
sock_write, sock_read,
NULL /* puts */, NULL /* gets, */,
- sock_ctrl, sock_new,
+ sock_ctrl, NULL /* create */,
sock_free, NULL /* callback_ctrl */,
};
diff --git a/deps/boringssl/src/crypto/bytestring/bytestring_test.cc b/deps/boringssl/src/crypto/bytestring/bytestring_test.cc
index eafb0de..0877a2e 100644
--- a/deps/boringssl/src/crypto/bytestring/bytestring_test.cc
+++ b/deps/boringssl/src/crypto/bytestring/bytestring_test.cc
@@ -115,6 +115,28 @@ TEST(CBSTest, GetPrefixedBad) {
EXPECT_FALSE(CBS_get_u24_length_prefixed(&data, &prefixed));
}
+TEST(CBSTest, GetUntilFirst) {
+ static const uint8_t kData[] = {0, 1, 2, 3, 0, 1, 2, 3};
+ CBS data;
+ CBS_init(&data, kData, sizeof(kData));
+
+ CBS prefix;
+ EXPECT_FALSE(CBS_get_until_first(&data, &prefix, 4));
+ EXPECT_EQ(CBS_data(&data), kData);
+ EXPECT_EQ(CBS_len(&data), sizeof(kData));
+
+ ASSERT_TRUE(CBS_get_until_first(&data, &prefix, 0));
+ EXPECT_EQ(CBS_len(&prefix), 0u);
+ EXPECT_EQ(CBS_data(&data), kData);
+ EXPECT_EQ(CBS_len(&data), sizeof(kData));
+
+ ASSERT_TRUE(CBS_get_until_first(&data, &prefix, 2));
+ EXPECT_EQ(CBS_data(&prefix), kData);
+ EXPECT_EQ(CBS_len(&prefix), 2u);
+ EXPECT_EQ(CBS_data(&data), kData + 2);
+ EXPECT_EQ(CBS_len(&data), sizeof(kData) - 2);
+}
+
TEST(CBSTest, GetASN1) {
static const uint8_t kData1[] = {0x30, 2, 1, 2};
static const uint8_t kData2[] = {0x30, 3, 1, 2};
@@ -322,11 +344,11 @@ TEST(CBBTest, InitUninitialized) {
}
TEST(CBBTest, Basic) {
- static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7,
- 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe,
- 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 3, 2,
- 10, 9, 8, 7, 0x12, 0x11, 0x10,
- 0xf, 0xe, 0xd, 0xc, 0xb};
+ static const uint8_t kExpected[] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x03, 0x02, 0x0a, 0x09, 0x08, 0x07, 0x12, 0x11, 0x10, 0x0f,
+ 0x0e, 0x0d, 0x0c, 0x0b, 0x00, 0x00, 0x00, 0x00};
uint8_t *buf;
size_t buf_len;
@@ -335,6 +357,7 @@ TEST(CBBTest, Basic) {
cbb.Reset();
ASSERT_TRUE(CBB_init(cbb.get(), 0));
+ ASSERT_TRUE(CBB_add_zeros(cbb.get(), 0));
ASSERT_TRUE(CBB_add_u8(cbb.get(), 1));
ASSERT_TRUE(CBB_add_u16(cbb.get(), 0x203));
ASSERT_TRUE(CBB_add_u24(cbb.get(), 0x40506));
@@ -344,6 +367,7 @@ TEST(CBBTest, Basic) {
ASSERT_TRUE(CBB_add_u16le(cbb.get(), 0x203));
ASSERT_TRUE(CBB_add_u32le(cbb.get(), 0x708090a));
ASSERT_TRUE(CBB_add_u64le(cbb.get(), 0xb0c0d0e0f101112));
+ ASSERT_TRUE(CBB_add_zeros(cbb.get(), 4));
ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
bssl::UniquePtr<uint8_t> scoper(buf);
diff --git a/deps/boringssl/src/crypto/bytestring/cbb.c b/deps/boringssl/src/crypto/bytestring/cbb.c
index efb89c7..12587cd 100644
--- a/deps/boringssl/src/crypto/bytestring/cbb.c
+++ b/deps/boringssl/src/crypto/bytestring/cbb.c
@@ -404,6 +404,15 @@ int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len) {
return 1;
}
+int CBB_add_zeros(CBB *cbb, size_t len) {
+ uint8_t *out;
+ if (!CBB_add_space(cbb, &out, len)) {
+ return 0;
+ }
+ OPENSSL_memset(out, 0, len);
+ return 1;
+}
+
int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len) {
if (!CBB_flush(cbb) ||
!cbb_buffer_add(cbb->base, out_data, len)) {
diff --git a/deps/boringssl/src/crypto/bytestring/cbs.c b/deps/boringssl/src/crypto/bytestring/cbs.c
index 5590ec8..803c97a 100644
--- a/deps/boringssl/src/crypto/bytestring/cbs.c
+++ b/deps/boringssl/src/crypto/bytestring/cbs.c
@@ -216,6 +216,14 @@ int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) {
return cbs_get_length_prefixed(cbs, out, 3);
}
+int CBS_get_until_first(CBS *cbs, CBS *out, uint8_t c) {
+ const uint8_t *split = OPENSSL_memchr(CBS_data(cbs), c, CBS_len(cbs));
+ if (split == NULL) {
+ return 0;
+ }
+ return CBS_get_bytes(cbs, out, split - CBS_data(cbs));
+}
+
// parse_base128_integer reads a big-endian base-128 integer from |cbs| and sets
// |*out| to the result. This is the encoding used in DER for both high tag
// number form and OID components.
diff --git a/deps/boringssl/src/crypto/cipher_extra/aead_test.cc b/deps/boringssl/src/crypto/cipher_extra/aead_test.cc
index bf02e78..9e5dcee 100644
--- a/deps/boringssl/src/crypto/cipher_extra/aead_test.cc
+++ b/deps/boringssl/src/crypto/cipher_extra/aead_test.cc
@@ -125,10 +125,6 @@ static const struct KnownAEAD kAEADs[] = {
"aes_128_cbc_sha1_tls_implicit_iv_tests.txt",
kLimitedImplementation | RequiresADLength(11)},
- {"AES_128_CBC_SHA256_TLS", EVP_aead_aes_128_cbc_sha256_tls,
- "aes_128_cbc_sha256_tls_tests.txt",
- kLimitedImplementation | RequiresADLength(11)},
-
{"AES_256_CBC_SHA1_TLS", EVP_aead_aes_256_cbc_sha1_tls,
"aes_256_cbc_sha1_tls_tests.txt",
kLimitedImplementation | RequiresADLength(11)},
@@ -138,14 +134,6 @@ static const struct KnownAEAD kAEADs[] = {
"aes_256_cbc_sha1_tls_implicit_iv_tests.txt",
kLimitedImplementation | RequiresADLength(11)},
- {"AES_256_CBC_SHA256_TLS", EVP_aead_aes_256_cbc_sha256_tls,
- "aes_256_cbc_sha256_tls_tests.txt",
- kLimitedImplementation | RequiresADLength(11)},
-
- {"AES_256_CBC_SHA384_TLS", EVP_aead_aes_256_cbc_sha384_tls,
- "aes_256_cbc_sha384_tls_tests.txt",
- kLimitedImplementation | RequiresADLength(11)},
-
{"DES_EDE3_CBC_SHA1_TLS", EVP_aead_des_ede3_cbc_sha1_tls,
"des_ede3_cbc_sha1_tls_tests.txt",
kLimitedImplementation | RequiresADLength(11)},
@@ -808,6 +796,7 @@ TEST_P(PerAEADTest, ABI) {
: sizeof(ad_buf) - 1;
uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
+ OPENSSL_memset(nonce, 'N', sizeof(nonce));
const size_t nonce_len = EVP_AEAD_nonce_length(aead());
ASSERT_LE(nonce_len, sizeof(nonce));
diff --git a/deps/boringssl/src/crypto/cipher_extra/cipher_extra.c b/deps/boringssl/src/crypto/cipher_extra/cipher_extra.c
index b132265..786a5d5 100644
--- a/deps/boringssl/src/crypto/cipher_extra/cipher_extra.c
+++ b/deps/boringssl/src/crypto/cipher_extra/cipher_extra.c
@@ -89,6 +89,10 @@ const EVP_CIPHER *EVP_get_cipherbynid(int nid) {
}
const EVP_CIPHER *EVP_get_cipherbyname(const char *name) {
+ if (name == NULL) {
+ return NULL;
+ }
+
if (OPENSSL_strcasecmp(name, "rc4") == 0) {
return EVP_rc4();
} else if (OPENSSL_strcasecmp(name, "des-cbc") == 0) {
diff --git a/deps/boringssl/src/crypto/cipher_extra/cipher_test.cc b/deps/boringssl/src/crypto/cipher_extra/cipher_test.cc
index af7e0e7..57fdc8a 100644
--- a/deps/boringssl/src/crypto/cipher_extra/cipher_test.cc
+++ b/deps/boringssl/src/crypto/cipher_extra/cipher_test.cc
@@ -65,11 +65,14 @@
#include <openssl/cipher.h>
#include <openssl/err.h>
#include <openssl/nid.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
#include <openssl/span.h>
#include "../test/file_test.h"
#include "../test/test_util.h"
#include "../test/wycheproof_util.h"
+#include "./internal.h"
static const EVP_CIPHER *GetCipher(const std::string &name) {
@@ -474,3 +477,50 @@ TEST(CipherTest, WycheproofAESCBC) {
}
});
}
+
+TEST(CipherTest, SHA1WithSecretSuffix) {
+ uint8_t buf[SHA_CBLOCK * 4];
+ RAND_bytes(buf, sizeof(buf));
+ // Hashing should run in time independent of the bytes.
+ CONSTTIME_SECRET(buf, sizeof(buf));
+
+ // Exhaustively testing interesting cases in this function is cubic in the
+ // block size, so we test in 3-byte increments.
+ constexpr size_t kSkip = 3;
+ // This value should be less than 8 to test the edge case when the 8-byte
+ // length wraps to the next block.
+ static_assert(kSkip < 8, "kSkip is too large");
+
+ // |EVP_sha1_final_with_secret_suffix| is sensitive to the public length of
+ // the partial block previously hashed. In TLS, this is the HMAC prefix, the
+ // header, and the public minimum padding length.
+ for (size_t prefix = 0; prefix < SHA_CBLOCK; prefix += kSkip) {
+ SCOPED_TRACE(prefix);
+ // The first block is treated differently, so we run with up to three
+ // blocks of length variability.
+ for (size_t max_len = 0; max_len < 3 * SHA_CBLOCK; max_len += kSkip) {
+ SCOPED_TRACE(max_len);
+ for (size_t len = 0; len <= max_len; len += kSkip) {
+ SCOPED_TRACE(len);
+
+ uint8_t expected[SHA_DIGEST_LENGTH];
+ SHA1(buf, prefix + len, expected);
+ CONSTTIME_DECLASSIFY(expected, sizeof(expected));
+
+ // Make a copy of the secret length to avoid interfering with the loop.
+ size_t secret_len = len;
+ CONSTTIME_SECRET(&secret_len, sizeof(secret_len));
+
+ SHA_CTX ctx;
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, buf, prefix);
+ uint8_t computed[SHA_DIGEST_LENGTH];
+ ASSERT_TRUE(EVP_sha1_final_with_secret_suffix(
+ &ctx, computed, buf + prefix, secret_len, max_len));
+
+ CONSTTIME_DECLASSIFY(computed, sizeof(computed));
+ EXPECT_EQ(Bytes(expected), Bytes(computed));
+ }
+ }
+ }
+}
diff --git a/deps/boringssl/src/crypto/cipher_extra/e_tls.c b/deps/boringssl/src/crypto/cipher_extra/e_tls.c
index c812b6b..6d84f7f 100644
--- a/deps/boringssl/src/crypto/cipher_extra/e_tls.c
+++ b/deps/boringssl/src/crypto/cipher_extra/e_tls.c
@@ -343,7 +343,7 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE &&
EVP_tls_cbc_record_digest_supported(tls_ctx->hmac_ctx.md)) {
if (!EVP_tls_cbc_digest_record(tls_ctx->hmac_ctx.md, mac, &mac_len,
- ad_fixed, out, data_plus_mac_len, total,
+ ad_fixed, out, data_len, total,
tls_ctx->mac_key, tls_ctx->mac_key_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
return 0;
@@ -406,14 +406,6 @@ static int aead_aes_128_cbc_sha1_tls_implicit_iv_init(
EVP_sha1(), 1);
}
-static int aead_aes_128_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx,
- const uint8_t *key, size_t key_len,
- size_t tag_len,
- enum evp_aead_direction_t dir) {
- return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(),
- EVP_sha256(), 0);
-}
-
static int aead_aes_256_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
size_t key_len, size_t tag_len,
enum evp_aead_direction_t dir) {
@@ -428,22 +420,6 @@ static int aead_aes_256_cbc_sha1_tls_implicit_iv_init(
EVP_sha1(), 1);
}
-static int aead_aes_256_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx,
- const uint8_t *key, size_t key_len,
- size_t tag_len,
- enum evp_aead_direction_t dir) {
- return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(),
- EVP_sha256(), 0);
-}
-
-static int aead_aes_256_cbc_sha384_tls_init(EVP_AEAD_CTX *ctx,
- const uint8_t *key, size_t key_len,
- size_t tag_len,
- enum evp_aead_direction_t dir) {
- return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(),
- EVP_sha384(), 0);
-}
-
static int aead_des_ede3_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx,
const uint8_t *key, size_t key_len,
size_t tag_len,
@@ -513,23 +489,6 @@ static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = {
aead_tls_tag_len,
};
-static const EVP_AEAD aead_aes_128_cbc_sha256_tls = {
- SHA256_DIGEST_LENGTH + 16, // key len (SHA256 + AES128)
- 16, // nonce len (IV)
- 16 + SHA256_DIGEST_LENGTH, // overhead (padding + SHA256)
- SHA256_DIGEST_LENGTH, // max tag length
- 0, // seal_scatter_supports_extra_in
-
- NULL, // init
- aead_aes_128_cbc_sha256_tls_init,
- aead_tls_cleanup,
- aead_tls_open,
- aead_tls_seal_scatter,
- NULL, // open_gather
- NULL, // get_iv
- aead_tls_tag_len,
-};
-
static const EVP_AEAD aead_aes_256_cbc_sha1_tls = {
SHA_DIGEST_LENGTH + 32, // key len (SHA1 + AES256)
16, // nonce len (IV)
@@ -564,40 +523,6 @@ static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = {
aead_tls_tag_len,
};
-static const EVP_AEAD aead_aes_256_cbc_sha256_tls = {
- SHA256_DIGEST_LENGTH + 32, // key len (SHA256 + AES256)
- 16, // nonce len (IV)
- 16 + SHA256_DIGEST_LENGTH, // overhead (padding + SHA256)
- SHA256_DIGEST_LENGTH, // max tag length
- 0, // seal_scatter_supports_extra_in
-
- NULL, // init
- aead_aes_256_cbc_sha256_tls_init,
- aead_tls_cleanup,
- aead_tls_open,
- aead_tls_seal_scatter,
- NULL, // open_gather
- NULL, // get_iv
- aead_tls_tag_len,
-};
-
-static const EVP_AEAD aead_aes_256_cbc_sha384_tls = {
- SHA384_DIGEST_LENGTH + 32, // key len (SHA384 + AES256)
- 16, // nonce len (IV)
- 16 + SHA384_DIGEST_LENGTH, // overhead (padding + SHA384)
- SHA384_DIGEST_LENGTH, // max tag length
- 0, // seal_scatter_supports_extra_in
-
- NULL, // init
- aead_aes_256_cbc_sha384_tls_init,
- aead_tls_cleanup,
- aead_tls_open,
- aead_tls_seal_scatter,
- NULL, // open_gather
- NULL, // get_iv
- aead_tls_tag_len,
-};
-
static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = {
SHA_DIGEST_LENGTH + 24, // key len (SHA1 + 3DES)
8, // nonce len (IV)
@@ -657,10 +582,6 @@ const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(void) {
return &aead_aes_128_cbc_sha1_tls_implicit_iv;
}
-const EVP_AEAD *EVP_aead_aes_128_cbc_sha256_tls(void) {
- return &aead_aes_128_cbc_sha256_tls;
-}
-
const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls(void) {
return &aead_aes_256_cbc_sha1_tls;
}
@@ -669,14 +590,6 @@ const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(void) {
return &aead_aes_256_cbc_sha1_tls_implicit_iv;
}
-const EVP_AEAD *EVP_aead_aes_256_cbc_sha256_tls(void) {
- return &aead_aes_256_cbc_sha256_tls;
-}
-
-const EVP_AEAD *EVP_aead_aes_256_cbc_sha384_tls(void) {
- return &aead_aes_256_cbc_sha384_tls;
-}
-
const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls(void) {
return &aead_des_ede3_cbc_sha1_tls;
}
diff --git a/deps/boringssl/src/crypto/cipher_extra/internal.h b/deps/boringssl/src/crypto/cipher_extra/internal.h
index c2af48e..a2ec30b 100644
--- a/deps/boringssl/src/crypto/cipher_extra/internal.h
+++ b/deps/boringssl/src/crypto/cipher_extra/internal.h
@@ -99,6 +99,17 @@ void EVP_tls_cbc_copy_mac(uint8_t *out, size_t md_size, const uint8_t *in,
// which EVP_tls_cbc_digest_record supports.
int EVP_tls_cbc_record_digest_supported(const EVP_MD *md);
+// EVP_sha1_final_with_secret_suffix computes the result of hashing |len| bytes
+// from |in| to |ctx| and writes the resulting hash to |out|. |len| is treated
+// as secret and must be at most |max_len|, which is treated as public. |in|
+// must point to a buffer of at least |max_len| bytes. It returns one on success
+// and zero if inputs are too long.
+//
+// This function is exported for unit tests.
+OPENSSL_EXPORT int EVP_sha1_final_with_secret_suffix(
+ SHA_CTX *ctx, uint8_t out[SHA_DIGEST_LENGTH], const uint8_t *in, size_t len,
+ size_t max_len);
+
// EVP_tls_cbc_digest_record computes the MAC of a decrypted, padded TLS
// record.
//
@@ -108,8 +119,8 @@ int EVP_tls_cbc_record_digest_supported(const EVP_MD *md);
// md_out_size: the number of output bytes is written here.
// header: the 13-byte, TLS record header.
// data: the record data itself
-// data_plus_mac_size: the secret, reported length of the data and MAC
-// once the padding has been removed.
+// data_size: the secret, reported length of the data once the padding and MAC
+// have been removed.
// data_plus_mac_plus_padding_size: the public length of the whole
// record, including padding.
//
@@ -119,7 +130,7 @@ int EVP_tls_cbc_record_digest_supported(const EVP_MD *md);
// padding too. )
int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out,
size_t *md_out_size, const uint8_t header[13],
- const uint8_t *data, size_t data_plus_mac_size,
+ const uint8_t *data, size_t data_size,
size_t data_plus_mac_plus_padding_size,
const uint8_t *mac_secret,
unsigned mac_secret_length);
diff --git a/deps/boringssl/src/crypto/cipher_extra/tls_cbc.c b/deps/boringssl/src/crypto/cipher_extra/tls_cbc.c
index 5e97a1c..e1e95d4 100644
--- a/deps/boringssl/src/crypto/cipher_extra/tls_cbc.c
+++ b/deps/boringssl/src/crypto/cipher_extra/tls_cbc.c
@@ -62,15 +62,6 @@
#include "../fipsmodule/cipher/internal.h"
-// MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length
-// field. (SHA-384/512 have 128-bit length.)
-#define MAX_HASH_BIT_COUNT_BYTES 16
-
-// MAX_HASH_BLOCK_SIZE is the maximum hash block size that we'll support.
-// Currently SHA-384/512 has a 128-byte block size and that's the largest
-// supported by TLS.)
-#define MAX_HASH_BLOCK_SIZE 128
-
int EVP_tls_cbc_remove_padding(crypto_word_t *out_padding_ok, size_t *out_len,
const uint8_t *in, size_t in_len,
size_t block_size, size_t mac_size) {
@@ -183,134 +174,110 @@ void EVP_tls_cbc_copy_mac(uint8_t *out, size_t md_size, const uint8_t *in,
OPENSSL_memcpy(out, rotated_mac, md_size);
}
-// u32toBE serialises an unsigned, 32-bit number (n) as four bytes at (p) in
-// big-endian order. The value of p is advanced by four.
-#define u32toBE(n, p) \
- do { \
- *((p)++) = (uint8_t)((n) >> 24); \
- *((p)++) = (uint8_t)((n) >> 16); \
- *((p)++) = (uint8_t)((n) >> 8); \
- *((p)++) = (uint8_t)((n)); \
- } while (0)
-
-// u64toBE serialises an unsigned, 64-bit number (n) as eight bytes at (p) in
-// big-endian order. The value of p is advanced by eight.
-#define u64toBE(n, p) \
- do { \
- *((p)++) = (uint8_t)((n) >> 56); \
- *((p)++) = (uint8_t)((n) >> 48); \
- *((p)++) = (uint8_t)((n) >> 40); \
- *((p)++) = (uint8_t)((n) >> 32); \
- *((p)++) = (uint8_t)((n) >> 24); \
- *((p)++) = (uint8_t)((n) >> 16); \
- *((p)++) = (uint8_t)((n) >> 8); \
- *((p)++) = (uint8_t)((n)); \
- } while (0)
-
-typedef union {
- SHA_CTX sha1;
- SHA256_CTX sha256;
- SHA512_CTX sha512;
-} HASH_CTX;
-
-static void tls1_sha1_transform(HASH_CTX *ctx, const uint8_t *block) {
- SHA1_Transform(&ctx->sha1, block);
-}
+int EVP_sha1_final_with_secret_suffix(SHA_CTX *ctx,
+ uint8_t out[SHA_DIGEST_LENGTH],
+ const uint8_t *in, size_t len,
+ size_t max_len) {
+ // Bound the input length so |total_bits| below fits in four bytes. This is
+ // redundant with TLS record size limits. This also ensures |input_idx| below
+ // does not overflow.
+ size_t max_len_bits = max_len << 3;
+ if (ctx->Nh != 0 ||
+ (max_len_bits >> 3) != max_len || // Overflow
+ ctx->Nl + max_len_bits < max_len_bits ||
+ ctx->Nl + max_len_bits > UINT32_MAX) {
+ return 0;
+ }
-static void tls1_sha256_transform(HASH_CTX *ctx, const uint8_t *block) {
- SHA256_Transform(&ctx->sha256, block);
-}
+ // We need to hash the following into |ctx|:
+ //
+ // - ctx->data[:ctx->num]
+ // - in[:len]
+ // - A 0x80 byte
+ // - However many zero bytes are needed to pad up to a block.
+ // - Eight bytes of length.
+ size_t num_blocks = (ctx->num + len + 1 + 8 + SHA_CBLOCK - 1) >> 6;
+ size_t last_block = num_blocks - 1;
+ size_t max_blocks = (ctx->num + max_len + 1 + 8 + SHA_CBLOCK - 1) >> 6;
+
+ // The bounds above imply |total_bits| fits in four bytes.
+ size_t total_bits = ctx->Nl + (len << 3);
+ uint8_t length_bytes[4];
+ length_bytes[0] = (uint8_t)(total_bits >> 24);
+ length_bytes[1] = (uint8_t)(total_bits >> 16);
+ length_bytes[2] = (uint8_t)(total_bits >> 8);
+ length_bytes[3] = (uint8_t)total_bits;
+
+ // We now construct and process each expected block in constant-time.
+ uint8_t block[SHA_CBLOCK] = {0};
+ uint32_t result[5] = {0};
+ // input_idx is the index into |in| corresponding to the current block.
+ // However, we allow this index to overflow beyond |max_len|, to simplify the
+ // 0x80 byte.
+ size_t input_idx = 0;
+ for (size_t i = 0; i < max_blocks; i++) {
+ // Fill |block| with data from the partial block in |ctx| and |in|. We copy
+ // as if we were hashing up to |max_len| and then zero the excess later.
+ size_t block_start = 0;
+ if (i == 0) {
+ OPENSSL_memcpy(block, ctx->data, ctx->num);
+ block_start = ctx->num;
+ }
+ if (input_idx < max_len) {
+ size_t to_copy = SHA_CBLOCK - block_start;
+ if (to_copy > max_len - input_idx) {
+ to_copy = max_len - input_idx;
+ }
+ OPENSSL_memcpy(block + block_start, in + input_idx, to_copy);
+ }
-static void tls1_sha512_transform(HASH_CTX *ctx, const uint8_t *block) {
- SHA512_Transform(&ctx->sha512, block);
-}
+ // Zero any bytes beyond |len| and add the 0x80 byte.
+ for (size_t j = block_start; j < SHA_CBLOCK; j++) {
+ // input[idx] corresponds to block[j].
+ size_t idx = input_idx + j - block_start;
+ // The barriers on |len| are not strictly necessary. However, without
+ // them, GCC compiles this code by incorporating |len| into the loop
+ // counter and subtracting it out later. This is still constant-time, but
+ // it frustrates attempts to validate this.
+ uint8_t is_in_bounds = constant_time_lt_8(idx, value_barrier_w(len));
+ uint8_t is_padding_byte = constant_time_eq_8(idx, value_barrier_w(len));
+ block[j] &= is_in_bounds;
+ block[j] |= 0x80 & is_padding_byte;
+ }
-// These functions serialize the state of a hash and thus perform the standard
-// "final" operation without adding the padding and length that such a function
-// typically does.
-static void tls1_sha1_final_raw(HASH_CTX *ctx, uint8_t *md_out) {
- SHA_CTX *sha1 = &ctx->sha1;
- u32toBE(sha1->h[0], md_out);
- u32toBE(sha1->h[1], md_out);
- u32toBE(sha1->h[2], md_out);
- u32toBE(sha1->h[3], md_out);
- u32toBE(sha1->h[4], md_out);
-}
+ input_idx += SHA_CBLOCK - block_start;
-static void tls1_sha256_final_raw(HASH_CTX *ctx, uint8_t *md_out) {
- SHA256_CTX *sha256 = &ctx->sha256;
- for (unsigned i = 0; i < 8; i++) {
- u32toBE(sha256->h[i], md_out);
+ // Fill in the length if this is the last block.
+ crypto_word_t is_last_block = constant_time_eq_w(i, last_block);
+ for (size_t j = 0; j < 4; j++) {
+ block[SHA_CBLOCK - 4 + j] |= is_last_block & length_bytes[j];
+ }
+
+ // Process the block and save the hash state if it is the final value.
+ SHA1_Transform(ctx, block);
+ for (size_t j = 0; j < 5; j++) {
+ result[j] |= is_last_block & ctx->h[j];
+ }
}
-}
-static void tls1_sha512_final_raw(HASH_CTX *ctx, uint8_t *md_out) {
- SHA512_CTX *sha512 = &ctx->sha512;
- for (unsigned i = 0; i < 8; i++) {
- u64toBE(sha512->h[i], md_out);
+ // Write the output.
+ for (size_t i = 0; i < 5; i++) {
+ CRYPTO_store_u32_be(out + 4 * i, result[i]);
}
+ return 1;
}
int EVP_tls_cbc_record_digest_supported(const EVP_MD *md) {
- switch (EVP_MD_type(md)) {
- case NID_sha1:
- case NID_sha256:
- case NID_sha384:
- return 1;
-
- default:
- return 0;
- }
+ return EVP_MD_type(md) == NID_sha1;
}
int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out,
size_t *md_out_size, const uint8_t header[13],
- const uint8_t *data, size_t data_plus_mac_size,
+ const uint8_t *data, size_t data_size,
size_t data_plus_mac_plus_padding_size,
const uint8_t *mac_secret,
unsigned mac_secret_length) {
- HASH_CTX md_state;
- void (*md_final_raw)(HASH_CTX *ctx, uint8_t *md_out);
- void (*md_transform)(HASH_CTX *ctx, const uint8_t *block);
- unsigned md_size, md_block_size = 64, md_block_shift = 6;
- // md_length_size is the number of bytes in the length field that terminates
- // the hash.
- unsigned md_length_size = 8;
-
- // Bound the acceptable input so we can forget about many possible overflows
- // later in this function. This is redundant with the record size limits in
- // TLS.
- if (data_plus_mac_plus_padding_size >= 1024 * 1024) {
- assert(0);
- return 0;
- }
-
- switch (EVP_MD_type(md)) {
- case NID_sha1:
- SHA1_Init(&md_state.sha1);
- md_final_raw = tls1_sha1_final_raw;
- md_transform = tls1_sha1_transform;
- md_size = SHA_DIGEST_LENGTH;
- break;
-
- case NID_sha256:
- SHA256_Init(&md_state.sha256);
- md_final_raw = tls1_sha256_final_raw;
- md_transform = tls1_sha256_transform;
- md_size = SHA256_DIGEST_LENGTH;
- break;
-
- case NID_sha384:
- SHA384_Init(&md_state.sha512);
- md_final_raw = tls1_sha512_final_raw;
- md_transform = tls1_sha512_transform;
- md_size = SHA384_DIGEST_LENGTH;
- md_block_size = 128;
- md_block_shift = 7;
- md_length_size = 16;
- break;
-
- default:
+ if (EVP_MD_type(md) != NID_sha1) {
// EVP_tls_cbc_record_digest_supported should have been called first to
// check that the hash function is supported.
assert(0);
@@ -318,175 +285,54 @@ int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out,
return 0;
}
- assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES);
- assert(md_block_size <= MAX_HASH_BLOCK_SIZE);
- assert(md_block_size == (1u << md_block_shift));
- assert(md_size <= EVP_MAX_MD_SIZE);
-
- static const size_t kHeaderLength = 13;
-
- // kVarianceBlocks is the number of blocks of the hash that we have to
- // calculate in constant time because they could be altered by the
- // padding value.
- //
- // TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not
- // required to be minimal. Therefore we say that the final |kVarianceBlocks|
- // blocks can vary based on the padding and on the hash used. This value
- // must be derived from public information.
- const size_t kVarianceBlocks =
- ( 255 + 1 + // maximum padding bytes + padding length
- md_size + // length of hash's output
- md_block_size - 1 // ceiling
- ) / md_block_size
- + 1; // the 0x80 marker and the encoded message length could or not
- // require an extra block; since the exact value depends on the
- // message length; thus, one extra block is always added to run
- // in constant time.
-
- // From now on we're dealing with the MAC, which conceptually has 13
- // bytes of `header' before the start of the data.
- size_t len = data_plus_mac_plus_padding_size + kHeaderLength;
- // max_mac_bytes contains the maximum bytes of bytes in the MAC, including
- // |header|, assuming that there's no padding.
- size_t max_mac_bytes = len - md_size - 1;
- // num_blocks is the maximum number of hash blocks.
- size_t num_blocks =
- (max_mac_bytes + 1 + md_length_size + md_block_size - 1) / md_block_size;
- // In order to calculate the MAC in constant time we have to handle
- // the final blocks specially because the padding value could cause the
- // end to appear somewhere in the final |kVarianceBlocks| blocks and we
- // can't leak where. However, |num_starting_blocks| worth of data can
- // be hashed right away because no padding value can affect whether
- // they are plaintext.
- size_t num_starting_blocks = 0;
- // k is the starting byte offset into the conceptual header||data where
- // we start processing.
- size_t k = 0;
- // mac_end_offset is the index just past the end of the data to be MACed.
- size_t mac_end_offset = data_plus_mac_size + kHeaderLength - md_size;
- // c is the index of the 0x80 byte in the final hash block that contains
- // application data.
- size_t c = mac_end_offset & (md_block_size - 1);
- // index_a is the hash block number that contains the 0x80 terminating value.
- size_t index_a = mac_end_offset >> md_block_shift;
- // index_b is the hash block number that contains the 64-bit hash length, in
- // bits.
- size_t index_b = (mac_end_offset + md_length_size) >> md_block_shift;
-
- if (num_blocks > kVarianceBlocks) {
- num_starting_blocks = num_blocks - kVarianceBlocks;
- k = md_block_size * num_starting_blocks;
+ if (mac_secret_length > SHA_CBLOCK) {
+ // HMAC pads small keys with zeros and hashes large keys down. This function
+ // should never reach the large key case.
+ assert(0);
+ return 0;
}
- // bits is the hash-length in bits. It includes the additional hash
- // block for the masked HMAC key.
- size_t bits = 8 * mac_end_offset; // at most 18 bits to represent
-
// Compute the initial HMAC block.
- bits += 8 * md_block_size;
- // hmac_pad is the masked HMAC key.
- uint8_t hmac_pad[MAX_HASH_BLOCK_SIZE];
- OPENSSL_memset(hmac_pad, 0, md_block_size);
- assert(mac_secret_length <= sizeof(hmac_pad));
+ uint8_t hmac_pad[SHA_CBLOCK];
+ OPENSSL_memset(hmac_pad, 0, sizeof(hmac_pad));
OPENSSL_memcpy(hmac_pad, mac_secret, mac_secret_length);
- for (size_t i = 0; i < md_block_size; i++) {
+ for (size_t i = 0; i < SHA_CBLOCK; i++) {
hmac_pad[i] ^= 0x36;
}
- md_transform(&md_state, hmac_pad);
-
- // The length check means |bits| fits in four bytes.
- uint8_t length_bytes[MAX_HASH_BIT_COUNT_BYTES];
- OPENSSL_memset(length_bytes, 0, md_length_size - 4);
- length_bytes[md_length_size - 4] = (uint8_t)(bits >> 24);
- length_bytes[md_length_size - 3] = (uint8_t)(bits >> 16);
- length_bytes[md_length_size - 2] = (uint8_t)(bits >> 8);
- length_bytes[md_length_size - 1] = (uint8_t)bits;
-
- if (k > 0) {
- // k is a multiple of md_block_size.
- uint8_t first_block[MAX_HASH_BLOCK_SIZE];
- OPENSSL_memcpy(first_block, header, 13);
- OPENSSL_memcpy(first_block + 13, data, md_block_size - 13);
- md_transform(&md_state, first_block);
- for (size_t i = 1; i < k / md_block_size; i++) {
- md_transform(&md_state, data + md_block_size * i - 13);
- }
- }
-
- uint8_t mac_out[EVP_MAX_MD_SIZE];
- OPENSSL_memset(mac_out, 0, sizeof(mac_out));
-
- // We now process the final hash blocks. For each block, we construct
- // it in constant time. If the |i==index_a| then we'll include the 0x80
- // bytes and zero pad etc. For each block we selectively copy it, in
- // constant time, to |mac_out|.
- for (size_t i = num_starting_blocks;
- i <= num_starting_blocks + kVarianceBlocks; i++) {
- uint8_t block[MAX_HASH_BLOCK_SIZE];
- uint8_t is_block_a = constant_time_eq_8(i, index_a);
- uint8_t is_block_b = constant_time_eq_8(i, index_b);
- for (size_t j = 0; j < md_block_size; j++) {
- uint8_t b = 0;
- if (k < kHeaderLength) {
- b = header[k];
- } else if (k < data_plus_mac_plus_padding_size + kHeaderLength) {
- b = data[k - kHeaderLength];
- }
- k++;
-
- uint8_t is_past_c = is_block_a & constant_time_ge_8(j, c);
- uint8_t is_past_cp1 = is_block_a & constant_time_ge_8(j, c + 1);
- // If this is the block containing the end of the
- // application data, and we are at the offset for the
- // 0x80 value, then overwrite b with 0x80.
- b = constant_time_select_8(is_past_c, 0x80, b);
- // If this the the block containing the end of the
- // application data and we're past the 0x80 value then
- // just write zero.
- b = b & ~is_past_cp1;
- // If this is index_b (the final block), but not
- // index_a (the end of the data), then the 64-bit
- // length didn't fit into index_a and we're having to
- // add an extra block of zeros.
- b &= ~is_block_b | is_block_a;
-
- // The final bytes of one of the blocks contains the
- // length.
- if (j >= md_block_size - md_length_size) {
- // If this is index_b, write a length byte.
- b = constant_time_select_8(
- is_block_b, length_bytes[j - (md_block_size - md_length_size)], b);
- }
- block[j] = b;
- }
+ SHA_CTX ctx;
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, hmac_pad, SHA_CBLOCK);
+ SHA1_Update(&ctx, header, 13);
- md_transform(&md_state, block);
- md_final_raw(&md_state, block);
- // If this is index_b, copy the hash value to |mac_out|.
- for (size_t j = 0; j < md_size; j++) {
- mac_out[j] |= block[j] & is_block_b;
- }
+ // There are at most 256 bytes of padding, so we can compute the public
+ // minimum length for |data_size|.
+ size_t min_data_size = 0;
+ if (data_plus_mac_plus_padding_size > SHA_DIGEST_LENGTH + 256) {
+ min_data_size = data_plus_mac_plus_padding_size - SHA_DIGEST_LENGTH - 256;
}
- EVP_MD_CTX md_ctx;
- EVP_MD_CTX_init(&md_ctx);
- if (!EVP_DigestInit_ex(&md_ctx, md, NULL /* engine */)) {
- EVP_MD_CTX_cleanup(&md_ctx);
+ // Hash the public minimum length directly. This reduces the number of blocks
+ // that must be computed in constant-time.
+ SHA1_Update(&ctx, data, min_data_size);
+
+ // Hash the remaining data without leaking |data_size|.
+ uint8_t mac_out[SHA_DIGEST_LENGTH];
+ if (!EVP_sha1_final_with_secret_suffix(
+ &ctx, mac_out, data + min_data_size, data_size - min_data_size,
+ data_plus_mac_plus_padding_size - min_data_size)) {
return 0;
}
// Complete the HMAC in the standard manner.
- for (size_t i = 0; i < md_block_size; i++) {
+ SHA1_Init(&ctx);
+ for (size_t i = 0; i < SHA_CBLOCK; i++) {
hmac_pad[i] ^= 0x6a;
}
- EVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size);
- EVP_DigestUpdate(&md_ctx, mac_out, md_size);
- unsigned md_out_size_u;
- EVP_DigestFinal(&md_ctx, md_out, &md_out_size_u);
- *md_out_size = md_out_size_u;
- EVP_MD_CTX_cleanup(&md_ctx);
-
+ SHA1_Update(&ctx, hmac_pad, SHA_CBLOCK);
+ SHA1_Update(&ctx, mac_out, SHA_DIGEST_LENGTH);
+ SHA1_Final(md_out, &ctx);
+ *md_out_size = SHA_DIGEST_LENGTH;
return 1;
}
diff --git a/deps/boringssl/src/crypto/conf/conf.c b/deps/boringssl/src/crypto/conf/conf.c
index 7070ca8..c1e4e96 100644
--- a/deps/boringssl/src/crypto/conf/conf.c
+++ b/deps/boringssl/src/crypto/conf/conf.c
@@ -68,6 +68,7 @@
#include "conf_def.h"
#include "internal.h"
#include "../internal.h"
+#include "../lhash/internal.h"
DEFINE_LHASH_OF(CONF_VALUE)
@@ -76,12 +77,16 @@ struct conf_st {
LHASH_OF(CONF_VALUE) *data;
};
+static const char kDefaultSectionName[] = "default";
+
// The maximum length we can grow a value to after variable expansion. 64k
// should be more than enough for all reasonable uses.
#define MAX_CONF_VALUE_LENGTH 65536
static uint32_t conf_value_hash(const CONF_VALUE *v) {
- return (lh_strhash(v->section) << 2) ^ lh_strhash(v->name);
+ const uint32_t section_hash = v->section ? OPENSSL_strhash(v->section) : 0;
+ const uint32_t name_hash = v->name ? OPENSSL_strhash(v->name) : 0;
+ return (section_hash << 2) ^ name_hash;
}
static int conf_value_cmp(const CONF_VALUE *a, const CONF_VALUE *b) {
@@ -155,12 +160,14 @@ static void value_free(CONF_VALUE *value) {
OPENSSL_free(value);
}
+static void value_free_arg(CONF_VALUE *value, void *arg) { value_free(value); }
+
void NCONF_free(CONF *conf) {
if (conf == NULL || conf->data == NULL) {
return;
}
- lh_CONF_VALUE_doall(conf->data, value_free);
+ lh_CONF_VALUE_doall_arg(conf->data, value_free_arg, NULL);
lh_CONF_VALUE_free(conf->data);
OPENSSL_free(conf);
}
@@ -390,6 +397,10 @@ const char *NCONF_get_string(const CONF *conf, const char *section,
const char *name) {
CONF_VALUE template, *value;
+ if (section == NULL) {
+ section = kDefaultSectionName;
+ }
+
OPENSSL_memset(&template, 0, sizeof(template));
template.section = (char *) section;
template.name = (char *) name;
@@ -538,7 +549,7 @@ static int def_load_bio(CONF *conf, BIO *in, long *out_error_line) {
goto err;
}
- section = OPENSSL_strdup("default");
+ section = OPENSSL_strdup(kDefaultSectionName);
if (section == NULL) {
OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
goto err;
diff --git a/deps/boringssl/src/crypto/conf/conf_test.cc b/deps/boringssl/src/crypto/conf/conf_test.cc
new file mode 100644
index 0000000..65938e1
--- /dev/null
+++ b/deps/boringssl/src/crypto/conf/conf_test.cc
@@ -0,0 +1,44 @@
+/* Copyright (c) 2021, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/bio.h>
+#include <openssl/conf.h>
+
+#include <gtest/gtest.h>
+
+
+TEST(ConfTest, Parse) {
+ // Check that basic parsing works. (We strongly recommend that people don't
+ // use the [N]CONF functions.)
+
+ static const char kConf[] = R"(
+# Comment
+
+key=value
+
+[section_name]
+key=value2
+)";
+
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kConf, sizeof(kConf) - 1));
+ ASSERT_TRUE(bio);
+ bssl::UniquePtr<CONF> conf(NCONF_new(nullptr));
+ ASSERT_TRUE(conf);
+ ASSERT_TRUE(NCONF_load_bio(conf.get(), bio.get(), nullptr));
+ EXPECT_TRUE(NCONF_get_section(conf.get(), "section_name"));
+ EXPECT_FALSE(NCONF_get_section(conf.get(), "other_section"));
+ EXPECT_STREQ(NCONF_get_string(conf.get(), nullptr, "key"), "value");
+ EXPECT_STREQ(NCONF_get_string(conf.get(), "section_name", "key"), "value2");
+ EXPECT_STREQ(NCONF_get_string(conf.get(), "other_section", "key"), nullptr);
+}
diff --git a/deps/boringssl/src/crypto/cpu-arm-linux.c b/deps/boringssl/src/crypto/cpu-arm-linux.c
index c9d771f..962a4a5 100644
--- a/deps/boringssl/src/crypto/cpu-arm-linux.c
+++ b/deps/boringssl/src/crypto/cpu-arm-linux.c
@@ -175,7 +175,13 @@ void OPENSSL_cpuid_setup(void) {
hwcap = crypto_get_arm_hwcap_from_cpuinfo(&cpuinfo);
}
- // Clear NEON support if known broken.
+ // Clear NEON support if known broken. Note, if NEON is available statically,
+ // the non-NEON code is dropped and this workaround is a no-op.
+ //
+ // TODO(davidben): The Android NDK now builds with NEON statically available
+ // by default. Cronet still has some consumers that support NEON-less devices
+ // (b/150371744). Get metrics on whether they still see this CPU and, if not,
+ // remove this check entirely.
g_has_broken_neon = crypto_cpuinfo_has_broken_neon(&cpuinfo);
if (g_has_broken_neon) {
hwcap &= ~HWCAP_NEON;
@@ -186,7 +192,10 @@ void OPENSSL_cpuid_setup(void) {
OPENSSL_armcap_P |= ARMV7_NEON;
// Some ARMv8 Android devices don't expose AT_HWCAP2. Fall back to
- // /proc/cpuinfo. See https://crbug.com/596156.
+ // /proc/cpuinfo. See https://crbug.com/boringssl/46. As of February 2021,
+ // this is now rare (see Chrome's Net.NeedsHWCAP2Workaround metric), but AES
+ // and PMULL extensions are very useful, so we still carry the workaround
+ // for now.
unsigned long hwcap2 = 0;
if (getauxval != NULL) {
hwcap2 = getauxval(AT_HWCAP2);
diff --git a/deps/boringssl/src/crypto/cpu-arm.c b/deps/boringssl/src/crypto/cpu-arm.c
index ef395ea..e8596ac 100644
--- a/deps/boringssl/src/crypto/cpu-arm.c
+++ b/deps/boringssl/src/crypto/cpu-arm.c
@@ -22,15 +22,15 @@
extern uint32_t OPENSSL_armcap_P;
-char CRYPTO_is_NEON_capable_at_runtime(void) {
+int CRYPTO_is_NEON_capable_at_runtime(void) {
return (OPENSSL_armcap_P & ARMV7_NEON) != 0;
}
-int CRYPTO_is_ARMv8_AES_capable(void) {
+int CRYPTO_is_ARMv8_AES_capable_at_runtime(void) {
return (OPENSSL_armcap_P & ARMV8_AES) != 0;
}
-int CRYPTO_is_ARMv8_PMULL_capable(void) {
+int CRYPTO_is_ARMv8_PMULL_capable_at_runtime(void) {
return (OPENSSL_armcap_P & ARMV8_PMULL) != 0;
}
diff --git a/deps/boringssl/src/crypto/crypto_test.cc b/deps/boringssl/src/crypto/crypto_test.cc
index f6c2374..bf0bcd7 100644
--- a/deps/boringssl/src/crypto/crypto_test.cc
+++ b/deps/boringssl/src/crypto/crypto_test.cc
@@ -19,6 +19,8 @@
#include <openssl/base.h>
#include <openssl/crypto.h>
+#include <openssl/cipher.h>
+#include <openssl/mem.h>
#include <gtest/gtest.h>
@@ -33,3 +35,47 @@ TEST(CryptoTest, Version) {
EXPECT_EQ(expected,
std::string(OPENSSL_VERSION_TEXT).substr(0, strlen(expected)));
}
+
+TEST(CryptoTest, Strndup) {
+ bssl::UniquePtr<char> str(OPENSSL_strndup(nullptr, 0));
+ EXPECT_TRUE(str);
+ EXPECT_STREQ("", str.get());
+}
+
+#if defined(BORINGSSL_FIPS_COUNTERS)
+TEST(CryptoTest, FIPSCountersEVP) {
+ constexpr struct {
+ const EVP_CIPHER *(*cipher)();
+ fips_counter_t counter;
+ } kTests[] = {
+ {
+ EVP_aes_128_gcm,
+ fips_counter_evp_aes_128_gcm,
+ },
+ {
+ EVP_aes_256_gcm,
+ fips_counter_evp_aes_256_gcm,
+ },
+ {
+ EVP_aes_128_ctr,
+ fips_counter_evp_aes_128_ctr,
+ },
+ {
+ EVP_aes_256_ctr,
+ fips_counter_evp_aes_256_ctr,
+ },
+ };
+
+ uint8_t key[EVP_MAX_KEY_LENGTH] = {0};
+ uint8_t iv[EVP_MAX_IV_LENGTH] = {1};
+
+ for (const auto& test : kTests) {
+ const size_t before = FIPS_read_counter(test.counter);
+
+ bssl::ScopedEVP_CIPHER_CTX ctx;
+ ASSERT_TRUE(EVP_EncryptInit_ex(ctx.get(), test.cipher(), /*engine=*/nullptr,
+ key, iv));
+ ASSERT_GT(FIPS_read_counter(test.counter), before);
+ }
+}
+#endif // BORINGSSL_FIPS_COUNTERS
diff --git a/deps/boringssl/src/crypto/curve25519/curve25519.c b/deps/boringssl/src/crypto/curve25519/curve25519.c
index 232f6e0..ea48810 100644
--- a/deps/boringssl/src/crypto/curve25519/curve25519.c
+++ b/deps/boringssl/src/crypto/curve25519/curve25519.c
@@ -820,7 +820,7 @@ static void table_select(ge_precomp *t, int pos, signed char b) {
//
// Preconditions:
// a[31] <= 127
-void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t *a) {
+void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]) {
signed char e[64];
signed char carry;
ge_p1p1 r;
diff --git a/deps/boringssl/src/crypto/curve25519/internal.h b/deps/boringssl/src/crypto/curve25519/internal.h
index 01be307..76ff78f 100644
--- a/deps/boringssl/src/crypto/curve25519/internal.h
+++ b/deps/boringssl/src/crypto/curve25519/internal.h
@@ -106,7 +106,7 @@ typedef struct {
} ge_cached;
void x25519_ge_tobytes(uint8_t s[32], const ge_p2 *h);
-int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t *s);
+int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t s[32]);
void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
void x25519_ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
diff --git a/deps/boringssl/src/crypto/digest_extra/digest_extra.c b/deps/boringssl/src/crypto/digest_extra/digest_extra.c
index 311c5cb..8cbb28e 100644
--- a/deps/boringssl/src/crypto/digest_extra/digest_extra.c
+++ b/deps/boringssl/src/crypto/digest_extra/digest_extra.c
@@ -58,11 +58,12 @@
#include <string.h>
-#include <openssl/asn1.h>
#include <openssl/blake2.h>
#include <openssl/bytestring.h>
+#include <openssl/obj.h>
#include <openssl/nid.h>
+#include "../asn1/internal.h"
#include "../internal.h"
#include "../fipsmodule/digest/internal.h"
@@ -82,6 +83,7 @@ static const struct nid_to_digest nid_to_digest_mapping[] = {
{NID_sha256, EVP_sha256, SN_sha256, LN_sha256},
{NID_sha384, EVP_sha384, SN_sha384, LN_sha384},
{NID_sha512, EVP_sha512, SN_sha512, LN_sha512},
+ {NID_sha512_256, EVP_sha512_256, SN_sha512_256, LN_sha512_256},
{NID_md5_sha1, EVP_md5_sha1, SN_md5_sha1, LN_md5_sha1},
// As a remnant of signing |EVP_MD|s, OpenSSL returned the corresponding
// hash function when given a signature OID. To avoid unintended lax parsing
@@ -152,13 +154,14 @@ static const EVP_MD *cbs_to_md(const CBS *cbs) {
}
const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj) {
- // Handle objects with no corresponding OID.
+ // Handle objects with no corresponding OID. Note we don't use |OBJ_obj2nid|
+ // here to avoid pulling in the OID table.
if (obj->nid != NID_undef) {
return EVP_get_digestbynid(obj->nid);
}
CBS cbs;
- CBS_init(&cbs, obj->data, obj->length);
+ CBS_init(&cbs, OBJ_get0_data(obj), OBJ_length(obj));
return cbs_to_md(&cbs);
}
diff --git a/deps/boringssl/src/crypto/digest_extra/digest_test.cc b/deps/boringssl/src/crypto/digest_extra/digest_test.cc
index 80b5106..12858e2 100644
--- a/deps/boringssl/src/crypto/digest_extra/digest_test.cc
+++ b/deps/boringssl/src/crypto/digest_extra/digest_test.cc
@@ -163,7 +163,7 @@ static void TestDigest(const DigestTestVector *test) {
bssl::ScopedEVP_MD_CTX ctx;
// Test the input provided.
- ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), NULL));
+ ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
for (size_t i = 0; i < test->repeat; i++) {
ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), test->input, strlen(test->input)));
}
@@ -173,8 +173,8 @@ static void TestDigest(const DigestTestVector *test) {
CompareDigest(test, digest.get(), digest_len);
// Test the input one character at a time.
- ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), NULL));
- ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), NULL, 0));
+ ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
+ ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), nullptr, 0));
for (size_t i = 0; i < test->repeat; i++) {
for (const char *p = test->input; *p; p++) {
ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), p, 1));
@@ -185,7 +185,7 @@ static void TestDigest(const DigestTestVector *test) {
CompareDigest(test, digest.get(), digest_len);
// Test with unaligned input.
- ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), NULL));
+ ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
std::vector<char> unaligned(strlen(test->input) + 1);
char *ptr = unaligned.data();
if ((reinterpret_cast<uintptr_t>(ptr) & 1) == 0) {
@@ -199,7 +199,7 @@ static void TestDigest(const DigestTestVector *test) {
CompareDigest(test, digest.get(), digest_len);
// Make a copy of the digest in the initial state.
- ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), NULL));
+ ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
bssl::ScopedEVP_MD_CTX copy;
ASSERT_TRUE(EVP_MD_CTX_copy_ex(copy.get(), ctx.get()));
for (size_t i = 0; i < test->repeat; i++) {
@@ -220,6 +220,27 @@ static void TestDigest(const DigestTestVector *test) {
ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len));
CompareDigest(test, digest.get(), digest_len);
+ // Move the digest from the initial state.
+ ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
+ copy = std::move(ctx);
+ for (size_t i = 0; i < test->repeat; i++) {
+ ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input, strlen(test->input)));
+ }
+ ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len));
+ CompareDigest(test, digest.get(), digest_len);
+
+ // Move the digest with half the input provided.
+ ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr));
+ ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), test->input, half));
+ copy = std::move(ctx);
+ ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input + half,
+ strlen(test->input) - half));
+ for (size_t i = 1; i < test->repeat; i++) {
+ ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input, strlen(test->input)));
+ }
+ ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len));
+ CompareDigest(test, digest.get(), digest_len);
+
// Test the one-shot function.
if (test->md.one_shot_func && test->repeat == 1) {
uint8_t *out = test->md.one_shot_func((const uint8_t *)test->input,
diff --git a/deps/boringssl/src/crypto/err/err.c b/deps/boringssl/src/crypto/err/err.c
index 7973a0e..4aab75b 100644
--- a/deps/boringssl/src/crypto/err/err.c
+++ b/deps/boringssl/src/crypto/err/err.c
@@ -368,84 +368,6 @@ void ERR_clear_system_error(void) {
errno = 0;
}
-char *ERR_error_string(uint32_t packed_error, char *ret) {
- static char buf[ERR_ERROR_STRING_BUF_LEN];
-
- if (ret == NULL) {
- // TODO(fork): remove this.
- ret = buf;
- }
-
-#if !defined(NDEBUG)
- // This is aimed to help catch callers who don't provide
- // |ERR_ERROR_STRING_BUF_LEN| bytes of space.
- OPENSSL_memset(ret, 0, ERR_ERROR_STRING_BUF_LEN);
-#endif
-
- return ERR_error_string_n(packed_error, ret, ERR_ERROR_STRING_BUF_LEN);
-}
-
-char *ERR_error_string_n(uint32_t packed_error, char *buf, size_t len) {
- char lib_buf[64], reason_buf[64];
- const char *lib_str, *reason_str;
- unsigned lib, reason;
-
- if (len == 0) {
- return NULL;
- }
-
- lib = ERR_GET_LIB(packed_error);
- reason = ERR_GET_REASON(packed_error);
-
- lib_str = ERR_lib_error_string(packed_error);
- reason_str = ERR_reason_error_string(packed_error);
-
- if (lib_str == NULL) {
- BIO_snprintf(lib_buf, sizeof(lib_buf), "lib(%u)", lib);
- lib_str = lib_buf;
- }
-
- if (reason_str == NULL) {
- BIO_snprintf(reason_buf, sizeof(reason_buf), "reason(%u)", reason);
- reason_str = reason_buf;
- }
-
- BIO_snprintf(buf, len, "error:%08" PRIx32 ":%s:OPENSSL_internal:%s",
- packed_error, lib_str, reason_str);
-
- if (strlen(buf) == len - 1) {
- // output may be truncated; make sure we always have 5 colon-separated
- // fields, i.e. 4 colons.
- static const unsigned num_colons = 4;
- unsigned i;
- char *s = buf;
-
- if (len <= num_colons) {
- // In this situation it's not possible to ensure that the correct number
- // of colons are included in the output.
- return buf;
- }
-
- for (i = 0; i < num_colons; i++) {
- char *colon = strchr(s, ':');
- char *last_pos = &buf[len - 1] - num_colons + i;
-
- if (colon == NULL || colon > last_pos) {
- // set colon |i| at last possible position (buf[len-1] is the
- // terminating 0). If we're setting this colon, then all whole of the
- // rest of the string must be colons in order to have the correct
- // number.
- OPENSSL_memset(last_pos, ':', num_colons - i);
- break;
- }
-
- s = colon + 1;
- }
- }
-
- return buf;
-}
-
// err_string_cmp is a compare function for searching error values with
// |bsearch| in |err_string_lookup|.
static int err_string_cmp(const void *a, const void *b) {
@@ -530,7 +452,7 @@ static const char *const kLibraryNames[ERR_NUM_LIBS] = {
"User defined functions", // ERR_LIB_USER
};
-const char *ERR_lib_error_string(uint32_t packed_error) {
+static const char *err_lib_error_string(uint32_t packed_error) {
const uint32_t lib = ERR_GET_LIB(packed_error);
if (lib >= ERR_NUM_LIBS) {
@@ -539,11 +461,16 @@ const char *ERR_lib_error_string(uint32_t packed_error) {
return kLibraryNames[lib];
}
+const char *ERR_lib_error_string(uint32_t packed_error) {
+ const char *ret = err_lib_error_string(packed_error);
+ return ret == NULL ? "unknown library" : ret;
+}
+
const char *ERR_func_error_string(uint32_t packed_error) {
return "OPENSSL_internal";
}
-const char *ERR_reason_error_string(uint32_t packed_error) {
+static const char *err_reason_error_string(uint32_t packed_error) {
const uint32_t lib = ERR_GET_LIB(packed_error);
const uint32_t reason = ERR_GET_REASON(packed_error);
@@ -579,6 +506,86 @@ const char *ERR_reason_error_string(uint32_t packed_error) {
kOpenSSLReasonValuesLen, kOpenSSLReasonStringData);
}
+const char *ERR_reason_error_string(uint32_t packed_error) {
+ const char *ret = err_reason_error_string(packed_error);
+ return ret == NULL ? "unknown error" : ret;
+}
+
+char *ERR_error_string(uint32_t packed_error, char *ret) {
+ static char buf[ERR_ERROR_STRING_BUF_LEN];
+
+ if (ret == NULL) {
+ // TODO(fork): remove this.
+ ret = buf;
+ }
+
+#if !defined(NDEBUG)
+ // This is aimed to help catch callers who don't provide
+ // |ERR_ERROR_STRING_BUF_LEN| bytes of space.
+ OPENSSL_memset(ret, 0, ERR_ERROR_STRING_BUF_LEN);
+#endif
+
+ return ERR_error_string_n(packed_error, ret, ERR_ERROR_STRING_BUF_LEN);
+}
+
+char *ERR_error_string_n(uint32_t packed_error, char *buf, size_t len) {
+ if (len == 0) {
+ return NULL;
+ }
+
+ unsigned lib = ERR_GET_LIB(packed_error);
+ unsigned reason = ERR_GET_REASON(packed_error);
+
+ const char *lib_str = err_lib_error_string(packed_error);
+ const char *reason_str = err_reason_error_string(packed_error);
+
+ char lib_buf[64], reason_buf[64];
+ if (lib_str == NULL) {
+ BIO_snprintf(lib_buf, sizeof(lib_buf), "lib(%u)", lib);
+ lib_str = lib_buf;
+ }
+
+ if (reason_str == NULL) {
+ BIO_snprintf(reason_buf, sizeof(reason_buf), "reason(%u)", reason);
+ reason_str = reason_buf;
+ }
+
+ BIO_snprintf(buf, len, "error:%08" PRIx32 ":%s:OPENSSL_internal:%s",
+ packed_error, lib_str, reason_str);
+
+ if (strlen(buf) == len - 1) {
+ // output may be truncated; make sure we always have 5 colon-separated
+ // fields, i.e. 4 colons.
+ static const unsigned num_colons = 4;
+ unsigned i;
+ char *s = buf;
+
+ if (len <= num_colons) {
+ // In this situation it's not possible to ensure that the correct number
+ // of colons are included in the output.
+ return buf;
+ }
+
+ for (i = 0; i < num_colons; i++) {
+ char *colon = strchr(s, ':');
+ char *last_pos = &buf[len - 1] - num_colons + i;
+
+ if (colon == NULL || colon > last_pos) {
+ // set colon |i| at last possible position (buf[len-1] is the
+ // terminating 0). If we're setting this colon, then all whole of the
+ // rest of the string must be colons in order to have the correct
+ // number.
+ OPENSSL_memset(last_pos, ':', num_colons - i);
+ break;
+ }
+
+ s = colon + 1;
+ }
+ }
+
+ return buf;
+}
+
void ERR_print_errors_cb(ERR_print_errors_callback_t callback, void *ctx) {
char buf[ERR_ERROR_STRING_BUF_LEN];
char buf2[1024];
diff --git a/deps/boringssl/src/crypto/err/err_test.cc b/deps/boringssl/src/crypto/err/err_test.cc
index 41bcc78..b41f8dd 100644
--- a/deps/boringssl/src/crypto/err/err_test.cc
+++ b/deps/boringssl/src/crypto/err/err_test.cc
@@ -283,3 +283,13 @@ TEST(ErrTest, String) {
// A buffer length of zero should not touch the buffer.
ERR_error_string_n(err, nullptr, 0);
}
+
+// Error-printing functions should return something with unknown errors.
+TEST(ErrTest, UnknownError) {
+ uint32_t err = ERR_PACK(0xff, 0xfff);
+ EXPECT_TRUE(ERR_lib_error_string(err));
+ EXPECT_TRUE(ERR_reason_error_string(err));
+ char buf[128];
+ ERR_error_string_n(err, buf, sizeof(buf));
+ EXPECT_NE(0u, strlen(buf));
+}
diff --git a/deps/boringssl/src/crypto/evp/evp.c b/deps/boringssl/src/crypto/evp/evp.c
index 653d657..bb31645 100644
--- a/deps/boringssl/src/crypto/evp/evp.c
+++ b/deps/boringssl/src/crypto/evp/evp.c
@@ -429,6 +429,15 @@ int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
0, (void *)out_md);
}
+void *EVP_PKEY_get0(const EVP_PKEY *pkey) {
+ // Node references, but never calls this function, so for now we return NULL.
+ // If other projects require complete support, call |EVP_PKEY_get0_RSA|, etc.,
+ // rather than reading |pkey->pkey.ptr| directly. This avoids problems if our
+ // internal representation does not match the type the caller expects from
+ // OpenSSL.
+ return NULL;
+}
+
void OpenSSL_add_all_algorithms(void) {}
void OPENSSL_add_all_algorithms_conf(void) {}
diff --git a/deps/boringssl/src/crypto/fipsmodule/CMakeLists.txt b/deps/boringssl/src/crypto/fipsmodule/CMakeLists.txt
index 83cf3f7..73f8a02 100644
--- a/deps/boringssl/src/crypto/fipsmodule/CMakeLists.txt
+++ b/deps/boringssl/src/crypto/fipsmodule/CMakeLists.txt
@@ -1,6 +1,6 @@
include_directories(../../include)
-if(${ARCH} STREQUAL "x86_64")
+if(ARCH STREQUAL "x86_64")
set(
BCM_ASM_SOURCES
@@ -22,7 +22,7 @@ if(${ARCH} STREQUAL "x86_64")
)
endif()
-if(${ARCH} STREQUAL "x86")
+if(ARCH STREQUAL "x86")
set(
BCM_ASM_SOURCES
@@ -40,7 +40,7 @@ if(${ARCH} STREQUAL "x86")
)
endif()
-if(${ARCH} STREQUAL "arm")
+if(ARCH STREQUAL "arm")
set(
BCM_ASM_SOURCES
@@ -56,7 +56,7 @@ if(${ARCH} STREQUAL "arm")
)
endif()
-if(${ARCH} STREQUAL "aarch64")
+if(ARCH STREQUAL "aarch64")
set(
BCM_ASM_SOURCES
@@ -71,7 +71,7 @@ if(${ARCH} STREQUAL "aarch64")
)
endif()
-if(${ARCH} STREQUAL "ppc64le")
+if(ARCH STREQUAL "ppc64le")
set(
BCM_ASM_SOURCES
@@ -160,7 +160,7 @@ if(FIPS_DELOCATE)
bcm.c
)
- if(${ARCH} STREQUAL "aarch64")
+ if(ARCH STREQUAL "aarch64")
# Perlasm output on Aarch64 needs to pass through the C preprocessor before
# it can be parsed by delocate.
foreach(asm ${BCM_ASM_SOURCES})
@@ -199,12 +199,15 @@ if(FIPS_DELOCATE)
set_target_properties(bcm_hashunset PROPERTIES LINKER_LANGUAGE C)
set(MAYBE_INJECT_HASH_SHA256_FLAG "")
- if (ARCH STREQUAL "aarch64")
+ # If building with OPENSSL_NO_ASM then ARCH will be "generic", but we still
+ # need to use SHA-256. Since this only matters for FIPS, we only need to
+ # worry about the Linux spelling of AArch64.
+ if (ARCH STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
set(MAYBE_INJECT_HASH_SHA256_FLAG "-sha256")
endif()
go_executable(inject_hash
- boringssl.googlesource.com/boringssl/util/fipstools/inject_hash)
+ boringssl.googlesource.com/boringssl/util/fipstools/inject_hash)
add_custom_command(
OUTPUT bcm.o
COMMAND ./inject_hash -o bcm.o -in-archive $<TARGET_FILE:bcm_hashunset> ${MAYBE_INJECT_HASH_SHA256_FLAG}
@@ -223,7 +226,6 @@ if(FIPS_DELOCATE)
OBJECT
fips_shared_support.c
- is_fips.c
)
add_dependencies(fipsmodule global_target)
@@ -240,7 +242,6 @@ elseif(FIPS_SHARED)
OBJECT
fips_shared_support.c
- is_fips.c
)
add_dependencies(fipsmodule global_target)
@@ -273,7 +274,6 @@ else()
bcm.c
fips_shared_support.c
- is_fips.c
${BCM_ASM_SOURCES}
)
diff --git a/deps/boringssl/src/crypto/fipsmodule/bcm.c b/deps/boringssl/src/crypto/fipsmodule/bcm.c
index 601c4a8..3a1ad15 100644
--- a/deps/boringssl/src/crypto/fipsmodule/bcm.c
+++ b/deps/boringssl/src/crypto/fipsmodule/bcm.c
@@ -97,6 +97,7 @@
#include "rsa/padding.c"
#include "rsa/rsa.c"
#include "rsa/rsa_impl.c"
+#include "self_check/fips.c"
#include "self_check/self_check.c"
#include "sha/sha1-altivec.c"
#include "sha/sha1.c"
diff --git a/deps/boringssl/src/crypto/fipsmodule/bn/bn_test.cc b/deps/boringssl/src/crypto/fipsmodule/bn/bn_test.cc
index 9791437..72ec8c2 100644
--- a/deps/boringssl/src/crypto/fipsmodule/bn/bn_test.cc
+++ b/deps/boringssl/src/crypto/fipsmodule/bn/bn_test.cc
@@ -556,6 +556,19 @@ static void TestQuotient(BIGNUMFileTest *t, BN_CTX *ctx) {
EXPECT_BIGNUMS_EQUAL("A / B", quotient.get(), ret.get());
EXPECT_BIGNUMS_EQUAL("A % B", remainder.get(), ret2.get());
+ ASSERT_TRUE(BN_copy(ret.get(), a.get()));
+ ASSERT_TRUE(BN_copy(ret2.get(), b.get()));
+ ASSERT_TRUE(BN_div(ret.get(), ret2.get(), ret.get(), ret2.get(), ctx));
+ EXPECT_BIGNUMS_EQUAL("A / B (in-place)", quotient.get(), ret.get());
+ EXPECT_BIGNUMS_EQUAL("A % B (in-place)", remainder.get(), ret2.get());
+
+ ASSERT_TRUE(BN_copy(ret2.get(), a.get()));
+ ASSERT_TRUE(BN_copy(ret.get(), b.get()));
+ ASSERT_TRUE(BN_div(ret.get(), ret2.get(), ret2.get(), ret.get(), ctx));
+ EXPECT_BIGNUMS_EQUAL("A / B (in-place, swapped)", quotient.get(), ret.get());
+ EXPECT_BIGNUMS_EQUAL("A % B (in-place, swapped)", remainder.get(),
+ ret2.get());
+
ASSERT_TRUE(BN_mul(ret.get(), quotient.get(), b.get(), ctx));
ASSERT_TRUE(BN_add(ret.get(), ret.get(), remainder.get()));
EXPECT_BIGNUMS_EQUAL("Quotient * B + Remainder", a.get(), ret.get());
@@ -600,9 +613,17 @@ static void TestQuotient(BIGNUMFileTest *t, BN_CTX *ctx) {
}
}
- ASSERT_TRUE(bn_div_consttime(ret.get(), ret2.get(), a.get(), b.get(), ctx));
+ ASSERT_TRUE(bn_div_consttime(ret.get(), ret2.get(), a.get(), b.get(),
+ /*divisor_min_bits=*/0, ctx));
EXPECT_BIGNUMS_EQUAL("A / B (constant-time)", quotient.get(), ret.get());
EXPECT_BIGNUMS_EQUAL("A % B (constant-time)", remainder.get(), ret2.get());
+
+ ASSERT_TRUE(bn_div_consttime(ret.get(), ret2.get(), a.get(), b.get(),
+ /*divisor_min_bits=*/BN_num_bits(b.get()), ctx));
+ EXPECT_BIGNUMS_EQUAL("A / B (constant-time, public width)", quotient.get(),
+ ret.get());
+ EXPECT_BIGNUMS_EQUAL("A % B (constant-time, public width)", remainder.get(),
+ ret2.get());
}
static void TestModMul(BIGNUMFileTest *t, BN_CTX *ctx) {
diff --git a/deps/boringssl/src/crypto/fipsmodule/bn/div.c b/deps/boringssl/src/crypto/fipsmodule/bn/div.c
index 333c770..02b9931 100644
--- a/deps/boringssl/src/crypto/fipsmodule/bn/div.c
+++ b/deps/boringssl/src/crypto/fipsmodule/bn/div.c
@@ -285,8 +285,10 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
// pointer to the 'top' of snum
wnump = &(snum->d[num_n - 1]);
- // Setup to 'res'
- res->neg = (numerator->neg ^ divisor->neg);
+ // Setup |res|. |numerator| and |res| may alias, so we save |numerator->neg|
+ // for later.
+ const int numerator_neg = numerator->neg;
+ res->neg = (numerator_neg ^ divisor->neg);
if (!bn_wexpand(res, loop + 1)) {
goto err;
}
@@ -379,14 +381,11 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
bn_set_minimal_width(snum);
if (rem != NULL) {
- // Keep a copy of the neg flag in numerator because if |rem| == |numerator|
- // |BN_rshift| will overwrite it.
- int neg = numerator->neg;
if (!BN_rshift(rem, snum, norm_shift)) {
goto err;
}
if (!BN_is_zero(rem)) {
- rem->neg = neg;
+ rem->neg = numerator_neg;
}
}
@@ -457,7 +456,7 @@ void bn_mod_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
int bn_div_consttime(BIGNUM *quotient, BIGNUM *remainder,
const BIGNUM *numerator, const BIGNUM *divisor,
- BN_CTX *ctx) {
+ unsigned divisor_min_bits, BN_CTX *ctx) {
if (BN_is_negative(numerator) || BN_is_negative(divisor)) {
OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
return 0;
@@ -497,8 +496,26 @@ int bn_div_consttime(BIGNUM *quotient, BIGNUM *remainder,
r->neg = 0;
// Incorporate |numerator| into |r|, one bit at a time, reducing after each
- // step. At the start of each loop iteration, |r| < |divisor|
- for (int i = numerator->width - 1; i >= 0; i--) {
+ // step. We maintain the invariant that |0 <= r < divisor| and
+ // |q * divisor + r = n| where |n| is the portion of |numerator| incorporated
+ // so far.
+ //
+ // First, we short-circuit the loop: if we know |divisor| has at least
+ // |divisor_min_bits| bits, the top |divisor_min_bits - 1| can be incorporated
+ // without reductions. This significantly speeds up |RSA_check_key|. For
+ // simplicity, we round down to a whole number of words.
+ assert(divisor_min_bits <= BN_num_bits(divisor));
+ int initial_words = 0;
+ if (divisor_min_bits > 0) {
+ initial_words = (divisor_min_bits - 1) / BN_BITS2;
+ if (initial_words > numerator->width) {
+ initial_words = numerator->width;
+ }
+ OPENSSL_memcpy(r->d, numerator->d + numerator->width - initial_words,
+ initial_words * sizeof(BN_ULONG));
+ }
+
+ for (int i = numerator->width - initial_words - 1; i >= 0; i--) {
for (int bit = BN_BITS2 - 1; bit >= 0; bit--) {
// Incorporate the next bit of the numerator, by computing
// r = 2*r or 2*r + 1. Note the result fits in one more word. We store the
diff --git a/deps/boringssl/src/crypto/fipsmodule/bn/gcd_extra.c b/deps/boringssl/src/crypto/fipsmodule/bn/gcd_extra.c
index 30540e3..53ab170 100644
--- a/deps/boringssl/src/crypto/fipsmodule/bn/gcd_extra.c
+++ b/deps/boringssl/src/crypto/fipsmodule/bn/gcd_extra.c
@@ -157,10 +157,11 @@ int bn_lcm_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
BN_CTX_start(ctx);
unsigned shift;
BIGNUM *gcd = BN_CTX_get(ctx);
- int ret = gcd != NULL &&
+ int ret = gcd != NULL && //
bn_mul_consttime(r, a, b, ctx) &&
bn_gcd_consttime(gcd, &shift, a, b, ctx) &&
- bn_div_consttime(r, NULL, r, gcd, ctx) &&
+ // |gcd| has a secret bit width.
+ bn_div_consttime(r, NULL, r, gcd, /*divisor_min_bits=*/0, ctx) &&
bn_rshift_secret_shift(r, r, shift, ctx);
BN_CTX_end(ctx);
return ret;
diff --git a/deps/boringssl/src/crypto/fipsmodule/bn/internal.h b/deps/boringssl/src/crypto/fipsmodule/bn/internal.h
index 623e0c6..cab9a81 100644
--- a/deps/boringssl/src/crypto/fipsmodule/bn/internal.h
+++ b/deps/boringssl/src/crypto/fipsmodule/bn/internal.h
@@ -297,7 +297,7 @@ void bn_mul_comba4(BN_ULONG r[8], const BN_ULONG a[4], const BN_ULONG b[4]);
void bn_mul_comba8(BN_ULONG r[16], const BN_ULONG a[8], const BN_ULONG b[8]);
// bn_sqr_comba8 sets |r| to |a|^2.
-void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[4]);
+void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[8]);
// bn_sqr_comba4 sets |r| to |a|^2.
void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]);
@@ -552,12 +552,15 @@ int bn_sqr_consttime(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx);
// bn_div_consttime behaves like |BN_div|, but it rejects negative inputs and
// treats both inputs, including their magnitudes, as secret. It is, as a
// result, much slower than |BN_div| and should only be used for rare operations
-// where Montgomery reduction is not available.
+// where Montgomery reduction is not available. |divisor_min_bits| is a
+// public lower bound for |BN_num_bits(divisor)|. When |divisor|'s bit width is
+// public, this can speed up the operation.
//
// Note that |quotient->width| will be set pessimally to |numerator->width|.
OPENSSL_EXPORT int bn_div_consttime(BIGNUM *quotient, BIGNUM *remainder,
const BIGNUM *numerator,
- const BIGNUM *divisor, BN_CTX *ctx);
+ const BIGNUM *divisor,
+ unsigned divisor_min_bits, BN_CTX *ctx);
// bn_is_relatively_prime checks whether GCD(|x|, |y|) is one. On success, it
// returns one and sets |*out_relatively_prime| to one if the GCD was one and
diff --git a/deps/boringssl/src/crypto/fipsmodule/bn/prime.c b/deps/boringssl/src/crypto/fipsmodule/bn/prime.c
index 262822f..2e58cae 100644
--- a/deps/boringssl/src/crypto/fipsmodule/bn/prime.c
+++ b/deps/boringssl/src/crypto/fipsmodule/bn/prime.c
@@ -115,10 +115,6 @@
#include "../../internal.h"
-// The quick sieve algorithm approach to weeding out primes is Philip
-// Zimmermann's, as implemented in PGP. I have had a read of his comments and
-// implemented my own version.
-
// kPrimes contains the first 1024 primes.
static const uint16_t kPrimes[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
diff --git a/deps/boringssl/src/crypto/fipsmodule/cipher/cipher.c b/deps/boringssl/src/crypto/fipsmodule/cipher/cipher.c
index c50c6c5..51c96b4 100644
--- a/deps/boringssl/src/crypto/fipsmodule/cipher/cipher.c
+++ b/deps/boringssl/src/crypto/fipsmodule/cipher/cipher.c
@@ -57,6 +57,7 @@
#include <openssl/cipher.h>
#include <assert.h>
+#include <limits.h>
#include <string.h>
#include <openssl/err.h>
@@ -224,7 +225,6 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
ctx->buf_len = 0;
ctx->final_used = 0;
- ctx->block_mask = ctx->cipher->block_size - 1;
return 1;
}
@@ -238,16 +238,31 @@ int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 0);
}
+// block_remainder returns the number of bytes to remove from |len| to get a
+// multiple of |ctx|'s block size.
+static int block_remainder(const EVP_CIPHER_CTX *ctx, int len) {
+ // |block_size| must be a power of two.
+ assert(ctx->cipher->block_size != 0);
+ assert((ctx->cipher->block_size & (ctx->cipher->block_size - 1)) == 0);
+ return len & (ctx->cipher->block_size - 1);
+}
+
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, int in_len) {
- int i, j, bl;
+ // Ciphers that use blocks may write up to |bl| extra bytes. Ensure the output
+ // does not overflow |*out_len|.
+ int bl = ctx->cipher->block_size;
+ if (bl > 1 && in_len > INT_MAX - bl) {
+ OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW);
+ return 0;
+ }
if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
- i = ctx->cipher->cipher(ctx, out, in, in_len);
- if (i < 0) {
+ int ret = ctx->cipher->cipher(ctx, out, in, in_len);
+ if (ret < 0) {
return 0;
} else {
- *out_len = i;
+ *out_len = ret;
}
return 1;
}
@@ -257,7 +272,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
return in_len == 0;
}
- if (ctx->buf_len == 0 && (in_len & ctx->block_mask) == 0) {
+ if (ctx->buf_len == 0 && block_remainder(ctx, in_len) == 0) {
if (ctx->cipher->cipher(ctx, out, in, in_len)) {
*out_len = in_len;
return 1;
@@ -267,8 +282,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
}
}
- i = ctx->buf_len;
- bl = ctx->cipher->block_size;
+ int i = ctx->buf_len;
assert(bl <= (int)sizeof(ctx->buf));
if (i != 0) {
if (bl - i > in_len) {
@@ -277,7 +291,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
*out_len = 0;
return 1;
} else {
- j = bl - i;
+ int j = bl - i;
OPENSSL_memcpy(&ctx->buf[i], in, j);
if (!ctx->cipher->cipher(ctx, out, ctx->buf, bl)) {
return 0;
@@ -291,7 +305,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
*out_len = 0;
}
- i = in_len & ctx->block_mask;
+ i = block_remainder(ctx, in_len);
in_len -= i;
if (in_len > 0) {
if (!ctx->cipher->cipher(ctx, out, in, in_len)) {
@@ -353,8 +367,13 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, int in_len) {
- int fix_len;
- unsigned int b;
+ // Ciphers that use blocks may write up to |bl| extra bytes. Ensure the output
+ // does not overflow |*out_len|.
+ unsigned int b = ctx->cipher->block_size;
+ if (b > 1 && in_len > INT_MAX - (int)b) {
+ OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW);
+ return 0;
+ }
if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
int r = ctx->cipher->cipher(ctx, out, in, in_len);
@@ -376,15 +395,12 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
return EVP_EncryptUpdate(ctx, out, out_len, in, in_len);
}
- b = ctx->cipher->block_size;
assert(b <= sizeof(ctx->final));
-
+ int fix_len = 0;
if (ctx->final_used) {
OPENSSL_memcpy(out, ctx->final, b);
out += b;
fix_len = 1;
- } else {
- fix_len = 0;
}
if (!EVP_EncryptUpdate(ctx, out, out_len, in, in_len)) {
diff --git a/deps/boringssl/src/crypto/fipsmodule/cipher/e_aes.c b/deps/boringssl/src/crypto/fipsmodule/cipher/e_aes.c
index 6df2b7b..f77133f 100644
--- a/deps/boringssl/src/crypto/fipsmodule/cipher/e_aes.c
+++ b/deps/boringssl/src/crypto/fipsmodule/cipher/e_aes.c
@@ -141,10 +141,22 @@ typedef struct {
static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
const uint8_t *iv, int enc) {
- int ret, mode;
+ int ret;
EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+ const int mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK;
+
+ if (mode == EVP_CIPH_CTR_MODE) {
+ switch (ctx->key_len) {
+ case 16:
+ boringssl_fips_inc_counter(fips_counter_evp_aes_128_ctr);
+ break;
+
+ case 32:
+ boringssl_fips_inc_counter(fips_counter_evp_aes_256_ctr);
+ break;
+ }
+ }
- mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK;
if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) {
if (hwaes_capable()) {
ret = aes_hw_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
@@ -353,6 +365,17 @@ static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
if (!iv && !key) {
return 1;
}
+
+ switch (ctx->key_len) {
+ case 16:
+ boringssl_fips_inc_counter(fips_counter_evp_aes_128_gcm);
+ break;
+
+ case 32:
+ boringssl_fips_inc_counter(fips_counter_evp_aes_256_gcm);
+ break;
+ }
+
if (key) {
OPENSSL_memset(&gctx->gcm, 0, sizeof(gctx->gcm));
gctx->ctr = aes_ctr_set_key(&gctx->ks.ks, &gctx->gcm.gcm_key, NULL, key,
diff --git a/deps/boringssl/src/crypto/fipsmodule/digest/digest.c b/deps/boringssl/src/crypto/fipsmodule/digest/digest.c
index 6b0c198..059d72c 100644
--- a/deps/boringssl/src/crypto/fipsmodule/digest/digest.c
+++ b/deps/boringssl/src/crypto/fipsmodule/digest/digest.c
@@ -68,6 +68,8 @@
int EVP_MD_type(const EVP_MD *md) { return md->type; }
+int EVP_MD_nid(const EVP_MD *md) { return EVP_MD_type(md); }
+
uint32_t EVP_MD_flags(const EVP_MD *md) { return md->flags; }
size_t EVP_MD_size(const EVP_MD *md) { return md->md_size; }
@@ -177,6 +179,13 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
return 1;
}
+void EVP_MD_CTX_move(EVP_MD_CTX *out, EVP_MD_CTX *in) {
+ EVP_MD_CTX_cleanup(out);
+ // While not guaranteed, |EVP_MD_CTX| is currently safe to move with |memcpy|.
+ OPENSSL_memcpy(out, in, sizeof(EVP_MD_CTX));
+ EVP_MD_CTX_init(in);
+}
+
int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
EVP_MD_CTX_init(out);
return EVP_MD_CTX_copy_ex(out, in);
diff --git a/deps/boringssl/src/crypto/fipsmodule/digest/digests.c b/deps/boringssl/src/crypto/fipsmodule/digest/digests.c
index 16daeba..f006ebb 100644
--- a/deps/boringssl/src/crypto/fipsmodule/digest/digests.c
+++ b/deps/boringssl/src/crypto/fipsmodule/digest/digests.c
@@ -247,13 +247,21 @@ static void sha512_256_init(EVP_MD_CTX *ctx) {
CHECK(SHA512_256_Init(ctx->md_data));
}
+static void sha512_256_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+ CHECK(SHA512_256_Update(ctx->md_data, data, count));
+}
+
+static void sha512_256_final(EVP_MD_CTX *ctx, uint8_t *md) {
+ CHECK(SHA512_256_Final(md, ctx->md_data));
+}
+
DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha512_256) {
out->type = NID_sha512_256;
out->md_size = SHA512_256_DIGEST_LENGTH;
out->flags = 0;
out->init = sha512_256_init;
- out->update = sha512_update;
- out->final = sha512_final;
+ out->update = sha512_256_update;
+ out->final = sha512_256_final;
out->block_size = 128;
out->ctx_size = sizeof(SHA512_CTX);
}
diff --git a/deps/boringssl/src/crypto/fipsmodule/digest/md32_common.h b/deps/boringssl/src/crypto/fipsmodule/digest/md32_common.h
index 07d39d9..129ec48 100644
--- a/deps/boringssl/src/crypto/fipsmodule/digest/md32_common.h
+++ b/deps/boringssl/src/crypto/fipsmodule/digest/md32_common.h
@@ -46,6 +46,9 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ==================================================================== */
+#ifndef OPENSSL_HEADER_DIGEST_MD32_COMMON_H
+#define OPENSSL_HEADER_DIGEST_MD32_COMMON_H
+
#include <openssl/base.h>
#include <assert.h>
@@ -59,22 +62,15 @@ extern "C" {
// This is a generic 32-bit "collector" for message digest algorithms. It
// collects input character stream into chunks of 32-bit values and invokes the
-// block function that performs the actual hash calculations. To make use of
-// this mechanism, the following macros must be defined before including
-// md32_common.h.
-//
-// One of |DATA_ORDER_IS_BIG_ENDIAN| or |DATA_ORDER_IS_LITTLE_ENDIAN| must be
-// defined to specify the byte order of the input stream.
-//
-// |HASH_CBLOCK| must be defined as the integer block size, in bytes.
+// block function that performs the actual hash calculations.
//
-// |HASH_CTX| must be defined as the name of the context structure, which must
-// have at least the following members:
+// To make use of this mechanism, the hash context should be defined with the
+// following parameters.
//
// typedef struct <name>_state_st {
// uint32_t h[<chaining length> / sizeof(uint32_t)];
// uint32_t Nl, Nh;
-// uint8_t data[HASH_CBLOCK];
+// uint8_t data[<block size>];
// unsigned num;
// ...
// } <NAME>_CTX;
@@ -83,186 +79,117 @@ extern "C" {
// any truncation (e.g. 64 for SHA-224 and SHA-256, 128 for SHA-384 and
// SHA-512).
//
-// |HASH_UPDATE| must be defined as the name of the "Update" function to
-// generate.
-//
-// |HASH_TRANSFORM| must be defined as the the name of the "Transform"
-// function to generate.
-//
-// |HASH_FINAL| must be defined as the name of "Final" function to generate.
-//
-// |HASH_BLOCK_DATA_ORDER| must be defined as the name of the "Block" function.
-// That function must be implemented manually. It must be capable of operating
-// on *unaligned* input data in its original (data) byte order. It must have
-// this signature:
-//
-// void HASH_BLOCK_DATA_ORDER(uint32_t *state, const uint8_t *data,
-// size_t num);
-//
-// It must update the hash state |state| with |num| blocks of data from |data|,
-// where each block is |HASH_CBLOCK| bytes; i.e. |data| points to a array of
-// |HASH_CBLOCK * num| bytes. |state| points to the |h| member of a |HASH_CTX|,
-// and so will have |<chaining length> / sizeof(uint32_t)| elements.
-//
-// |HASH_MAKE_STRING(c, s)| must be defined as a block statement that converts
-// the hash state |c->h| into the output byte order, storing the result in |s|.
-
-#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN)
-#error "DATA_ORDER must be defined!"
-#endif
-
-#ifndef HASH_CBLOCK
-#error "HASH_CBLOCK must be defined!"
-#endif
-#ifndef HASH_CTX
-#error "HASH_CTX must be defined!"
-#endif
-
-#ifndef HASH_UPDATE
-#error "HASH_UPDATE must be defined!"
-#endif
-#ifndef HASH_TRANSFORM
-#error "HASH_TRANSFORM must be defined!"
-#endif
-#ifndef HASH_FINAL
-#error "HASH_FINAL must be defined!"
-#endif
-
-#ifndef HASH_BLOCK_DATA_ORDER
-#error "HASH_BLOCK_DATA_ORDER must be defined!"
-#endif
-
-#ifndef HASH_MAKE_STRING
-#error "HASH_MAKE_STRING must be defined!"
-#endif
-
-#if defined(DATA_ORDER_IS_BIG_ENDIAN)
-
-#define HOST_c2l(c, l) \
- do { \
- (l) = (((uint32_t)(*((c)++))) << 24); \
- (l) |= (((uint32_t)(*((c)++))) << 16); \
- (l) |= (((uint32_t)(*((c)++))) << 8); \
- (l) |= (((uint32_t)(*((c)++)))); \
- } while (0)
-
-#define HOST_l2c(l, c) \
- do { \
- *((c)++) = (uint8_t)(((l) >> 24) & 0xff); \
- *((c)++) = (uint8_t)(((l) >> 16) & 0xff); \
- *((c)++) = (uint8_t)(((l) >> 8) & 0xff); \
- *((c)++) = (uint8_t)(((l)) & 0xff); \
- } while (0)
-
-#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
-
-#define HOST_c2l(c, l) \
- do { \
- (l) = (((uint32_t)(*((c)++)))); \
- (l) |= (((uint32_t)(*((c)++))) << 8); \
- (l) |= (((uint32_t)(*((c)++))) << 16); \
- (l) |= (((uint32_t)(*((c)++))) << 24); \
- } while (0)
-
-#define HOST_l2c(l, c) \
- do { \
- *((c)++) = (uint8_t)(((l)) & 0xff); \
- *((c)++) = (uint8_t)(((l) >> 8) & 0xff); \
- *((c)++) = (uint8_t)(((l) >> 16) & 0xff); \
- *((c)++) = (uint8_t)(((l) >> 24) & 0xff); \
- } while (0)
-
-#endif // DATA_ORDER
-
-int HASH_UPDATE(HASH_CTX *c, const void *data_, size_t len) {
- const uint8_t *data = data_;
-
+// |h| is the hash state and is updated by a function of type
+// |crypto_md32_block_func|. |data| is the partial unprocessed block and has
+// |num| bytes. |Nl| and |Nh| maintain the number of bits processed so far.
+
+// A crypto_md32_block_func should incorporate |num_blocks| of input from |data|
+// into |state|. It is assumed the caller has sized |state| and |data| for the
+// hash function.
+typedef void (*crypto_md32_block_func)(uint32_t *state, const uint8_t *data,
+ size_t num_blocks);
+
+// crypto_md32_update adds |len| bytes from |in| to the digest. |data| must be a
+// buffer of length |block_size| with the first |*num| bytes containing a
+// partial block. This function combines the partial block with |in| and
+// incorporates any complete blocks into the digest state |h|. It then updates
+// |data| and |*num| with the new partial block and updates |*Nh| and |*Nl| with
+// the data consumed.
+static inline void crypto_md32_update(crypto_md32_block_func block_func,
+ uint32_t *h, uint8_t *data,
+ size_t block_size, unsigned *num,
+ uint32_t *Nh, uint32_t *Nl,
+ const uint8_t *in, size_t len) {
if (len == 0) {
- return 1;
+ return;
}
- uint32_t l = c->Nl + (((uint32_t)len) << 3);
- if (l < c->Nl) {
+ uint32_t l = *Nl + (((uint32_t)len) << 3);
+ if (l < *Nl) {
// Handle carries.
- c->Nh++;
+ (*Nh)++;
}
- c->Nh += (uint32_t)(len >> 29);
- c->Nl = l;
+ *Nh += (uint32_t)(len >> 29);
+ *Nl = l;
- size_t n = c->num;
+ size_t n = *num;
if (n != 0) {
- if (len >= HASH_CBLOCK || len + n >= HASH_CBLOCK) {
- OPENSSL_memcpy(c->data + n, data, HASH_CBLOCK - n);
- HASH_BLOCK_DATA_ORDER(c->h, c->data, 1);
- n = HASH_CBLOCK - n;
- data += n;
+ if (len >= block_size || len + n >= block_size) {
+ OPENSSL_memcpy(data + n, in, block_size - n);
+ block_func(h, data, 1);
+ n = block_size - n;
+ in += n;
len -= n;
- c->num = 0;
- // Keep |c->data| zeroed when unused.
- OPENSSL_memset(c->data, 0, HASH_CBLOCK);
+ *num = 0;
+ // Keep |data| zeroed when unused.
+ OPENSSL_memset(data, 0, block_size);
} else {
- OPENSSL_memcpy(c->data + n, data, len);
- c->num += (unsigned)len;
- return 1;
+ OPENSSL_memcpy(data + n, in, len);
+ *num += (unsigned)len;
+ return;
}
}
- n = len / HASH_CBLOCK;
+ n = len / block_size;
if (n > 0) {
- HASH_BLOCK_DATA_ORDER(c->h, data, n);
- n *= HASH_CBLOCK;
- data += n;
+ block_func(h, in, n);
+ n *= block_size;
+ in += n;
len -= n;
}
if (len != 0) {
- c->num = (unsigned)len;
- OPENSSL_memcpy(c->data, data, len);
+ *num = (unsigned)len;
+ OPENSSL_memcpy(data, in, len);
}
- return 1;
}
-
-void HASH_TRANSFORM(HASH_CTX *c, const uint8_t data[HASH_CBLOCK]) {
- HASH_BLOCK_DATA_ORDER(c->h, data, 1);
-}
-
-
-int HASH_FINAL(uint8_t out[HASH_DIGEST_LENGTH], HASH_CTX *c) {
- // |c->data| always has room for at least one byte. A full block would have
+// crypto_md32_final incorporates the partial block and trailing length into the
+// digest state |h|. The trailing length is encoded in little-endian if
+// |is_big_endian| is zero and big-endian otherwise. |data| must be a buffer of
+// length |block_size| with the first |*num| bytes containing a partial block.
+// |Nh| and |Nl| contain the total number of bits processed. On return, this
+// function clears the partial block in |data| and
+// |*num|.
+//
+// This function does not serialize |h| into a final digest. This is the
+// responsibility of the caller.
+static inline void crypto_md32_final(crypto_md32_block_func block_func,
+ uint32_t *h, uint8_t *data,
+ size_t block_size, unsigned *num,
+ uint32_t Nh, uint32_t Nl,
+ int is_big_endian) {
+ // |data| always has room for at least one byte. A full block would have
// been consumed.
- size_t n = c->num;
- assert(n < HASH_CBLOCK);
- c->data[n] = 0x80;
+ size_t n = *num;
+ assert(n < block_size);
+ data[n] = 0x80;
n++;
// Fill the block with zeros if there isn't room for a 64-bit length.
- if (n > (HASH_CBLOCK - 8)) {
- OPENSSL_memset(c->data + n, 0, HASH_CBLOCK - n);
+ if (n > block_size - 8) {
+ OPENSSL_memset(data + n, 0, block_size - n);
n = 0;
- HASH_BLOCK_DATA_ORDER(c->h, c->data, 1);
+ block_func(h, data, 1);
}
- OPENSSL_memset(c->data + n, 0, HASH_CBLOCK - 8 - n);
+ OPENSSL_memset(data + n, 0, block_size - 8 - n);
// Append a 64-bit length to the block and process it.
- uint8_t *p = c->data + HASH_CBLOCK - 8;
-#if defined(DATA_ORDER_IS_BIG_ENDIAN)
- HOST_l2c(c->Nh, p);
- HOST_l2c(c->Nl, p);
-#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
- HOST_l2c(c->Nl, p);
- HOST_l2c(c->Nh, p);
-#endif
- assert(p == c->data + HASH_CBLOCK);
- HASH_BLOCK_DATA_ORDER(c->h, c->data, 1);
- c->num = 0;
- OPENSSL_memset(c->data, 0, HASH_CBLOCK);
-
- HASH_MAKE_STRING(c, out);
- return 1;
+ if (is_big_endian) {
+ CRYPTO_store_u32_be(data + block_size - 8, Nh);
+ CRYPTO_store_u32_be(data + block_size - 4, Nl);
+ } else {
+ CRYPTO_store_u32_le(data + block_size - 8, Nl);
+ CRYPTO_store_u32_le(data + block_size - 4, Nh);
+ }
+ block_func(h, data, 1);
+ *num = 0;
+ OPENSSL_memset(data, 0, block_size);
}
#if defined(__cplusplus)
} // extern C
#endif
+
+#endif // OPENSSL_HEADER_DIGEST_MD32_COMMON_H
diff --git a/deps/boringssl/src/crypto/fipsmodule/ec/ec.c b/deps/boringssl/src/crypto/fipsmodule/ec/ec.c
index c976341..1f03e15 100644
--- a/deps/boringssl/src/crypto/fipsmodule/ec/ec.c
+++ b/deps/boringssl/src/crypto/fipsmodule/ec/ec.c
@@ -1232,6 +1232,10 @@ void ec_set_to_safe_point(const EC_GROUP *group, EC_RAW_POINT *out) {
void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag) {}
+int EC_GROUP_get_asn1_flag(const EC_GROUP *group) {
+ return OPENSSL_EC_NAMED_CURVE;
+}
+
const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group) {
// This function exists purely to give callers a way to call
// |EC_METHOD_get_field_type|. cryptography.io crashes if |EC_GROUP_method_of|
diff --git a/deps/boringssl/src/crypto/fipsmodule/ec/ec_key.c b/deps/boringssl/src/crypto/fipsmodule/ec/ec_key.c
index bc09e0e..7a6daab 100644
--- a/deps/boringssl/src/crypto/fipsmodule/ec/ec_key.c
+++ b/deps/boringssl/src/crypto/fipsmodule/ec/ec_key.c
@@ -171,7 +171,6 @@ void EC_KEY_free(EC_KEY *r) {
EC_GROUP_free(r->group);
EC_POINT_free(r->pub_key);
ec_wrapped_scalar_free(r->priv_key);
- BN_free(r->fixed_k);
CRYPTO_free_ex_data(g_ec_ex_data_class_bss_get(), r, &r->ex_data);
diff --git a/deps/boringssl/src/crypto/fipsmodule/ec/internal.h b/deps/boringssl/src/crypto/fipsmodule/ec/internal.h
index 18aabb0..289c3aa 100644
--- a/deps/boringssl/src/crypto/fipsmodule/ec/internal.h
+++ b/deps/boringssl/src/crypto/fipsmodule/ec/internal.h
@@ -729,10 +729,6 @@ struct ec_key_st {
EC_POINT *pub_key;
EC_WRAPPED_SCALAR *priv_key;
- // fixed_k may contain a specific value of 'k', to be used in ECDSA signing.
- // This is only for the FIPS power-on tests.
- BIGNUM *fixed_k;
-
unsigned int enc_flag;
point_conversion_form_t conv_form;
diff --git a/deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa.c b/deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa.c
index 096b615..591f1bc 100644
--- a/deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa.c
+++ b/deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa.c
@@ -61,9 +61,10 @@
#include <openssl/sha.h>
#include <openssl/type_check.h>
+#include "../../internal.h"
#include "../bn/internal.h"
#include "../ec/internal.h"
-#include "../../internal.h"
+#include "internal.h"
// digest_to_scalar interprets |digest_len| bytes from |digest| as a scalar for
@@ -198,70 +199,74 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
return 1;
}
-static int ecdsa_sign_setup(const EC_KEY *eckey, EC_SCALAR *out_kinv_mont,
- EC_SCALAR *out_r, const uint8_t *digest,
- size_t digest_len, const EC_SCALAR *priv_key) {
+static ECDSA_SIG *ecdsa_sign_impl(const EC_GROUP *group, int *out_retry,
+ const EC_SCALAR *priv_key, const EC_SCALAR *k,
+ const uint8_t *digest, size_t digest_len) {
+ *out_retry = 0;
+
// Check that the size of the group order is FIPS compliant (FIPS 186-4
// B.5.2).
- const EC_GROUP *group = EC_KEY_get0_group(eckey);
const BIGNUM *order = EC_GROUP_get0_order(group);
if (BN_num_bits(order) < 160) {
OPENSSL_PUT_ERROR(ECDSA, EC_R_INVALID_GROUP_ORDER);
- return 0;
+ return NULL;
}
- int ret = 0;
- EC_SCALAR k;
+ // Compute r, the x-coordinate of k * generator.
EC_RAW_POINT tmp_point;
- do {
- // Include the private key and message digest in the k generation.
- if (eckey->fixed_k != NULL) {
- if (!ec_bignum_to_scalar(group, &k, eckey->fixed_k)) {
- goto err;
- }
- if (ec_scalar_is_zero(group, &k)) {
- OPENSSL_PUT_ERROR(ECDSA, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- } else {
- // Pass a SHA512 hash of the private key and digest as additional data
- // into the RBG. This is a hardening measure against entropy failure.
- OPENSSL_STATIC_ASSERT(SHA512_DIGEST_LENGTH >= 32,
- "additional_data is too large for SHA-512");
- SHA512_CTX sha;
- uint8_t additional_data[SHA512_DIGEST_LENGTH];
- SHA512_Init(&sha);
- SHA512_Update(&sha, priv_key->words, order->width * sizeof(BN_ULONG));
- SHA512_Update(&sha, digest, digest_len);
- SHA512_Final(additional_data, &sha);
- if (!ec_random_nonzero_scalar(group, &k, additional_data)) {
- goto err;
- }
- }
+ EC_SCALAR r;
+ if (!ec_point_mul_scalar_base(group, &tmp_point, k) ||
+ !ec_get_x_coordinate_as_scalar(group, &r, &tmp_point)) {
+ return NULL;
+ }
- // Compute k^-1 in the Montgomery domain. This is |ec_scalar_to_montgomery|
- // followed by |ec_scalar_inv0_montgomery|, but |ec_scalar_inv0_montgomery|
- // followed by |ec_scalar_from_montgomery| is equivalent and slightly more
- // efficient. Note k is non-zero, so the inverse must exist.
- ec_scalar_inv0_montgomery(group, out_kinv_mont, &k);
- ec_scalar_from_montgomery(group, out_kinv_mont, out_kinv_mont);
-
- // Compute r, the x-coordinate of generator * k.
- if (!ec_point_mul_scalar_base(group, &tmp_point, &k) ||
- !ec_get_x_coordinate_as_scalar(group, out_r, &tmp_point)) {
- goto err;
- }
- } while (ec_scalar_is_zero(group, out_r));
+ if (ec_scalar_is_zero(group, &r)) {
+ *out_retry = 1;
+ return NULL;
+ }
- ret = 1;
+ // s = priv_key * r. Note if only one parameter is in the Montgomery domain,
+ // |ec_scalar_mod_mul_montgomery| will compute the answer in the normal
+ // domain.
+ EC_SCALAR s;
+ ec_scalar_to_montgomery(group, &s, &r);
+ ec_scalar_mul_montgomery(group, &s, priv_key, &s);
+
+ // s = m + priv_key * r.
+ EC_SCALAR tmp;
+ digest_to_scalar(group, &tmp, digest, digest_len);
+ ec_scalar_add(group, &s, &s, &tmp);
+
+ // s = k^-1 * (m + priv_key * r). First, we compute k^-1 in the Montgomery
+ // domain. This is |ec_scalar_to_montgomery| followed by
+ // |ec_scalar_inv0_montgomery|, but |ec_scalar_inv0_montgomery| followed by
+ // |ec_scalar_from_montgomery| is equivalent and slightly more efficient.
+ // Then, as above, only one parameter is in the Montgomery domain, so the
+ // result is in the normal domain. Finally, note k is non-zero (or computing r
+ // would fail), so the inverse must exist.
+ ec_scalar_inv0_montgomery(group, &tmp, k); // tmp = k^-1 R^2
+ ec_scalar_from_montgomery(group, &tmp, &tmp); // tmp = k^-1 R
+ ec_scalar_mul_montgomery(group, &s, &s, &tmp);
+ if (ec_scalar_is_zero(group, &s)) {
+ *out_retry = 1;
+ return NULL;
+ }
-err:
- OPENSSL_cleanse(&k, sizeof(k));
+ ECDSA_SIG *ret = ECDSA_SIG_new();
+ if (ret == NULL || //
+ !bn_set_words(ret->r, r.words, order->width) ||
+ !bn_set_words(ret->s, s.words, order->width)) {
+ ECDSA_SIG_free(ret);
+ return NULL;
+ }
return ret;
}
-ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
- const EC_KEY *eckey) {
+ECDSA_SIG *ecdsa_sign_with_nonce_for_known_answer_test(const uint8_t *digest,
+ size_t digest_len,
+ const EC_KEY *eckey,
+ const uint8_t *nonce,
+ size_t nonce_len) {
if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
return NULL;
@@ -272,57 +277,63 @@ ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
- const BIGNUM *order = EC_GROUP_get0_order(group);
const EC_SCALAR *priv_key = &eckey->priv_key->scalar;
- int ok = 0;
- ECDSA_SIG *ret = ECDSA_SIG_new();
- EC_SCALAR kinv_mont, r_mont, s, m, tmp;
- if (ret == NULL) {
- OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
+ EC_SCALAR k;
+ if (!ec_scalar_from_bytes(group, &k, nonce, nonce_len)) {
return NULL;
}
+ int retry_ignored;
+ return ecdsa_sign_impl(group, &retry_ignored, priv_key, &k, digest,
+ digest_len);
+}
- digest_to_scalar(group, &m, digest, digest_len);
- for (;;) {
- if (!ecdsa_sign_setup(eckey, &kinv_mont, &r_mont, digest, digest_len,
- priv_key) ||
- !bn_set_words(ret->r, r_mont.words, order->width)) {
- goto err;
- }
-
- // Compute priv_key * r (mod order). Note if only one parameter is in the
- // Montgomery domain, |ec_scalar_mod_mul_montgomery| will compute the answer
- // in the normal domain.
- ec_scalar_to_montgomery(group, &r_mont, &r_mont);
- ec_scalar_mul_montgomery(group, &s, priv_key, &r_mont);
+// This function is only exported for testing and is not called in production
+// code.
+ECDSA_SIG *ECDSA_sign_with_nonce_and_leak_private_key_for_testing(
+ const uint8_t *digest, size_t digest_len, const EC_KEY *eckey,
+ const uint8_t *nonce, size_t nonce_len) {
+ return ecdsa_sign_with_nonce_for_known_answer_test(digest, digest_len, eckey,
+ nonce, nonce_len);
+}
- // Compute tmp = m + priv_key * r.
- ec_scalar_add(group, &tmp, &m, &s);
+ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
+ const EC_KEY *eckey) {
+ if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
+ return NULL;
+ }
- // Finally, multiply s by k^-1. That was retained in Montgomery form, so the
- // same technique as the previous multiplication works.
- ec_scalar_mul_montgomery(group, &s, &tmp, &kinv_mont);
- if (!bn_set_words(ret->s, s.words, order->width)) {
- goto err;
- }
- if (!BN_is_zero(ret->s)) {
- // s != 0 => we have a valid signature
- break;
- }
+ const EC_GROUP *group = EC_KEY_get0_group(eckey);
+ if (group == NULL || eckey->priv_key == NULL) {
+ OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
+ return NULL;
}
+ const BIGNUM *order = EC_GROUP_get0_order(group);
+ const EC_SCALAR *priv_key = &eckey->priv_key->scalar;
- ok = 1;
+ // Pass a SHA512 hash of the private key and digest as additional data
+ // into the RBG. This is a hardening measure against entropy failure.
+ OPENSSL_STATIC_ASSERT(SHA512_DIGEST_LENGTH >= 32,
+ "additional_data is too large for SHA-512");
+ SHA512_CTX sha;
+ uint8_t additional_data[SHA512_DIGEST_LENGTH];
+ SHA512_Init(&sha);
+ SHA512_Update(&sha, priv_key->words, order->width * sizeof(BN_ULONG));
+ SHA512_Update(&sha, digest, digest_len);
+ SHA512_Final(additional_data, &sha);
-err:
- if (!ok) {
- ECDSA_SIG_free(ret);
- ret = NULL;
+ for (;;) {
+ EC_SCALAR k;
+ if (!ec_random_nonzero_scalar(group, &k, additional_data)) {
+ return NULL;
+ }
+
+ int retry;
+ ECDSA_SIG *sig =
+ ecdsa_sign_impl(group, &retry, priv_key, &k, digest, digest_len);
+ if (sig != NULL || !retry) {
+ return sig;
+ }
}
- OPENSSL_cleanse(&kinv_mont, sizeof(kinv_mont));
- OPENSSL_cleanse(&r_mont, sizeof(r_mont));
- OPENSSL_cleanse(&s, sizeof(s));
- OPENSSL_cleanse(&tmp, sizeof(tmp));
- OPENSSL_cleanse(&m, sizeof(m));
- return ret;
}
diff --git a/deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc b/deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc
index 4c95df9..18fdb83 100644
--- a/deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc
+++ b/deps/boringssl/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc
@@ -66,6 +66,7 @@
#include "../ec/internal.h"
#include "../../test/file_test.h"
+#include "../../test/test_util.h"
static bssl::UniquePtr<BIGNUM> HexToBIGNUM(const char *hex) {
@@ -228,6 +229,15 @@ TEST(ECDSATest, BuiltinCurves) {
ECDSA_sign(0, digest, 20, signature.data(), &sig_len, eckey.get()));
signature.resize(sig_len);
+ // ECDSA signing should be non-deterministic. This does not verify k is
+ // generated securely but at least checks it was randomized at all.
+ sig_len = ECDSA_size(eckey.get());
+ std::vector<uint8_t> signature2(sig_len);
+ ASSERT_TRUE(
+ ECDSA_sign(0, digest, 20, signature2.data(), &sig_len, eckey.get()));
+ signature2.resize(sig_len);
+ EXPECT_NE(Bytes(signature), Bytes(signature2));
+
// Verify the signature.
EXPECT_TRUE(ECDSA_verify(0, digest, 20, signature.data(), signature.size(),
eckey.get()));
@@ -424,8 +434,8 @@ TEST(ECDSATest, SignTestVectors) {
ASSERT_TRUE(x);
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
ASSERT_TRUE(y);
- bssl::UniquePtr<BIGNUM> k = GetBIGNUM(t, "K");
- ASSERT_TRUE(k);
+ std::vector<uint8_t> k;
+ ASSERT_TRUE(t->GetBytes(&k, "K"));
bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R");
ASSERT_TRUE(r);
bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S");
@@ -444,10 +454,9 @@ TEST(ECDSATest, SignTestVectors) {
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
ASSERT_TRUE(EC_KEY_check_key(key.get()));
- // Set the fixed k for testing purposes.
- key->fixed_k = k.release();
bssl::UniquePtr<ECDSA_SIG> sig(
- ECDSA_do_sign(digest.data(), digest.size(), key.get()));
+ ECDSA_sign_with_nonce_and_leak_private_key_for_testing(
+ digest.data(), digest.size(), key.get(), k.data(), k.size()));
ASSERT_TRUE(sig);
EXPECT_EQ(0, BN_cmp(r.get(), sig->r));
diff --git a/deps/boringssl/src/crypto/fipsmodule/ecdsa/internal.h b/deps/boringssl/src/crypto/fipsmodule/ecdsa/internal.h
new file mode 100644
index 0000000..5115dfa
--- /dev/null
+++ b/deps/boringssl/src/crypto/fipsmodule/ecdsa/internal.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2021, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_CRYPTO_FIPSMODULE_ECDSA_INTERNAL_H
+#define OPENSSL_HEADER_CRYPTO_FIPSMODULE_ECDSA_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+// ecdsa_sign_with_nonce_for_known_answer_test behaves like |ECDSA_do_sign| but
+// takes a fixed nonce. This function is used as part of known-answer tests in
+// the FIPS module.
+ECDSA_SIG *ecdsa_sign_with_nonce_for_known_answer_test(const uint8_t *digest,
+ size_t digest_len,
+ const EC_KEY *eckey,
+ const uint8_t *nonce,
+ size_t nonce_len);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // OPENSSL_HEADER_CRYPTO_FIPSMODULE_ECDSA_INTERNAL_H
diff --git a/deps/boringssl/src/crypto/fipsmodule/is_fips.c b/deps/boringssl/src/crypto/fipsmodule/is_fips.c
deleted file mode 100644
index 2f8e408..0000000
--- a/deps/boringssl/src/crypto/fipsmodule/is_fips.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Copyright (c) 2017, Google Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
-#include <openssl/crypto.h>
-
-
-// This file exists in order to give the fipsmodule target, in non-FIPS mode,
-// something to compile.
-
-int FIPS_mode(void) {
-#if defined(BORINGSSL_FIPS) && !defined(OPENSSL_ASAN)
- return 1;
-#else
- return 0;
-#endif
-}
-
-int FIPS_mode_set(int on) { return on == FIPS_mode(); }
diff --git a/deps/boringssl/src/crypto/fipsmodule/md4/md4.c b/deps/boringssl/src/crypto/fipsmodule/md4/md4.c
index cc2a631..a505d05 100644
--- a/deps/boringssl/src/crypto/fipsmodule/md4/md4.c
+++ b/deps/boringssl/src/crypto/fipsmodule/md4/md4.c
@@ -60,6 +60,7 @@
#include <string.h>
#include "../../internal.h"
+#include "../digest/md32_common.h"
uint8_t *MD4(const uint8_t *data, size_t len, uint8_t out[MD4_DIGEST_LENGTH]) {
@@ -71,7 +72,7 @@ uint8_t *MD4(const uint8_t *data, size_t len, uint8_t out[MD4_DIGEST_LENGTH]) {
return out;
}
-// Implemented from RFC1186 The MD4 Message-Digest Algorithm.
+// Implemented from RFC 1186 The MD4 Message-Digest Algorithm.
int MD4_Init(MD4_CTX *md4) {
OPENSSL_memset(md4, 0, sizeof(MD4_CTX));
@@ -84,29 +85,26 @@ int MD4_Init(MD4_CTX *md4) {
void md4_block_data_order(uint32_t *state, const uint8_t *data, size_t num);
-#define DATA_ORDER_IS_LITTLE_ENDIAN
+void MD4_Transform(MD4_CTX *c, const uint8_t data[MD4_CBLOCK]) {
+ md4_block_data_order(c->h, data, 1);
+}
-#define HASH_CTX MD4_CTX
-#define HASH_CBLOCK 64
-#define HASH_DIGEST_LENGTH 16
-#define HASH_UPDATE MD4_Update
-#define HASH_TRANSFORM MD4_Transform
-#define HASH_FINAL MD4_Final
-#define HASH_MAKE_STRING(c, s) \
- do { \
- uint32_t ll; \
- ll = (c)->h[0]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[1]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[2]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[3]; \
- HOST_l2c(ll, (s)); \
- } while (0)
-#define HASH_BLOCK_DATA_ORDER md4_block_data_order
+int MD4_Update(MD4_CTX *c, const void *data, size_t len) {
+ crypto_md32_update(&md4_block_data_order, c->h, c->data, MD4_CBLOCK, &c->num,
+ &c->Nh, &c->Nl, data, len);
+ return 1;
+}
-#include "../digest/md32_common.h"
+int MD4_Final(uint8_t out[MD4_DIGEST_LENGTH], MD4_CTX *c) {
+ crypto_md32_final(&md4_block_data_order, c->h, c->data, MD4_CBLOCK, &c->num,
+ c->Nh, c->Nl, /*is_big_endian=*/0);
+
+ CRYPTO_store_u32_le(out, c->h[0]);
+ CRYPTO_store_u32_le(out + 4, c->h[1]);
+ CRYPTO_store_u32_le(out + 8, c->h[2]);
+ CRYPTO_store_u32_le(out + 12, c->h[3]);
+ return 1;
+}
// As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
// simplified to the code below. Wei attributes these optimizations
@@ -136,7 +134,7 @@ void md4_block_data_order(uint32_t *state, const uint8_t *data, size_t num);
} while (0)
void md4_block_data_order(uint32_t *state, const uint8_t *data, size_t num) {
- uint32_t A, B, C, D, l;
+ uint32_t A, B, C, D;
uint32_t X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15;
A = state[0];
@@ -145,53 +143,53 @@ void md4_block_data_order(uint32_t *state, const uint8_t *data, size_t num) {
D = state[3];
for (; num--;) {
- HOST_c2l(data, l);
- X0 = l;
- HOST_c2l(data, l);
- X1 = l;
+ X0 = CRYPTO_load_u32_le(data);
+ data += 4;
+ X1 = CRYPTO_load_u32_le(data);
+ data += 4;
// Round 0
R0(A, B, C, D, X0, 3, 0);
- HOST_c2l(data, l);
- X2 = l;
+ X2 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(D, A, B, C, X1, 7, 0);
- HOST_c2l(data, l);
- X3 = l;
+ X3 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(C, D, A, B, X2, 11, 0);
- HOST_c2l(data, l);
- X4 = l;
+ X4 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(B, C, D, A, X3, 19, 0);
- HOST_c2l(data, l);
- X5 = l;
+ X5 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(A, B, C, D, X4, 3, 0);
- HOST_c2l(data, l);
- X6 = l;
+ X6 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(D, A, B, C, X5, 7, 0);
- HOST_c2l(data, l);
- X7 = l;
+ X7 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(C, D, A, B, X6, 11, 0);
- HOST_c2l(data, l);
- X8 = l;
+ X8 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(B, C, D, A, X7, 19, 0);
- HOST_c2l(data, l);
- X9 = l;
+ X9 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(A, B, C, D, X8, 3, 0);
- HOST_c2l(data, l);
- X10 = l;
+ X10 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(D, A, B, C, X9, 7, 0);
- HOST_c2l(data, l);
- X11 = l;
+ X11 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(C, D, A, B, X10, 11, 0);
- HOST_c2l(data, l);
- X12 = l;
+ X12 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(B, C, D, A, X11, 19, 0);
- HOST_c2l(data, l);
- X13 = l;
+ X13 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(A, B, C, D, X12, 3, 0);
- HOST_c2l(data, l);
- X14 = l;
+ X14 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(D, A, B, C, X13, 7, 0);
- HOST_c2l(data, l);
- X15 = l;
+ X15 = CRYPTO_load_u32_le(data);
+ data += 4;
R0(C, D, A, B, X14, 11, 0);
R0(B, C, D, A, X15, 19, 0);
// Round 1
@@ -236,15 +234,6 @@ void md4_block_data_order(uint32_t *state, const uint8_t *data, size_t num) {
}
}
-#undef DATA_ORDER_IS_LITTLE_ENDIAN
-#undef HASH_CTX
-#undef HASH_CBLOCK
-#undef HASH_DIGEST_LENGTH
-#undef HASH_UPDATE
-#undef HASH_TRANSFORM
-#undef HASH_FINAL
-#undef HASH_MAKE_STRING
-#undef HASH_BLOCK_DATA_ORDER
#undef F
#undef G
#undef H
@@ -252,5 +241,3 @@ void md4_block_data_order(uint32_t *state, const uint8_t *data, size_t num) {
#undef R0
#undef R1
#undef R2
-#undef HOST_c2l
-#undef HOST_l2c
diff --git a/deps/boringssl/src/crypto/fipsmodule/md5/md5.c b/deps/boringssl/src/crypto/fipsmodule/md5/md5.c
index a48d704..eba34bc 100644
--- a/deps/boringssl/src/crypto/fipsmodule/md5/md5.c
+++ b/deps/boringssl/src/crypto/fipsmodule/md5/md5.c
@@ -60,8 +60,9 @@
#include <openssl/mem.h>
-#include "internal.h"
#include "../../internal.h"
+#include "../digest/md32_common.h"
+#include "internal.h"
uint8_t *MD5(const uint8_t *data, size_t len, uint8_t out[MD5_DIGEST_LENGTH]) {
@@ -89,30 +90,26 @@ static void md5_block_data_order(uint32_t *state, const uint8_t *data,
size_t num);
#endif
+void MD5_Transform(MD5_CTX *c, const uint8_t data[MD5_CBLOCK]) {
+ md5_block_data_order(c->h, data, 1);
+}
-#define DATA_ORDER_IS_LITTLE_ENDIAN
+int MD5_Update(MD5_CTX *c, const void *data, size_t len) {
+ crypto_md32_update(&md5_block_data_order, c->h, c->data, MD5_CBLOCK, &c->num,
+ &c->Nh, &c->Nl, data, len);
+ return 1;
+}
-#define HASH_CTX MD5_CTX
-#define HASH_CBLOCK 64
-#define HASH_DIGEST_LENGTH 16
-#define HASH_UPDATE MD5_Update
-#define HASH_TRANSFORM MD5_Transform
-#define HASH_FINAL MD5_Final
-#define HASH_MAKE_STRING(c, s) \
- do { \
- uint32_t ll; \
- ll = (c)->h[0]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[1]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[2]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[3]; \
- HOST_l2c(ll, (s)); \
- } while (0)
-#define HASH_BLOCK_DATA_ORDER md5_block_data_order
+int MD5_Final(uint8_t out[MD5_DIGEST_LENGTH], MD5_CTX *c) {
+ crypto_md32_final(&md5_block_data_order, c->h, c->data, MD5_CBLOCK, &c->num,
+ c->Nh, c->Nl, /*is_big_endian=*/0);
-#include "../digest/md32_common.h"
+ CRYPTO_store_u32_le(out, c->h[0]);
+ CRYPTO_store_u32_le(out + 4, c->h[1]);
+ CRYPTO_store_u32_le(out + 8, c->h[2]);
+ CRYPTO_store_u32_le(out + 12, c->h[3]);
+ return 1;
+}
// As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
// simplified to the code below. Wei attributes these optimizations
@@ -158,7 +155,7 @@ static void md5_block_data_order(uint32_t *state, const uint8_t *data,
#endif
static void md5_block_data_order(uint32_t *state, const uint8_t *data,
size_t num) {
- uint32_t A, B, C, D, l;
+ uint32_t A, B, C, D;
uint32_t XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9, XX10, XX11, XX12,
XX13, XX14, XX15;
#define X(i) XX##i
@@ -169,53 +166,53 @@ static void md5_block_data_order(uint32_t *state, const uint8_t *data,
D = state[3];
for (; num--;) {
- HOST_c2l(data, l);
- X(0) = l;
- HOST_c2l(data, l);
- X(1) = l;
+ X(0) = CRYPTO_load_u32_le(data);
+ data += 4;
+ X(1) = CRYPTO_load_u32_le(data);
+ data += 4;
// Round 0
R0(A, B, C, D, X(0), 7, 0xd76aa478L);
- HOST_c2l(data, l);
- X(2) = l;
+ X(2) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(D, A, B, C, X(1), 12, 0xe8c7b756L);
- HOST_c2l(data, l);
- X(3) = l;
+ X(3) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(C, D, A, B, X(2), 17, 0x242070dbL);
- HOST_c2l(data, l);
- X(4) = l;
+ X(4) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(B, C, D, A, X(3), 22, 0xc1bdceeeL);
- HOST_c2l(data, l);
- X(5) = l;
+ X(5) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(A, B, C, D, X(4), 7, 0xf57c0fafL);
- HOST_c2l(data, l);
- X(6) = l;
+ X(6) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(D, A, B, C, X(5), 12, 0x4787c62aL);
- HOST_c2l(data, l);
- X(7) = l;
+ X(7) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(C, D, A, B, X(6), 17, 0xa8304613L);
- HOST_c2l(data, l);
- X(8) = l;
+ X(8) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(B, C, D, A, X(7), 22, 0xfd469501L);
- HOST_c2l(data, l);
- X(9) = l;
+ X(9) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(A, B, C, D, X(8), 7, 0x698098d8L);
- HOST_c2l(data, l);
- X(10) = l;
+ X(10) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(D, A, B, C, X(9), 12, 0x8b44f7afL);
- HOST_c2l(data, l);
- X(11) = l;
+ X(11) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(C, D, A, B, X(10), 17, 0xffff5bb1L);
- HOST_c2l(data, l);
- X(12) = l;
+ X(12) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(B, C, D, A, X(11), 22, 0x895cd7beL);
- HOST_c2l(data, l);
- X(13) = l;
+ X(13) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(A, B, C, D, X(12), 7, 0x6b901122L);
- HOST_c2l(data, l);
- X(14) = l;
+ X(14) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(D, A, B, C, X(13), 12, 0xfd987193L);
- HOST_c2l(data, l);
- X(15) = l;
+ X(15) = CRYPTO_load_u32_le(data);
+ data += 4;
R0(C, D, A, B, X(14), 17, 0xa679438eL);
R0(B, C, D, A, X(15), 22, 0x49b40821L);
// Round 1
@@ -279,15 +276,6 @@ static void md5_block_data_order(uint32_t *state, const uint8_t *data,
#undef X
#endif
-#undef DATA_ORDER_IS_LITTLE_ENDIAN
-#undef HASH_CTX
-#undef HASH_CBLOCK
-#undef HASH_DIGEST_LENGTH
-#undef HASH_UPDATE
-#undef HASH_TRANSFORM
-#undef HASH_FINAL
-#undef HASH_MAKE_STRING
-#undef HASH_BLOCK_DATA_ORDER
#undef F
#undef G
#undef H
@@ -297,5 +285,3 @@ static void md5_block_data_order(uint32_t *state, const uint8_t *data,
#undef R1
#undef R2
#undef R3
-#undef HOST_c2l
-#undef HOST_l2c
diff --git a/deps/boringssl/src/crypto/fipsmodule/modes/cbc.c b/deps/boringssl/src/crypto/fipsmodule/modes/cbc.c
index 3f1d777..192580e 100644
--- a/deps/boringssl/src/crypto/fipsmodule/modes/cbc.c
+++ b/deps/boringssl/src/crypto/fipsmodule/modes/cbc.c
@@ -52,20 +52,25 @@
#include <openssl/type_check.h>
#include "internal.h"
+#include "../../internal.h"
void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
const AES_KEY *key, uint8_t ivec[16],
block128_f block) {
- size_t n;
- const uint8_t *iv = ivec;
-
assert(key != NULL && ivec != NULL);
- assert(len == 0 || (in != NULL && out != NULL));
+ if (len == 0) {
+ // Avoid |ivec| == |iv| in the |memcpy| below, which is not legal in C.
+ return;
+ }
+ assert(in != NULL && out != NULL);
+ size_t n;
+ const uint8_t *iv = ivec;
while (len >= 16) {
- for (n = 0; n < 16; n += sizeof(size_t)) {
- store_word_le(out + n, load_word_le(in + n) ^ load_word_le(iv + n));
+ for (n = 0; n < 16; n += sizeof(crypto_word_t)) {
+ CRYPTO_store_word_le(
+ out + n, CRYPTO_load_word_le(in + n) ^ CRYPTO_load_word_le(iv + n));
}
(*block)(out, out, key);
iv = out;
@@ -97,30 +102,36 @@ void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
const AES_KEY *key, uint8_t ivec[16],
block128_f block) {
- size_t n;
- union {
- size_t t[16 / sizeof(size_t)];
- uint8_t c[16];
- } tmp;
-
assert(key != NULL && ivec != NULL);
- assert(len == 0 || (in != NULL && out != NULL));
+ if (len == 0) {
+ // Avoid |ivec| == |iv| in the |memcpy| below, which is not legal in C.
+ return;
+ }
+
+ assert(in != NULL && out != NULL);
const uintptr_t inptr = (uintptr_t) in;
const uintptr_t outptr = (uintptr_t) out;
// If |in| and |out| alias, |in| must be ahead.
assert(inptr >= outptr || inptr + len <= outptr);
+ size_t n;
+ union {
+ crypto_word_t t[16 / sizeof(crypto_word_t)];
+ uint8_t c[16];
+ } tmp;
+
if ((inptr >= 32 && outptr <= inptr - 32) || inptr < outptr) {
// If |out| is at least two blocks behind |in| or completely disjoint, there
// is no need to decrypt to a temporary block.
- OPENSSL_STATIC_ASSERT(16 % sizeof(size_t) == 0,
+ OPENSSL_STATIC_ASSERT(16 % sizeof(crypto_word_t) == 0,
"block cannot be evenly divided into words");
const uint8_t *iv = ivec;
while (len >= 16) {
(*block)(in, out, key);
- for (n = 0; n < 16; n += sizeof(size_t)) {
- store_word_le(out + n, load_word_le(out + n) ^ load_word_le(iv + n));
+ for (n = 0; n < 16; n += sizeof(crypto_word_t)) {
+ CRYPTO_store_word_le(out + n, CRYPTO_load_word_le(out + n) ^
+ CRYPTO_load_word_le(iv + n));
}
iv = in;
len -= 16;
@@ -129,16 +140,16 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
}
OPENSSL_memcpy(ivec, iv, 16);
} else {
- OPENSSL_STATIC_ASSERT(16 % sizeof(size_t) == 0,
+ OPENSSL_STATIC_ASSERT(16 % sizeof(crypto_word_t) == 0,
"block cannot be evenly divided into words");
while (len >= 16) {
(*block)(in, tmp.c, key);
- for (n = 0; n < 16; n += sizeof(size_t)) {
- size_t c = load_word_le(in + n);
- store_word_le(out + n,
- tmp.t[n / sizeof(size_t)] ^ load_word_le(ivec + n));
- store_word_le(ivec + n, c);
+ for (n = 0; n < 16; n += sizeof(crypto_word_t)) {
+ crypto_word_t c = CRYPTO_load_word_le(in + n);
+ CRYPTO_store_word_le(out + n, tmp.t[n / sizeof(crypto_word_t)] ^
+ CRYPTO_load_word_le(ivec + n));
+ CRYPTO_store_word_le(ivec + n, c);
}
len -= 16;
in += 16;
diff --git a/deps/boringssl/src/crypto/fipsmodule/modes/cfb.c b/deps/boringssl/src/crypto/fipsmodule/modes/cfb.c
index 8ca9004..283a107 100644
--- a/deps/boringssl/src/crypto/fipsmodule/modes/cfb.c
+++ b/deps/boringssl/src/crypto/fipsmodule/modes/cfb.c
@@ -72,10 +72,11 @@ void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
}
while (len >= 16) {
(*block)(ivec, ivec, key);
- for (; n < 16; n += sizeof(size_t)) {
- size_t tmp = load_word_le(ivec + n) ^ load_word_le(in + n);
- store_word_le(ivec + n, tmp);
- store_word_le(out + n, tmp);
+ for (; n < 16; n += sizeof(crypto_word_t)) {
+ crypto_word_t tmp =
+ CRYPTO_load_word_le(ivec + n) ^ CRYPTO_load_word_le(in + n);
+ CRYPTO_store_word_le(ivec + n, tmp);
+ CRYPTO_store_word_le(out + n, tmp);
}
len -= 16;
out += 16;
@@ -101,10 +102,10 @@ void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
}
while (len >= 16) {
(*block)(ivec, ivec, key);
- for (; n < 16; n += sizeof(size_t)) {
- size_t t = load_word_le(in + n);
- store_word_le(out + n, load_word_le(ivec + n) ^ t);
- store_word_le(ivec + n, t);
+ for (; n < 16; n += sizeof(crypto_word_t)) {
+ crypto_word_t t = CRYPTO_load_word_le(in + n);
+ CRYPTO_store_word_le(out + n, CRYPTO_load_word_le(ivec + n) ^ t);
+ CRYPTO_store_word_le(ivec + n, t);
}
len -= 16;
out += 16;
diff --git a/deps/boringssl/src/crypto/fipsmodule/modes/ctr.c b/deps/boringssl/src/crypto/fipsmodule/modes/ctr.c
index 8b0e059..cea79ad 100644
--- a/deps/boringssl/src/crypto/fipsmodule/modes/ctr.c
+++ b/deps/boringssl/src/crypto/fipsmodule/modes/ctr.c
@@ -52,6 +52,7 @@
#include <string.h>
#include "internal.h"
+#include "../../internal.h"
// NOTE: the IV/counter CTR mode is big-endian. The code itself
@@ -69,8 +70,8 @@ static void ctr128_inc(uint8_t *counter) {
} while (n);
}
-OPENSSL_STATIC_ASSERT(16 % sizeof(size_t) == 0,
- "block cannot be divided into size_t");
+OPENSSL_STATIC_ASSERT(16 % sizeof(crypto_word_t) == 0,
+ "block cannot be divided into crypto_word_t");
// The input encrypted as though 128bit counter mode is being used. The extra
// state information to record how much of the 128bit block we have used is
@@ -102,9 +103,9 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
while (len >= 16) {
(*block)(ivec, ecount_buf, key);
ctr128_inc(ivec);
- for (n = 0; n < 16; n += sizeof(size_t)) {
- store_word_le(out + n,
- load_word_le(in + n) ^ load_word_le(ecount_buf + n));
+ for (n = 0; n < 16; n += sizeof(crypto_word_t)) {
+ CRYPTO_store_word_le(out + n, CRYPTO_load_word_le(in + n) ^
+ CRYPTO_load_word_le(ecount_buf + n));
}
len -= 16;
out += 16;
@@ -152,7 +153,7 @@ void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len,
n = (n + 1) % 16;
}
- ctr32 = GETU32(ivec + 12);
+ ctr32 = CRYPTO_load_u32_be(ivec + 12);
while (len >= 16) {
size_t blocks = len / 16;
// 1<<28 is just a not-so-small yet not-so-large number...
@@ -172,7 +173,7 @@ void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len,
}
(*func)(in, out, blocks, key, ivec);
// (*func) does not update ivec, caller does:
- PUTU32(ivec + 12, ctr32);
+ CRYPTO_store_u32_be(ivec + 12, ctr32);
// ... overflow was detected, propogate carry.
if (ctr32 == 0) {
ctr96_inc(ivec);
@@ -186,7 +187,7 @@ void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len,
OPENSSL_memset(ecount_buf, 0, 16);
(*func)(ecount_buf, ecount_buf, 1, key, ivec);
++ctr32;
- PUTU32(ivec + 12, ctr32);
+ CRYPTO_store_u32_be(ivec + 12, ctr32);
if (ctr32 == 0) {
ctr96_inc(ivec);
}
diff --git a/deps/boringssl/src/crypto/fipsmodule/modes/gcm.c b/deps/boringssl/src/crypto/fipsmodule/modes/gcm.c
index 14fff86..b010cd5 100644
--- a/deps/boringssl/src/crypto/fipsmodule/modes/gcm.c
+++ b/deps/boringssl/src/crypto/fipsmodule/modes/gcm.c
@@ -73,7 +73,7 @@ static const size_t kSizeTWithoutLower4Bits = (size_t) -16;
#if defined(GHASH_ASM_X86_64) || defined(GHASH_ASM_X86)
static inline void gcm_reduce_1bit(u128 *V) {
- if (sizeof(size_t) == 8) {
+ if (sizeof(crypto_word_t) == 8) {
uint64_t T = UINT64_C(0xe100000000000000) & (0 - (V->hi & 1));
V->hi = (V->lo << 63) | (V->hi >> 1);
V->lo = (V->lo >> 1) ^ T;
@@ -377,9 +377,10 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const AES_KEY *key,
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
- for (size_t i = 0; i < 16; i += sizeof(size_t)) {
- store_word_le(out + i,
- load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
+ for (size_t i = 0; i < 16; i += sizeof(crypto_word_t)) {
+ CRYPTO_store_word_le(out + i,
+ CRYPTO_load_word_le(in + i) ^
+ ctx->EKi.t[i / sizeof(crypto_word_t)]);
}
out += 16;
in += 16;
@@ -394,9 +395,10 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const AES_KEY *key,
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
- for (size_t i = 0; i < 16; i += sizeof(size_t)) {
- store_word_le(out + i,
- load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
+ for (size_t i = 0; i < 16; i += sizeof(crypto_word_t)) {
+ CRYPTO_store_word_le(out + i,
+ CRYPTO_load_word_le(in + i) ^
+ ctx->EKi.t[i / sizeof(crypto_word_t)]);
}
out += 16;
in += 16;
@@ -468,9 +470,10 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const AES_KEY *key,
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
- for (size_t i = 0; i < 16; i += sizeof(size_t)) {
- store_word_le(out + i,
- load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
+ for (size_t i = 0; i < 16; i += sizeof(crypto_word_t)) {
+ CRYPTO_store_word_le(out + i,
+ CRYPTO_load_word_le(in + i) ^
+ ctx->EKi.t[i / sizeof(crypto_word_t)]);
}
out += 16;
in += 16;
@@ -485,9 +488,10 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const AES_KEY *key,
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
- for (size_t i = 0; i < 16; i += sizeof(size_t)) {
- store_word_le(out + i,
- load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
+ for (size_t i = 0; i < 16; i += sizeof(crypto_word_t)) {
+ CRYPTO_store_word_le(out + i,
+ CRYPTO_load_word_le(in + i) ^
+ ctx->EKi.t[i / sizeof(crypto_word_t)]);
}
out += 16;
in += 16;
diff --git a/deps/boringssl/src/crypto/fipsmodule/modes/gcm_nohw.c b/deps/boringssl/src/crypto/fipsmodule/modes/gcm_nohw.c
index f8618b8..92d5441 100644
--- a/deps/boringssl/src/crypto/fipsmodule/modes/gcm_nohw.c
+++ b/deps/boringssl/src/crypto/fipsmodule/modes/gcm_nohw.c
@@ -193,7 +193,7 @@ static void gcm_mul64_nohw(uint64_t *out_lo, uint64_t *out_hi, uint64_t a,
#endif // BORINGSSL_HAS_UINT128
void gcm_init_nohw(u128 Htable[16], const uint64_t Xi[2]) {
- // We implement GHASH in terms of POLYVAL, as described in RFC8452. This
+ // We implement GHASH in terms of POLYVAL, as described in RFC 8452. This
// avoids a shift by 1 in the multiplication, needed to account for bit
// reversal losing a bit after multiplication, that is,
// rev128(X) * rev128(Y) = rev255(X*Y).
diff --git a/deps/boringssl/src/crypto/fipsmodule/modes/gcm_test.cc b/deps/boringssl/src/crypto/fipsmodule/modes/gcm_test.cc
index 031b06c..02ba2d1 100644
--- a/deps/boringssl/src/crypto/fipsmodule/modes/gcm_test.cc
+++ b/deps/boringssl/src/crypto/fipsmodule/modes/gcm_test.cc
@@ -125,7 +125,7 @@ TEST(GCMTest, ABI) {
UINT64_C(0x66e94bd4ef8a2c3b),
UINT64_C(0x884cfa59ca342b2e),
};
- static const size_t kBlockCounts[] = {1, 2, 3, 4, 7, 8, 15, 16, 31, 32};
+ static const size_t kBlockCounts[] = {1, 2, 3, 4, 5, 6, 7, 8, 15, 16, 31, 32};
uint8_t buf[16 * 32];
OPENSSL_memset(buf, 42, sizeof(buf));
diff --git a/deps/boringssl/src/crypto/fipsmodule/modes/internal.h b/deps/boringssl/src/crypto/fipsmodule/modes/internal.h
index 2693fa6..2fea558 100644
--- a/deps/boringssl/src/crypto/fipsmodule/modes/internal.h
+++ b/deps/boringssl/src/crypto/fipsmodule/modes/internal.h
@@ -64,27 +64,6 @@ extern "C" {
#endif
-static inline uint32_t GETU32(const void *in) {
- uint32_t v;
- OPENSSL_memcpy(&v, in, sizeof(v));
- return CRYPTO_bswap4(v);
-}
-
-static inline void PUTU32(void *out, uint32_t v) {
- v = CRYPTO_bswap4(v);
- OPENSSL_memcpy(out, &v, sizeof(v));
-}
-
-static inline size_t load_word_le(const void *in) {
- size_t v;
- OPENSSL_memcpy(&v, in, sizeof(v));
- return v;
-}
-
-static inline void store_word_le(void *out, size_t v) {
- OPENSSL_memcpy(out, &v, sizeof(v));
-}
-
// block128_f is the type of an AES block cipher implementation.
//
// Unlike upstream OpenSSL, it and the other functions in this file hard-code
@@ -171,7 +150,7 @@ typedef struct {
uint64_t u[2];
uint32_t d[4];
uint8_t c[16];
- size_t t[16 / sizeof(size_t)];
+ crypto_word_t t[16 / sizeof(crypto_word_t)];
} Yi, EKi, EK0, len, Xi;
// Note that the order of |Xi| and |gcm_key| is fixed by the MOVBE-based,
diff --git a/deps/boringssl/src/crypto/fipsmodule/modes/ofb.c b/deps/boringssl/src/crypto/fipsmodule/modes/ofb.c
index 4c70ce6..9d73d8a 100644
--- a/deps/boringssl/src/crypto/fipsmodule/modes/ofb.c
+++ b/deps/boringssl/src/crypto/fipsmodule/modes/ofb.c
@@ -60,7 +60,8 @@ OPENSSL_STATIC_ASSERT(16 % sizeof(size_t) == 0,
void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
const AES_KEY *key, uint8_t ivec[16], unsigned *num,
block128_f block) {
- assert(in && out && key && ivec && num);
+ assert(key != NULL && ivec != NULL && num != NULL);
+ assert(len == 0 || (in != NULL && out != NULL));
unsigned n = *num;
diff --git a/deps/boringssl/src/crypto/fipsmodule/rand/internal.h b/deps/boringssl/src/crypto/fipsmodule/rand/internal.h
index 598a17b..127e5d1 100644
--- a/deps/boringssl/src/crypto/fipsmodule/rand/internal.h
+++ b/deps/boringssl/src/crypto/fipsmodule/rand/internal.h
@@ -45,12 +45,10 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
// for seeding a DRBG, to |out_entropy|. It sets |*out_used_cpu| to one if the
// entropy came directly from the CPU and zero if it came from the OS. It
// actively obtains entropy from the CPU/OS and so should not be called from
-// within the FIPS module if |BORINGSSL_FIPS_PASSIVE_ENTROPY| is defined.
+// within the FIPS module.
void CRYPTO_get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
int *out_used_cpu);
-#if defined(BORINGSSL_FIPS_PASSIVE_ENTROPY)
-
// RAND_load_entropy supplies |entropy_len| bytes of entropy to the module. The
// |from_cpu| parameter is true iff the entropy was obtained directly from the
// CPU.
@@ -61,23 +59,22 @@ void RAND_load_entropy(const uint8_t *entropy, size_t entropy_len,
// when the module has stopped because it has run out of entropy.
void RAND_need_entropy(size_t bytes_needed);
-#endif // BORINGSSL_FIPS_PASSIVE_ENTROPY
#endif // BORINGSSL_FIPS
// CRYPTO_sysrand fills |len| bytes at |buf| with entropy from the operating
// system.
void CRYPTO_sysrand(uint8_t *buf, size_t len);
-#if defined(OPENSSL_URANDOM)
-// CRYPTO_init_sysrand initializes long-lived resources needed to draw entropy
-// from the operating system.
-void CRYPTO_init_sysrand(void);
-
// CRYPTO_sysrand_for_seed fills |len| bytes at |buf| with entropy from the
// operating system. It may draw from the |GRND_RANDOM| pool on Android,
// depending on the vendor's configuration.
void CRYPTO_sysrand_for_seed(uint8_t *buf, size_t len);
+#if defined(OPENSSL_URANDOM)
+// CRYPTO_init_sysrand initializes long-lived resources needed to draw entropy
+// from the operating system.
+void CRYPTO_init_sysrand(void);
+
// CRYPTO_sysrand_if_available fills |len| bytes at |buf| with entropy from the
// operating system, or early /dev/urandom data, and returns 1, _if_ the entropy
// pool is initialized or if getrandom() is not available and not in FIPS mode.
@@ -87,10 +84,6 @@ int CRYPTO_sysrand_if_available(uint8_t *buf, size_t len);
#else
OPENSSL_INLINE void CRYPTO_init_sysrand(void) {}
-OPENSSL_INLINE void CRYPTO_sysrand_for_seed(uint8_t *buf, size_t len) {
- CRYPTO_sysrand(buf, len);
-}
-
OPENSSL_INLINE int CRYPTO_sysrand_if_available(uint8_t *buf, size_t len) {
CRYPTO_sysrand(buf, len);
return 1;
diff --git a/deps/boringssl/src/crypto/fipsmodule/rand/rand.c b/deps/boringssl/src/crypto/fipsmodule/rand/rand.c
index aa0f05b..29c43ae 100644
--- a/deps/boringssl/src/crypto/fipsmodule/rand/rand.c
+++ b/deps/boringssl/src/crypto/fipsmodule/rand/rand.c
@@ -83,16 +83,18 @@ struct rand_thread_state {
// called when the whole process is exiting.
DEFINE_BSS_GET(struct rand_thread_state *, thread_states_list);
DEFINE_STATIC_MUTEX(thread_states_list_lock);
+DEFINE_STATIC_MUTEX(state_clear_all_lock);
static void rand_thread_state_clear_all(void) __attribute__((destructor));
static void rand_thread_state_clear_all(void) {
CRYPTO_STATIC_MUTEX_lock_write(thread_states_list_lock_bss_get());
+ CRYPTO_STATIC_MUTEX_lock_write(state_clear_all_lock_bss_get());
for (struct rand_thread_state *cur = *thread_states_list_bss_get();
cur != NULL; cur = cur->next) {
CTR_DRBG_clear(&cur->drbg);
}
- // |thread_states_list_lock is deliberately left locked so that any threads
- // that are still running will hang if they try to call |RAND_bytes|.
+ // The locks are deliberately left locked so that any threads that are still
+ // running will hang if they try to call |RAND_bytes|.
}
#endif
@@ -176,8 +178,6 @@ void CRYPTO_get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
#endif
}
-#if defined(BORINGSSL_FIPS_PASSIVE_ENTROPY)
-
// In passive entropy mode, entropy is supplied from outside of the module via
// |RAND_load_entropy| and is stored in global instance of the following
// structure.
@@ -240,17 +240,6 @@ static void get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
CRYPTO_STATIC_MUTEX_unlock_write(entropy_buffer_lock_bss_get());
}
-#else
-
-// In the active case, |get_seed_entropy| simply calls |CRYPTO_get_seed_entropy|
-// in order to obtain entropy from the CPU or OS.
-static void get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
- int *out_used_cpu) {
- CRYPTO_get_seed_entropy(out_entropy, out_entropy_len, out_used_cpu);
-}
-
-#endif // !BORINGSSL_FIPS_PASSIVE_ENTROPY
-
// rand_get_seed fills |seed| with entropy and sets |*out_used_cpu| to one if
// that entropy came directly from the CPU and zero otherwise.
static void rand_get_seed(struct rand_thread_state *state,
@@ -304,7 +293,7 @@ static void rand_get_seed(struct rand_thread_state *state,
int *out_used_cpu) {
// If not in FIPS mode, we don't overread from the system entropy source and
// we don't depend only on the hardware RDRAND.
- CRYPTO_sysrand(seed, CTR_DRBG_ENTROPY_LEN);
+ CRYPTO_sysrand_for_seed(seed, CTR_DRBG_ENTROPY_LEN);
*out_used_cpu = 0;
}
@@ -415,7 +404,7 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
// bug on ppc64le. glibc may implement pthread locks by wrapping user code
// in a hardware transaction, but, on some older versions of glibc and the
// kernel, syscalls made with |syscall| did not abort the transaction.
- CRYPTO_STATIC_MUTEX_lock_read(thread_states_list_lock_bss_get());
+ CRYPTO_STATIC_MUTEX_lock_read(state_clear_all_lock_bss_get());
#endif
if (!CTR_DRBG_reseed(&state->drbg, seed, NULL, 0)) {
abort();
@@ -424,7 +413,7 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
state->fork_generation = fork_generation;
} else {
#if defined(BORINGSSL_FIPS)
- CRYPTO_STATIC_MUTEX_lock_read(thread_states_list_lock_bss_get());
+ CRYPTO_STATIC_MUTEX_lock_read(state_clear_all_lock_bss_get());
#endif
}
@@ -453,7 +442,7 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
}
#if defined(BORINGSSL_FIPS)
- CRYPTO_STATIC_MUTEX_unlock_read(thread_states_list_lock_bss_get());
+ CRYPTO_STATIC_MUTEX_unlock_read(state_clear_all_lock_bss_get());
#endif
}
diff --git a/deps/boringssl/src/crypto/fipsmodule/rand/urandom.c b/deps/boringssl/src/crypto/fipsmodule/rand/urandom.c
index 3def3aa..fa0a333 100644
--- a/deps/boringssl/src/crypto/fipsmodule/rand/urandom.c
+++ b/deps/boringssl/src/crypto/fipsmodule/rand/urandom.c
@@ -62,6 +62,15 @@
#include <sys/random.h>
#endif
+#if defined(OPENSSL_FREEBSD)
+#define URANDOM_BLOCKS_FOR_ENTROPY
+#if __FreeBSD__ >= 12
+// getrandom is supported in FreeBSD 12 and up.
+#define FREEBSD_GETRANDOM
+#include <sys/random.h>
+#endif
+#endif
+
#include <openssl/thread.h>
#include <openssl/mem.h>
@@ -176,6 +185,11 @@ static void init_once(void) {
}
#endif
+#if defined(FREEBSD_GETRANDOM)
+ *urandom_fd_bss_get() = kHaveGetrandom;
+ return;
+#endif
+
// Android FIPS builds must support getrandom.
#if defined(BORINGSSL_FIPS) && defined(OPENSSL_ANDROID)
perror("getrandom not found");
@@ -256,11 +270,11 @@ static void wait_for_entropy(void) {
return;
}
-#if defined(BORINGSSL_FIPS)
- // In FIPS mode we ensure that the kernel has sufficient entropy before
- // continuing. This is automatically handled by getrandom, which requires
- // that the entropy pool has been initialised, but for urandom we have to
- // poll.
+#if defined(BORINGSSL_FIPS) && !defined(URANDOM_BLOCKS_FOR_ENTROPY)
+ // In FIPS mode on platforms where urandom doesn't block at startup, we ensure
+ // that the kernel has sufficient entropy before continuing. This is
+ // automatically handled by getrandom, which requires that the entropy pool
+ // has been initialised, but for urandom we have to poll.
for (;;) {
int entropy_bits;
if (ioctl(fd, RNDGETENTCNT, &entropy_bits)) {
@@ -277,7 +291,7 @@ static void wait_for_entropy(void) {
usleep(250000);
}
-#endif // BORINGSSL_FIPS
+#endif // BORINGSSL_FIPS && !URANDOM_BLOCKS_FOR_ENTROPY
}
// fill_with_entropy writes |len| bytes of entropy into |out|. It returns one
@@ -291,11 +305,14 @@ static int fill_with_entropy(uint8_t *out, size_t len, int block, int seed) {
return 1;
}
-#if defined(USE_NR_getrandom)
+#if defined(USE_NR_getrandom) || defined(FREEBSD_GETRANDOM)
int getrandom_flags = 0;
if (!block) {
getrandom_flags |= GRND_NONBLOCK;
}
+#endif
+
+#if defined (USE_NR_getrandom)
if (seed) {
getrandom_flags |= *extra_getrandom_flags_for_seed_bss_get();
}
@@ -315,6 +332,8 @@ static int fill_with_entropy(uint8_t *out, size_t len, int block, int seed) {
if (*urandom_fd_bss_get() == kHaveGetrandom) {
#if defined(USE_NR_getrandom)
r = boringssl_getrandom(out, len, getrandom_flags);
+#elif defined(FREEBSD_GETRANDOM)
+ r = getrandom(out, len, getrandom_flags);
#elif defined(OPENSSL_MACOS)
if (__builtin_available(macos 10.12, *)) {
// |getentropy| can only request 256 bytes at a time.
@@ -348,6 +367,10 @@ static int fill_with_entropy(uint8_t *out, size_t len, int block, int seed) {
return 1;
}
+void CRYPTO_init_sysrand(void) {
+ CRYPTO_once(rand_once_bss_get(), init_once);
+}
+
// CRYPTO_sysrand puts |requested| random bytes into |out|.
void CRYPTO_sysrand(uint8_t *out, size_t requested) {
if (!fill_with_entropy(out, requested, /*block=*/1, /*seed=*/0)) {
@@ -356,18 +379,12 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
}
}
-void CRYPTO_init_sysrand(void) {
- CRYPTO_once(rand_once_bss_get(), init_once);
-}
-
-#if defined(BORINGSSL_FIPS)
void CRYPTO_sysrand_for_seed(uint8_t *out, size_t requested) {
if (!fill_with_entropy(out, requested, /*block=*/1, /*seed=*/1)) {
perror("entropy fill failed");
abort();
}
}
-#endif // BORINGSSL_FIPS
int CRYPTO_sysrand_if_available(uint8_t *out, size_t requested) {
if (fill_with_entropy(out, requested, /*block=*/0, /*seed=*/0)) {
diff --git a/deps/boringssl/src/crypto/fipsmodule/rsa/rsa.c b/deps/boringssl/src/crypto/fipsmodule/rsa/rsa.c
index ae63e1a..fd84cba 100644
--- a/deps/boringssl/src/crypto/fipsmodule/rsa/rsa.c
+++ b/deps/boringssl/src/crypto/fipsmodule/rsa/rsa.c
@@ -458,18 +458,18 @@ static const struct pkcs1_sig_prefix kPKCS1SigPrefixes[] = {
};
int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len,
- int *is_alloced, int hash_nid, const uint8_t *msg,
- size_t msg_len) {
+ int *is_alloced, int hash_nid, const uint8_t *digest,
+ size_t digest_len) {
unsigned i;
if (hash_nid == NID_md5_sha1) {
// Special case: SSL signature, just check the length.
- if (msg_len != SSL_SIG_LENGTH) {
+ if (digest_len != SSL_SIG_LENGTH) {
OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
- *out_msg = (uint8_t*) msg;
+ *out_msg = (uint8_t *)digest;
*out_msg_len = SSL_SIG_LENGTH;
*is_alloced = 0;
return 1;
@@ -481,7 +481,7 @@ int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len,
continue;
}
- if (msg_len != sig_prefix->hash_len) {
+ if (digest_len != sig_prefix->hash_len) {
OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
@@ -491,7 +491,7 @@ int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len,
unsigned signed_msg_len;
uint8_t *signed_msg;
- signed_msg_len = prefix_len + msg_len;
+ signed_msg_len = prefix_len + digest_len;
if (signed_msg_len < prefix_len) {
OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_LONG);
return 0;
@@ -504,7 +504,7 @@ int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len,
}
OPENSSL_memcpy(signed_msg, prefix, prefix_len);
- OPENSSL_memcpy(signed_msg + prefix_len, msg, msg_len);
+ OPENSSL_memcpy(signed_msg + prefix_len, digest, digest_len);
*out_msg = signed_msg;
*out_msg_len = signed_msg_len;
@@ -517,8 +517,8 @@ int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len,
return 0;
}
-int RSA_sign(int hash_nid, const uint8_t *in, unsigned in_len, uint8_t *out,
- unsigned *out_len, RSA *rsa) {
+int RSA_sign(int hash_nid, const uint8_t *digest, unsigned digest_len,
+ uint8_t *out, unsigned *out_len, RSA *rsa) {
const unsigned rsa_size = RSA_size(rsa);
int ret = 0;
uint8_t *signed_msg = NULL;
@@ -527,11 +527,12 @@ int RSA_sign(int hash_nid, const uint8_t *in, unsigned in_len, uint8_t *out,
size_t size_t_out_len;
if (rsa->meth->sign) {
- return rsa->meth->sign(hash_nid, in, in_len, out, out_len, rsa);
+ return rsa->meth->sign(hash_nid, digest, digest_len, out, out_len, rsa);
}
if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len,
- &signed_msg_is_alloced, hash_nid, in, in_len) ||
+ &signed_msg_is_alloced, hash_nid, digest,
+ digest_len) ||
!RSA_sign_raw(rsa, &size_t_out_len, out, rsa_size, signed_msg,
signed_msg_len, RSA_PKCS1_PADDING)) {
goto err;
@@ -548,9 +549,9 @@ err:
}
int RSA_sign_pss_mgf1(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
- const uint8_t *in, size_t in_len, const EVP_MD *md,
- const EVP_MD *mgf1_md, int salt_len) {
- if (in_len != EVP_MD_size(md)) {
+ const uint8_t *digest, size_t digest_len,
+ const EVP_MD *md, const EVP_MD *mgf1_md, int salt_len) {
+ if (digest_len != EVP_MD_size(md)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
@@ -562,15 +563,15 @@ int RSA_sign_pss_mgf1(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
return 0;
}
- int ret =
- RSA_padding_add_PKCS1_PSS_mgf1(rsa, padded, in, md, mgf1_md, salt_len) &&
- RSA_sign_raw(rsa, out_len, out, max_out, padded, padded_len,
- RSA_NO_PADDING);
+ int ret = RSA_padding_add_PKCS1_PSS_mgf1(rsa, padded, digest, md, mgf1_md,
+ salt_len) &&
+ RSA_sign_raw(rsa, out_len, out, max_out, padded, padded_len,
+ RSA_NO_PADDING);
OPENSSL_free(padded);
return ret;
}
-int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
+int RSA_verify(int hash_nid, const uint8_t *digest, size_t digest_len,
const uint8_t *sig, size_t sig_len, RSA *rsa) {
if (rsa->n == NULL || rsa->e == NULL) {
OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
@@ -584,7 +585,7 @@ int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
size_t signed_msg_len = 0, len;
int signed_msg_is_alloced = 0;
- if (hash_nid == NID_md5_sha1 && msg_len != SSL_SIG_LENGTH) {
+ if (hash_nid == NID_md5_sha1 && digest_len != SSL_SIG_LENGTH) {
OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
@@ -601,7 +602,8 @@ int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
}
if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len,
- &signed_msg_is_alloced, hash_nid, msg, msg_len)) {
+ &signed_msg_is_alloced, hash_nid, digest,
+ digest_len)) {
goto out;
}
@@ -622,10 +624,10 @@ out:
return ret;
}
-int RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *msg, size_t msg_len,
+int RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *digest, size_t digest_len,
const EVP_MD *md, const EVP_MD *mgf1_md, int salt_len,
const uint8_t *sig, size_t sig_len) {
- if (msg_len != EVP_MD_size(md)) {
+ if (digest_len != EVP_MD_size(md)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
@@ -647,7 +649,7 @@ int RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *msg, size_t msg_len,
goto err;
}
- ret = RSA_verify_PKCS1_PSS_mgf1(rsa, msg, md, mgf1_md, em, salt_len);
+ ret = RSA_verify_PKCS1_PSS_mgf1(rsa, digest, md, mgf1_md, em, salt_len);
err:
OPENSSL_free(em);
@@ -655,7 +657,8 @@ err:
}
static int check_mod_inverse(int *out_ok, const BIGNUM *a, const BIGNUM *ainv,
- const BIGNUM *m, BN_CTX *ctx) {
+ const BIGNUM *m, unsigned m_min_bits,
+ BN_CTX *ctx) {
if (BN_is_negative(ainv) || BN_cmp(ainv, m) >= 0) {
*out_ok = 0;
return 1;
@@ -668,7 +671,7 @@ static int check_mod_inverse(int *out_ok, const BIGNUM *a, const BIGNUM *ainv,
BIGNUM *tmp = BN_CTX_get(ctx);
int ret = tmp != NULL &&
bn_mul_consttime(tmp, a, ainv, ctx) &&
- bn_div_consttime(NULL, tmp, tmp, m, ctx);
+ bn_div_consttime(NULL, tmp, tmp, m, m_min_bits, ctx);
if (ret) {
*out_ok = BN_is_one(tmp);
}
@@ -748,10 +751,15 @@ int RSA_check_key(const RSA *key) {
// simply check that d * e is one mod p-1 and mod q-1. Note d and e were bound
// by earlier checks in this function.
if (!bn_usub_consttime(&pm1, key->p, BN_value_one()) ||
- !bn_usub_consttime(&qm1, key->q, BN_value_one()) ||
- !bn_mul_consttime(&de, key->d, key->e, ctx) ||
- !bn_div_consttime(NULL, &tmp, &de, &pm1, ctx) ||
- !bn_div_consttime(NULL, &de, &de, &qm1, ctx)) {
+ !bn_usub_consttime(&qm1, key->q, BN_value_one())) {
+ OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
+ goto out;
+ }
+ const unsigned pm1_bits = BN_num_bits(&pm1);
+ const unsigned qm1_bits = BN_num_bits(&qm1);
+ if (!bn_mul_consttime(&de, key->d, key->e, ctx) ||
+ !bn_div_consttime(NULL, &tmp, &de, &pm1, pm1_bits, ctx) ||
+ !bn_div_consttime(NULL, &de, &de, &qm1, qm1_bits, ctx)) {
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
goto out;
}
@@ -770,9 +778,12 @@ int RSA_check_key(const RSA *key) {
if (has_crt_values) {
int dmp1_ok, dmq1_ok, iqmp_ok;
- if (!check_mod_inverse(&dmp1_ok, key->e, key->dmp1, &pm1, ctx) ||
- !check_mod_inverse(&dmq1_ok, key->e, key->dmq1, &qm1, ctx) ||
- !check_mod_inverse(&iqmp_ok, key->q, key->iqmp, key->p, ctx)) {
+ if (!check_mod_inverse(&dmp1_ok, key->e, key->dmp1, &pm1, pm1_bits, ctx) ||
+ !check_mod_inverse(&dmq1_ok, key->e, key->dmq1, &qm1, qm1_bits, ctx) ||
+ // |p| is odd, so |pm1| and |p| have the same bit width. If they didn't,
+ // we only need a lower bound anyway.
+ !check_mod_inverse(&iqmp_ok, key->q, key->iqmp, key->p, pm1_bits,
+ ctx)) {
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
goto out;
}
diff --git a/deps/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.c b/deps/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.c
index 2f76e9e..a6865c0 100644
--- a/deps/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.c
+++ b/deps/boringssl/src/crypto/fipsmodule/rsa/rsa_impl.c
@@ -79,9 +79,8 @@ int rsa_check_public_key(const RSA *rsa) {
return 0;
}
- unsigned rsa_bits = BN_num_bits(rsa->n);
-
- if (rsa_bits > 16 * 1024) {
+ unsigned n_bits = BN_num_bits(rsa->n);
+ if (n_bits > 16 * 1024) {
OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE);
return 0;
}
@@ -96,17 +95,21 @@ int rsa_check_public_key(const RSA *rsa) {
// [2] https://www.imperialviolet.org/2012/03/17/rsados.html
// [3] https://msdn.microsoft.com/en-us/library/aa387685(VS.85).aspx
static const unsigned kMaxExponentBits = 33;
-
- if (BN_num_bits(rsa->e) > kMaxExponentBits) {
+ unsigned e_bits = BN_num_bits(rsa->e);
+ if (e_bits > kMaxExponentBits ||
+ // Additionally reject e = 1 or even e. e must be odd to be relatively
+ // prime with phi(n).
+ e_bits < 2 ||
+ !BN_is_odd(rsa->e)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
return 0;
}
- // Verify |n > e|. Comparing |rsa_bits| to |kMaxExponentBits| is a small
+ // Verify |n > e|. Comparing |n_bits| to |kMaxExponentBits| is a small
// shortcut to comparing |n| and |e| directly. In reality, |kMaxExponentBits|
// is much smaller than the minimum RSA key size that any application should
// accept.
- if (rsa_bits <= kMaxExponentBits) {
+ if (n_bits <= kMaxExponentBits) {
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
@@ -1259,12 +1262,14 @@ static int rsa_generate_key_impl(RSA *rsa, int bits, const BIGNUM *e_value,
// values for d.
} while (BN_cmp(rsa->d, pow2_prime_bits) <= 0);
+ assert(BN_num_bits(pm1) == (unsigned)prime_bits);
+ assert(BN_num_bits(qm1) == (unsigned)prime_bits);
if (// Calculate n.
!bn_mul_consttime(rsa->n, rsa->p, rsa->q, ctx) ||
// Calculate d mod (p-1).
- !bn_div_consttime(NULL, rsa->dmp1, rsa->d, pm1, ctx) ||
+ !bn_div_consttime(NULL, rsa->dmp1, rsa->d, pm1, prime_bits, ctx) ||
// Calculate d mod (q-1)
- !bn_div_consttime(NULL, rsa->dmq1, rsa->d, qm1, ctx)) {
+ !bn_div_consttime(NULL, rsa->dmq1, rsa->d, qm1, prime_bits, ctx)) {
goto bn_err;
}
bn_set_minimal_width(rsa->n);
diff --git a/deps/boringssl/src/crypto/fipsmodule/self_check/fips.c b/deps/boringssl/src/crypto/fipsmodule/self_check/fips.c
new file mode 100644
index 0000000..d55c493
--- /dev/null
+++ b/deps/boringssl/src/crypto/fipsmodule/self_check/fips.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2017, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/crypto.h>
+
+#include "../../internal.h"
+#include "../delocate.h"
+
+
+int FIPS_mode(void) {
+#if defined(BORINGSSL_FIPS) && !defined(OPENSSL_ASAN)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+int FIPS_mode_set(int on) { return on == FIPS_mode(); }
+
+#if defined(BORINGSSL_FIPS_COUNTERS)
+
+size_t FIPS_read_counter(enum fips_counter_t counter) {
+ if (counter < 0 || counter > fips_counter_max) {
+ abort();
+ }
+
+ const size_t *array =
+ CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_FIPS_COUNTERS);
+ if (!array) {
+ return 0;
+ }
+
+ return array[counter];
+}
+
+void boringssl_fips_inc_counter(enum fips_counter_t counter) {
+ if (counter < 0 || counter > fips_counter_max) {
+ abort();
+ }
+
+ size_t *array =
+ CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_FIPS_COUNTERS);
+ if (!array) {
+ const size_t num_bytes = sizeof(size_t) * (fips_counter_max + 1);
+ array = OPENSSL_malloc(num_bytes);
+ if (!array) {
+ return;
+ }
+
+ OPENSSL_memset(array, 0, num_bytes);
+ if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_FIPS_COUNTERS, array,
+ OPENSSL_free)) {
+ // |OPENSSL_free| has already been called by |CRYPTO_set_thread_local|.
+ return;
+ }
+ }
+
+ array[counter]++;
+}
+
+#else
+
+size_t FIPS_read_counter(enum fips_counter_t counter) { return 0; }
+
+// boringssl_fips_inc_counter is a no-op, inline function in internal.h in this
+// case. That should let the compiler optimise away the callsites.
+
+#endif
diff --git a/deps/boringssl/src/crypto/fipsmodule/self_check/self_check.c b/deps/boringssl/src/crypto/fipsmodule/self_check/self_check.c
index 638500b..2a58cd3 100644
--- a/deps/boringssl/src/crypto/fipsmodule/self_check/self_check.c
+++ b/deps/boringssl/src/crypto/fipsmodule/self_check/self_check.c
@@ -32,13 +32,20 @@
#include "../../internal.h"
#include "../ec/internal.h"
+#include "../ecdsa/internal.h"
#include "../rand/internal.h"
#include "../tls/internal.h"
// MSVC wants to put a NUL byte at the end of non-char arrays and so cannot
-// compile this.
-#if !defined(_MSC_VER)
+// compile the real logic.
+#if defined(_MSC_VER)
+
+int BORINGSSL_self_test(void) {
+ return 0;
+}
+
+#else
#if defined(BORINGSSL_FIPS) && defined(OPENSSL_ANDROID)
// FIPS builds on Android will test for flag files, named after the module hash,
@@ -727,14 +734,12 @@ int boringssl_fips_self_test(
// ECDSA Sign/Verify KAT
// The 'k' value for ECDSA is fixed to avoid an entropy draw.
- ec_key->fixed_k = BN_new();
- if (ec_key->fixed_k == NULL ||
- !BN_set_word(ec_key->fixed_k, 42)) {
- fprintf(stderr, "Out of memory\n");
- goto err;
- }
+ uint8_t ecdsa_k[32] = {0};
+ ecdsa_k[31] = 42;
- sig = ECDSA_do_sign(kPlaintextSHA256, sizeof(kPlaintextSHA256), ec_key);
+ sig = ecdsa_sign_with_nonce_for_known_answer_test(
+ kPlaintextSHA256, sizeof(kPlaintextSHA256), ec_key, ecdsa_k,
+ sizeof(ecdsa_k));
uint8_t ecdsa_r_bytes[sizeof(kECDSASigR)];
uint8_t ecdsa_s_bytes[sizeof(kECDSASigS)];
diff --git a/deps/boringssl/src/crypto/fipsmodule/sha/sha1.c b/deps/boringssl/src/crypto/fipsmodule/sha/sha1.c
index 3b76194..c629308 100644
--- a/deps/boringssl/src/crypto/fipsmodule/sha/sha1.c
+++ b/deps/boringssl/src/crypto/fipsmodule/sha/sha1.c
@@ -60,8 +60,9 @@
#include <openssl/mem.h>
-#include "internal.h"
#include "../../internal.h"
+#include "../digest/md32_common.h"
+#include "internal.h"
int SHA1_Init(SHA_CTX *sha) {
@@ -83,30 +84,33 @@ uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t out[SHA_DIGEST_LENGTH]) {
return out;
}
-#define DATA_ORDER_IS_BIG_ENDIAN
-
-#define HASH_CTX SHA_CTX
-#define HASH_CBLOCK 64
-#define HASH_DIGEST_LENGTH 20
-#define HASH_MAKE_STRING(c, s) \
- do { \
- uint32_t ll; \
- ll = (c)->h[0]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[1]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[2]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[3]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[4]; \
- HOST_l2c(ll, (s)); \
- } while (0)
+#if !defined(SHA1_ASM)
+static void sha1_block_data_order(uint32_t *state, const uint8_t *data,
+ size_t num);
+#endif
+
+void SHA1_Transform(SHA_CTX *c, const uint8_t data[SHA_CBLOCK]) {
+ sha1_block_data_order(c->h, data, 1);
+}
+
+int SHA1_Update(SHA_CTX *c, const void *data, size_t len) {
+ crypto_md32_update(&sha1_block_data_order, c->h, c->data, SHA_CBLOCK, &c->num,
+ &c->Nh, &c->Nl, data, len);
+ return 1;
+}
+
+int SHA1_Final(uint8_t out[SHA_DIGEST_LENGTH], SHA_CTX *c) {
+ crypto_md32_final(&sha1_block_data_order, c->h, c->data, SHA_CBLOCK, &c->num,
+ c->Nh, c->Nl, /*is_big_endian=*/1);
+
+ CRYPTO_store_u32_be(out, c->h[0]);
+ CRYPTO_store_u32_be(out + 4, c->h[1]);
+ CRYPTO_store_u32_be(out + 8, c->h[2]);
+ CRYPTO_store_u32_be(out + 12, c->h[3]);
+ CRYPTO_store_u32_be(out + 16, c->h[4]);
+ return 1;
+}
-#define HASH_UPDATE SHA1_Update
-#define HASH_TRANSFORM SHA1_Transform
-#define HASH_FINAL SHA1_Final
-#define HASH_BLOCK_DATA_ORDER sha1_block_data_order
#define ROTATE(a, n) (((a) << (n)) | ((a) >> (32 - (n))))
#define Xupdate(a, ix, ia, ib, ic, id) \
do { \
@@ -114,13 +118,6 @@ uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t out[SHA_DIGEST_LENGTH]) {
(ix) = (a) = ROTATE((a), 1); \
} while (0)
-#if !defined(SHA1_ASM)
-static void sha1_block_data_order(uint32_t *state, const uint8_t *data,
- size_t num);
-#endif
-
-#include "../digest/md32_common.h"
-
#define K_00_19 0x5a827999UL
#define K_20_39 0x6ed9eba1UL
#define K_40_59 0x8f1bbcdcUL
@@ -193,7 +190,7 @@ static void sha1_block_data_order(uint32_t *state, const uint8_t *data,
#if !defined(SHA1_ASM)
static void sha1_block_data_order(uint32_t *state, const uint8_t *data,
size_t num) {
- register uint32_t A, B, C, D, E, T, l;
+ register uint32_t A, B, C, D, E, T;
uint32_t XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9, XX10,
XX11, XX12, XX13, XX14, XX15;
@@ -204,52 +201,52 @@ static void sha1_block_data_order(uint32_t *state, const uint8_t *data,
E = state[4];
for (;;) {
- HOST_c2l(data, l);
- X(0) = l;
- HOST_c2l(data, l);
- X(1) = l;
+ X(0) = CRYPTO_load_u32_be(data);
+ data += 4;
+ X(1) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(0, A, B, C, D, E, T, X(0));
- HOST_c2l(data, l);
- X(2) = l;
+ X(2) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(1, T, A, B, C, D, E, X(1));
- HOST_c2l(data, l);
- X(3) = l;
+ X(3) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(2, E, T, A, B, C, D, X(2));
- HOST_c2l(data, l);
- X(4) = l;
+ X(4) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(3, D, E, T, A, B, C, X(3));
- HOST_c2l(data, l);
- X(5) = l;
+ X(5) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(4, C, D, E, T, A, B, X(4));
- HOST_c2l(data, l);
- X(6) = l;
+ X(6) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(5, B, C, D, E, T, A, X(5));
- HOST_c2l(data, l);
- X(7) = l;
+ X(7) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(6, A, B, C, D, E, T, X(6));
- HOST_c2l(data, l);
- X(8) = l;
+ X(8) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(7, T, A, B, C, D, E, X(7));
- HOST_c2l(data, l);
- X(9) = l;
+ X(9) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(8, E, T, A, B, C, D, X(8));
- HOST_c2l(data, l);
- X(10) = l;
+ X(10) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(9, D, E, T, A, B, C, X(9));
- HOST_c2l(data, l);
- X(11) = l;
+ X(11) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(10, C, D, E, T, A, B, X(10));
- HOST_c2l(data, l);
- X(12) = l;
+ X(12) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(11, B, C, D, E, T, A, X(11));
- HOST_c2l(data, l);
- X(13) = l;
+ X(13) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(12, A, B, C, D, E, T, X(12));
- HOST_c2l(data, l);
- X(14) = l;
+ X(14) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(13, T, A, B, C, D, E, X(13));
- HOST_c2l(data, l);
- X(15) = l;
+ X(15) = CRYPTO_load_u32_be(data);
+ data += 4;
BODY_00_15(14, E, T, A, B, C, D, X(14));
BODY_00_15(15, D, E, T, A, B, C, X(15));
@@ -341,15 +338,6 @@ static void sha1_block_data_order(uint32_t *state, const uint8_t *data,
}
#endif
-#undef DATA_ORDER_IS_BIG_ENDIAN
-#undef HASH_CTX
-#undef HASH_CBLOCK
-#undef HASH_DIGEST_LENGTH
-#undef HASH_MAKE_STRING
-#undef HASH_UPDATE
-#undef HASH_TRANSFORM
-#undef HASH_FINAL
-#undef HASH_BLOCK_DATA_ORDER
#undef ROTATE
#undef Xupdate
#undef K_00_19
@@ -367,5 +355,3 @@ static void sha1_block_data_order(uint32_t *state, const uint8_t *data,
#undef BODY_40_59
#undef BODY_60_79
#undef X
-#undef HOST_c2l
-#undef HOST_l2c
diff --git a/deps/boringssl/src/crypto/fipsmodule/sha/sha256.c b/deps/boringssl/src/crypto/fipsmodule/sha/sha256.c
index 0e42446..4394f4a 100644
--- a/deps/boringssl/src/crypto/fipsmodule/sha/sha256.c
+++ b/deps/boringssl/src/crypto/fipsmodule/sha/sha256.c
@@ -60,8 +60,9 @@
#include <openssl/mem.h>
-#include "internal.h"
#include "../../internal.h"
+#include "../digest/md32_common.h"
+#include "internal.h"
int SHA224_Init(SHA256_CTX *sha) {
@@ -112,71 +113,60 @@ uint8_t *SHA256(const uint8_t *data, size_t len,
return out;
}
-int SHA224_Update(SHA256_CTX *ctx, const void *data, size_t len) {
- return SHA256_Update(ctx, data, len);
-}
+#ifndef SHA256_ASM
+static void sha256_block_data_order(uint32_t *state, const uint8_t *in,
+ size_t num);
+#endif
-int SHA224_Final(uint8_t out[SHA224_DIGEST_LENGTH], SHA256_CTX *ctx) {
- // SHA224_Init sets |ctx->md_len| to |SHA224_DIGEST_LENGTH|, so this has a
- // smaller output.
- return SHA256_Final(out, ctx);
+void SHA256_Transform(SHA256_CTX *c, const uint8_t data[SHA256_CBLOCK]) {
+ sha256_block_data_order(c->h, data, 1);
}
-#define DATA_ORDER_IS_BIG_ENDIAN
+int SHA256_Update(SHA256_CTX *c, const void *data, size_t len) {
+ crypto_md32_update(&sha256_block_data_order, c->h, c->data, SHA256_CBLOCK,
+ &c->num, &c->Nh, &c->Nl, data, len);
+ return 1;
+}
-#define HASH_CTX SHA256_CTX
-#define HASH_CBLOCK 64
-#define HASH_DIGEST_LENGTH 32
+int SHA224_Update(SHA256_CTX *ctx, const void *data, size_t len) {
+ return SHA256_Update(ctx, data, len);
+}
-// Note that FIPS180-2 discusses "Truncation of the Hash Function Output."
-// default: case below covers for it. It's not clear however if it's permitted
-// to truncate to amount of bytes not divisible by 4. I bet not, but if it is,
-// then default: case shall be extended. For reference. Idea behind separate
-// cases for pre-defined lenghts is to let the compiler decide if it's
-// appropriate to unroll small loops.
-//
-// TODO(davidben): The small |md_len| case is one of the few places a low-level
-// hash 'final' function can fail. This should never happen.
-#define HASH_MAKE_STRING(c, s) \
- do { \
- uint32_t ll; \
- unsigned int nn; \
- switch ((c)->md_len) { \
- case SHA224_DIGEST_LENGTH: \
- for (nn = 0; nn < SHA224_DIGEST_LENGTH / 4; nn++) { \
- ll = (c)->h[nn]; \
- HOST_l2c(ll, (s)); \
- } \
- break; \
- case SHA256_DIGEST_LENGTH: \
- for (nn = 0; nn < SHA256_DIGEST_LENGTH / 4; nn++) { \
- ll = (c)->h[nn]; \
- HOST_l2c(ll, (s)); \
- } \
- break; \
- default: \
- if ((c)->md_len > SHA256_DIGEST_LENGTH) { \
- return 0; \
- } \
- for (nn = 0; nn < (c)->md_len / 4; nn++) { \
- ll = (c)->h[nn]; \
- HOST_l2c(ll, (s)); \
- } \
- break; \
- } \
- } while (0)
+static int sha256_final_impl(uint8_t *out, SHA256_CTX *c) {
+ crypto_md32_final(&sha256_block_data_order, c->h, c->data, SHA256_CBLOCK,
+ &c->num, c->Nh, c->Nl, /*is_big_endian=*/1);
+ // TODO(davidben): This overflow check one of the few places a low-level hash
+ // 'final' function can fail. SHA-512 does not have a corresponding check.
+ // These functions already misbehave if the caller arbitrarily mutates |c|, so
+ // can we assume one of |SHA256_Init| or |SHA224_Init| was used?
+ if (c->md_len > SHA256_DIGEST_LENGTH) {
+ return 0;
+ }
-#define HASH_UPDATE SHA256_Update
-#define HASH_TRANSFORM SHA256_Transform
-#define HASH_FINAL SHA256_Final
-#define HASH_BLOCK_DATA_ORDER sha256_block_data_order
-#ifndef SHA256_ASM
-static void sha256_block_data_order(uint32_t *state, const uint8_t *in,
- size_t num);
-#endif
+ assert(c->md_len % 4 == 0);
+ const size_t out_words = c->md_len / 4;
+ for (size_t i = 0; i < out_words; i++) {
+ CRYPTO_store_u32_be(out, c->h[i]);
+ out += 4;
+ }
+ return 1;
+}
-#include "../digest/md32_common.h"
+int SHA256_Final(uint8_t out[SHA256_DIGEST_LENGTH], SHA256_CTX *c) {
+ // Ideally we would assert |sha->md_len| is |SHA256_DIGEST_LENGTH| to match
+ // the size hint, but calling code often pairs |SHA224_Init| with
+ // |SHA256_Final| and expects |sha->md_len| to carry the size over.
+ //
+ // TODO(davidben): Add an assert and fix code to match them up.
+ return sha256_final_impl(out, c);
+}
+int SHA224_Final(uint8_t out[SHA224_DIGEST_LENGTH], SHA256_CTX *ctx) {
+ // SHA224_Init sets |ctx->md_len| to |SHA224_DIGEST_LENGTH|, so this has a
+ // smaller output.
+ assert(ctx->md_len == SHA224_DIGEST_LENGTH);
+ return sha256_final_impl(out, ctx);
+}
#ifndef SHA256_ASM
static const uint32_t K256[64] = {
@@ -241,55 +231,53 @@ static void sha256_block_data_order(uint32_t *state, const uint8_t *data,
g = state[6];
h = state[7];
- uint32_t l;
-
- HOST_c2l(data, l);
- T1 = X[0] = l;
+ T1 = X[0] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(0, a, b, c, d, e, f, g, h);
- HOST_c2l(data, l);
- T1 = X[1] = l;
+ T1 = X[1] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(1, h, a, b, c, d, e, f, g);
- HOST_c2l(data, l);
- T1 = X[2] = l;
+ T1 = X[2] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(2, g, h, a, b, c, d, e, f);
- HOST_c2l(data, l);
- T1 = X[3] = l;
+ T1 = X[3] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(3, f, g, h, a, b, c, d, e);
- HOST_c2l(data, l);
- T1 = X[4] = l;
+ T1 = X[4] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(4, e, f, g, h, a, b, c, d);
- HOST_c2l(data, l);
- T1 = X[5] = l;
+ T1 = X[5] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(5, d, e, f, g, h, a, b, c);
- HOST_c2l(data, l);
- T1 = X[6] = l;
+ T1 = X[6] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(6, c, d, e, f, g, h, a, b);
- HOST_c2l(data, l);
- T1 = X[7] = l;
+ T1 = X[7] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(7, b, c, d, e, f, g, h, a);
- HOST_c2l(data, l);
- T1 = X[8] = l;
+ T1 = X[8] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(8, a, b, c, d, e, f, g, h);
- HOST_c2l(data, l);
- T1 = X[9] = l;
+ T1 = X[9] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(9, h, a, b, c, d, e, f, g);
- HOST_c2l(data, l);
- T1 = X[10] = l;
+ T1 = X[10] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(10, g, h, a, b, c, d, e, f);
- HOST_c2l(data, l);
- T1 = X[11] = l;
+ T1 = X[11] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(11, f, g, h, a, b, c, d, e);
- HOST_c2l(data, l);
- T1 = X[12] = l;
+ T1 = X[12] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(12, e, f, g, h, a, b, c, d);
- HOST_c2l(data, l);
- T1 = X[13] = l;
+ T1 = X[13] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(13, d, e, f, g, h, a, b, c);
- HOST_c2l(data, l);
- T1 = X[14] = l;
+ T1 = X[14] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(14, c, d, e, f, g, h, a, b);
- HOST_c2l(data, l);
- T1 = X[15] = l;
+ T1 = X[15] = CRYPTO_load_u32_be(data);
+ data += 4;
ROUND_00_15(15, b, c, d, e, f, g, h, a);
for (i = 16; i < 64; i += 8) {
@@ -321,15 +309,6 @@ void SHA256_TransformBlocks(uint32_t state[8], const uint8_t *data,
sha256_block_data_order(state, data, num_blocks);
}
-#undef DATA_ORDER_IS_BIG_ENDIAN
-#undef HASH_CTX
-#undef HASH_CBLOCK
-#undef HASH_DIGEST_LENGTH
-#undef HASH_MAKE_STRING
-#undef HASH_UPDATE
-#undef HASH_TRANSFORM
-#undef HASH_FINAL
-#undef HASH_BLOCK_DATA_ORDER
#undef ROTATE
#undef Sigma0
#undef Sigma1
@@ -339,5 +318,3 @@ void SHA256_TransformBlocks(uint32_t state[8], const uint8_t *data,
#undef Maj
#undef ROUND_00_15
#undef ROUND_16_63
-#undef HOST_c2l
-#undef HOST_l2c
diff --git a/deps/boringssl/src/crypto/fipsmodule/sha/sha512.c b/deps/boringssl/src/crypto/fipsmodule/sha/sha512.c
index fd02574..befdd52 100644
--- a/deps/boringssl/src/crypto/fipsmodule/sha/sha512.c
+++ b/deps/boringssl/src/crypto/fipsmodule/sha/sha512.c
@@ -70,6 +70,8 @@
// this writing, so there is no need for a common collector/padding
// implementation yet.
+static int sha512_final_impl(uint8_t *out, SHA512_CTX *sha);
+
int SHA384_Init(SHA512_CTX *sha) {
sha->h[0] = UINT64_C(0xcbbb9d5dc1059ed8);
sha->h[1] = UINT64_C(0x629a292a367cd507);
@@ -146,8 +148,8 @@ uint8_t *SHA512_256(const uint8_t *data, size_t len,
uint8_t out[SHA512_256_DIGEST_LENGTH]) {
SHA512_CTX ctx;
SHA512_256_Init(&ctx);
- SHA512_Update(&ctx, data, len);
- SHA512_Final(out, &ctx);
+ SHA512_256_Update(&ctx, data, len);
+ SHA512_256_Final(out, &ctx);
OPENSSL_cleanse(&ctx, sizeof(ctx));
return out;
}
@@ -160,8 +162,9 @@ static void sha512_block_data_order(uint64_t *state, const uint8_t *in,
int SHA384_Final(uint8_t out[SHA384_DIGEST_LENGTH], SHA512_CTX *sha) {
// |SHA384_Init| sets |sha->md_len| to |SHA384_DIGEST_LENGTH|, so this has a
- // |smaller output.
- return SHA512_Final(out, sha);
+ // smaller output.
+ assert(sha->md_len == SHA384_DIGEST_LENGTH);
+ return sha512_final_impl(out, sha);
}
int SHA384_Update(SHA512_CTX *sha, const void *data, size_t len) {
@@ -172,11 +175,11 @@ int SHA512_256_Update(SHA512_CTX *sha, const void *data, size_t len) {
return SHA512_Update(sha, data, len);
}
-int SHA512_256_Final(uint8_t out[SHA512_256_DIGEST_LENGTH],
- SHA512_CTX *sha) {
+int SHA512_256_Final(uint8_t out[SHA512_256_DIGEST_LENGTH], SHA512_CTX *sha) {
// |SHA512_256_Init| sets |sha->md_len| to |SHA512_256_DIGEST_LENGTH|, so this
// has a |smaller output.
- return SHA512_Final(out, sha);
+ assert(sha->md_len == SHA512_256_DIGEST_LENGTH);
+ return sha512_final_impl(out, sha);
}
void SHA512_Transform(SHA512_CTX *c, const uint8_t block[SHA512_CBLOCK]) {
@@ -232,6 +235,15 @@ int SHA512_Update(SHA512_CTX *c, const void *in_data, size_t len) {
}
int SHA512_Final(uint8_t out[SHA512_DIGEST_LENGTH], SHA512_CTX *sha) {
+ // Ideally we would assert |sha->md_len| is |SHA512_DIGEST_LENGTH| to match
+ // the size hint, but calling code often pairs |SHA384_Init| with
+ // |SHA512_Final| and expects |sha->md_len| to carry the size over.
+ //
+ // TODO(davidben): Add an assert and fix code to match them up.
+ return sha512_final_impl(out, sha);
+}
+
+static int sha512_final_impl(uint8_t *out, SHA512_CTX *sha) {
uint8_t *p = sha->p;
size_t n = sha->num;
@@ -244,22 +256,8 @@ int SHA512_Final(uint8_t out[SHA512_DIGEST_LENGTH], SHA512_CTX *sha) {
}
OPENSSL_memset(p + n, 0, sizeof(sha->p) - 16 - n);
- p[sizeof(sha->p) - 1] = (uint8_t)(sha->Nl);
- p[sizeof(sha->p) - 2] = (uint8_t)(sha->Nl >> 8);
- p[sizeof(sha->p) - 3] = (uint8_t)(sha->Nl >> 16);
- p[sizeof(sha->p) - 4] = (uint8_t)(sha->Nl >> 24);
- p[sizeof(sha->p) - 5] = (uint8_t)(sha->Nl >> 32);
- p[sizeof(sha->p) - 6] = (uint8_t)(sha->Nl >> 40);
- p[sizeof(sha->p) - 7] = (uint8_t)(sha->Nl >> 48);
- p[sizeof(sha->p) - 8] = (uint8_t)(sha->Nl >> 56);
- p[sizeof(sha->p) - 9] = (uint8_t)(sha->Nh);
- p[sizeof(sha->p) - 10] = (uint8_t)(sha->Nh >> 8);
- p[sizeof(sha->p) - 11] = (uint8_t)(sha->Nh >> 16);
- p[sizeof(sha->p) - 12] = (uint8_t)(sha->Nh >> 24);
- p[sizeof(sha->p) - 13] = (uint8_t)(sha->Nh >> 32);
- p[sizeof(sha->p) - 14] = (uint8_t)(sha->Nh >> 40);
- p[sizeof(sha->p) - 15] = (uint8_t)(sha->Nh >> 48);
- p[sizeof(sha->p) - 16] = (uint8_t)(sha->Nh >> 56);
+ CRYPTO_store_u64_be(p + sizeof(sha->p) - 16, sha->Nh);
+ CRYPTO_store_u64_be(p + sizeof(sha->p) - 8, sha->Nl);
sha512_block_data_order(sha->h, p, 1);
@@ -272,9 +270,8 @@ int SHA512_Final(uint8_t out[SHA512_DIGEST_LENGTH], SHA512_CTX *sha) {
assert(sha->md_len % 8 == 0);
const size_t out_words = sha->md_len / 8;
for (size_t i = 0; i < out_words; i++) {
- const uint64_t t = CRYPTO_bswap8(sha->h[i]);
- memcpy(out, &t, sizeof(t));
- out += sizeof(t);
+ CRYPTO_store_u64_be(out, sha->h[i]);
+ out += 8;
}
return 1;
@@ -356,12 +353,6 @@ static const uint64_t K512[80] = {
#define ROTR(x, s) (((x) >> s) | (x) << (64 - s))
#endif
-static inline uint64_t load_u64_be(const void *ptr) {
- uint64_t ret;
- OPENSSL_memcpy(&ret, ptr, sizeof(ret));
- return CRYPTO_bswap8(ret);
-}
-
#define Sigma0(x) (ROTR((x), 28) ^ ROTR((x), 34) ^ ROTR((x), 39))
#define Sigma1(x) (ROTR((x), 14) ^ ROTR((x), 18) ^ ROTR((x), 41))
#define sigma0(x) (ROTR((x), 1) ^ ROTR((x), 8) ^ ((x) >> 7))
@@ -392,7 +383,7 @@ static void sha512_block_data_order(uint64_t *state, const uint8_t *in,
F[7] = state[7];
for (i = 0; i < 16; i++, F--) {
- T = load_u64_be(in + i * 8);
+ T = CRYPTO_load_u64_be(in + i * 8);
F[0] = A;
F[4] = E;
F[8] = T;
@@ -464,37 +455,37 @@ static void sha512_block_data_order(uint64_t *state, const uint8_t *in,
g = state[6];
h = state[7];
- T1 = X[0] = load_u64_be(in);
+ T1 = X[0] = CRYPTO_load_u64_be(in);
ROUND_00_15(0, a, b, c, d, e, f, g, h);
- T1 = X[1] = load_u64_be(in + 8);
+ T1 = X[1] = CRYPTO_load_u64_be(in + 8);
ROUND_00_15(1, h, a, b, c, d, e, f, g);
- T1 = X[2] = load_u64_be(in + 2 * 8);
+ T1 = X[2] = CRYPTO_load_u64_be(in + 2 * 8);
ROUND_00_15(2, g, h, a, b, c, d, e, f);
- T1 = X[3] = load_u64_be(in + 3 * 8);
+ T1 = X[3] = CRYPTO_load_u64_be(in + 3 * 8);
ROUND_00_15(3, f, g, h, a, b, c, d, e);
- T1 = X[4] = load_u64_be(in + 4 * 8);
+ T1 = X[4] = CRYPTO_load_u64_be(in + 4 * 8);
ROUND_00_15(4, e, f, g, h, a, b, c, d);
- T1 = X[5] = load_u64_be(in + 5 * 8);
+ T1 = X[5] = CRYPTO_load_u64_be(in + 5 * 8);
ROUND_00_15(5, d, e, f, g, h, a, b, c);
- T1 = X[6] = load_u64_be(in + 6 * 8);
+ T1 = X[6] = CRYPTO_load_u64_be(in + 6 * 8);
ROUND_00_15(6, c, d, e, f, g, h, a, b);
- T1 = X[7] = load_u64_be(in + 7 * 8);
+ T1 = X[7] = CRYPTO_load_u64_be(in + 7 * 8);
ROUND_00_15(7, b, c, d, e, f, g, h, a);
- T1 = X[8] = load_u64_be(in + 8 * 8);
+ T1 = X[8] = CRYPTO_load_u64_be(in + 8 * 8);
ROUND_00_15(8, a, b, c, d, e, f, g, h);
- T1 = X[9] = load_u64_be(in + 9 * 8);
+ T1 = X[9] = CRYPTO_load_u64_be(in + 9 * 8);
ROUND_00_15(9, h, a, b, c, d, e, f, g);
- T1 = X[10] = load_u64_be(in + 10 * 8);
+ T1 = X[10] = CRYPTO_load_u64_be(in + 10 * 8);
ROUND_00_15(10, g, h, a, b, c, d, e, f);
- T1 = X[11] = load_u64_be(in + 11 * 8);
+ T1 = X[11] = CRYPTO_load_u64_be(in + 11 * 8);
ROUND_00_15(11, f, g, h, a, b, c, d, e);
- T1 = X[12] = load_u64_be(in + 12 * 8);
+ T1 = X[12] = CRYPTO_load_u64_be(in + 12 * 8);
ROUND_00_15(12, e, f, g, h, a, b, c, d);
- T1 = X[13] = load_u64_be(in + 13 * 8);
+ T1 = X[13] = CRYPTO_load_u64_be(in + 13 * 8);
ROUND_00_15(13, d, e, f, g, h, a, b, c);
- T1 = X[14] = load_u64_be(in + 14 * 8);
+ T1 = X[14] = CRYPTO_load_u64_be(in + 14 * 8);
ROUND_00_15(14, c, d, e, f, g, h, a, b);
- T1 = X[15] = load_u64_be(in + 15 * 8);
+ T1 = X[15] = CRYPTO_load_u64_be(in + 15 * 8);
ROUND_00_15(15, b, c, d, e, f, g, h, a);
for (i = 16; i < 80; i += 16) {
diff --git a/deps/boringssl/src/crypto/hpke/hpke.c b/deps/boringssl/src/crypto/hpke/hpke.c
index ee03e53..222e329 100644
--- a/deps/boringssl/src/crypto/hpke/hpke.c
+++ b/deps/boringssl/src/crypto/hpke/hpke.c
@@ -12,59 +12,66 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#include <openssl/hpke.h>
+
#include <assert.h>
#include <string.h>
#include <openssl/aead.h>
#include <openssl/bytestring.h>
+#include <openssl/curve25519.h>
#include <openssl/digest.h>
#include <openssl/err.h>
-#include <openssl/evp.h>
+#include <openssl/evp_errors.h>
#include <openssl/hkdf.h>
+#include <openssl/rand.h>
#include <openssl/sha.h>
#include "../internal.h"
-#include "internal.h"
-// This file implements draft-irtf-cfrg-hpke-07.
+// This file implements draft-irtf-cfrg-hpke-08.
-#define KEM_CONTEXT_LEN (2 * X25519_PUBLIC_VALUE_LEN)
+#define MAX_SEED_LEN X25519_PRIVATE_KEY_LEN
+#define MAX_SHARED_SECRET_LEN SHA256_DIGEST_LENGTH
-// HPKE KEM scheme IDs.
-#define HPKE_DHKEM_X25519_HKDF_SHA256 0x0020
+struct evp_hpke_kem_st {
+ uint16_t id;
+ size_t public_key_len;
+ size_t private_key_len;
+ size_t seed_len;
+ int (*init_key)(EVP_HPKE_KEY *key, const uint8_t *priv_key,
+ size_t priv_key_len);
+ int (*generate_key)(EVP_HPKE_KEY *key);
+ int (*encap_with_seed)(const EVP_HPKE_KEM *kem, uint8_t *out_shared_secret,
+ size_t *out_shared_secret_len, uint8_t *out_enc,
+ size_t *out_enc_len, size_t max_enc,
+ const uint8_t *peer_public_key,
+ size_t peer_public_key_len, const uint8_t *seed,
+ size_t seed_len);
+ int (*decap)(const EVP_HPKE_KEY *key, uint8_t *out_shared_secret,
+ size_t *out_shared_secret_len, const uint8_t *enc,
+ size_t enc_len);
+};
-// This is strlen("HPKE") + 3 * sizeof(uint16_t).
-#define HPKE_SUITE_ID_LEN 10
+struct evp_hpke_kdf_st {
+ uint16_t id;
+ // We only support HKDF-based KDFs.
+ const EVP_MD *(*hkdf_md_func)(void);
+};
-#define HPKE_MODE_BASE 0
-#define HPKE_MODE_PSK 1
+struct evp_hpke_aead_st {
+ uint16_t id;
+ const EVP_AEAD *(*aead_func)(void);
+};
-static const char kHpkeRfcId[] = "HPKE-07";
-static int add_label_string(CBB *cbb, const char *label) {
- return CBB_add_bytes(cbb, (const uint8_t *)label, strlen(label));
-}
+// Low-level labeled KDF functions.
-// The suite_id for the KEM is defined as concat("KEM", I2OSP(kem_id, 2)). Note
-// that the suite_id used outside of the KEM also includes the kdf_id and
-// aead_id.
-static const uint8_t kX25519SuiteID[] = {
- 'K', 'E', 'M', HPKE_DHKEM_X25519_HKDF_SHA256 >> 8,
- HPKE_DHKEM_X25519_HKDF_SHA256 & 0x00ff};
+static const char kHpkeVersionId[] = "HPKE-v1";
-// The suite_id for non-KEM pieces of HPKE is defined as concat("HPKE",
-// I2OSP(kem_id, 2), I2OSP(kdf_id, 2), I2OSP(aead_id, 2)).
-static int hpke_build_suite_id(uint8_t out[HPKE_SUITE_ID_LEN], uint16_t kdf_id,
- uint16_t aead_id) {
- CBB cbb;
- int ret = CBB_init_fixed(&cbb, out, HPKE_SUITE_ID_LEN) &&
- add_label_string(&cbb, "HPKE") &&
- CBB_add_u16(&cbb, HPKE_DHKEM_X25519_HKDF_SHA256) &&
- CBB_add_u16(&cbb, kdf_id) &&
- CBB_add_u16(&cbb, aead_id);
- CBB_cleanup(&cbb);
- return ret;
+static int add_label_string(CBB *cbb, const char *label) {
+ return CBB_add_bytes(cbb, (const uint8_t *)label, strlen(label));
}
static int hpke_labeled_extract(const EVP_MD *hkdf_md, uint8_t *out_key,
@@ -72,10 +79,10 @@ static int hpke_labeled_extract(const EVP_MD *hkdf_md, uint8_t *out_key,
size_t salt_len, const uint8_t *suite_id,
size_t suite_id_len, const char *label,
const uint8_t *ikm, size_t ikm_len) {
- // labeledIKM = concat("RFCXXXX ", suite_id, label, IKM)
+ // labeledIKM = concat("HPKE-v1", suite_id, label, IKM)
CBB labeled_ikm;
int ok = CBB_init(&labeled_ikm, 0) &&
- add_label_string(&labeled_ikm, kHpkeRfcId) &&
+ add_label_string(&labeled_ikm, kHpkeVersionId) &&
CBB_add_bytes(&labeled_ikm, suite_id, suite_id_len) &&
add_label_string(&labeled_ikm, label) &&
CBB_add_bytes(&labeled_ikm, ikm, ikm_len) &&
@@ -90,11 +97,11 @@ static int hpke_labeled_expand(const EVP_MD *hkdf_md, uint8_t *out_key,
size_t prk_len, const uint8_t *suite_id,
size_t suite_id_len, const char *label,
const uint8_t *info, size_t info_len) {
- // labeledInfo = concat(I2OSP(L, 2), "RFCXXXX ", suite_id, label, info)
+ // labeledInfo = concat(I2OSP(L, 2), "HPKE-v1", suite_id, label, info)
CBB labeled_info;
int ok = CBB_init(&labeled_info, 0) &&
CBB_add_u16(&labeled_info, out_len) &&
- add_label_string(&labeled_info, kHpkeRfcId) &&
+ add_label_string(&labeled_info, kHpkeVersionId) &&
CBB_add_bytes(&labeled_info, suite_id, suite_id_len) &&
add_label_string(&labeled_info, label) &&
CBB_add_bytes(&labeled_info, info, info_len) &&
@@ -104,102 +111,280 @@ static int hpke_labeled_expand(const EVP_MD *hkdf_md, uint8_t *out_key,
return ok;
}
-static int hpke_extract_and_expand(const EVP_MD *hkdf_md, uint8_t *out_key,
- size_t out_len,
- const uint8_t dh[X25519_PUBLIC_VALUE_LEN],
- const uint8_t kem_context[KEM_CONTEXT_LEN]) {
+
+// KEM implementations.
+
+// dhkem_extract_and_expand implements the ExtractAndExpand operation in the
+// DHKEM construction. See section 4.1 of draft-irtf-cfrg-hpke-08.
+static int dhkem_extract_and_expand(uint16_t kem_id, const EVP_MD *hkdf_md,
+ uint8_t *out_key, size_t out_len,
+ const uint8_t *dh, size_t dh_len,
+ const uint8_t *kem_context,
+ size_t kem_context_len) {
+ // concat("KEM", I2OSP(kem_id, 2))
+ uint8_t suite_id[5] = {'K', 'E', 'M', kem_id >> 8, kem_id & 0xff};
uint8_t prk[EVP_MAX_MD_SIZE];
size_t prk_len;
- static const char kEaePrkLabel[] = "eae_prk";
- if (!hpke_labeled_extract(hkdf_md, prk, &prk_len, NULL, 0, kX25519SuiteID,
- sizeof(kX25519SuiteID), kEaePrkLabel, dh,
- X25519_PUBLIC_VALUE_LEN)) {
+ return hpke_labeled_extract(hkdf_md, prk, &prk_len, NULL, 0, suite_id,
+ sizeof(suite_id), "eae_prk", dh, dh_len) &&
+ hpke_labeled_expand(hkdf_md, out_key, out_len, prk, prk_len, suite_id,
+ sizeof(suite_id), "shared_secret", kem_context,
+ kem_context_len);
+}
+
+static int x25519_init_key(EVP_HPKE_KEY *key, const uint8_t *priv_key,
+ size_t priv_key_len) {
+ if (priv_key_len != X25519_PRIVATE_KEY_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
- static const char kPRKExpandLabel[] = "shared_secret";
- if (!hpke_labeled_expand(hkdf_md, out_key, out_len, prk, prk_len,
- kX25519SuiteID, sizeof(kX25519SuiteID),
- kPRKExpandLabel, kem_context, KEM_CONTEXT_LEN)) {
+
+ OPENSSL_memcpy(key->private_key, priv_key, priv_key_len);
+ X25519_public_from_private(key->public_key, priv_key);
+ return 1;
+}
+
+static int x25519_generate_key(EVP_HPKE_KEY *key) {
+ X25519_keypair(key->public_key, key->private_key);
+ return 1;
+}
+
+static int x25519_encap_with_seed(
+ const EVP_HPKE_KEM *kem, uint8_t *out_shared_secret,
+ size_t *out_shared_secret_len, uint8_t *out_enc, size_t *out_enc_len,
+ size_t max_enc, const uint8_t *peer_public_key, size_t peer_public_key_len,
+ const uint8_t *seed, size_t seed_len) {
+ if (max_enc < X25519_PUBLIC_VALUE_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
+ return 0;
+ }
+ if (seed_len != X25519_PRIVATE_KEY_LEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+ X25519_public_from_private(out_enc, seed);
+
+ uint8_t dh[X25519_SHARED_KEY_LEN];
+ if (peer_public_key_len != X25519_PUBLIC_VALUE_LEN ||
+ !X25519(dh, seed, peer_public_key)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
+ return 0;
+ }
+
+ uint8_t kem_context[2 * X25519_PUBLIC_VALUE_LEN];
+ OPENSSL_memcpy(kem_context, out_enc, X25519_PUBLIC_VALUE_LEN);
+ OPENSSL_memcpy(kem_context + X25519_PUBLIC_VALUE_LEN, peer_public_key,
+ X25519_PUBLIC_VALUE_LEN);
+ if (!dhkem_extract_and_expand(kem->id, EVP_sha256(), out_shared_secret,
+ SHA256_DIGEST_LENGTH, dh, sizeof(dh),
+ kem_context, sizeof(kem_context))) {
return 0;
}
+
+ *out_enc_len = X25519_PUBLIC_VALUE_LEN;
+ *out_shared_secret_len = SHA256_DIGEST_LENGTH;
return 1;
}
-const EVP_AEAD *EVP_HPKE_get_aead(uint16_t aead_id) {
- switch (aead_id) {
- case EVP_HPKE_AEAD_AES_GCM_128:
- return EVP_aead_aes_128_gcm();
- case EVP_HPKE_AEAD_AES_GCM_256:
- return EVP_aead_aes_256_gcm();
- case EVP_HPKE_AEAD_CHACHA20POLY1305:
- return EVP_aead_chacha20_poly1305();
+static int x25519_decap(const EVP_HPKE_KEY *key, uint8_t *out_shared_secret,
+ size_t *out_shared_secret_len, const uint8_t *enc,
+ size_t enc_len) {
+ uint8_t dh[X25519_SHARED_KEY_LEN];
+ if (enc_len != X25519_PUBLIC_VALUE_LEN ||
+ !X25519(dh, key->private_key, enc)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
+ return 0;
}
- OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
- return NULL;
+
+ uint8_t kem_context[2 * X25519_PUBLIC_VALUE_LEN];
+ OPENSSL_memcpy(kem_context, enc, X25519_PUBLIC_VALUE_LEN);
+ OPENSSL_memcpy(kem_context + X25519_PUBLIC_VALUE_LEN, key->public_key,
+ X25519_PUBLIC_VALUE_LEN);
+ if (!dhkem_extract_and_expand(key->kem->id, EVP_sha256(), out_shared_secret,
+ SHA256_DIGEST_LENGTH, dh, sizeof(dh),
+ kem_context, sizeof(kem_context))) {
+ return 0;
+ }
+
+ *out_shared_secret_len = SHA256_DIGEST_LENGTH;
+ return 1;
+}
+
+const EVP_HPKE_KEM *EVP_hpke_x25519_hkdf_sha256(void) {
+ static const EVP_HPKE_KEM kKEM = {
+ /*id=*/EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
+ /*public_key_len=*/X25519_PUBLIC_VALUE_LEN,
+ /*private_key_len=*/X25519_PRIVATE_KEY_LEN,
+ /*seed_len=*/X25519_PRIVATE_KEY_LEN,
+ x25519_init_key,
+ x25519_generate_key,
+ x25519_encap_with_seed,
+ x25519_decap,
+ };
+ return &kKEM;
+}
+
+uint16_t EVP_HPKE_KEM_id(const EVP_HPKE_KEM *kem) { return kem->id; }
+
+void EVP_HPKE_KEY_zero(EVP_HPKE_KEY *key) {
+ OPENSSL_memset(key, 0, sizeof(EVP_HPKE_KEY));
}
-const EVP_MD *EVP_HPKE_get_hkdf_md(uint16_t kdf_id) {
- switch (kdf_id) {
- case EVP_HPKE_HKDF_SHA256:
- return EVP_sha256();
- case EVP_HPKE_HKDF_SHA384:
- return EVP_sha384();
- case EVP_HPKE_HKDF_SHA512:
- return EVP_sha512();
+void EVP_HPKE_KEY_cleanup(EVP_HPKE_KEY *key) {
+ // Nothing to clean up for now, but we may introduce a cleanup process in the
+ // future.
+}
+
+EVP_HPKE_KEY *EVP_HPKE_KEY_new(void) {
+ EVP_HPKE_KEY *key = OPENSSL_malloc(sizeof(EVP_HPKE_KEY));
+ if (key == NULL) {
+ OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
+ return NULL;
}
- OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
- return NULL;
+ EVP_HPKE_KEY_zero(key);
+ return key;
}
-static int hpke_key_schedule(EVP_HPKE_CTX *hpke, uint8_t mode,
- const uint8_t *shared_secret,
- size_t shared_secret_len, const uint8_t *info,
- size_t info_len, const uint8_t *psk,
- size_t psk_len, const uint8_t *psk_id,
- size_t psk_id_len) {
- // Verify the PSK inputs.
- switch (mode) {
- case HPKE_MODE_BASE:
- // This is an internal error, unreachable from the caller.
- assert(psk_len == 0 && psk_id_len == 0);
- break;
- case HPKE_MODE_PSK:
- if (psk_len == 0 || psk_id_len == 0) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_EMPTY_PSK);
- return 0;
- }
- break;
- default:
- return 0;
- }
-
- // Attempt to get an EVP_AEAD*.
- const EVP_AEAD *aead = EVP_HPKE_get_aead(hpke->aead_id);
- if (aead == NULL) {
+void EVP_HPKE_KEY_free(EVP_HPKE_KEY *key) {
+ if (key != NULL) {
+ EVP_HPKE_KEY_cleanup(key);
+ OPENSSL_free(key);
+ }
+}
+
+int EVP_HPKE_KEY_copy(EVP_HPKE_KEY *dst, const EVP_HPKE_KEY *src) {
+ // For now, |EVP_HPKE_KEY| is trivially copyable.
+ OPENSSL_memcpy(dst, src, sizeof(EVP_HPKE_KEY));
+ return 1;
+}
+
+int EVP_HPKE_KEY_init(EVP_HPKE_KEY *key, const EVP_HPKE_KEM *kem,
+ const uint8_t *priv_key, size_t priv_key_len) {
+ EVP_HPKE_KEY_zero(key);
+ key->kem = kem;
+ if (!kem->init_key(key, priv_key, priv_key_len)) {
+ key->kem = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+int EVP_HPKE_KEY_generate(EVP_HPKE_KEY *key, const EVP_HPKE_KEM *kem) {
+ EVP_HPKE_KEY_zero(key);
+ key->kem = kem;
+ if (!kem->generate_key(key)) {
+ key->kem = NULL;
return 0;
}
+ return 1;
+}
+
+const EVP_HPKE_KEM *EVP_HPKE_KEY_kem(const EVP_HPKE_KEY *key) {
+ return key->kem;
+}
+
+int EVP_HPKE_KEY_public_key(const EVP_HPKE_KEY *key, uint8_t *out,
+ size_t *out_len, size_t max_out) {
+ if (max_out < key->kem->public_key_len) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
+ return 0;
+ }
+ OPENSSL_memcpy(out, key->public_key, key->kem->public_key_len);
+ *out_len = key->kem->public_key_len;
+ return 1;
+}
+
+int EVP_HPKE_KEY_private_key(const EVP_HPKE_KEY *key, uint8_t *out,
+ size_t *out_len, size_t max_out) {
+ if (max_out < key->kem->private_key_len) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
+ return 0;
+ }
+ OPENSSL_memcpy(out, key->private_key, key->kem->private_key_len);
+ *out_len = key->kem->private_key_len;
+ return 1;
+}
+
+
+// Supported KDFs and AEADs.
+
+const EVP_HPKE_KDF *EVP_hpke_hkdf_sha256(void) {
+ static const EVP_HPKE_KDF kKDF = {EVP_HPKE_HKDF_SHA256, &EVP_sha256};
+ return &kKDF;
+}
+
+uint16_t EVP_HPKE_KDF_id(const EVP_HPKE_KDF *kdf) { return kdf->id; }
+
+const EVP_HPKE_AEAD *EVP_hpke_aes_128_gcm(void) {
+ static const EVP_HPKE_AEAD kAEAD = {EVP_HPKE_AES_128_GCM,
+ &EVP_aead_aes_128_gcm};
+ return &kAEAD;
+}
+
+const EVP_HPKE_AEAD *EVP_hpke_aes_256_gcm(void) {
+ static const EVP_HPKE_AEAD kAEAD = {EVP_HPKE_AES_256_GCM,
+ &EVP_aead_aes_256_gcm};
+ return &kAEAD;
+}
+
+const EVP_HPKE_AEAD *EVP_hpke_chacha20_poly1305(void) {
+ static const EVP_HPKE_AEAD kAEAD = {EVP_HPKE_CHACHA20_POLY1305,
+ &EVP_aead_chacha20_poly1305};
+ return &kAEAD;
+}
+
+uint16_t EVP_HPKE_AEAD_id(const EVP_HPKE_AEAD *aead) { return aead->id; }
+
+const EVP_AEAD *EVP_HPKE_AEAD_aead(const EVP_HPKE_AEAD *aead) {
+ return aead->aead_func();
+}
+
+
+// HPKE implementation.
+
+// This is strlen("HPKE") + 3 * sizeof(uint16_t).
+#define HPKE_SUITE_ID_LEN 10
+// The suite_id for non-KEM pieces of HPKE is defined as concat("HPKE",
+// I2OSP(kem_id, 2), I2OSP(kdf_id, 2), I2OSP(aead_id, 2)).
+static int hpke_build_suite_id(const EVP_HPKE_CTX *ctx,
+ uint8_t out[HPKE_SUITE_ID_LEN]) {
+ CBB cbb;
+ int ret = CBB_init_fixed(&cbb, out, HPKE_SUITE_ID_LEN) &&
+ add_label_string(&cbb, "HPKE") &&
+ CBB_add_u16(&cbb, EVP_HPKE_DHKEM_X25519_HKDF_SHA256) &&
+ CBB_add_u16(&cbb, ctx->kdf->id) &&
+ CBB_add_u16(&cbb, ctx->aead->id);
+ CBB_cleanup(&cbb);
+ return ret;
+}
+
+#define HPKE_MODE_BASE 0
+
+static int hpke_key_schedule(EVP_HPKE_CTX *ctx, const uint8_t *shared_secret,
+ size_t shared_secret_len, const uint8_t *info,
+ size_t info_len) {
uint8_t suite_id[HPKE_SUITE_ID_LEN];
- if (!hpke_build_suite_id(suite_id, hpke->kdf_id, hpke->aead_id)) {
+ if (!hpke_build_suite_id(ctx, suite_id)) {
return 0;
}
// psk_id_hash = LabeledExtract("", "psk_id_hash", psk_id)
- static const char kPskIdHashLabel[] = "psk_id_hash";
+ // TODO(davidben): Precompute this value and store it with the EVP_HPKE_KDF.
+ const EVP_MD *hkdf_md = ctx->kdf->hkdf_md_func();
uint8_t psk_id_hash[EVP_MAX_MD_SIZE];
size_t psk_id_hash_len;
- if (!hpke_labeled_extract(hpke->hkdf_md, psk_id_hash, &psk_id_hash_len, NULL,
- 0, suite_id, sizeof(suite_id), kPskIdHashLabel,
- psk_id, psk_id_len)) {
+ if (!hpke_labeled_extract(hkdf_md, psk_id_hash, &psk_id_hash_len, NULL, 0,
+ suite_id, sizeof(suite_id), "psk_id_hash", NULL,
+ 0)) {
return 0;
}
// info_hash = LabeledExtract("", "info_hash", info)
- static const char kInfoHashLabel[] = "info_hash";
uint8_t info_hash[EVP_MAX_MD_SIZE];
size_t info_hash_len;
- if (!hpke_labeled_extract(hpke->hkdf_md, info_hash, &info_hash_len, NULL, 0,
- suite_id, sizeof(suite_id), kInfoHashLabel, info,
+ if (!hpke_labeled_extract(hkdf_md, info_hash, &info_hash_len, NULL, 0,
+ suite_id, sizeof(suite_id), "info_hash", info,
info_len)) {
return 0;
}
@@ -209,7 +394,7 @@ static int hpke_key_schedule(EVP_HPKE_CTX *hpke, uint8_t mode,
size_t context_len;
CBB context_cbb;
if (!CBB_init_fixed(&context_cbb, context, sizeof(context)) ||
- !CBB_add_u8(&context_cbb, mode) ||
+ !CBB_add_u8(&context_cbb, HPKE_MODE_BASE) ||
!CBB_add_bytes(&context_cbb, psk_id_hash, psk_id_hash_len) ||
!CBB_add_bytes(&context_cbb, info_hash, info_hash_len) ||
!CBB_finish(&context_cbb, NULL, &context_len)) {
@@ -217,97 +402,44 @@ static int hpke_key_schedule(EVP_HPKE_CTX *hpke, uint8_t mode,
}
// secret = LabeledExtract(shared_secret, "secret", psk)
- static const char kSecretExtractLabel[] = "secret";
uint8_t secret[EVP_MAX_MD_SIZE];
size_t secret_len;
- if (!hpke_labeled_extract(hpke->hkdf_md, secret, &secret_len, shared_secret,
+ if (!hpke_labeled_extract(hkdf_md, secret, &secret_len, shared_secret,
shared_secret_len, suite_id, sizeof(suite_id),
- kSecretExtractLabel, psk, psk_len)) {
+ "secret", NULL, 0)) {
return 0;
}
// key = LabeledExpand(secret, "key", key_schedule_context, Nk)
- static const char kKeyExpandLabel[] = "key";
+ const EVP_AEAD *aead = EVP_HPKE_AEAD_aead(ctx->aead);
uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
const size_t kKeyLen = EVP_AEAD_key_length(aead);
- if (!hpke_labeled_expand(hpke->hkdf_md, key, kKeyLen, secret, secret_len,
- suite_id, sizeof(suite_id), kKeyExpandLabel, context,
- context_len)) {
- return 0;
- }
-
- // Initialize the HPKE context's AEAD context, storing a copy of |key|.
- if (!EVP_AEAD_CTX_init(&hpke->aead_ctx, aead, key, kKeyLen, 0, NULL)) {
+ if (!hpke_labeled_expand(hkdf_md, key, kKeyLen, secret, secret_len, suite_id,
+ sizeof(suite_id), "key", context, context_len) ||
+ !EVP_AEAD_CTX_init(&ctx->aead_ctx, aead, key, kKeyLen,
+ EVP_AEAD_DEFAULT_TAG_LENGTH, NULL)) {
return 0;
}
// base_nonce = LabeledExpand(secret, "base_nonce", key_schedule_context, Nn)
- static const char kNonceExpandLabel[] = "base_nonce";
- if (!hpke_labeled_expand(hpke->hkdf_md, hpke->base_nonce,
+ if (!hpke_labeled_expand(hkdf_md, ctx->base_nonce,
EVP_AEAD_nonce_length(aead), secret, secret_len,
- suite_id, sizeof(suite_id), kNonceExpandLabel,
- context, context_len)) {
+ suite_id, sizeof(suite_id), "base_nonce", context,
+ context_len)) {
return 0;
}
// exporter_secret = LabeledExpand(secret, "exp", key_schedule_context, Nh)
- static const char kExporterSecretExpandLabel[] = "exp";
- if (!hpke_labeled_expand(hpke->hkdf_md, hpke->exporter_secret,
- EVP_MD_size(hpke->hkdf_md), secret, secret_len,
- suite_id, sizeof(suite_id),
- kExporterSecretExpandLabel, context, context_len)) {
+ if (!hpke_labeled_expand(hkdf_md, ctx->exporter_secret, EVP_MD_size(hkdf_md),
+ secret, secret_len, suite_id, sizeof(suite_id),
+ "exp", context, context_len)) {
return 0;
}
return 1;
}
-// The number of bytes written to |out_shared_secret| is the size of the KEM's
-// KDF (currently we only support SHA256).
-static int hpke_encap(EVP_HPKE_CTX *hpke,
- uint8_t out_shared_secret[SHA256_DIGEST_LENGTH],
- const uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN],
- const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
- const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]) {
- uint8_t dh[X25519_PUBLIC_VALUE_LEN];
- if (!X25519(dh, ephemeral_private, public_key_r)) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
- return 0;
- }
-
- uint8_t kem_context[KEM_CONTEXT_LEN];
- OPENSSL_memcpy(kem_context, ephemeral_public, X25519_PUBLIC_VALUE_LEN);
- OPENSSL_memcpy(kem_context + X25519_PUBLIC_VALUE_LEN, public_key_r,
- X25519_PUBLIC_VALUE_LEN);
- if (!hpke_extract_and_expand(EVP_sha256(), out_shared_secret,
- SHA256_DIGEST_LENGTH, dh, kem_context)) {
- return 0;
- }
- return 1;
-}
-
-static int hpke_decap(const EVP_HPKE_CTX *hpke,
- uint8_t out_shared_secret[SHA256_DIGEST_LENGTH],
- const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
- const uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN],
- const uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN]) {
- uint8_t dh[X25519_PUBLIC_VALUE_LEN];
- if (!X25519(dh, secret_key_r, enc)) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
- return 0;
- }
- uint8_t kem_context[KEM_CONTEXT_LEN];
- OPENSSL_memcpy(kem_context, enc, X25519_PUBLIC_VALUE_LEN);
- OPENSSL_memcpy(kem_context + X25519_PUBLIC_VALUE_LEN, public_key_r,
- X25519_PUBLIC_VALUE_LEN);
- if (!hpke_extract_and_expand(EVP_sha256(), out_shared_secret,
- SHA256_DIGEST_LENGTH, dh, kem_context)) {
- return 0;
- }
- return 1;
-}
-
-void EVP_HPKE_CTX_init(EVP_HPKE_CTX *ctx) {
+void EVP_HPKE_CTX_zero(EVP_HPKE_CTX *ctx) {
OPENSSL_memset(ctx, 0, sizeof(EVP_HPKE_CTX));
EVP_AEAD_CTX_zero(&ctx->aead_ctx);
}
@@ -316,217 +448,171 @@ void EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX *ctx) {
EVP_AEAD_CTX_cleanup(&ctx->aead_ctx);
}
-int EVP_HPKE_CTX_setup_base_s_x25519(
- EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
- uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len) {
- // The GenerateKeyPair() step technically belongs in the KEM's Encap()
- // function, but we've moved it up a layer to make it easier for tests to
- // inject an ephemeral keypair.
- uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN];
- X25519_keypair(out_enc, ephemeral_private);
- return EVP_HPKE_CTX_setup_base_s_x25519_for_test(
- hpke, kdf_id, aead_id, peer_public_value, info, info_len,
- ephemeral_private, out_enc);
-}
-
-int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len,
- const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
- const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]) {
- hpke->is_sender = 1;
- hpke->kdf_id = kdf_id;
- hpke->aead_id = aead_id;
- hpke->hkdf_md = EVP_HPKE_get_hkdf_md(kdf_id);
- if (hpke->hkdf_md == NULL) {
- return 0;
- }
- uint8_t shared_secret[SHA256_DIGEST_LENGTH];
- if (!hpke_encap(hpke, shared_secret, peer_public_value, ephemeral_private,
- ephemeral_public) ||
- !hpke_key_schedule(hpke, HPKE_MODE_BASE, shared_secret,
- sizeof(shared_secret), info, info_len, NULL, 0, NULL,
- 0)) {
- return 0;
+EVP_HPKE_CTX *EVP_HPKE_CTX_new(void) {
+ EVP_HPKE_CTX *ctx = OPENSSL_malloc(sizeof(EVP_HPKE_CTX));
+ if (ctx == NULL) {
+ OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
+ return NULL;
}
- return 1;
+ EVP_HPKE_CTX_zero(ctx);
+ return ctx;
}
-int EVP_HPKE_CTX_setup_base_r_x25519(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
- const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
- const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
- size_t info_len) {
- hpke->is_sender = 0;
- hpke->kdf_id = kdf_id;
- hpke->aead_id = aead_id;
- hpke->hkdf_md = EVP_HPKE_get_hkdf_md(kdf_id);
- if (hpke->hkdf_md == NULL) {
- return 0;
+void EVP_HPKE_CTX_free(EVP_HPKE_CTX *ctx) {
+ if (ctx != NULL) {
+ EVP_HPKE_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
}
- uint8_t shared_secret[SHA256_DIGEST_LENGTH];
- if (!hpke_decap(hpke, shared_secret, enc, public_key, private_key) ||
- !hpke_key_schedule(hpke, HPKE_MODE_BASE, shared_secret,
- sizeof(shared_secret), info, info_len, NULL, 0, NULL,
- 0)) {
- return 0;
- }
- return 1;
}
-int EVP_HPKE_CTX_setup_psk_s_x25519(
- EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
- uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
- const uint8_t *psk_id, size_t psk_id_len) {
- // The GenerateKeyPair() step technically belongs in the KEM's Encap()
- // function, but we've moved it up a layer to make it easier for tests to
- // inject an ephemeral keypair.
- uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN];
- X25519_keypair(out_enc, ephemeral_private);
- return EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
- hpke, kdf_id, aead_id, peer_public_value, info, info_len, psk, psk_len,
- psk_id, psk_id_len, ephemeral_private, out_enc);
-}
-
-int EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
- const uint8_t *psk_id, size_t psk_id_len,
- const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
- const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]) {
- hpke->is_sender = 1;
- hpke->kdf_id = kdf_id;
- hpke->aead_id = aead_id;
- hpke->hkdf_md = EVP_HPKE_get_hkdf_md(kdf_id);
- if (hpke->hkdf_md == NULL) {
- return 0;
- }
- uint8_t shared_secret[SHA256_DIGEST_LENGTH];
- if (!hpke_encap(hpke, shared_secret, peer_public_value, ephemeral_private,
- ephemeral_public) ||
- !hpke_key_schedule(hpke, HPKE_MODE_PSK, shared_secret,
- sizeof(shared_secret), info, info_len, psk, psk_len,
- psk_id, psk_id_len)) {
+int EVP_HPKE_CTX_setup_sender(EVP_HPKE_CTX *ctx, uint8_t *out_enc,
+ size_t *out_enc_len, size_t max_enc,
+ const EVP_HPKE_KEM *kem, const EVP_HPKE_KDF *kdf,
+ const EVP_HPKE_AEAD *aead,
+ const uint8_t *peer_public_key,
+ size_t peer_public_key_len, const uint8_t *info,
+ size_t info_len) {
+ uint8_t seed[MAX_SEED_LEN];
+ RAND_bytes(seed, kem->seed_len);
+ return EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
+ ctx, out_enc, out_enc_len, max_enc, kem, kdf, aead, peer_public_key,
+ peer_public_key_len, info, info_len, seed, kem->seed_len);
+}
+
+int EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
+ EVP_HPKE_CTX *ctx, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc,
+ const EVP_HPKE_KEM *kem, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead,
+ const uint8_t *peer_public_key, size_t peer_public_key_len,
+ const uint8_t *info, size_t info_len, const uint8_t *seed,
+ size_t seed_len) {
+ EVP_HPKE_CTX_zero(ctx);
+ ctx->is_sender = 1;
+ ctx->kdf = kdf;
+ ctx->aead = aead;
+ uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
+ size_t shared_secret_len;
+ if (!kem->encap_with_seed(kem, shared_secret, &shared_secret_len, out_enc,
+ out_enc_len, max_enc, peer_public_key,
+ peer_public_key_len, seed, seed_len) ||
+ !hpke_key_schedule(ctx, shared_secret, shared_secret_len, info,
+ info_len)) {
+ EVP_HPKE_CTX_cleanup(ctx);
return 0;
}
return 1;
}
-int EVP_HPKE_CTX_setup_psk_r_x25519(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
- const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
- const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
- size_t info_len, const uint8_t *psk, size_t psk_len, const uint8_t *psk_id,
- size_t psk_id_len) {
- hpke->is_sender = 0;
- hpke->kdf_id = kdf_id;
- hpke->aead_id = aead_id;
- hpke->hkdf_md = EVP_HPKE_get_hkdf_md(kdf_id);
- if (hpke->hkdf_md == NULL) {
- return 0;
- }
- uint8_t shared_secret[SHA256_DIGEST_LENGTH];
- if (!hpke_decap(hpke, shared_secret, enc, public_key, private_key) ||
- !hpke_key_schedule(hpke, HPKE_MODE_PSK, shared_secret,
- sizeof(shared_secret), info, info_len, psk, psk_len,
- psk_id, psk_id_len)) {
+int EVP_HPKE_CTX_setup_recipient(EVP_HPKE_CTX *ctx, const EVP_HPKE_KEY *key,
+ const EVP_HPKE_KDF *kdf,
+ const EVP_HPKE_AEAD *aead, const uint8_t *enc,
+ size_t enc_len, const uint8_t *info,
+ size_t info_len) {
+ EVP_HPKE_CTX_zero(ctx);
+ ctx->is_sender = 0;
+ ctx->kdf = kdf;
+ ctx->aead = aead;
+ uint8_t shared_secret[MAX_SHARED_SECRET_LEN];
+ size_t shared_secret_len;
+ if (!key->kem->decap(key, shared_secret, &shared_secret_len, enc, enc_len) ||
+ !hpke_key_schedule(ctx, shared_secret, sizeof(shared_secret), info,
+ info_len)) {
+ EVP_HPKE_CTX_cleanup(ctx);
return 0;
}
return 1;
}
-static void hpke_nonce(const EVP_HPKE_CTX *hpke, uint8_t *out_nonce,
+static void hpke_nonce(const EVP_HPKE_CTX *ctx, uint8_t *out_nonce,
size_t nonce_len) {
assert(nonce_len >= 8);
- // Write padded big-endian bytes of |hpke->seq| to |out_nonce|.
+ // Write padded big-endian bytes of |ctx->seq| to |out_nonce|.
OPENSSL_memset(out_nonce, 0, nonce_len);
- uint64_t seq_copy = hpke->seq;
+ uint64_t seq_copy = ctx->seq;
for (size_t i = 0; i < 8; i++) {
out_nonce[nonce_len - i - 1] = seq_copy & 0xff;
seq_copy >>= 8;
}
- // XOR the encoded sequence with the |hpke->base_nonce|.
+ // XOR the encoded sequence with the |ctx->base_nonce|.
for (size_t i = 0; i < nonce_len; i++) {
- out_nonce[i] ^= hpke->base_nonce[i];
+ out_nonce[i] ^= ctx->base_nonce[i];
}
}
-size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *hpke) {
- assert(hpke->is_sender);
- return EVP_AEAD_max_overhead(hpke->aead_ctx.aead);
-}
-
-int EVP_HPKE_CTX_open(EVP_HPKE_CTX *hpke, uint8_t *out, size_t *out_len,
+int EVP_HPKE_CTX_open(EVP_HPKE_CTX *ctx, uint8_t *out, size_t *out_len,
size_t max_out_len, const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len) {
- if (hpke->is_sender) {
+ if (ctx->is_sender) {
OPENSSL_PUT_ERROR(EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
- if (hpke->seq == UINT64_MAX) {
+ if (ctx->seq == UINT64_MAX) {
OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW);
return 0;
}
uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
- const size_t nonce_len = EVP_AEAD_nonce_length(hpke->aead_ctx.aead);
- hpke_nonce(hpke, nonce, nonce_len);
+ const size_t nonce_len = EVP_AEAD_nonce_length(ctx->aead_ctx.aead);
+ hpke_nonce(ctx, nonce, nonce_len);
- if (!EVP_AEAD_CTX_open(&hpke->aead_ctx, out, out_len, max_out_len, nonce,
+ if (!EVP_AEAD_CTX_open(&ctx->aead_ctx, out, out_len, max_out_len, nonce,
nonce_len, in, in_len, ad, ad_len)) {
return 0;
}
- hpke->seq++;
+ ctx->seq++;
return 1;
}
-int EVP_HPKE_CTX_seal(EVP_HPKE_CTX *hpke, uint8_t *out, size_t *out_len,
+int EVP_HPKE_CTX_seal(EVP_HPKE_CTX *ctx, uint8_t *out, size_t *out_len,
size_t max_out_len, const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len) {
- if (!hpke->is_sender) {
+ if (!ctx->is_sender) {
OPENSSL_PUT_ERROR(EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
- if (hpke->seq == UINT64_MAX) {
+ if (ctx->seq == UINT64_MAX) {
OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW);
return 0;
}
uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
- const size_t nonce_len = EVP_AEAD_nonce_length(hpke->aead_ctx.aead);
- hpke_nonce(hpke, nonce, nonce_len);
+ const size_t nonce_len = EVP_AEAD_nonce_length(ctx->aead_ctx.aead);
+ hpke_nonce(ctx, nonce, nonce_len);
- if (!EVP_AEAD_CTX_seal(&hpke->aead_ctx, out, out_len, max_out_len, nonce,
+ if (!EVP_AEAD_CTX_seal(&ctx->aead_ctx, out, out_len, max_out_len, nonce,
nonce_len, in, in_len, ad, ad_len)) {
return 0;
}
- hpke->seq++;
+ ctx->seq++;
return 1;
}
-int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *hpke, uint8_t *out,
+int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *ctx, uint8_t *out,
size_t secret_len, const uint8_t *context,
size_t context_len) {
uint8_t suite_id[HPKE_SUITE_ID_LEN];
- if (!hpke_build_suite_id(suite_id, hpke->kdf_id, hpke->aead_id)) {
+ if (!hpke_build_suite_id(ctx, suite_id)) {
return 0;
}
- static const char kExportExpandLabel[] = "sec";
- if (!hpke_labeled_expand(hpke->hkdf_md, out, secret_len,
- hpke->exporter_secret, EVP_MD_size(hpke->hkdf_md),
- suite_id, sizeof(suite_id), kExportExpandLabel,
- context, context_len)) {
+ const EVP_MD *hkdf_md = ctx->kdf->hkdf_md_func();
+ if (!hpke_labeled_expand(hkdf_md, out, secret_len, ctx->exporter_secret,
+ EVP_MD_size(hkdf_md), suite_id, sizeof(suite_id),
+ "sec", context, context_len)) {
return 0;
}
return 1;
}
+
+size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *ctx) {
+ assert(ctx->is_sender);
+ return EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(&ctx->aead_ctx));
+}
+
+const EVP_HPKE_AEAD *EVP_HPKE_CTX_aead(const EVP_HPKE_CTX *ctx) {
+ return ctx->aead;
+}
+
+const EVP_HPKE_KDF *EVP_HPKE_CTX_kdf(const EVP_HPKE_CTX *ctx) {
+ return ctx->kdf;
+}
diff --git a/deps/boringssl/src/crypto/hpke/hpke_test.cc b/deps/boringssl/src/crypto/hpke/hpke_test.cc
index c007b3d..a7bfe75 100644
--- a/deps/boringssl/src/crypto/hpke/hpke_test.cc
+++ b/deps/boringssl/src/crypto/hpke/hpke_test.cc
@@ -12,6 +12,8 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#include <openssl/hpke.h>
+
#include <cstdint>
#include <limits>
#include <string>
@@ -24,20 +26,25 @@
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#include <openssl/rand.h>
#include <openssl/sha.h>
#include <openssl/span.h>
#include "../test/file_test.h"
#include "../test/test_util.h"
-#include "internal.h"
namespace bssl {
namespace {
-enum class HPKEMode {
- kBase = 0,
- kPSK = 1,
+const decltype(&EVP_hpke_aes_128_gcm) kAllAEADs[] = {
+ &EVP_hpke_aes_128_gcm,
+ &EVP_hpke_aes_256_gcm,
+ &EVP_hpke_chacha20_poly1305,
+};
+
+const decltype(&EVP_hpke_hkdf_sha256) kAllKDFs[] = {
+ &EVP_hpke_hkdf_sha256,
};
// HPKETestVector corresponds to one array member in the published
@@ -50,80 +57,104 @@ class HPKETestVector {
bool ReadFromFileTest(FileTest *t);
void Verify() const {
+ const EVP_HPKE_KEM *kem = EVP_hpke_x25519_hkdf_sha256();
+ const EVP_HPKE_AEAD *aead = GetAEAD();
+ ASSERT_TRUE(aead);
+ const EVP_HPKE_KDF *kdf = GetKDF();
+ ASSERT_TRUE(kdf);
+
+ // Test the sender.
ScopedEVP_HPKE_CTX sender_ctx;
- ScopedEVP_HPKE_CTX receiver_ctx;
-
- switch (mode_) {
- case HPKEMode::kBase:
- ASSERT_GT(secret_key_e_.size(), 0u);
- ASSERT_EQ(psk_.size(), 0u);
- ASSERT_EQ(psk_id_.size(), 0u);
-
- // Set up the sender.
- ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519_for_test(
- sender_ctx.get(), kdf_id_, aead_id_, public_key_r_.data(),
- info_.data(), info_.size(), secret_key_e_.data(),
- public_key_e_.data()));
-
- // Set up the receiver.
- ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
- receiver_ctx.get(), kdf_id_, aead_id_, public_key_e_.data(),
- public_key_r_.data(), secret_key_r_.data(), info_.data(),
- info_.size()));
- break;
-
- case HPKEMode::kPSK:
- ASSERT_GT(secret_key_e_.size(), 0u);
- ASSERT_GT(psk_.size(), 0u);
- ASSERT_GT(psk_id_.size(), 0u);
-
- // Set up the sender.
- ASSERT_TRUE(EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
- sender_ctx.get(), kdf_id_, aead_id_, public_key_r_.data(),
- info_.data(), info_.size(), psk_.data(), psk_.size(),
- psk_id_.data(), psk_id_.size(), secret_key_e_.data(),
- public_key_e_.data()));
-
- // Set up the receiver.
- ASSERT_TRUE(EVP_HPKE_CTX_setup_psk_r_x25519(
- receiver_ctx.get(), kdf_id_, aead_id_, public_key_e_.data(),
- public_key_r_.data(), secret_key_r_.data(), info_.data(),
- info_.size(), psk_.data(), psk_.size(), psk_id_.data(),
- psk_id_.size()));
- break;
- default:
- FAIL() << "Unsupported mode";
- return;
- }
+ uint8_t enc[EVP_HPKE_MAX_ENC_LENGTH];
+ size_t enc_len;
+ ASSERT_TRUE(EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
+ sender_ctx.get(), enc, &enc_len, sizeof(enc), kem, kdf, aead,
+ public_key_r_.data(), public_key_r_.size(), info_.data(), info_.size(),
+ secret_key_e_.data(), secret_key_e_.size()));
+ EXPECT_EQ(Bytes(enc, enc_len), Bytes(public_key_e_));
+ VerifySender(sender_ctx.get());
+
+ // Test the recipient.
+ ScopedEVP_HPKE_KEY base_key;
+ ASSERT_TRUE(EVP_HPKE_KEY_init(base_key.get(), kem, secret_key_r_.data(),
+ secret_key_r_.size()));
+ for (bool copy : {false, true}) {
+ SCOPED_TRACE(copy);
+ const EVP_HPKE_KEY *key = base_key.get();
+ ScopedEVP_HPKE_KEY key_copy;
+ if (copy) {
+ ASSERT_TRUE(EVP_HPKE_KEY_copy(key_copy.get(), base_key.get()));
+ key = key_copy.get();
+ }
- VerifyEncryptions(sender_ctx.get(), receiver_ctx.get());
- VerifyExports(sender_ctx.get());
- VerifyExports(receiver_ctx.get());
+ uint8_t public_key[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH];
+ size_t public_key_len;
+ ASSERT_TRUE(EVP_HPKE_KEY_public_key(key, public_key, &public_key_len,
+ sizeof(public_key)));
+ EXPECT_EQ(Bytes(public_key, public_key_len), Bytes(public_key_r_));
+
+ uint8_t private_key[EVP_HPKE_MAX_PRIVATE_KEY_LENGTH];
+ size_t private_key_len;
+ ASSERT_TRUE(EVP_HPKE_KEY_private_key(key, private_key, &private_key_len,
+ sizeof(private_key)));
+ EXPECT_EQ(Bytes(private_key, private_key_len), Bytes(secret_key_r_));
+
+ // Set up the recipient.
+ ScopedEVP_HPKE_CTX recipient_ctx;
+ ASSERT_TRUE(EVP_HPKE_CTX_setup_recipient(recipient_ctx.get(), key, kdf,
+ aead, enc, enc_len, info_.data(),
+ info_.size()));
+
+ VerifyRecipient(recipient_ctx.get());
+ }
}
private:
- void VerifyEncryptions(EVP_HPKE_CTX *sender_ctx,
- EVP_HPKE_CTX *receiver_ctx) const {
+ const EVP_HPKE_AEAD *GetAEAD() const {
+ for (const auto aead : kAllAEADs) {
+ if (EVP_HPKE_AEAD_id(aead()) == aead_id_) {
+ return aead();
+ }
+ }
+ return nullptr;
+ }
+
+ const EVP_HPKE_KDF *GetKDF() const {
+ for (const auto kdf : kAllKDFs) {
+ if (EVP_HPKE_KDF_id(kdf()) == kdf_id_) {
+ return kdf();
+ }
+ }
+ return nullptr;
+ }
+
+ void VerifySender(EVP_HPKE_CTX *ctx) const {
for (const Encryption &task : encryptions_) {
std::vector<uint8_t> encrypted(task.plaintext.size() +
- EVP_HPKE_CTX_max_overhead(sender_ctx));
+ EVP_HPKE_CTX_max_overhead(ctx));
size_t encrypted_len;
- ASSERT_TRUE(EVP_HPKE_CTX_seal(
- sender_ctx, encrypted.data(), &encrypted_len, encrypted.size(),
- task.plaintext.data(), task.plaintext.size(), task.aad.data(),
- task.aad.size()));
+ ASSERT_TRUE(EVP_HPKE_CTX_seal(ctx, encrypted.data(), &encrypted_len,
+ encrypted.size(), task.plaintext.data(),
+ task.plaintext.size(), task.aad.data(),
+ task.aad.size()));
ASSERT_EQ(Bytes(encrypted.data(), encrypted_len), Bytes(task.ciphertext));
+ }
+ VerifyExports(ctx);
+ }
+ void VerifyRecipient(EVP_HPKE_CTX *ctx) const {
+ for (const Encryption &task : encryptions_) {
std::vector<uint8_t> decrypted(task.ciphertext.size());
size_t decrypted_len;
- ASSERT_TRUE(EVP_HPKE_CTX_open(
- receiver_ctx, decrypted.data(), &decrypted_len, decrypted.size(),
- task.ciphertext.data(), task.ciphertext.size(), task.aad.data(),
- task.aad.size()));
+ ASSERT_TRUE(EVP_HPKE_CTX_open(ctx, decrypted.data(), &decrypted_len,
+ decrypted.size(), task.ciphertext.data(),
+ task.ciphertext.size(), task.aad.data(),
+ task.aad.size()));
ASSERT_EQ(Bytes(decrypted.data(), decrypted_len), Bytes(task.plaintext));
}
+ VerifyExports(ctx);
}
void VerifyExports(EVP_HPKE_CTX *ctx) const {
@@ -149,7 +180,6 @@ class HPKETestVector {
std::vector<uint8_t> exported_value;
};
- HPKEMode mode_;
uint16_t kdf_id_;
uint16_t aead_id_;
std::vector<uint8_t> context_;
@@ -160,8 +190,6 @@ class HPKETestVector {
std::vector<uint8_t> secret_key_r_;
std::vector<Encryption> encryptions_;
std::vector<Export> exports_;
- std::vector<uint8_t> psk_; // Empty when mode is not PSK.
- std::vector<uint8_t> psk_id_; // Empty when mode is not PSK.
};
// Match FileTest's naming scheme for duplicated attribute names.
@@ -197,13 +225,10 @@ bool FileTestReadInt(FileTest *file_test, T *out, const std::string &key) {
bool HPKETestVector::ReadFromFileTest(FileTest *t) {
- uint8_t mode_tmp;
- if (!FileTestReadInt(t, &mode_tmp, "mode")) {
- return false;
- }
- mode_ = static_cast<HPKEMode>(mode_tmp);
-
- if (!FileTestReadInt(t, &kdf_id_, "kdf_id") ||
+ uint8_t mode = 0;
+ if (!FileTestReadInt(t, &mode, "mode") ||
+ mode != 0 /* mode_base */ ||
+ !FileTestReadInt(t, &kdf_id_, "kdf_id") ||
!FileTestReadInt(t, &aead_id_, "aead_id") ||
!t->GetBytes(&info_, "info") ||
!t->GetBytes(&secret_key_r_, "skRm") ||
@@ -213,13 +238,6 @@ bool HPKETestVector::ReadFromFileTest(FileTest *t) {
return false;
}
- if (mode_ == HPKEMode::kPSK) {
- if (!t->GetBytes(&psk_, "psk") ||
- !t->GetBytes(&psk_id_, "psk_id")) {
- return false;
- }
- }
-
for (int i = 1; t->HasAttribute(BuildAttrName("aad", i)); i++) {
Encryption encryption;
if (!t->GetBytes(&encryption.aad, BuildAttrName("aad", i)) ||
@@ -257,11 +275,6 @@ TEST(HPKETest, VerifyTestVectors) {
// generates new keys for each context. Test this codepath by checking we can
// decrypt our own messages.
TEST(HPKETest, RoundTrip) {
- uint16_t kdf_ids[] = {EVP_HPKE_HKDF_SHA256, EVP_HPKE_HKDF_SHA384,
- EVP_HPKE_HKDF_SHA512};
- uint16_t aead_ids[] = {EVP_HPKE_AEAD_AES_GCM_128, EVP_HPKE_AEAD_AES_GCM_256,
- EVP_HPKE_AEAD_CHACHA20POLY1305};
-
const uint8_t info_a[] = {1, 1, 2, 3, 5, 8};
const uint8_t info_b[] = {42, 42, 42};
const uint8_t ad_a[] = {1, 2, 4, 8, 16};
@@ -269,31 +282,40 @@ TEST(HPKETest, RoundTrip) {
Span<const uint8_t> info_values[] = {{nullptr, 0}, info_a, info_b};
Span<const uint8_t> ad_values[] = {{nullptr, 0}, ad_a, ad_b};
- // Generate the receiver's keypair.
- uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
+ // Generate the recipient's keypair.
+ ScopedEVP_HPKE_KEY key;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()));
uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
- X25519_keypair(public_key_r, secret_key_r);
-
- for (uint16_t kdf_id : kdf_ids) {
- for (uint16_t aead_id : aead_ids) {
+ size_t public_key_r_len;
+ ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key_r,
+ &public_key_r_len, sizeof(public_key_r)));
+
+ for (const auto kdf : kAllKDFs) {
+ SCOPED_TRACE(EVP_HPKE_KDF_id(kdf()));
+ for (const auto aead : kAllAEADs) {
+ SCOPED_TRACE(EVP_HPKE_AEAD_id(aead()));
for (const Span<const uint8_t> &info : info_values) {
+ SCOPED_TRACE(Bytes(info));
for (const Span<const uint8_t> &ad : ad_values) {
+ SCOPED_TRACE(Bytes(ad));
// Set up the sender.
ScopedEVP_HPKE_CTX sender_ctx;
uint8_t enc[X25519_PUBLIC_VALUE_LEN];
- ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519(
- sender_ctx.get(), enc, kdf_id, aead_id, public_key_r, info.data(),
- info.size()));
-
- // Set up the receiver.
- ScopedEVP_HPKE_CTX receiver_ctx;
- ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
- receiver_ctx.get(), kdf_id, aead_id, enc, public_key_r,
- secret_key_r, info.data(), info.size()));
+ size_t enc_len;
+ ASSERT_TRUE(EVP_HPKE_CTX_setup_sender(
+ sender_ctx.get(), enc, &enc_len, sizeof(enc),
+ EVP_hpke_x25519_hkdf_sha256(), kdf(), aead(), public_key_r,
+ public_key_r_len, info.data(), info.size()));
+
+ // Set up the recipient.
+ ScopedEVP_HPKE_CTX recipient_ctx;
+ ASSERT_TRUE(EVP_HPKE_CTX_setup_recipient(
+ recipient_ctx.get(), key.get(), kdf(), aead(), enc, enc_len,
+ info.data(), info.size()));
const char kCleartextPayload[] = "foobar";
- // Have sender encrypt message for the receiver.
+ // Have sender encrypt message for the recipient.
std::vector<uint8_t> ciphertext(
sizeof(kCleartextPayload) +
EVP_HPKE_CTX_max_overhead(sender_ctx.get()));
@@ -304,10 +326,10 @@ TEST(HPKETest, RoundTrip) {
reinterpret_cast<const uint8_t *>(kCleartextPayload),
sizeof(kCleartextPayload), ad.data(), ad.size()));
- // Have receiver decrypt the message.
+ // Have recipient decrypt the message.
std::vector<uint8_t> cleartext(ciphertext.size());
size_t cleartext_len;
- ASSERT_TRUE(EVP_HPKE_CTX_open(receiver_ctx.get(), cleartext.data(),
+ ASSERT_TRUE(EVP_HPKE_CTX_open(recipient_ctx.get(), cleartext.data(),
&cleartext_len, cleartext.size(),
ciphertext.data(), ciphertext_len,
ad.data(), ad.size()));
@@ -331,55 +353,50 @@ TEST(HPKETest, X25519EncapSmallOrderPoint) {
0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8,
};
- // Generate a valid keypair for the receiver.
- uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
- uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
- X25519_keypair(public_key_r, secret_key_r);
-
- uint16_t kdf_ids[] = {EVP_HPKE_HKDF_SHA256, EVP_HPKE_HKDF_SHA384,
- EVP_HPKE_HKDF_SHA512};
- uint16_t aead_ids[] = {EVP_HPKE_AEAD_AES_GCM_128, EVP_HPKE_AEAD_AES_GCM_256,
- EVP_HPKE_AEAD_CHACHA20POLY1305};
+ ScopedEVP_HPKE_KEY key;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()));
- for (uint16_t kdf_id : kdf_ids) {
- for (uint16_t aead_id : aead_ids) {
- // Set up the sender, passing in kSmallOrderPoint as |peer_public_value|.
+ for (const auto kdf : kAllKDFs) {
+ SCOPED_TRACE(EVP_HPKE_KDF_id(kdf()));
+ for (const auto aead : kAllAEADs) {
+ SCOPED_TRACE(EVP_HPKE_AEAD_id(aead()));
+ // Set up the sender, passing in kSmallOrderPoint as |peer_public_key|.
ScopedEVP_HPKE_CTX sender_ctx;
uint8_t enc[X25519_PUBLIC_VALUE_LEN];
- ASSERT_FALSE(EVP_HPKE_CTX_setup_base_s_x25519(
- sender_ctx.get(), enc, kdf_id, aead_id, kSmallOrderPoint, nullptr,
- 0));
-
- // Set up the receiver, passing in kSmallOrderPoint as |enc|.
- ScopedEVP_HPKE_CTX receiver_ctx;
- ASSERT_FALSE(EVP_HPKE_CTX_setup_base_r_x25519(
- receiver_ctx.get(), kdf_id, aead_id, kSmallOrderPoint, public_key_r,
- secret_key_r, nullptr, 0));
+ size_t enc_len;
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_sender(
+ sender_ctx.get(), enc, &enc_len, sizeof(enc),
+ EVP_hpke_x25519_hkdf_sha256(), kdf(), aead(), kSmallOrderPoint,
+ sizeof(kSmallOrderPoint), nullptr, 0));
+
+ // Set up the recipient, passing in kSmallOrderPoint as |enc|.
+ ScopedEVP_HPKE_CTX recipient_ctx;
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_recipient(
+ recipient_ctx.get(), key.get(), kdf(), aead(), kSmallOrderPoint,
+ sizeof(kSmallOrderPoint), nullptr, 0));
}
}
}
-// Test that Seal() fails when the context has been initialized as a receiver.
-TEST(HPKETest, ReceiverInvalidSeal) {
+// Test that Seal() fails when the context has been initialized as a recipient.
+TEST(HPKETest, RecipientInvalidSeal) {
const uint8_t kMockEnc[X25519_PUBLIC_VALUE_LEN] = {0xff};
const char kCleartextPayload[] = "foobar";
- // Generate the receiver's keypair.
- uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
- uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
- X25519_keypair(public_key_r, secret_key_r);
+ ScopedEVP_HPKE_KEY key;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()));
- // Set up the receiver.
- ScopedEVP_HPKE_CTX receiver_ctx;
- ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
- receiver_ctx.get(), EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
- kMockEnc, public_key_r, secret_key_r, nullptr, 0));
+ // Set up the recipient.
+ ScopedEVP_HPKE_CTX recipient_ctx;
+ ASSERT_TRUE(EVP_HPKE_CTX_setup_recipient(
+ recipient_ctx.get(), key.get(), EVP_hpke_hkdf_sha256(),
+ EVP_hpke_aes_128_gcm(), kMockEnc, sizeof(kMockEnc), nullptr, 0));
- // Call Seal() on the receiver.
+ // Call Seal() on the recipient.
size_t ciphertext_len;
uint8_t ciphertext[100];
ASSERT_FALSE(EVP_HPKE_CTX_seal(
- receiver_ctx.get(), ciphertext, &ciphertext_len, sizeof(ciphertext),
+ recipient_ctx.get(), ciphertext, &ciphertext_len, sizeof(ciphertext),
reinterpret_cast<const uint8_t *>(kCleartextPayload),
sizeof(kCleartextPayload), nullptr, 0));
}
@@ -389,7 +406,7 @@ TEST(HPKETest, SenderInvalidOpen) {
const uint8_t kMockCiphertext[100] = {0xff};
const size_t kMockCiphertextLen = 80;
- // Generate the receiver's keypair.
+ // Generate the recipient's keypair.
uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
X25519_keypair(public_key_r, secret_key_r);
@@ -397,9 +414,11 @@ TEST(HPKETest, SenderInvalidOpen) {
// Set up the sender.
ScopedEVP_HPKE_CTX sender_ctx;
uint8_t enc[X25519_PUBLIC_VALUE_LEN];
- ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519(
- sender_ctx.get(), enc, EVP_HPKE_HKDF_SHA256, EVP_HPKE_AEAD_AES_GCM_128,
- public_key_r, nullptr, 0));
+ size_t enc_len;
+ ASSERT_TRUE(EVP_HPKE_CTX_setup_sender(
+ sender_ctx.get(), enc, &enc_len, sizeof(enc),
+ EVP_hpke_x25519_hkdf_sha256(), EVP_hpke_hkdf_sha256(),
+ EVP_hpke_aes_128_gcm(), public_key_r, sizeof(public_key_r), nullptr, 0));
// Call Open() on the sender.
uint8_t cleartext[128];
@@ -409,58 +428,78 @@ TEST(HPKETest, SenderInvalidOpen) {
kMockCiphertextLen, nullptr, 0));
}
-// Test that the PSK variants of Setup functions fail when any of the PSK inputs
-// are empty.
-TEST(HPKETest, EmptyPSK) {
- const uint8_t kMockEnc[X25519_PUBLIC_VALUE_LEN] = {0xff};
- const std::vector<uint8_t> kPSKValues[] = {std::vector<uint8_t>(100, 0xff),
- {}};
+TEST(HPKETest, SetupSenderBufferTooSmall) {
+ uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
+ uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
+ X25519_keypair(public_key_r, secret_key_r);
+
+ ScopedEVP_HPKE_CTX sender_ctx;
+ uint8_t enc[X25519_PUBLIC_VALUE_LEN - 1];
+ size_t enc_len;
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_sender(
+ sender_ctx.get(), enc, &enc_len, sizeof(enc),
+ EVP_hpke_x25519_hkdf_sha256(), EVP_hpke_hkdf_sha256(),
+ EVP_hpke_aes_128_gcm(), public_key_r, sizeof(public_key_r), nullptr, 0));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_INVALID_BUFFER_SIZE, ERR_GET_REASON(err));
+ ERR_clear_error();
+}
- // Generate the receiver's keypair.
+TEST(HPKETest, SetupSenderBufferTooLarge) {
uint8_t secret_key_r[X25519_PRIVATE_KEY_LEN];
uint8_t public_key_r[X25519_PUBLIC_VALUE_LEN];
X25519_keypair(public_key_r, secret_key_r);
- // Vary the PSK and PSKID inputs for the sender and receiver, trying all four
- // permutations of empty and nonempty inputs.
+ // Too large of an output buffer is fine because the function reports the
+ // actual length.
+ ScopedEVP_HPKE_CTX sender_ctx;
+ uint8_t enc[X25519_PUBLIC_VALUE_LEN + 1];
+ size_t enc_len;
+ EXPECT_TRUE(EVP_HPKE_CTX_setup_sender(
+ sender_ctx.get(), enc, &enc_len, sizeof(enc),
+ EVP_hpke_x25519_hkdf_sha256(), EVP_hpke_hkdf_sha256(),
+ EVP_hpke_aes_128_gcm(), public_key_r, sizeof(public_key_r), nullptr, 0));
+ EXPECT_EQ(size_t{X25519_PUBLIC_VALUE_LEN}, enc_len);
+}
- for (const auto &psk : kPSKValues) {
- for (const auto &psk_id : kPSKValues) {
- const bool kExpectSuccess = psk.size() > 0 && psk_id.size() > 0;
+TEST(HPKETest, SetupRecipientWrongLengthEnc) {
+ ScopedEVP_HPKE_KEY key;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()));
- ASSERT_EQ(ERR_get_error(), 0u);
+ const uint8_t bogus_enc[X25519_PUBLIC_VALUE_LEN + 5] = {0xff};
- ScopedEVP_HPKE_CTX sender_ctx;
- uint8_t enc[X25519_PUBLIC_VALUE_LEN];
- ASSERT_EQ(EVP_HPKE_CTX_setup_psk_s_x25519(
- sender_ctx.get(), enc, EVP_HPKE_HKDF_SHA256,
- EVP_HPKE_AEAD_AES_GCM_128, public_key_r, nullptr, 0,
- psk.data(), psk.size(), psk_id.data(), psk_id.size()),
- kExpectSuccess);
-
- if (!kExpectSuccess) {
- uint32_t err = ERR_get_error();
- EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
- EXPECT_EQ(EVP_R_EMPTY_PSK, ERR_GET_REASON(err));
- }
- ERR_clear_error();
-
- ScopedEVP_HPKE_CTX receiver_ctx;
- ASSERT_EQ(
- EVP_HPKE_CTX_setup_psk_r_x25519(
- receiver_ctx.get(), EVP_HPKE_HKDF_SHA256,
- EVP_HPKE_AEAD_AES_GCM_128, kMockEnc, public_key_r, secret_key_r,
- nullptr, 0, psk.data(), psk.size(), psk_id.data(), psk_id.size()),
- kExpectSuccess);
-
- if (!kExpectSuccess) {
- uint32_t err = ERR_get_error();
- EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
- EXPECT_EQ(EVP_R_EMPTY_PSK, ERR_GET_REASON(err));
- }
- ERR_clear_error();
- }
- }
+ ScopedEVP_HPKE_CTX recipient_ctx;
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_recipient(
+ recipient_ctx.get(), key.get(), EVP_hpke_hkdf_sha256(),
+ EVP_hpke_aes_128_gcm(), bogus_enc, sizeof(bogus_enc), nullptr, 0));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_INVALID_PEER_KEY, ERR_GET_REASON(err));
+ ERR_clear_error();
+}
+
+TEST(HPKETest, SetupSenderWrongLengthPeerPublicValue) {
+ const uint8_t bogus_public_key_r[X25519_PRIVATE_KEY_LEN + 5] = {0xff};
+ ScopedEVP_HPKE_CTX sender_ctx;
+ uint8_t enc[X25519_PUBLIC_VALUE_LEN];
+ size_t enc_len;
+ ASSERT_FALSE(EVP_HPKE_CTX_setup_sender(
+ sender_ctx.get(), enc, &enc_len, sizeof(enc),
+ EVP_hpke_x25519_hkdf_sha256(), EVP_hpke_hkdf_sha256(),
+ EVP_hpke_aes_128_gcm(), bogus_public_key_r, sizeof(bogus_public_key_r),
+ nullptr, 0));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_EVP, ERR_GET_LIB(err));
+ EXPECT_EQ(EVP_R_INVALID_PEER_KEY, ERR_GET_REASON(err));
+ ERR_clear_error();
+}
+
+TEST(HPKETest, InvalidRecipientKey) {
+ const uint8_t private_key[X25519_PUBLIC_VALUE_LEN + 5] = {0xff};
+ ScopedEVP_HPKE_KEY key;
+ EXPECT_FALSE(EVP_HPKE_KEY_init(key.get(), EVP_hpke_x25519_hkdf_sha256(),
+ private_key, sizeof(private_key)));
}
TEST(HPKETest, InternalParseIntSafe) {
diff --git a/deps/boringssl/src/crypto/hpke/internal.h b/deps/boringssl/src/crypto/hpke/internal.h
deleted file mode 100644
index 3d2f4ba..0000000
--- a/deps/boringssl/src/crypto/hpke/internal.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/* Copyright (c) 2020, Google Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
-#ifndef OPENSSL_HEADER_CRYPTO_HPKE_INTERNAL_H
-#define OPENSSL_HEADER_CRYPTO_HPKE_INTERNAL_H
-
-#include <openssl/aead.h>
-#include <openssl/base.h>
-#include <openssl/curve25519.h>
-#include <openssl/digest.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-
-// Hybrid Public Key Encryption.
-//
-// Hybrid Public Key Encryption (HPKE) enables a sender to encrypt messages to a
-// receiver with a public key. Optionally, the sender may authenticate its
-// possession of a pre-shared key to the recipient.
-//
-// See https://tools.ietf.org/html/draft-irtf-cfrg-hpke-07.
-
-// EVP_HPKE_AEAD_* are AEAD identifiers.
-#define EVP_HPKE_AEAD_AES_GCM_128 0x0001
-#define EVP_HPKE_AEAD_AES_GCM_256 0x0002
-#define EVP_HPKE_AEAD_CHACHA20POLY1305 0x0003
-
-// EVP_HPKE_HKDF_* are HKDF identifiers.
-#define EVP_HPKE_HKDF_SHA256 0x0001
-#define EVP_HPKE_HKDF_SHA384 0x0002
-#define EVP_HPKE_HKDF_SHA512 0x0003
-
-// EVP_HPKE_MAX_OVERHEAD contains the largest value that
-// |EVP_HPKE_CTX_max_overhead| would ever return for any context.
-#define EVP_HPKE_MAX_OVERHEAD EVP_AEAD_MAX_OVERHEAD
-
-
-// Encryption contexts.
-
-// An |EVP_HPKE_CTX| is an HPKE encryption context.
-typedef struct evp_hpke_ctx_st {
- const EVP_MD *hkdf_md;
- EVP_AEAD_CTX aead_ctx;
- uint16_t kdf_id;
- uint16_t aead_id;
- uint8_t base_nonce[EVP_AEAD_MAX_NONCE_LENGTH];
- uint8_t exporter_secret[EVP_MAX_MD_SIZE];
- uint64_t seq;
- int is_sender;
-} EVP_HPKE_CTX;
-
-// EVP_HPKE_CTX_init initializes an already-allocated |EVP_HPKE_CTX|. The caller
-// should then use one of the |EVP_HPKE_CTX_setup_*| functions.
-//
-// It is safe, but not necessary to call |EVP_HPKE_CTX_cleanup| in this state.
-OPENSSL_EXPORT void EVP_HPKE_CTX_init(EVP_HPKE_CTX *ctx);
-
-// EVP_HPKE_CTX_cleanup releases memory referenced by |ctx|. |ctx| must have
-// been initialized with |EVP_HPKE_CTX_init|.
-OPENSSL_EXPORT void EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX *ctx);
-
-
-// Setting up HPKE contexts.
-//
-// In each of the following functions, |hpke| must have been initialized with
-// |EVP_HPKE_CTX_init|. |kdf_id| selects the KDF for non-KEM HPKE operations and
-// must be one of the |EVP_HPKE_HKDF_*| constants. |aead_id| selects the AEAD
-// for the "open" and "seal" operations and must be one of the |EVP_HPKE_AEAD_*|
-// constants.
-
-// EVP_HPKE_CTX_setup_base_s_x25519 sets up |hpke| as a sender context that can
-// encrypt for the private key corresponding to |peer_public_value| (the
-// recipient's public key). It returns one on success, and zero otherwise. Note
-// that this function will fail if |peer_public_value| is invalid.
-//
-// This function writes the encapsulated shared secret to |out_enc|.
-OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519(
- EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
- uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len);
-
-// EVP_HPKE_CTX_setup_base_s_x25519_for_test behaves like
-// |EVP_HPKE_CTX_setup_base_s_x25519|, but takes a pre-generated ephemeral
-// sender key.
-OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len,
- const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
- const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]);
-
-// EVP_HPKE_CTX_setup_base_r_x25519 sets up |hpke| as a recipient context that
-// can decrypt messages. |private_key| is the recipient's private key, and |enc|
-// is the encapsulated shared secret from the sender. Note that this function
-// will fail if |enc| is invalid.
-OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_r_x25519(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
- const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
- const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
- size_t info_len);
-
-// EVP_HPKE_CTX_setup_psk_s_x25519 sets up |hpke| as a sender context that can
-// encrypt for the private key corresponding to |peer_public_value| (the
-// recipient's public key) and authenticate its possession of a PSK. It returns
-// one on success, and zero otherwise. Note that this function will fail if
-// |peer_public_value| is invalid.
-//
-// The PSK and its ID must be provided in |psk| and |psk_id|, respectively. Both
-// must be nonempty (|psk_len| and |psk_id_len| must be non-zero), or this
-// function will fail.
-//
-// This function writes the encapsulated shared secret to |out_enc|.
-OPENSSL_EXPORT int EVP_HPKE_CTX_setup_psk_s_x25519(
- EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
- uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
- const uint8_t *psk_id, size_t psk_id_len);
-
-// EVP_HPKE_CTX_setup_psk_s_x25519_for_test behaves like
-// |EVP_HPKE_CTX_setup_psk_s_x25519|, but takes a pre-generated ephemeral sender
-// key.
-OPENSSL_EXPORT int EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
- const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
- const uint8_t *psk_id, size_t psk_id_len,
- const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
- const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]);
-
-// EVP_HPKE_CTX_setup_psk_r_x25519 sets up |hpke| as a recipient context that
-// can decrypt messages. Future open (decrypt) operations will fail if the
-// sender does not possess the PSK indicated by |psk| and |psk_id|.
-// |private_key| is the recipient's private key, and |enc| is the encapsulated
-// shared secret from the sender. If |enc| is invalid, this function will fail.
-//
-// The PSK and its ID must be provided in |psk| and |psk_id|, respectively. Both
-// must be nonempty (|psk_len| and |psk_id_len| must be non-zero), or this
-// function will fail.
-OPENSSL_EXPORT int EVP_HPKE_CTX_setup_psk_r_x25519(
- EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
- const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
- const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
- const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
- size_t info_len, const uint8_t *psk, size_t psk_len, const uint8_t *psk_id,
- size_t psk_id_len);
-
-
-// Using an HPKE context.
-
-// EVP_HPKE_CTX_open uses the HPKE context |hpke| to authenticate |in_len| bytes
-// from |in| and |ad_len| bytes from |ad| and to decrypt at most |in_len| bytes
-// into |out|. It returns one on success, and zero otherwise.
-//
-// This operation will fail if the |hpke| context is not set up as a receiver.
-//
-// Note that HPKE encryption is stateful and ordered. The sender's first call to
-// |EVP_HPKE_CTX_seal| must correspond to the recipient's first call to
-// |EVP_HPKE_CTX_open|, etc.
-//
-// At most |in_len| bytes are written to |out|. In order to ensure success,
-// |max_out_len| should be at least |in_len|. On successful return, |*out_len|
-// is set to the actual number of bytes written.
-OPENSSL_EXPORT int EVP_HPKE_CTX_open(EVP_HPKE_CTX *hpke, uint8_t *out,
- size_t *out_len, size_t max_out_len,
- const uint8_t *in, size_t in_len,
- const uint8_t *ad, size_t ad_len);
-
-// EVP_HPKE_CTX_seal uses the HPKE context |hpke| to encrypt and authenticate
-// |in_len| bytes of ciphertext |in| and authenticate |ad_len| bytes from |ad|,
-// writing the result to |out|. It returns one on success and zero otherwise.
-//
-// This operation will fail if the |hpke| context is not set up as a sender.
-//
-// Note that HPKE encryption is stateful and ordered. The sender's first call to
-// |EVP_HPKE_CTX_seal| must correspond to the recipient's first call to
-// |EVP_HPKE_CTX_open|, etc.
-//
-// At most, |max_out_len| encrypted bytes are written to |out|. On successful
-// return, |*out_len| is set to the actual number of bytes written.
-//
-// To ensure success, |max_out_len| should be |in_len| plus the result of
-// |EVP_HPKE_CTX_max_overhead| or |EVP_HPKE_MAX_OVERHEAD|.
-OPENSSL_EXPORT int EVP_HPKE_CTX_seal(EVP_HPKE_CTX *hpke, uint8_t *out,
- size_t *out_len, size_t max_out_len,
- const uint8_t *in, size_t in_len,
- const uint8_t *ad, size_t ad_len);
-
-// EVP_HPKE_CTX_export uses the HPKE context |hpke| to export a secret of
-// |secret_len| bytes into |out|. This function uses |context_len| bytes from
-// |context| as a context string for the secret. This is necessary to separate
-// different uses of exported secrets and bind relevant caller-specific context
-// into the output. It returns one on success and zero otherwise.
-OPENSSL_EXPORT int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *hpke, uint8_t *out,
- size_t secret_len,
- const uint8_t *context,
- size_t context_len);
-
-// EVP_HPKE_CTX_max_overhead returns the maximum number of additional bytes
-// added by sealing data with |EVP_HPKE_CTX_seal|. The |hpke| context must be
-// set up as a sender.
-OPENSSL_EXPORT size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *hpke);
-
-// EVP_HPKE_get_aead returns the AEAD corresponding to |aead_id|, or NULL if
-// |aead_id| is not a known AEAD identifier.
-OPENSSL_EXPORT const EVP_AEAD *EVP_HPKE_get_aead(uint16_t aead_id);
-
-// EVP_HPKE_get_hkdf_md returns the hash function associated with |kdf_id|, or
-// NULL if |kdf_id| is not a known KDF identifier that uses HKDF.
-OPENSSL_EXPORT const EVP_MD *EVP_HPKE_get_hkdf_md(uint16_t kdf_id);
-
-
-#if defined(__cplusplus)
-} // extern C
-#endif
-
-#if !defined(BORINGSSL_NO_CXX)
-extern "C++" {
-
-BSSL_NAMESPACE_BEGIN
-
-using ScopedEVP_HPKE_CTX =
- internal::StackAllocated<EVP_HPKE_CTX, void, EVP_HPKE_CTX_init,
- EVP_HPKE_CTX_cleanup>;
-
-BSSL_NAMESPACE_END
-
-} // extern C++
-#endif
-
-#endif // OPENSSL_HEADER_CRYPTO_HPKE_INTERNAL_H
diff --git a/deps/boringssl/src/crypto/hrss/asm/poly_rq_mul.S b/deps/boringssl/src/crypto/hrss/asm/poly_rq_mul.S
index 835d716..c37d7d0 100644
--- a/deps/boringssl/src/crypto/hrss/asm/poly_rq_mul.S
+++ b/deps/boringssl/src/crypto/hrss/asm/poly_rq_mul.S
@@ -26,23 +26,6 @@
# This file was generated by poly_rq_mul.py
.text
.align 32
-mask_low9words:
-.word 0xffff
-.word 0xffff
-.word 0xffff
-.word 0xffff
-.word 0xffff
-.word 0xffff
-.word 0xffff
-.word 0xffff
-.word 0xffff
-.word 0x0
-.word 0x0
-.word 0x0
-.word 0x0
-.word 0x0
-.word 0x0
-.word 0x0
const3:
.word 3
.word 3
@@ -327,15 +310,21 @@ movq %rsp, %rbp
.cfi_def_cfa_register rbp
push %r12
.cfi_offset r12, -24
-mov %rsp, %r8
-andq $-32, %rsp
-subq $6144, %rsp
-mov %rsp, %rax
-subq $6144, %rsp
-mov %rsp, %r11
-subq $12288, %rsp
-mov %rsp, %r12
-subq $512, %rsp
+# This function originally used a significant amount of stack space. As an
+# alternative, the needed scratch space is now passed in as the 4th argument.
+# The amount of scratch space used must thus be kept in sync with
+# POLY_MUL_RQ_SCRATCH_SPACE in internal.h.
+#
+# Setting RSP to point into the given scratch space upsets the ABI tests
+# therefore all references to RSP are switched to R8.
+mov %rcx, %r8
+addq $6144+12288+512+9408+32, %r8
+mov %r8, %rax
+subq $6144, %r8
+mov %r8, %r11
+subq $12288, %r8
+mov %r8, %r12
+subq $512, %r8
vmovdqa const3(%rip), %ymm3
vmovdqu 0(%rsi), %ymm0
vmovdqu 88(%rsi), %ymm1
@@ -377,38 +366,38 @@ vpaddw %ymm5, %ymm7, %ymm15
vmovdqa %ymm15, 5856(%rax)
vpaddw %ymm14, %ymm15, %ymm14
vmovdqa %ymm14, 5952(%rax)
-vmovdqa %ymm0, 0(%rsp)
-vmovdqa %ymm1, 32(%rsp)
-vmovdqa %ymm2, 64(%rsp)
-vmovdqa %ymm12, 96(%rsp)
-vmovdqa %ymm8, 128(%rsp)
-vmovdqa %ymm9, 160(%rsp)
-vmovdqa %ymm10, 192(%rsp)
-vmovdqa %ymm11, 224(%rsp)
+vmovdqa %ymm0, 0(%r8)
+vmovdqa %ymm1, 32(%r8)
+vmovdqa %ymm2, 64(%r8)
+vmovdqa %ymm12, 96(%r8)
+vmovdqa %ymm8, 128(%r8)
+vmovdqa %ymm9, 160(%r8)
+vmovdqa %ymm10, 192(%r8)
+vmovdqa %ymm11, 224(%r8)
vmovdqu 704(%rsi), %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm1
-vpaddw 128(%rsp), %ymm4, %ymm2
+vpaddw 0(%r8), %ymm0, %ymm1
+vpaddw 128(%r8), %ymm4, %ymm2
vpaddw %ymm2, %ymm1, %ymm8
vpsubw %ymm2, %ymm1, %ymm12
-vmovdqa %ymm0, 256(%rsp)
+vmovdqa %ymm0, 256(%r8)
vmovdqu 792(%rsi), %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm1
-vpaddw 160(%rsp), %ymm5, %ymm2
+vpaddw 32(%r8), %ymm0, %ymm1
+vpaddw 160(%r8), %ymm5, %ymm2
vpaddw %ymm2, %ymm1, %ymm9
vpsubw %ymm2, %ymm1, %ymm13
-vmovdqa %ymm0, 288(%rsp)
+vmovdqa %ymm0, 288(%r8)
vmovdqu 880(%rsi), %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm1
-vpaddw 192(%rsp), %ymm6, %ymm2
+vpaddw 64(%r8), %ymm0, %ymm1
+vpaddw 192(%r8), %ymm6, %ymm2
vpaddw %ymm2, %ymm1, %ymm10
vpsubw %ymm2, %ymm1, %ymm14
-vmovdqa %ymm0, 320(%rsp)
+vmovdqa %ymm0, 320(%r8)
vmovdqu 968(%rsi), %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm1
-vpaddw 224(%rsp), %ymm7, %ymm2
+vpaddw 96(%r8), %ymm0, %ymm1
+vpaddw 224(%r8), %ymm7, %ymm2
vpaddw %ymm2, %ymm1, %ymm11
vpsubw %ymm2, %ymm1, %ymm15
-vmovdqa %ymm0, 352(%rsp)
+vmovdqa %ymm0, 352(%r8)
vmovdqa %ymm8, 864(%rax)
vmovdqa %ymm9, 960(%rax)
vpaddw %ymm8, %ymm9, %ymm0
@@ -437,35 +426,35 @@ vpaddw %ymm13, %ymm15, %ymm1
vmovdqa %ymm1, 2400(%rax)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 2496(%rax)
-vmovdqa 256(%rsp), %ymm0
+vmovdqa 256(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm0
+vpaddw 0(%r8), %ymm0, %ymm0
vpsllw $2, %ymm4, %ymm1
-vpaddw 128(%rsp), %ymm1, %ymm1
+vpaddw 128(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm8
vpsubw %ymm1, %ymm0, %ymm12
-vmovdqa 288(%rsp), %ymm0
+vmovdqa 288(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm0
+vpaddw 32(%r8), %ymm0, %ymm0
vpsllw $2, %ymm5, %ymm1
-vpaddw 160(%rsp), %ymm1, %ymm1
+vpaddw 160(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm9
vpsubw %ymm1, %ymm0, %ymm13
-vmovdqa 320(%rsp), %ymm0
+vmovdqa 320(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm0
+vpaddw 64(%r8), %ymm0, %ymm0
vpsllw $2, %ymm6, %ymm1
-vpaddw 192(%rsp), %ymm1, %ymm1
+vpaddw 192(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm10
vpsubw %ymm1, %ymm0, %ymm14
-vmovdqa 352(%rsp), %ymm0
+vmovdqa 352(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm0
+vpaddw 96(%r8), %ymm0, %ymm0
vpsllw $2, %ymm7, %ymm1
-vpaddw 224(%rsp), %ymm1, %ymm1
+vpaddw 224(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm11
vpsubw %ymm1, %ymm0, %ymm15
@@ -498,29 +487,29 @@ vmovdqa %ymm1, 4128(%rax)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 4224(%rax)
vpmullw %ymm3, %ymm4, %ymm0
-vpaddw 256(%rsp), %ymm0, %ymm0
+vpaddw 256(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 128(%rsp), %ymm0, %ymm0
+vpaddw 128(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm12
+vpaddw 0(%r8), %ymm0, %ymm12
vpmullw %ymm3, %ymm5, %ymm0
-vpaddw 288(%rsp), %ymm0, %ymm0
+vpaddw 288(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 160(%rsp), %ymm0, %ymm0
+vpaddw 160(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm13
+vpaddw 32(%r8), %ymm0, %ymm13
vpmullw %ymm3, %ymm6, %ymm0
-vpaddw 320(%rsp), %ymm0, %ymm0
+vpaddw 320(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 192(%rsp), %ymm0, %ymm0
+vpaddw 192(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm14
+vpaddw 64(%r8), %ymm0, %ymm14
vpmullw %ymm3, %ymm7, %ymm0
-vpaddw 352(%rsp), %ymm0, %ymm0
+vpaddw 352(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 224(%rsp), %ymm0, %ymm0
+vpaddw 224(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm15
+vpaddw 96(%r8), %ymm0, %ymm15
vmovdqa %ymm12, 4320(%rax)
vmovdqa %ymm13, 4416(%rax)
vpaddw %ymm12, %ymm13, %ymm0
@@ -575,38 +564,38 @@ vpaddw %ymm5, %ymm7, %ymm15
vmovdqa %ymm15, 5888(%rax)
vpaddw %ymm14, %ymm15, %ymm14
vmovdqa %ymm14, 5984(%rax)
-vmovdqa %ymm0, 0(%rsp)
-vmovdqa %ymm1, 32(%rsp)
-vmovdqa %ymm2, 64(%rsp)
-vmovdqa %ymm12, 96(%rsp)
-vmovdqa %ymm8, 128(%rsp)
-vmovdqa %ymm9, 160(%rsp)
-vmovdqa %ymm10, 192(%rsp)
-vmovdqa %ymm11, 224(%rsp)
+vmovdqa %ymm0, 0(%r8)
+vmovdqa %ymm1, 32(%r8)
+vmovdqa %ymm2, 64(%r8)
+vmovdqa %ymm12, 96(%r8)
+vmovdqa %ymm8, 128(%r8)
+vmovdqa %ymm9, 160(%r8)
+vmovdqa %ymm10, 192(%r8)
+vmovdqa %ymm11, 224(%r8)
vmovdqu 736(%rsi), %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm1
-vpaddw 128(%rsp), %ymm4, %ymm2
+vpaddw 0(%r8), %ymm0, %ymm1
+vpaddw 128(%r8), %ymm4, %ymm2
vpaddw %ymm2, %ymm1, %ymm8
vpsubw %ymm2, %ymm1, %ymm12
-vmovdqa %ymm0, 256(%rsp)
+vmovdqa %ymm0, 256(%r8)
vmovdqu 824(%rsi), %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm1
-vpaddw 160(%rsp), %ymm5, %ymm2
+vpaddw 32(%r8), %ymm0, %ymm1
+vpaddw 160(%r8), %ymm5, %ymm2
vpaddw %ymm2, %ymm1, %ymm9
vpsubw %ymm2, %ymm1, %ymm13
-vmovdqa %ymm0, 288(%rsp)
+vmovdqa %ymm0, 288(%r8)
vmovdqu 912(%rsi), %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm1
-vpaddw 192(%rsp), %ymm6, %ymm2
+vpaddw 64(%r8), %ymm0, %ymm1
+vpaddw 192(%r8), %ymm6, %ymm2
vpaddw %ymm2, %ymm1, %ymm10
vpsubw %ymm2, %ymm1, %ymm14
-vmovdqa %ymm0, 320(%rsp)
+vmovdqa %ymm0, 320(%r8)
vmovdqu 1000(%rsi), %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm1
-vpaddw 224(%rsp), %ymm7, %ymm2
+vpaddw 96(%r8), %ymm0, %ymm1
+vpaddw 224(%r8), %ymm7, %ymm2
vpaddw %ymm2, %ymm1, %ymm11
vpsubw %ymm2, %ymm1, %ymm15
-vmovdqa %ymm0, 352(%rsp)
+vmovdqa %ymm0, 352(%r8)
vmovdqa %ymm8, 896(%rax)
vmovdqa %ymm9, 992(%rax)
vpaddw %ymm8, %ymm9, %ymm0
@@ -635,35 +624,35 @@ vpaddw %ymm13, %ymm15, %ymm1
vmovdqa %ymm1, 2432(%rax)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 2528(%rax)
-vmovdqa 256(%rsp), %ymm0
+vmovdqa 256(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm0
+vpaddw 0(%r8), %ymm0, %ymm0
vpsllw $2, %ymm4, %ymm1
-vpaddw 128(%rsp), %ymm1, %ymm1
+vpaddw 128(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm8
vpsubw %ymm1, %ymm0, %ymm12
-vmovdqa 288(%rsp), %ymm0
+vmovdqa 288(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm0
+vpaddw 32(%r8), %ymm0, %ymm0
vpsllw $2, %ymm5, %ymm1
-vpaddw 160(%rsp), %ymm1, %ymm1
+vpaddw 160(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm9
vpsubw %ymm1, %ymm0, %ymm13
-vmovdqa 320(%rsp), %ymm0
+vmovdqa 320(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm0
+vpaddw 64(%r8), %ymm0, %ymm0
vpsllw $2, %ymm6, %ymm1
-vpaddw 192(%rsp), %ymm1, %ymm1
+vpaddw 192(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm10
vpsubw %ymm1, %ymm0, %ymm14
-vmovdqa 352(%rsp), %ymm0
+vmovdqa 352(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm0
+vpaddw 96(%r8), %ymm0, %ymm0
vpsllw $2, %ymm7, %ymm1
-vpaddw 224(%rsp), %ymm1, %ymm1
+vpaddw 224(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm11
vpsubw %ymm1, %ymm0, %ymm15
@@ -696,29 +685,29 @@ vmovdqa %ymm1, 4160(%rax)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 4256(%rax)
vpmullw %ymm3, %ymm4, %ymm0
-vpaddw 256(%rsp), %ymm0, %ymm0
+vpaddw 256(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 128(%rsp), %ymm0, %ymm0
+vpaddw 128(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm12
+vpaddw 0(%r8), %ymm0, %ymm12
vpmullw %ymm3, %ymm5, %ymm0
-vpaddw 288(%rsp), %ymm0, %ymm0
+vpaddw 288(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 160(%rsp), %ymm0, %ymm0
+vpaddw 160(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm13
+vpaddw 32(%r8), %ymm0, %ymm13
vpmullw %ymm3, %ymm6, %ymm0
-vpaddw 320(%rsp), %ymm0, %ymm0
+vpaddw 320(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 192(%rsp), %ymm0, %ymm0
+vpaddw 192(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm14
+vpaddw 64(%r8), %ymm0, %ymm14
vpmullw %ymm3, %ymm7, %ymm0
-vpaddw 352(%rsp), %ymm0, %ymm0
+vpaddw 352(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 224(%rsp), %ymm0, %ymm0
+vpaddw 224(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm15
+vpaddw 96(%r8), %ymm0, %ymm15
vmovdqa %ymm12, 4352(%rax)
vmovdqa %ymm13, 4448(%rax)
vpaddw %ymm12, %ymm13, %ymm0
@@ -740,8 +729,20 @@ vmovdqu 328(%rsi), %ymm12
vmovdqu 1120(%rsi), %ymm4
vmovdqu 1208(%rsi), %ymm5
vmovdqu 1296(%rsi), %ymm6
-vmovdqu 1384(%rsi), %ymm7
-vpand mask_low9words(%rip), %ymm7, %ymm7
+
+# Only 18 bytes more can be read, but vmovdqu reads 32.
+# Copy 18 bytes to the red zone and zero pad to 32 bytes.
+xor %r9, %r9
+movq %r9, -16(%rsp)
+movq %r9, -8(%rsp)
+movq 1384(%rsi), %r9
+movq %r9, -32(%rsp)
+movq 1384+8(%rsi), %r9
+movq %r9, -24(%rsp)
+movw 1384+16(%rsi), %r9w
+movw %r9w, -16(%rsp)
+vmovdqu -32(%rsp), %ymm7
+
vmovdqu 416(%rsi), %ymm8
vmovdqu 504(%rsi), %ymm9
vmovdqu 592(%rsi), %ymm10
@@ -774,38 +775,38 @@ vpaddw %ymm5, %ymm7, %ymm15
vmovdqa %ymm15, 5920(%rax)
vpaddw %ymm14, %ymm15, %ymm14
vmovdqa %ymm14, 6016(%rax)
-vmovdqa %ymm0, 0(%rsp)
-vmovdqa %ymm1, 32(%rsp)
-vmovdqa %ymm2, 64(%rsp)
-vmovdqa %ymm12, 96(%rsp)
-vmovdqa %ymm8, 128(%rsp)
-vmovdqa %ymm9, 160(%rsp)
-vmovdqa %ymm10, 192(%rsp)
-vmovdqa %ymm11, 224(%rsp)
+vmovdqa %ymm0, 0(%r8)
+vmovdqa %ymm1, 32(%r8)
+vmovdqa %ymm2, 64(%r8)
+vmovdqa %ymm12, 96(%r8)
+vmovdqa %ymm8, 128(%r8)
+vmovdqa %ymm9, 160(%r8)
+vmovdqa %ymm10, 192(%r8)
+vmovdqa %ymm11, 224(%r8)
vmovdqu 768(%rsi), %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm1
-vpaddw 128(%rsp), %ymm4, %ymm2
+vpaddw 0(%r8), %ymm0, %ymm1
+vpaddw 128(%r8), %ymm4, %ymm2
vpaddw %ymm2, %ymm1, %ymm8
vpsubw %ymm2, %ymm1, %ymm12
-vmovdqa %ymm0, 256(%rsp)
+vmovdqa %ymm0, 256(%r8)
vmovdqu 856(%rsi), %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm1
-vpaddw 160(%rsp), %ymm5, %ymm2
+vpaddw 32(%r8), %ymm0, %ymm1
+vpaddw 160(%r8), %ymm5, %ymm2
vpaddw %ymm2, %ymm1, %ymm9
vpsubw %ymm2, %ymm1, %ymm13
-vmovdqa %ymm0, 288(%rsp)
+vmovdqa %ymm0, 288(%r8)
vmovdqu 944(%rsi), %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm1
-vpaddw 192(%rsp), %ymm6, %ymm2
+vpaddw 64(%r8), %ymm0, %ymm1
+vpaddw 192(%r8), %ymm6, %ymm2
vpaddw %ymm2, %ymm1, %ymm10
vpsubw %ymm2, %ymm1, %ymm14
-vmovdqa %ymm0, 320(%rsp)
+vmovdqa %ymm0, 320(%r8)
vmovdqu 1032(%rsi), %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm1
-vpaddw 224(%rsp), %ymm7, %ymm2
+vpaddw 96(%r8), %ymm0, %ymm1
+vpaddw 224(%r8), %ymm7, %ymm2
vpaddw %ymm2, %ymm1, %ymm11
vpsubw %ymm2, %ymm1, %ymm15
-vmovdqa %ymm0, 352(%rsp)
+vmovdqa %ymm0, 352(%r8)
vmovdqa %ymm8, 928(%rax)
vmovdqa %ymm9, 1024(%rax)
vpaddw %ymm8, %ymm9, %ymm0
@@ -834,35 +835,35 @@ vpaddw %ymm13, %ymm15, %ymm1
vmovdqa %ymm1, 2464(%rax)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 2560(%rax)
-vmovdqa 256(%rsp), %ymm0
+vmovdqa 256(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm0
+vpaddw 0(%r8), %ymm0, %ymm0
vpsllw $2, %ymm4, %ymm1
-vpaddw 128(%rsp), %ymm1, %ymm1
+vpaddw 128(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm8
vpsubw %ymm1, %ymm0, %ymm12
-vmovdqa 288(%rsp), %ymm0
+vmovdqa 288(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm0
+vpaddw 32(%r8), %ymm0, %ymm0
vpsllw $2, %ymm5, %ymm1
-vpaddw 160(%rsp), %ymm1, %ymm1
+vpaddw 160(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm9
vpsubw %ymm1, %ymm0, %ymm13
-vmovdqa 320(%rsp), %ymm0
+vmovdqa 320(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm0
+vpaddw 64(%r8), %ymm0, %ymm0
vpsllw $2, %ymm6, %ymm1
-vpaddw 192(%rsp), %ymm1, %ymm1
+vpaddw 192(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm10
vpsubw %ymm1, %ymm0, %ymm14
-vmovdqa 352(%rsp), %ymm0
+vmovdqa 352(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm0
+vpaddw 96(%r8), %ymm0, %ymm0
vpsllw $2, %ymm7, %ymm1
-vpaddw 224(%rsp), %ymm1, %ymm1
+vpaddw 224(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm11
vpsubw %ymm1, %ymm0, %ymm15
@@ -895,29 +896,29 @@ vmovdqa %ymm1, 4192(%rax)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 4288(%rax)
vpmullw %ymm3, %ymm4, %ymm0
-vpaddw 256(%rsp), %ymm0, %ymm0
+vpaddw 256(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 128(%rsp), %ymm0, %ymm0
+vpaddw 128(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm12
+vpaddw 0(%r8), %ymm0, %ymm12
vpmullw %ymm3, %ymm5, %ymm0
-vpaddw 288(%rsp), %ymm0, %ymm0
+vpaddw 288(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 160(%rsp), %ymm0, %ymm0
+vpaddw 160(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm13
+vpaddw 32(%r8), %ymm0, %ymm13
vpmullw %ymm3, %ymm6, %ymm0
-vpaddw 320(%rsp), %ymm0, %ymm0
+vpaddw 320(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 192(%rsp), %ymm0, %ymm0
+vpaddw 192(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm14
+vpaddw 64(%r8), %ymm0, %ymm14
vpmullw %ymm3, %ymm7, %ymm0
-vpaddw 352(%rsp), %ymm0, %ymm0
+vpaddw 352(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 224(%rsp), %ymm0, %ymm0
+vpaddw 224(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm15
+vpaddw 96(%r8), %ymm0, %ymm15
vmovdqa %ymm12, 4384(%rax)
vmovdqa %ymm13, 4480(%rax)
vpaddw %ymm12, %ymm13, %ymm0
@@ -972,38 +973,38 @@ vpaddw %ymm5, %ymm7, %ymm15
vmovdqa %ymm15, 5856(%r11)
vpaddw %ymm14, %ymm15, %ymm14
vmovdqa %ymm14, 5952(%r11)
-vmovdqa %ymm0, 0(%rsp)
-vmovdqa %ymm1, 32(%rsp)
-vmovdqa %ymm2, 64(%rsp)
-vmovdqa %ymm12, 96(%rsp)
-vmovdqa %ymm8, 128(%rsp)
-vmovdqa %ymm9, 160(%rsp)
-vmovdqa %ymm10, 192(%rsp)
-vmovdqa %ymm11, 224(%rsp)
+vmovdqa %ymm0, 0(%r8)
+vmovdqa %ymm1, 32(%r8)
+vmovdqa %ymm2, 64(%r8)
+vmovdqa %ymm12, 96(%r8)
+vmovdqa %ymm8, 128(%r8)
+vmovdqa %ymm9, 160(%r8)
+vmovdqa %ymm10, 192(%r8)
+vmovdqa %ymm11, 224(%r8)
vmovdqu 704(%rdx), %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm1
-vpaddw 128(%rsp), %ymm4, %ymm2
+vpaddw 0(%r8), %ymm0, %ymm1
+vpaddw 128(%r8), %ymm4, %ymm2
vpaddw %ymm2, %ymm1, %ymm8
vpsubw %ymm2, %ymm1, %ymm12
-vmovdqa %ymm0, 256(%rsp)
+vmovdqa %ymm0, 256(%r8)
vmovdqu 792(%rdx), %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm1
-vpaddw 160(%rsp), %ymm5, %ymm2
+vpaddw 32(%r8), %ymm0, %ymm1
+vpaddw 160(%r8), %ymm5, %ymm2
vpaddw %ymm2, %ymm1, %ymm9
vpsubw %ymm2, %ymm1, %ymm13
-vmovdqa %ymm0, 288(%rsp)
+vmovdqa %ymm0, 288(%r8)
vmovdqu 880(%rdx), %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm1
-vpaddw 192(%rsp), %ymm6, %ymm2
+vpaddw 64(%r8), %ymm0, %ymm1
+vpaddw 192(%r8), %ymm6, %ymm2
vpaddw %ymm2, %ymm1, %ymm10
vpsubw %ymm2, %ymm1, %ymm14
-vmovdqa %ymm0, 320(%rsp)
+vmovdqa %ymm0, 320(%r8)
vmovdqu 968(%rdx), %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm1
-vpaddw 224(%rsp), %ymm7, %ymm2
+vpaddw 96(%r8), %ymm0, %ymm1
+vpaddw 224(%r8), %ymm7, %ymm2
vpaddw %ymm2, %ymm1, %ymm11
vpsubw %ymm2, %ymm1, %ymm15
-vmovdqa %ymm0, 352(%rsp)
+vmovdqa %ymm0, 352(%r8)
vmovdqa %ymm8, 864(%r11)
vmovdqa %ymm9, 960(%r11)
vpaddw %ymm8, %ymm9, %ymm0
@@ -1032,35 +1033,35 @@ vpaddw %ymm13, %ymm15, %ymm1
vmovdqa %ymm1, 2400(%r11)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 2496(%r11)
-vmovdqa 256(%rsp), %ymm0
+vmovdqa 256(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm0
+vpaddw 0(%r8), %ymm0, %ymm0
vpsllw $2, %ymm4, %ymm1
-vpaddw 128(%rsp), %ymm1, %ymm1
+vpaddw 128(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm8
vpsubw %ymm1, %ymm0, %ymm12
-vmovdqa 288(%rsp), %ymm0
+vmovdqa 288(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm0
+vpaddw 32(%r8), %ymm0, %ymm0
vpsllw $2, %ymm5, %ymm1
-vpaddw 160(%rsp), %ymm1, %ymm1
+vpaddw 160(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm9
vpsubw %ymm1, %ymm0, %ymm13
-vmovdqa 320(%rsp), %ymm0
+vmovdqa 320(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm0
+vpaddw 64(%r8), %ymm0, %ymm0
vpsllw $2, %ymm6, %ymm1
-vpaddw 192(%rsp), %ymm1, %ymm1
+vpaddw 192(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm10
vpsubw %ymm1, %ymm0, %ymm14
-vmovdqa 352(%rsp), %ymm0
+vmovdqa 352(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm0
+vpaddw 96(%r8), %ymm0, %ymm0
vpsllw $2, %ymm7, %ymm1
-vpaddw 224(%rsp), %ymm1, %ymm1
+vpaddw 224(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm11
vpsubw %ymm1, %ymm0, %ymm15
@@ -1093,29 +1094,29 @@ vmovdqa %ymm1, 4128(%r11)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 4224(%r11)
vpmullw %ymm3, %ymm4, %ymm0
-vpaddw 256(%rsp), %ymm0, %ymm0
+vpaddw 256(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 128(%rsp), %ymm0, %ymm0
+vpaddw 128(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm12
+vpaddw 0(%r8), %ymm0, %ymm12
vpmullw %ymm3, %ymm5, %ymm0
-vpaddw 288(%rsp), %ymm0, %ymm0
+vpaddw 288(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 160(%rsp), %ymm0, %ymm0
+vpaddw 160(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm13
+vpaddw 32(%r8), %ymm0, %ymm13
vpmullw %ymm3, %ymm6, %ymm0
-vpaddw 320(%rsp), %ymm0, %ymm0
+vpaddw 320(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 192(%rsp), %ymm0, %ymm0
+vpaddw 192(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm14
+vpaddw 64(%r8), %ymm0, %ymm14
vpmullw %ymm3, %ymm7, %ymm0
-vpaddw 352(%rsp), %ymm0, %ymm0
+vpaddw 352(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 224(%rsp), %ymm0, %ymm0
+vpaddw 224(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm15
+vpaddw 96(%r8), %ymm0, %ymm15
vmovdqa %ymm12, 4320(%r11)
vmovdqa %ymm13, 4416(%r11)
vpaddw %ymm12, %ymm13, %ymm0
@@ -1170,38 +1171,38 @@ vpaddw %ymm5, %ymm7, %ymm15
vmovdqa %ymm15, 5888(%r11)
vpaddw %ymm14, %ymm15, %ymm14
vmovdqa %ymm14, 5984(%r11)
-vmovdqa %ymm0, 0(%rsp)
-vmovdqa %ymm1, 32(%rsp)
-vmovdqa %ymm2, 64(%rsp)
-vmovdqa %ymm12, 96(%rsp)
-vmovdqa %ymm8, 128(%rsp)
-vmovdqa %ymm9, 160(%rsp)
-vmovdqa %ymm10, 192(%rsp)
-vmovdqa %ymm11, 224(%rsp)
+vmovdqa %ymm0, 0(%r8)
+vmovdqa %ymm1, 32(%r8)
+vmovdqa %ymm2, 64(%r8)
+vmovdqa %ymm12, 96(%r8)
+vmovdqa %ymm8, 128(%r8)
+vmovdqa %ymm9, 160(%r8)
+vmovdqa %ymm10, 192(%r8)
+vmovdqa %ymm11, 224(%r8)
vmovdqu 736(%rdx), %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm1
-vpaddw 128(%rsp), %ymm4, %ymm2
+vpaddw 0(%r8), %ymm0, %ymm1
+vpaddw 128(%r8), %ymm4, %ymm2
vpaddw %ymm2, %ymm1, %ymm8
vpsubw %ymm2, %ymm1, %ymm12
-vmovdqa %ymm0, 256(%rsp)
+vmovdqa %ymm0, 256(%r8)
vmovdqu 824(%rdx), %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm1
-vpaddw 160(%rsp), %ymm5, %ymm2
+vpaddw 32(%r8), %ymm0, %ymm1
+vpaddw 160(%r8), %ymm5, %ymm2
vpaddw %ymm2, %ymm1, %ymm9
vpsubw %ymm2, %ymm1, %ymm13
-vmovdqa %ymm0, 288(%rsp)
+vmovdqa %ymm0, 288(%r8)
vmovdqu 912(%rdx), %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm1
-vpaddw 192(%rsp), %ymm6, %ymm2
+vpaddw 64(%r8), %ymm0, %ymm1
+vpaddw 192(%r8), %ymm6, %ymm2
vpaddw %ymm2, %ymm1, %ymm10
vpsubw %ymm2, %ymm1, %ymm14
-vmovdqa %ymm0, 320(%rsp)
+vmovdqa %ymm0, 320(%r8)
vmovdqu 1000(%rdx), %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm1
-vpaddw 224(%rsp), %ymm7, %ymm2
+vpaddw 96(%r8), %ymm0, %ymm1
+vpaddw 224(%r8), %ymm7, %ymm2
vpaddw %ymm2, %ymm1, %ymm11
vpsubw %ymm2, %ymm1, %ymm15
-vmovdqa %ymm0, 352(%rsp)
+vmovdqa %ymm0, 352(%r8)
vmovdqa %ymm8, 896(%r11)
vmovdqa %ymm9, 992(%r11)
vpaddw %ymm8, %ymm9, %ymm0
@@ -1230,35 +1231,35 @@ vpaddw %ymm13, %ymm15, %ymm1
vmovdqa %ymm1, 2432(%r11)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 2528(%r11)
-vmovdqa 256(%rsp), %ymm0
+vmovdqa 256(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm0
+vpaddw 0(%r8), %ymm0, %ymm0
vpsllw $2, %ymm4, %ymm1
-vpaddw 128(%rsp), %ymm1, %ymm1
+vpaddw 128(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm8
vpsubw %ymm1, %ymm0, %ymm12
-vmovdqa 288(%rsp), %ymm0
+vmovdqa 288(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm0
+vpaddw 32(%r8), %ymm0, %ymm0
vpsllw $2, %ymm5, %ymm1
-vpaddw 160(%rsp), %ymm1, %ymm1
+vpaddw 160(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm9
vpsubw %ymm1, %ymm0, %ymm13
-vmovdqa 320(%rsp), %ymm0
+vmovdqa 320(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm0
+vpaddw 64(%r8), %ymm0, %ymm0
vpsllw $2, %ymm6, %ymm1
-vpaddw 192(%rsp), %ymm1, %ymm1
+vpaddw 192(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm10
vpsubw %ymm1, %ymm0, %ymm14
-vmovdqa 352(%rsp), %ymm0
+vmovdqa 352(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm0
+vpaddw 96(%r8), %ymm0, %ymm0
vpsllw $2, %ymm7, %ymm1
-vpaddw 224(%rsp), %ymm1, %ymm1
+vpaddw 224(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm11
vpsubw %ymm1, %ymm0, %ymm15
@@ -1291,29 +1292,29 @@ vmovdqa %ymm1, 4160(%r11)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 4256(%r11)
vpmullw %ymm3, %ymm4, %ymm0
-vpaddw 256(%rsp), %ymm0, %ymm0
+vpaddw 256(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 128(%rsp), %ymm0, %ymm0
+vpaddw 128(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm12
+vpaddw 0(%r8), %ymm0, %ymm12
vpmullw %ymm3, %ymm5, %ymm0
-vpaddw 288(%rsp), %ymm0, %ymm0
+vpaddw 288(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 160(%rsp), %ymm0, %ymm0
+vpaddw 160(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm13
+vpaddw 32(%r8), %ymm0, %ymm13
vpmullw %ymm3, %ymm6, %ymm0
-vpaddw 320(%rsp), %ymm0, %ymm0
+vpaddw 320(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 192(%rsp), %ymm0, %ymm0
+vpaddw 192(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm14
+vpaddw 64(%r8), %ymm0, %ymm14
vpmullw %ymm3, %ymm7, %ymm0
-vpaddw 352(%rsp), %ymm0, %ymm0
+vpaddw 352(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 224(%rsp), %ymm0, %ymm0
+vpaddw 224(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm15
+vpaddw 96(%r8), %ymm0, %ymm15
vmovdqa %ymm12, 4352(%r11)
vmovdqa %ymm13, 4448(%r11)
vpaddw %ymm12, %ymm13, %ymm0
@@ -1335,8 +1336,20 @@ vmovdqu 328(%rdx), %ymm12
vmovdqu 1120(%rdx), %ymm4
vmovdqu 1208(%rdx), %ymm5
vmovdqu 1296(%rdx), %ymm6
-vmovdqu 1384(%rdx), %ymm7
-vpand mask_low9words(%rip), %ymm7, %ymm7
+
+# Only 18 bytes more can be read, but vmovdqu reads 32.
+# Copy 18 bytes to the red zone and zero pad to 32 bytes.
+xor %r9, %r9
+movq %r9, -16(%rsp)
+movq %r9, -8(%rsp)
+movq 1384(%rdx), %r9
+movq %r9, -32(%rsp)
+movq 1384+8(%rdx), %r9
+movq %r9, -24(%rsp)
+movw 1384+16(%rdx), %r9w
+movw %r9w, -16(%rsp)
+vmovdqu -32(%rsp), %ymm7
+
vmovdqu 416(%rdx), %ymm8
vmovdqu 504(%rdx), %ymm9
vmovdqu 592(%rdx), %ymm10
@@ -1369,38 +1382,38 @@ vpaddw %ymm5, %ymm7, %ymm15
vmovdqa %ymm15, 5920(%r11)
vpaddw %ymm14, %ymm15, %ymm14
vmovdqa %ymm14, 6016(%r11)
-vmovdqa %ymm0, 0(%rsp)
-vmovdqa %ymm1, 32(%rsp)
-vmovdqa %ymm2, 64(%rsp)
-vmovdqa %ymm12, 96(%rsp)
-vmovdqa %ymm8, 128(%rsp)
-vmovdqa %ymm9, 160(%rsp)
-vmovdqa %ymm10, 192(%rsp)
-vmovdqa %ymm11, 224(%rsp)
+vmovdqa %ymm0, 0(%r8)
+vmovdqa %ymm1, 32(%r8)
+vmovdqa %ymm2, 64(%r8)
+vmovdqa %ymm12, 96(%r8)
+vmovdqa %ymm8, 128(%r8)
+vmovdqa %ymm9, 160(%r8)
+vmovdqa %ymm10, 192(%r8)
+vmovdqa %ymm11, 224(%r8)
vmovdqu 768(%rdx), %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm1
-vpaddw 128(%rsp), %ymm4, %ymm2
+vpaddw 0(%r8), %ymm0, %ymm1
+vpaddw 128(%r8), %ymm4, %ymm2
vpaddw %ymm2, %ymm1, %ymm8
vpsubw %ymm2, %ymm1, %ymm12
-vmovdqa %ymm0, 256(%rsp)
+vmovdqa %ymm0, 256(%r8)
vmovdqu 856(%rdx), %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm1
-vpaddw 160(%rsp), %ymm5, %ymm2
+vpaddw 32(%r8), %ymm0, %ymm1
+vpaddw 160(%r8), %ymm5, %ymm2
vpaddw %ymm2, %ymm1, %ymm9
vpsubw %ymm2, %ymm1, %ymm13
-vmovdqa %ymm0, 288(%rsp)
+vmovdqa %ymm0, 288(%r8)
vmovdqu 944(%rdx), %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm1
-vpaddw 192(%rsp), %ymm6, %ymm2
+vpaddw 64(%r8), %ymm0, %ymm1
+vpaddw 192(%r8), %ymm6, %ymm2
vpaddw %ymm2, %ymm1, %ymm10
vpsubw %ymm2, %ymm1, %ymm14
-vmovdqa %ymm0, 320(%rsp)
+vmovdqa %ymm0, 320(%r8)
vmovdqu 1032(%rdx), %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm1
-vpaddw 224(%rsp), %ymm7, %ymm2
+vpaddw 96(%r8), %ymm0, %ymm1
+vpaddw 224(%r8), %ymm7, %ymm2
vpaddw %ymm2, %ymm1, %ymm11
vpsubw %ymm2, %ymm1, %ymm15
-vmovdqa %ymm0, 352(%rsp)
+vmovdqa %ymm0, 352(%r8)
vmovdqa %ymm8, 928(%r11)
vmovdqa %ymm9, 1024(%r11)
vpaddw %ymm8, %ymm9, %ymm0
@@ -1429,35 +1442,35 @@ vpaddw %ymm13, %ymm15, %ymm1
vmovdqa %ymm1, 2464(%r11)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 2560(%r11)
-vmovdqa 256(%rsp), %ymm0
+vmovdqa 256(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm0
+vpaddw 0(%r8), %ymm0, %ymm0
vpsllw $2, %ymm4, %ymm1
-vpaddw 128(%rsp), %ymm1, %ymm1
+vpaddw 128(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm8
vpsubw %ymm1, %ymm0, %ymm12
-vmovdqa 288(%rsp), %ymm0
+vmovdqa 288(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm0
+vpaddw 32(%r8), %ymm0, %ymm0
vpsllw $2, %ymm5, %ymm1
-vpaddw 160(%rsp), %ymm1, %ymm1
+vpaddw 160(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm9
vpsubw %ymm1, %ymm0, %ymm13
-vmovdqa 320(%rsp), %ymm0
+vmovdqa 320(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm0
+vpaddw 64(%r8), %ymm0, %ymm0
vpsllw $2, %ymm6, %ymm1
-vpaddw 192(%rsp), %ymm1, %ymm1
+vpaddw 192(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm10
vpsubw %ymm1, %ymm0, %ymm14
-vmovdqa 352(%rsp), %ymm0
+vmovdqa 352(%r8), %ymm0
vpsllw $2, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm0
+vpaddw 96(%r8), %ymm0, %ymm0
vpsllw $2, %ymm7, %ymm1
-vpaddw 224(%rsp), %ymm1, %ymm1
+vpaddw 224(%r8), %ymm1, %ymm1
vpsllw $1, %ymm1, %ymm1
vpaddw %ymm1, %ymm0, %ymm11
vpsubw %ymm1, %ymm0, %ymm15
@@ -1490,29 +1503,29 @@ vmovdqa %ymm1, 4192(%r11)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 4288(%r11)
vpmullw %ymm3, %ymm4, %ymm0
-vpaddw 256(%rsp), %ymm0, %ymm0
+vpaddw 256(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 128(%rsp), %ymm0, %ymm0
+vpaddw 128(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 0(%rsp), %ymm0, %ymm12
+vpaddw 0(%r8), %ymm0, %ymm12
vpmullw %ymm3, %ymm5, %ymm0
-vpaddw 288(%rsp), %ymm0, %ymm0
+vpaddw 288(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 160(%rsp), %ymm0, %ymm0
+vpaddw 160(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 32(%rsp), %ymm0, %ymm13
+vpaddw 32(%r8), %ymm0, %ymm13
vpmullw %ymm3, %ymm6, %ymm0
-vpaddw 320(%rsp), %ymm0, %ymm0
+vpaddw 320(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 192(%rsp), %ymm0, %ymm0
+vpaddw 192(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 64(%rsp), %ymm0, %ymm14
+vpaddw 64(%r8), %ymm0, %ymm14
vpmullw %ymm3, %ymm7, %ymm0
-vpaddw 352(%rsp), %ymm0, %ymm0
+vpaddw 352(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 224(%rsp), %ymm0, %ymm0
+vpaddw 224(%r8), %ymm0, %ymm0
vpmullw %ymm3, %ymm0, %ymm0
-vpaddw 96(%rsp), %ymm0, %ymm15
+vpaddw 96(%r8), %ymm0, %ymm15
vmovdqa %ymm12, 4384(%r11)
vmovdqa %ymm13, 4480(%r11)
vpaddw %ymm12, %ymm13, %ymm0
@@ -1527,12 +1540,12 @@ vpaddw %ymm13, %ymm15, %ymm1
vmovdqa %ymm1, 5056(%r11)
vpaddw %ymm0, %ymm1, %ymm0
vmovdqa %ymm0, 5152(%r11)
-subq $9408, %rsp
+subq $9408, %r8
mov $4, %ecx
karatsuba_loop_4eced63f144beffcb0247f9c6f67d165:
-mov %rsp, %r9
-mov %rsp, %r10
-subq $32, %rsp
+mov %r8, %r9
+mov %r8, %r10
+subq $32, %r8
vmovdqa 0(%rax), %ymm0
vmovdqa 192(%rax), %ymm1
vmovdqa 384(%rax), %ymm2
@@ -1573,7 +1586,7 @@ vpunpcklwd 1248(%rax), %ymm2, %ymm0
vpunpckhwd 1248(%rax), %ymm2, %ymm1
vpunpcklwd 1440(%rax), %ymm3, %ymm2
vpunpckhwd 1440(%rax), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -1625,7 +1638,7 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 416(%r9)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 448(%r9)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 224(%r9)
vpermq $78, %ymm11, %ymm11
@@ -1671,7 +1684,7 @@ vpunpcklwd 1280(%rax), %ymm2, %ymm0
vpunpckhwd 1280(%rax), %ymm2, %ymm1
vpunpcklwd 1472(%rax), %ymm3, %ymm2
vpunpckhwd 1472(%rax), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -1723,7 +1736,7 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 928(%r9)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 960(%r9)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 736(%r9)
vpermq $78, %ymm11, %ymm11
@@ -1769,7 +1782,7 @@ vpunpcklwd 1312(%rax), %ymm2, %ymm0
vpunpckhwd 1312(%rax), %ymm2, %ymm1
vpunpcklwd 1504(%rax), %ymm3, %ymm2
vpunpckhwd 1504(%rax), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -1815,11 +1828,9 @@ vinserti128 $0, %xmm6, %ymm11, %ymm15
vmovdqa %ymm15, 1344(%r9)
vinserti128 $0, %xmm7, %ymm0, %ymm15
vmovdqa %ymm15, 1376(%r9)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 1248(%r9)
-addq $32, %rsp
-subq $32, %rsp
vmovdqa 0(%r11), %ymm0
vmovdqa 192(%r11), %ymm1
vmovdqa 384(%r11), %ymm2
@@ -1860,7 +1871,7 @@ vpunpcklwd 1248(%r11), %ymm2, %ymm0
vpunpckhwd 1248(%r11), %ymm2, %ymm1
vpunpcklwd 1440(%r11), %ymm3, %ymm2
vpunpckhwd 1440(%r11), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -1912,7 +1923,7 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 1824(%r9)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 1856(%r9)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 1632(%r9)
vpermq $78, %ymm11, %ymm11
@@ -1958,7 +1969,7 @@ vpunpcklwd 1280(%r11), %ymm2, %ymm0
vpunpckhwd 1280(%r11), %ymm2, %ymm1
vpunpcklwd 1472(%r11), %ymm3, %ymm2
vpunpckhwd 1472(%r11), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -2010,7 +2021,7 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 2336(%r9)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 2368(%r9)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 2144(%r9)
vpermq $78, %ymm11, %ymm11
@@ -2056,7 +2067,7 @@ vpunpcklwd 1312(%r11), %ymm2, %ymm0
vpunpckhwd 1312(%r11), %ymm2, %ymm1
vpunpcklwd 1504(%r11), %ymm3, %ymm2
vpunpckhwd 1504(%r11), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -2102,10 +2113,10 @@ vinserti128 $0, %xmm6, %ymm11, %ymm15
vmovdqa %ymm15, 2752(%r9)
vinserti128 $0, %xmm7, %ymm0, %ymm15
vmovdqa %ymm15, 2784(%r9)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 2656(%r9)
-addq $32, %rsp
+addq $32, %r8
innerloop_4eced63f144beffcb0247f9c6f67d165:
vmovdqa 0(%r9), %ymm0
vmovdqa 1408(%r9), %ymm6
@@ -2638,17 +2649,17 @@ vmovdqa 1568(%r9), %ymm11
vpaddw 512(%r9), %ymm5, %ymm5
vpaddw 1920(%r9), %ymm11, %ymm11
vpmullw %ymm0, %ymm6, %ymm12
-vmovdqa %ymm12, 5888(%rsp)
+vmovdqa %ymm12, 5888(%r8)
vpmullw %ymm0, %ymm7, %ymm13
vpmullw %ymm1, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 5920(%rsp)
+vmovdqa %ymm13, 5920(%r8)
vpmullw %ymm0, %ymm8, %ymm12
vpmullw %ymm1, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm2, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 5952(%rsp)
+vmovdqa %ymm12, 5952(%r8)
vpmullw %ymm0, %ymm9, %ymm13
vpmullw %ymm1, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -2656,7 +2667,7 @@ vpmullw %ymm2, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm3, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 5984(%rsp)
+vmovdqa %ymm13, 5984(%r8)
vpmullw %ymm0, %ymm10, %ymm12
vpmullw %ymm1, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -2666,7 +2677,7 @@ vpmullw %ymm3, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6016(%rsp)
+vmovdqa %ymm12, 6016(%r8)
vpmullw %ymm0, %ymm11, %ymm13
vpmullw %ymm1, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -2678,7 +2689,7 @@ vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm5, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6048(%rsp)
+vmovdqa %ymm13, 6048(%r8)
vpmullw %ymm1, %ymm11, %ymm12
vpmullw %ymm2, %ymm10, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -2688,7 +2699,7 @@ vpmullw %ymm4, %ymm8, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm5, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6080(%rsp)
+vmovdqa %ymm12, 6080(%r8)
vpmullw %ymm2, %ymm11, %ymm13
vpmullw %ymm3, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -2696,19 +2707,19 @@ vpmullw %ymm4, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm5, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6112(%rsp)
+vmovdqa %ymm13, 6112(%r8)
vpmullw %ymm3, %ymm11, %ymm12
vpmullw %ymm4, %ymm10, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm5, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6144(%rsp)
+vmovdqa %ymm12, 6144(%r8)
vpmullw %ymm4, %ymm11, %ymm13
vpmullw %ymm5, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6176(%rsp)
+vmovdqa %ymm13, 6176(%r8)
vpmullw %ymm5, %ymm11, %ymm12
-vmovdqa %ymm12, 6208(%rsp)
+vmovdqa %ymm12, 6208(%r8)
vmovdqa 192(%r9), %ymm0
vmovdqa 1600(%r9), %ymm6
vpaddw 544(%r9), %ymm0, %ymm0
@@ -2730,17 +2741,17 @@ vmovdqa 1728(%r9), %ymm10
vpaddw 672(%r9), %ymm4, %ymm4
vpaddw 2080(%r9), %ymm10, %ymm10
vpmullw %ymm0, %ymm6, %ymm12
-vmovdqa %ymm12, 6272(%rsp)
+vmovdqa %ymm12, 6272(%r8)
vpmullw %ymm0, %ymm7, %ymm13
vpmullw %ymm1, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6304(%rsp)
+vmovdqa %ymm13, 6304(%r8)
vpmullw %ymm0, %ymm8, %ymm12
vpmullw %ymm1, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm2, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6336(%rsp)
+vmovdqa %ymm12, 6336(%r8)
vpmullw %ymm0, %ymm9, %ymm13
vpmullw %ymm1, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -2748,7 +2759,7 @@ vpmullw %ymm2, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm3, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6368(%rsp)
+vmovdqa %ymm13, 6368(%r8)
vpmullw %ymm0, %ymm10, %ymm12
vpmullw %ymm1, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -2758,7 +2769,7 @@ vpmullw %ymm3, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6400(%rsp)
+vmovdqa %ymm12, 6400(%r8)
vpmullw %ymm1, %ymm10, %ymm13
vpmullw %ymm2, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -2766,19 +2777,19 @@ vpmullw %ymm3, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6432(%rsp)
+vmovdqa %ymm13, 6432(%r8)
vpmullw %ymm2, %ymm10, %ymm12
vpmullw %ymm3, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm8, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6464(%rsp)
+vmovdqa %ymm12, 6464(%r8)
vpmullw %ymm3, %ymm10, %ymm13
vpmullw %ymm4, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6496(%rsp)
+vmovdqa %ymm13, 6496(%r8)
vpmullw %ymm4, %ymm10, %ymm12
-vmovdqa %ymm12, 6528(%rsp)
+vmovdqa %ymm12, 6528(%r8)
vpaddw 0(%r9), %ymm0, %ymm0
vpaddw 1408(%r9), %ymm6, %ymm6
vpaddw 352(%r9), %ymm0, %ymm0
@@ -2810,9 +2821,9 @@ vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
vpmullw %ymm5, %ymm6, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
-vpsubw 6048(%rsp), %ymm12, %ymm12
-vpsubw 6432(%rsp), %ymm12, %ymm12
-vmovdqa %ymm12, 6240(%rsp)
+vpsubw 6048(%r8), %ymm12, %ymm12
+vpsubw 6432(%r8), %ymm12, %ymm12
+vmovdqa %ymm12, 6240(%r8)
vpmullw %ymm5, %ymm7, %ymm12
vpmullw %ymm5, %ymm8, %ymm13
vpmullw %ymm5, %ymm9, %ymm14
@@ -2862,134 +2873,134 @@ vpmullw %ymm0, %ymm7, %ymm8
vpmullw %ymm1, %ymm6, %ymm5
vpaddw %ymm5, %ymm8, %ymm8
vpmullw %ymm0, %ymm6, %ymm7
-vmovdqa 6080(%rsp), %ymm0
-vpsubw 6272(%rsp), %ymm0, %ymm0
+vmovdqa 6080(%r8), %ymm0
+vpsubw 6272(%r8), %ymm0, %ymm0
vpsubw %ymm0, %ymm12, %ymm6
-vpsubw 6464(%rsp), %ymm6, %ymm6
-vmovdqa %ymm6, 6272(%rsp)
+vpsubw 6464(%r8), %ymm6, %ymm6
+vmovdqa %ymm6, 6272(%r8)
vpaddw %ymm7, %ymm0, %ymm0
-vpsubw 5888(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 6080(%rsp)
-vmovdqa 6112(%rsp), %ymm1
-vpsubw 6304(%rsp), %ymm1, %ymm1
+vpsubw 5888(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 6080(%r8)
+vmovdqa 6112(%r8), %ymm1
+vpsubw 6304(%r8), %ymm1, %ymm1
vpsubw %ymm1, %ymm13, %ymm7
-vpsubw 6496(%rsp), %ymm7, %ymm7
-vmovdqa %ymm7, 6304(%rsp)
+vpsubw 6496(%r8), %ymm7, %ymm7
+vmovdqa %ymm7, 6304(%r8)
vpaddw %ymm8, %ymm1, %ymm1
-vpsubw 5920(%rsp), %ymm1, %ymm1
-vmovdqa %ymm1, 6112(%rsp)
-vmovdqa 6144(%rsp), %ymm2
-vpsubw 6336(%rsp), %ymm2, %ymm2
+vpsubw 5920(%r8), %ymm1, %ymm1
+vmovdqa %ymm1, 6112(%r8)
+vmovdqa 6144(%r8), %ymm2
+vpsubw 6336(%r8), %ymm2, %ymm2
vpsubw %ymm2, %ymm14, %ymm8
-vpsubw 6528(%rsp), %ymm8, %ymm8
-vmovdqa %ymm8, 6336(%rsp)
+vpsubw 6528(%r8), %ymm8, %ymm8
+vmovdqa %ymm8, 6336(%r8)
vpaddw %ymm9, %ymm2, %ymm2
-vpsubw 5952(%rsp), %ymm2, %ymm2
-vmovdqa %ymm2, 6144(%rsp)
-vmovdqa 6176(%rsp), %ymm3
-vpsubw 6368(%rsp), %ymm3, %ymm3
+vpsubw 5952(%r8), %ymm2, %ymm2
+vmovdqa %ymm2, 6144(%r8)
+vmovdqa 6176(%r8), %ymm3
+vpsubw 6368(%r8), %ymm3, %ymm3
vpsubw %ymm3, %ymm15, %ymm9
-vmovdqa %ymm9, 6368(%rsp)
+vmovdqa %ymm9, 6368(%r8)
vpaddw %ymm10, %ymm3, %ymm3
-vpsubw 5984(%rsp), %ymm3, %ymm3
-vmovdqa %ymm3, 6176(%rsp)
-vmovdqa 6208(%rsp), %ymm4
-vpsubw 6400(%rsp), %ymm4, %ymm4
+vpsubw 5984(%r8), %ymm3, %ymm3
+vmovdqa %ymm3, 6176(%r8)
+vmovdqa 6208(%r8), %ymm4
+vpsubw 6400(%r8), %ymm4, %ymm4
vpaddw %ymm11, %ymm4, %ymm4
-vpsubw 6016(%rsp), %ymm4, %ymm4
-vmovdqa %ymm4, 6208(%rsp)
-vmovdqa 6208(%rsp), %ymm0
+vpsubw 6016(%r8), %ymm4, %ymm4
+vmovdqa %ymm4, 6208(%r8)
+vmovdqa 6208(%r8), %ymm0
vpsubw 3136(%r10), %ymm0, %ymm0
vpsubw 3840(%r10), %ymm0, %ymm0
vmovdqa %ymm0, 3488(%r10)
vmovdqa 3168(%r10), %ymm0
vpsubw 3520(%r10), %ymm0, %ymm0
-vmovdqa 6240(%rsp), %ymm1
+vmovdqa 6240(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 3872(%r10), %ymm1, %ymm1
vpsubw 2816(%r10), %ymm0, %ymm0
-vpaddw 5888(%rsp), %ymm0, %ymm0
+vpaddw 5888(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3168(%r10)
vmovdqa %ymm1, 3520(%r10)
vmovdqa 3200(%r10), %ymm0
vpsubw 3552(%r10), %ymm0, %ymm0
-vmovdqa 6272(%rsp), %ymm1
+vmovdqa 6272(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 3904(%r10), %ymm1, %ymm1
vpsubw 2848(%r10), %ymm0, %ymm0
-vpaddw 5920(%rsp), %ymm0, %ymm0
+vpaddw 5920(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3200(%r10)
vmovdqa %ymm1, 3552(%r10)
vmovdqa 3232(%r10), %ymm0
vpsubw 3584(%r10), %ymm0, %ymm0
-vmovdqa 6304(%rsp), %ymm1
+vmovdqa 6304(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 3936(%r10), %ymm1, %ymm1
vpsubw 2880(%r10), %ymm0, %ymm0
-vpaddw 5952(%rsp), %ymm0, %ymm0
+vpaddw 5952(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3232(%r10)
vmovdqa %ymm1, 3584(%r10)
vmovdqa 3264(%r10), %ymm0
vpsubw 3616(%r10), %ymm0, %ymm0
-vmovdqa 6336(%rsp), %ymm1
+vmovdqa 6336(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 3968(%r10), %ymm1, %ymm1
vpsubw 2912(%r10), %ymm0, %ymm0
-vpaddw 5984(%rsp), %ymm0, %ymm0
+vpaddw 5984(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3264(%r10)
vmovdqa %ymm1, 3616(%r10)
vmovdqa 3296(%r10), %ymm0
vpsubw 3648(%r10), %ymm0, %ymm0
-vmovdqa 6368(%rsp), %ymm1
+vmovdqa 6368(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 4000(%r10), %ymm1, %ymm1
vpsubw 2944(%r10), %ymm0, %ymm0
-vpaddw 6016(%rsp), %ymm0, %ymm0
+vpaddw 6016(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3296(%r10)
vmovdqa %ymm1, 3648(%r10)
vmovdqa 3328(%r10), %ymm0
vpsubw 3680(%r10), %ymm0, %ymm0
-vmovdqa 6400(%rsp), %ymm1
+vmovdqa 6400(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 4032(%r10), %ymm1, %ymm1
vpsubw 2976(%r10), %ymm0, %ymm0
-vpaddw 6048(%rsp), %ymm0, %ymm0
+vpaddw 6048(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3328(%r10)
vmovdqa %ymm1, 3680(%r10)
vmovdqa 3360(%r10), %ymm0
vpsubw 3712(%r10), %ymm0, %ymm0
-vmovdqa 6432(%rsp), %ymm1
+vmovdqa 6432(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 4064(%r10), %ymm1, %ymm1
vpsubw 3008(%r10), %ymm0, %ymm0
-vpaddw 6080(%rsp), %ymm0, %ymm0
+vpaddw 6080(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3360(%r10)
vmovdqa %ymm1, 3712(%r10)
vmovdqa 3392(%r10), %ymm0
vpsubw 3744(%r10), %ymm0, %ymm0
-vmovdqa 6464(%rsp), %ymm1
+vmovdqa 6464(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 4096(%r10), %ymm1, %ymm1
vpsubw 3040(%r10), %ymm0, %ymm0
-vpaddw 6112(%rsp), %ymm0, %ymm0
+vpaddw 6112(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3392(%r10)
vmovdqa %ymm1, 3744(%r10)
vmovdqa 3424(%r10), %ymm0
vpsubw 3776(%r10), %ymm0, %ymm0
-vmovdqa 6496(%rsp), %ymm1
+vmovdqa 6496(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 4128(%r10), %ymm1, %ymm1
vpsubw 3072(%r10), %ymm0, %ymm0
-vpaddw 6144(%rsp), %ymm0, %ymm0
+vpaddw 6144(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3424(%r10)
vmovdqa %ymm1, 3776(%r10)
vmovdqa 3456(%r10), %ymm0
vpsubw 3808(%r10), %ymm0, %ymm0
-vmovdqa 6528(%rsp), %ymm1
+vmovdqa 6528(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 4160(%r10), %ymm1, %ymm1
vpsubw 3104(%r10), %ymm0, %ymm0
-vpaddw 6176(%rsp), %ymm0, %ymm0
+vpaddw 6176(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3456(%r10)
vmovdqa %ymm1, 3808(%r10)
neg %ecx
@@ -3002,160 +3013,160 @@ sub $704, %r9
sub $1408, %r10
vmovdqa 0(%r9), %ymm0
vpaddw 704(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6592(%rsp)
+vmovdqa %ymm0, 6592(%r8)
vmovdqa 1408(%r9), %ymm0
vpaddw 2112(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7296(%rsp)
+vmovdqa %ymm0, 7296(%r8)
vmovdqa 32(%r9), %ymm0
vpaddw 736(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6624(%rsp)
+vmovdqa %ymm0, 6624(%r8)
vmovdqa 1440(%r9), %ymm0
vpaddw 2144(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7328(%rsp)
+vmovdqa %ymm0, 7328(%r8)
vmovdqa 64(%r9), %ymm0
vpaddw 768(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6656(%rsp)
+vmovdqa %ymm0, 6656(%r8)
vmovdqa 1472(%r9), %ymm0
vpaddw 2176(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7360(%rsp)
+vmovdqa %ymm0, 7360(%r8)
vmovdqa 96(%r9), %ymm0
vpaddw 800(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6688(%rsp)
+vmovdqa %ymm0, 6688(%r8)
vmovdqa 1504(%r9), %ymm0
vpaddw 2208(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7392(%rsp)
+vmovdqa %ymm0, 7392(%r8)
vmovdqa 128(%r9), %ymm0
vpaddw 832(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6720(%rsp)
+vmovdqa %ymm0, 6720(%r8)
vmovdqa 1536(%r9), %ymm0
vpaddw 2240(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7424(%rsp)
+vmovdqa %ymm0, 7424(%r8)
vmovdqa 160(%r9), %ymm0
vpaddw 864(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6752(%rsp)
+vmovdqa %ymm0, 6752(%r8)
vmovdqa 1568(%r9), %ymm0
vpaddw 2272(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7456(%rsp)
+vmovdqa %ymm0, 7456(%r8)
vmovdqa 192(%r9), %ymm0
vpaddw 896(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6784(%rsp)
+vmovdqa %ymm0, 6784(%r8)
vmovdqa 1600(%r9), %ymm0
vpaddw 2304(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7488(%rsp)
+vmovdqa %ymm0, 7488(%r8)
vmovdqa 224(%r9), %ymm0
vpaddw 928(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6816(%rsp)
+vmovdqa %ymm0, 6816(%r8)
vmovdqa 1632(%r9), %ymm0
vpaddw 2336(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7520(%rsp)
+vmovdqa %ymm0, 7520(%r8)
vmovdqa 256(%r9), %ymm0
vpaddw 960(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6848(%rsp)
+vmovdqa %ymm0, 6848(%r8)
vmovdqa 1664(%r9), %ymm0
vpaddw 2368(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7552(%rsp)
+vmovdqa %ymm0, 7552(%r8)
vmovdqa 288(%r9), %ymm0
vpaddw 992(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6880(%rsp)
+vmovdqa %ymm0, 6880(%r8)
vmovdqa 1696(%r9), %ymm0
vpaddw 2400(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7584(%rsp)
+vmovdqa %ymm0, 7584(%r8)
vmovdqa 320(%r9), %ymm0
vpaddw 1024(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6912(%rsp)
+vmovdqa %ymm0, 6912(%r8)
vmovdqa 1728(%r9), %ymm0
vpaddw 2432(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7616(%rsp)
+vmovdqa %ymm0, 7616(%r8)
vmovdqa 352(%r9), %ymm0
vpaddw 1056(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6944(%rsp)
+vmovdqa %ymm0, 6944(%r8)
vmovdqa 1760(%r9), %ymm0
vpaddw 2464(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7648(%rsp)
+vmovdqa %ymm0, 7648(%r8)
vmovdqa 384(%r9), %ymm0
vpaddw 1088(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 6976(%rsp)
+vmovdqa %ymm0, 6976(%r8)
vmovdqa 1792(%r9), %ymm0
vpaddw 2496(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7680(%rsp)
+vmovdqa %ymm0, 7680(%r8)
vmovdqa 416(%r9), %ymm0
vpaddw 1120(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7008(%rsp)
+vmovdqa %ymm0, 7008(%r8)
vmovdqa 1824(%r9), %ymm0
vpaddw 2528(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7712(%rsp)
+vmovdqa %ymm0, 7712(%r8)
vmovdqa 448(%r9), %ymm0
vpaddw 1152(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7040(%rsp)
+vmovdqa %ymm0, 7040(%r8)
vmovdqa 1856(%r9), %ymm0
vpaddw 2560(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7744(%rsp)
+vmovdqa %ymm0, 7744(%r8)
vmovdqa 480(%r9), %ymm0
vpaddw 1184(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7072(%rsp)
+vmovdqa %ymm0, 7072(%r8)
vmovdqa 1888(%r9), %ymm0
vpaddw 2592(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7776(%rsp)
+vmovdqa %ymm0, 7776(%r8)
vmovdqa 512(%r9), %ymm0
vpaddw 1216(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7104(%rsp)
+vmovdqa %ymm0, 7104(%r8)
vmovdqa 1920(%r9), %ymm0
vpaddw 2624(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7808(%rsp)
+vmovdqa %ymm0, 7808(%r8)
vmovdqa 544(%r9), %ymm0
vpaddw 1248(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7136(%rsp)
+vmovdqa %ymm0, 7136(%r8)
vmovdqa 1952(%r9), %ymm0
vpaddw 2656(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7840(%rsp)
+vmovdqa %ymm0, 7840(%r8)
vmovdqa 576(%r9), %ymm0
vpaddw 1280(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7168(%rsp)
+vmovdqa %ymm0, 7168(%r8)
vmovdqa 1984(%r9), %ymm0
vpaddw 2688(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7872(%rsp)
+vmovdqa %ymm0, 7872(%r8)
vmovdqa 608(%r9), %ymm0
vpaddw 1312(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7200(%rsp)
+vmovdqa %ymm0, 7200(%r8)
vmovdqa 2016(%r9), %ymm0
vpaddw 2720(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7904(%rsp)
+vmovdqa %ymm0, 7904(%r8)
vmovdqa 640(%r9), %ymm0
vpaddw 1344(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7232(%rsp)
+vmovdqa %ymm0, 7232(%r8)
vmovdqa 2048(%r9), %ymm0
vpaddw 2752(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7936(%rsp)
+vmovdqa %ymm0, 7936(%r8)
vmovdqa 672(%r9), %ymm0
vpaddw 1376(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7264(%rsp)
+vmovdqa %ymm0, 7264(%r8)
vmovdqa 2080(%r9), %ymm0
vpaddw 2784(%r9), %ymm0, %ymm0
-vmovdqa %ymm0, 7968(%rsp)
-vmovdqa 6592(%rsp), %ymm0
-vmovdqa 7296(%rsp), %ymm6
-vmovdqa 6624(%rsp), %ymm1
-vmovdqa 7328(%rsp), %ymm7
-vmovdqa 6656(%rsp), %ymm2
-vmovdqa 7360(%rsp), %ymm8
-vmovdqa 6688(%rsp), %ymm3
-vmovdqa 7392(%rsp), %ymm9
-vmovdqa 6720(%rsp), %ymm4
-vmovdqa 7424(%rsp), %ymm10
-vmovdqa 6752(%rsp), %ymm5
-vmovdqa 7456(%rsp), %ymm11
+vmovdqa %ymm0, 7968(%r8)
+vmovdqa 6592(%r8), %ymm0
+vmovdqa 7296(%r8), %ymm6
+vmovdqa 6624(%r8), %ymm1
+vmovdqa 7328(%r8), %ymm7
+vmovdqa 6656(%r8), %ymm2
+vmovdqa 7360(%r8), %ymm8
+vmovdqa 6688(%r8), %ymm3
+vmovdqa 7392(%r8), %ymm9
+vmovdqa 6720(%r8), %ymm4
+vmovdqa 7424(%r8), %ymm10
+vmovdqa 6752(%r8), %ymm5
+vmovdqa 7456(%r8), %ymm11
vpmullw %ymm0, %ymm6, %ymm12
-vmovdqa %ymm12, 8000(%rsp)
+vmovdqa %ymm12, 8000(%r8)
vpmullw %ymm0, %ymm7, %ymm13
vpmullw %ymm1, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8032(%rsp)
+vmovdqa %ymm13, 8032(%r8)
vpmullw %ymm0, %ymm8, %ymm12
vpmullw %ymm1, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm2, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8064(%rsp)
+vmovdqa %ymm12, 8064(%r8)
vpmullw %ymm0, %ymm9, %ymm13
vpmullw %ymm1, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3163,7 +3174,7 @@ vpmullw %ymm2, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm3, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8096(%rsp)
+vmovdqa %ymm13, 8096(%r8)
vpmullw %ymm0, %ymm10, %ymm12
vpmullw %ymm1, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -3173,7 +3184,7 @@ vpmullw %ymm3, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8128(%rsp)
+vmovdqa %ymm12, 8128(%r8)
vpmullw %ymm0, %ymm11, %ymm13
vpmullw %ymm1, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3185,7 +3196,7 @@ vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm5, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8160(%rsp)
+vmovdqa %ymm13, 8160(%r8)
vpmullw %ymm1, %ymm11, %ymm12
vpmullw %ymm2, %ymm10, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -3195,7 +3206,7 @@ vpmullw %ymm4, %ymm8, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm5, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8192(%rsp)
+vmovdqa %ymm12, 8192(%r8)
vpmullw %ymm2, %ymm11, %ymm13
vpmullw %ymm3, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3203,41 +3214,41 @@ vpmullw %ymm4, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm5, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8224(%rsp)
+vmovdqa %ymm13, 8224(%r8)
vpmullw %ymm3, %ymm11, %ymm12
vpmullw %ymm4, %ymm10, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm5, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8256(%rsp)
+vmovdqa %ymm12, 8256(%r8)
vpmullw %ymm4, %ymm11, %ymm13
vpmullw %ymm5, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8288(%rsp)
+vmovdqa %ymm13, 8288(%r8)
vpmullw %ymm5, %ymm11, %ymm12
-vmovdqa %ymm12, 8320(%rsp)
-vmovdqa 6784(%rsp), %ymm0
-vmovdqa 7488(%rsp), %ymm6
-vmovdqa 6816(%rsp), %ymm1
-vmovdqa 7520(%rsp), %ymm7
-vmovdqa 6848(%rsp), %ymm2
-vmovdqa 7552(%rsp), %ymm8
-vmovdqa 6880(%rsp), %ymm3
-vmovdqa 7584(%rsp), %ymm9
-vmovdqa 6912(%rsp), %ymm4
-vmovdqa 7616(%rsp), %ymm10
+vmovdqa %ymm12, 8320(%r8)
+vmovdqa 6784(%r8), %ymm0
+vmovdqa 7488(%r8), %ymm6
+vmovdqa 6816(%r8), %ymm1
+vmovdqa 7520(%r8), %ymm7
+vmovdqa 6848(%r8), %ymm2
+vmovdqa 7552(%r8), %ymm8
+vmovdqa 6880(%r8), %ymm3
+vmovdqa 7584(%r8), %ymm9
+vmovdqa 6912(%r8), %ymm4
+vmovdqa 7616(%r8), %ymm10
vpmullw %ymm0, %ymm6, %ymm12
-vmovdqa %ymm12, 8384(%rsp)
+vmovdqa %ymm12, 8384(%r8)
vpmullw %ymm0, %ymm7, %ymm13
vpmullw %ymm1, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8416(%rsp)
+vmovdqa %ymm13, 8416(%r8)
vpmullw %ymm0, %ymm8, %ymm12
vpmullw %ymm1, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm2, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8448(%rsp)
+vmovdqa %ymm12, 8448(%r8)
vpmullw %ymm0, %ymm9, %ymm13
vpmullw %ymm1, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3245,7 +3256,7 @@ vpmullw %ymm2, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm3, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8480(%rsp)
+vmovdqa %ymm13, 8480(%r8)
vpmullw %ymm0, %ymm10, %ymm12
vpmullw %ymm1, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -3255,7 +3266,7 @@ vpmullw %ymm3, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8512(%rsp)
+vmovdqa %ymm12, 8512(%r8)
vpmullw %ymm1, %ymm10, %ymm13
vpmullw %ymm2, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3263,29 +3274,29 @@ vpmullw %ymm3, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8544(%rsp)
+vmovdqa %ymm13, 8544(%r8)
vpmullw %ymm2, %ymm10, %ymm12
vpmullw %ymm3, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm8, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8576(%rsp)
+vmovdqa %ymm12, 8576(%r8)
vpmullw %ymm3, %ymm10, %ymm13
vpmullw %ymm4, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8608(%rsp)
+vmovdqa %ymm13, 8608(%r8)
vpmullw %ymm4, %ymm10, %ymm12
-vmovdqa %ymm12, 8640(%rsp)
-vpaddw 6592(%rsp), %ymm0, %ymm0
-vpaddw 7296(%rsp), %ymm6, %ymm6
-vpaddw 6624(%rsp), %ymm1, %ymm1
-vpaddw 7328(%rsp), %ymm7, %ymm7
-vpaddw 6656(%rsp), %ymm2, %ymm2
-vpaddw 7360(%rsp), %ymm8, %ymm8
-vpaddw 6688(%rsp), %ymm3, %ymm3
-vpaddw 7392(%rsp), %ymm9, %ymm9
-vpaddw 6720(%rsp), %ymm4, %ymm4
-vpaddw 7424(%rsp), %ymm10, %ymm10
+vmovdqa %ymm12, 8640(%r8)
+vpaddw 6592(%r8), %ymm0, %ymm0
+vpaddw 7296(%r8), %ymm6, %ymm6
+vpaddw 6624(%r8), %ymm1, %ymm1
+vpaddw 7328(%r8), %ymm7, %ymm7
+vpaddw 6656(%r8), %ymm2, %ymm2
+vpaddw 7360(%r8), %ymm8, %ymm8
+vpaddw 6688(%r8), %ymm3, %ymm3
+vpaddw 7392(%r8), %ymm9, %ymm9
+vpaddw 6720(%r8), %ymm4, %ymm4
+vpaddw 7424(%r8), %ymm10, %ymm10
vpmullw %ymm0, %ymm11, %ymm12
vpmullw %ymm1, %ymm10, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
@@ -3297,9 +3308,9 @@ vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
vpmullw %ymm5, %ymm6, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
-vpsubw 8160(%rsp), %ymm12, %ymm12
-vpsubw 8544(%rsp), %ymm12, %ymm12
-vmovdqa %ymm12, 8352(%rsp)
+vpsubw 8160(%r8), %ymm12, %ymm12
+vpsubw 8544(%r8), %ymm12, %ymm12
+vmovdqa %ymm12, 8352(%r8)
vpmullw %ymm5, %ymm7, %ymm12
vpmullw %ymm5, %ymm8, %ymm13
vpmullw %ymm5, %ymm9, %ymm14
@@ -3349,66 +3360,66 @@ vpmullw %ymm0, %ymm7, %ymm8
vpmullw %ymm1, %ymm6, %ymm5
vpaddw %ymm5, %ymm8, %ymm8
vpmullw %ymm0, %ymm6, %ymm7
-vmovdqa 8192(%rsp), %ymm0
-vpsubw 8384(%rsp), %ymm0, %ymm0
+vmovdqa 8192(%r8), %ymm0
+vpsubw 8384(%r8), %ymm0, %ymm0
vpsubw %ymm0, %ymm12, %ymm6
-vpsubw 8576(%rsp), %ymm6, %ymm6
-vmovdqa %ymm6, 8384(%rsp)
+vpsubw 8576(%r8), %ymm6, %ymm6
+vmovdqa %ymm6, 8384(%r8)
vpaddw %ymm7, %ymm0, %ymm0
-vpsubw 8000(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8192(%rsp)
-vmovdqa 8224(%rsp), %ymm1
-vpsubw 8416(%rsp), %ymm1, %ymm1
+vpsubw 8000(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8192(%r8)
+vmovdqa 8224(%r8), %ymm1
+vpsubw 8416(%r8), %ymm1, %ymm1
vpsubw %ymm1, %ymm13, %ymm7
-vpsubw 8608(%rsp), %ymm7, %ymm7
-vmovdqa %ymm7, 8416(%rsp)
+vpsubw 8608(%r8), %ymm7, %ymm7
+vmovdqa %ymm7, 8416(%r8)
vpaddw %ymm8, %ymm1, %ymm1
-vpsubw 8032(%rsp), %ymm1, %ymm1
-vmovdqa %ymm1, 8224(%rsp)
-vmovdqa 8256(%rsp), %ymm2
-vpsubw 8448(%rsp), %ymm2, %ymm2
+vpsubw 8032(%r8), %ymm1, %ymm1
+vmovdqa %ymm1, 8224(%r8)
+vmovdqa 8256(%r8), %ymm2
+vpsubw 8448(%r8), %ymm2, %ymm2
vpsubw %ymm2, %ymm14, %ymm8
-vpsubw 8640(%rsp), %ymm8, %ymm8
-vmovdqa %ymm8, 8448(%rsp)
+vpsubw 8640(%r8), %ymm8, %ymm8
+vmovdqa %ymm8, 8448(%r8)
vpaddw %ymm9, %ymm2, %ymm2
-vpsubw 8064(%rsp), %ymm2, %ymm2
-vmovdqa %ymm2, 8256(%rsp)
-vmovdqa 8288(%rsp), %ymm3
-vpsubw 8480(%rsp), %ymm3, %ymm3
+vpsubw 8064(%r8), %ymm2, %ymm2
+vmovdqa %ymm2, 8256(%r8)
+vmovdqa 8288(%r8), %ymm3
+vpsubw 8480(%r8), %ymm3, %ymm3
vpsubw %ymm3, %ymm15, %ymm9
-vmovdqa %ymm9, 8480(%rsp)
+vmovdqa %ymm9, 8480(%r8)
vpaddw %ymm10, %ymm3, %ymm3
-vpsubw 8096(%rsp), %ymm3, %ymm3
-vmovdqa %ymm3, 8288(%rsp)
-vmovdqa 8320(%rsp), %ymm4
-vpsubw 8512(%rsp), %ymm4, %ymm4
+vpsubw 8096(%r8), %ymm3, %ymm3
+vmovdqa %ymm3, 8288(%r8)
+vmovdqa 8320(%r8), %ymm4
+vpsubw 8512(%r8), %ymm4, %ymm4
vpaddw %ymm11, %ymm4, %ymm4
-vpsubw 8128(%rsp), %ymm4, %ymm4
-vmovdqa %ymm4, 8320(%rsp)
-vmovdqa 6944(%rsp), %ymm0
-vmovdqa 7648(%rsp), %ymm6
-vmovdqa 6976(%rsp), %ymm1
-vmovdqa 7680(%rsp), %ymm7
-vmovdqa 7008(%rsp), %ymm2
-vmovdqa 7712(%rsp), %ymm8
-vmovdqa 7040(%rsp), %ymm3
-vmovdqa 7744(%rsp), %ymm9
-vmovdqa 7072(%rsp), %ymm4
-vmovdqa 7776(%rsp), %ymm10
-vmovdqa 7104(%rsp), %ymm5
-vmovdqa 7808(%rsp), %ymm11
+vpsubw 8128(%r8), %ymm4, %ymm4
+vmovdqa %ymm4, 8320(%r8)
+vmovdqa 6944(%r8), %ymm0
+vmovdqa 7648(%r8), %ymm6
+vmovdqa 6976(%r8), %ymm1
+vmovdqa 7680(%r8), %ymm7
+vmovdqa 7008(%r8), %ymm2
+vmovdqa 7712(%r8), %ymm8
+vmovdqa 7040(%r8), %ymm3
+vmovdqa 7744(%r8), %ymm9
+vmovdqa 7072(%r8), %ymm4
+vmovdqa 7776(%r8), %ymm10
+vmovdqa 7104(%r8), %ymm5
+vmovdqa 7808(%r8), %ymm11
vpmullw %ymm0, %ymm6, %ymm12
-vmovdqa %ymm12, 8704(%rsp)
+vmovdqa %ymm12, 8704(%r8)
vpmullw %ymm0, %ymm7, %ymm13
vpmullw %ymm1, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8736(%rsp)
+vmovdqa %ymm13, 8736(%r8)
vpmullw %ymm0, %ymm8, %ymm12
vpmullw %ymm1, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm2, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8768(%rsp)
+vmovdqa %ymm12, 8768(%r8)
vpmullw %ymm0, %ymm9, %ymm13
vpmullw %ymm1, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3416,7 +3427,7 @@ vpmullw %ymm2, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm3, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8800(%rsp)
+vmovdqa %ymm13, 8800(%r8)
vpmullw %ymm0, %ymm10, %ymm12
vpmullw %ymm1, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -3426,7 +3437,7 @@ vpmullw %ymm3, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8832(%rsp)
+vmovdqa %ymm12, 8832(%r8)
vpmullw %ymm0, %ymm11, %ymm13
vpmullw %ymm1, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3438,7 +3449,7 @@ vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm5, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8864(%rsp)
+vmovdqa %ymm13, 8864(%r8)
vpmullw %ymm1, %ymm11, %ymm12
vpmullw %ymm2, %ymm10, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -3448,7 +3459,7 @@ vpmullw %ymm4, %ymm8, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm5, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8896(%rsp)
+vmovdqa %ymm12, 8896(%r8)
vpmullw %ymm2, %ymm11, %ymm13
vpmullw %ymm3, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3456,41 +3467,41 @@ vpmullw %ymm4, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm5, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8928(%rsp)
+vmovdqa %ymm13, 8928(%r8)
vpmullw %ymm3, %ymm11, %ymm12
vpmullw %ymm4, %ymm10, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm5, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 8960(%rsp)
+vmovdqa %ymm12, 8960(%r8)
vpmullw %ymm4, %ymm11, %ymm13
vpmullw %ymm5, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 8992(%rsp)
+vmovdqa %ymm13, 8992(%r8)
vpmullw %ymm5, %ymm11, %ymm12
-vmovdqa %ymm12, 9024(%rsp)
-vmovdqa 7136(%rsp), %ymm0
-vmovdqa 7840(%rsp), %ymm6
-vmovdqa 7168(%rsp), %ymm1
-vmovdqa 7872(%rsp), %ymm7
-vmovdqa 7200(%rsp), %ymm2
-vmovdqa 7904(%rsp), %ymm8
-vmovdqa 7232(%rsp), %ymm3
-vmovdqa 7936(%rsp), %ymm9
-vmovdqa 7264(%rsp), %ymm4
-vmovdqa 7968(%rsp), %ymm10
+vmovdqa %ymm12, 9024(%r8)
+vmovdqa 7136(%r8), %ymm0
+vmovdqa 7840(%r8), %ymm6
+vmovdqa 7168(%r8), %ymm1
+vmovdqa 7872(%r8), %ymm7
+vmovdqa 7200(%r8), %ymm2
+vmovdqa 7904(%r8), %ymm8
+vmovdqa 7232(%r8), %ymm3
+vmovdqa 7936(%r8), %ymm9
+vmovdqa 7264(%r8), %ymm4
+vmovdqa 7968(%r8), %ymm10
vpmullw %ymm0, %ymm6, %ymm12
-vmovdqa %ymm12, 9088(%rsp)
+vmovdqa %ymm12, 9088(%r8)
vpmullw %ymm0, %ymm7, %ymm13
vpmullw %ymm1, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 9120(%rsp)
+vmovdqa %ymm13, 9120(%r8)
vpmullw %ymm0, %ymm8, %ymm12
vpmullw %ymm1, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm2, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 9152(%rsp)
+vmovdqa %ymm12, 9152(%r8)
vpmullw %ymm0, %ymm9, %ymm13
vpmullw %ymm1, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3498,7 +3509,7 @@ vpmullw %ymm2, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm3, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 9184(%rsp)
+vmovdqa %ymm13, 9184(%r8)
vpmullw %ymm0, %ymm10, %ymm12
vpmullw %ymm1, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -3508,7 +3519,7 @@ vpmullw %ymm3, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 9216(%rsp)
+vmovdqa %ymm12, 9216(%r8)
vpmullw %ymm1, %ymm10, %ymm13
vpmullw %ymm2, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3516,29 +3527,29 @@ vpmullw %ymm3, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 9248(%rsp)
+vmovdqa %ymm13, 9248(%r8)
vpmullw %ymm2, %ymm10, %ymm12
vpmullw %ymm3, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm8, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 9280(%rsp)
+vmovdqa %ymm12, 9280(%r8)
vpmullw %ymm3, %ymm10, %ymm13
vpmullw %ymm4, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 9312(%rsp)
+vmovdqa %ymm13, 9312(%r8)
vpmullw %ymm4, %ymm10, %ymm12
-vmovdqa %ymm12, 9344(%rsp)
-vpaddw 6944(%rsp), %ymm0, %ymm0
-vpaddw 7648(%rsp), %ymm6, %ymm6
-vpaddw 6976(%rsp), %ymm1, %ymm1
-vpaddw 7680(%rsp), %ymm7, %ymm7
-vpaddw 7008(%rsp), %ymm2, %ymm2
-vpaddw 7712(%rsp), %ymm8, %ymm8
-vpaddw 7040(%rsp), %ymm3, %ymm3
-vpaddw 7744(%rsp), %ymm9, %ymm9
-vpaddw 7072(%rsp), %ymm4, %ymm4
-vpaddw 7776(%rsp), %ymm10, %ymm10
+vmovdqa %ymm12, 9344(%r8)
+vpaddw 6944(%r8), %ymm0, %ymm0
+vpaddw 7648(%r8), %ymm6, %ymm6
+vpaddw 6976(%r8), %ymm1, %ymm1
+vpaddw 7680(%r8), %ymm7, %ymm7
+vpaddw 7008(%r8), %ymm2, %ymm2
+vpaddw 7712(%r8), %ymm8, %ymm8
+vpaddw 7040(%r8), %ymm3, %ymm3
+vpaddw 7744(%r8), %ymm9, %ymm9
+vpaddw 7072(%r8), %ymm4, %ymm4
+vpaddw 7776(%r8), %ymm10, %ymm10
vpmullw %ymm0, %ymm11, %ymm12
vpmullw %ymm1, %ymm10, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
@@ -3550,9 +3561,9 @@ vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
vpmullw %ymm5, %ymm6, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
-vpsubw 8864(%rsp), %ymm12, %ymm12
-vpsubw 9248(%rsp), %ymm12, %ymm12
-vmovdqa %ymm12, 9056(%rsp)
+vpsubw 8864(%r8), %ymm12, %ymm12
+vpsubw 9248(%r8), %ymm12, %ymm12
+vmovdqa %ymm12, 9056(%r8)
vpmullw %ymm5, %ymm7, %ymm12
vpmullw %ymm5, %ymm8, %ymm13
vpmullw %ymm5, %ymm9, %ymm14
@@ -3602,78 +3613,78 @@ vpmullw %ymm0, %ymm7, %ymm8
vpmullw %ymm1, %ymm6, %ymm5
vpaddw %ymm5, %ymm8, %ymm8
vpmullw %ymm0, %ymm6, %ymm7
-vmovdqa 8896(%rsp), %ymm0
-vpsubw 9088(%rsp), %ymm0, %ymm0
+vmovdqa 8896(%r8), %ymm0
+vpsubw 9088(%r8), %ymm0, %ymm0
vpsubw %ymm0, %ymm12, %ymm6
-vpsubw 9280(%rsp), %ymm6, %ymm6
-vmovdqa %ymm6, 9088(%rsp)
+vpsubw 9280(%r8), %ymm6, %ymm6
+vmovdqa %ymm6, 9088(%r8)
vpaddw %ymm7, %ymm0, %ymm0
-vpsubw 8704(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8896(%rsp)
-vmovdqa 8928(%rsp), %ymm1
-vpsubw 9120(%rsp), %ymm1, %ymm1
+vpsubw 8704(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8896(%r8)
+vmovdqa 8928(%r8), %ymm1
+vpsubw 9120(%r8), %ymm1, %ymm1
vpsubw %ymm1, %ymm13, %ymm7
-vpsubw 9312(%rsp), %ymm7, %ymm7
-vmovdqa %ymm7, 9120(%rsp)
+vpsubw 9312(%r8), %ymm7, %ymm7
+vmovdqa %ymm7, 9120(%r8)
vpaddw %ymm8, %ymm1, %ymm1
-vpsubw 8736(%rsp), %ymm1, %ymm1
-vmovdqa %ymm1, 8928(%rsp)
-vmovdqa 8960(%rsp), %ymm2
-vpsubw 9152(%rsp), %ymm2, %ymm2
+vpsubw 8736(%r8), %ymm1, %ymm1
+vmovdqa %ymm1, 8928(%r8)
+vmovdqa 8960(%r8), %ymm2
+vpsubw 9152(%r8), %ymm2, %ymm2
vpsubw %ymm2, %ymm14, %ymm8
-vpsubw 9344(%rsp), %ymm8, %ymm8
-vmovdqa %ymm8, 9152(%rsp)
+vpsubw 9344(%r8), %ymm8, %ymm8
+vmovdqa %ymm8, 9152(%r8)
vpaddw %ymm9, %ymm2, %ymm2
-vpsubw 8768(%rsp), %ymm2, %ymm2
-vmovdqa %ymm2, 8960(%rsp)
-vmovdqa 8992(%rsp), %ymm3
-vpsubw 9184(%rsp), %ymm3, %ymm3
+vpsubw 8768(%r8), %ymm2, %ymm2
+vmovdqa %ymm2, 8960(%r8)
+vmovdqa 8992(%r8), %ymm3
+vpsubw 9184(%r8), %ymm3, %ymm3
vpsubw %ymm3, %ymm15, %ymm9
-vmovdqa %ymm9, 9184(%rsp)
+vmovdqa %ymm9, 9184(%r8)
vpaddw %ymm10, %ymm3, %ymm3
-vpsubw 8800(%rsp), %ymm3, %ymm3
-vmovdqa %ymm3, 8992(%rsp)
-vmovdqa 9024(%rsp), %ymm4
-vpsubw 9216(%rsp), %ymm4, %ymm4
+vpsubw 8800(%r8), %ymm3, %ymm3
+vmovdqa %ymm3, 8992(%r8)
+vmovdqa 9024(%r8), %ymm4
+vpsubw 9216(%r8), %ymm4, %ymm4
vpaddw %ymm11, %ymm4, %ymm4
-vpsubw 8832(%rsp), %ymm4, %ymm4
-vmovdqa %ymm4, 9024(%rsp)
-vmovdqa 6592(%rsp), %ymm0
-vmovdqa 7296(%rsp), %ymm6
-vpaddw 6944(%rsp), %ymm0, %ymm0
-vpaddw 7648(%rsp), %ymm6, %ymm6
-vmovdqa 6624(%rsp), %ymm1
-vmovdqa 7328(%rsp), %ymm7
-vpaddw 6976(%rsp), %ymm1, %ymm1
-vpaddw 7680(%rsp), %ymm7, %ymm7
-vmovdqa 6656(%rsp), %ymm2
-vmovdqa 7360(%rsp), %ymm8
-vpaddw 7008(%rsp), %ymm2, %ymm2
-vpaddw 7712(%rsp), %ymm8, %ymm8
-vmovdqa 6688(%rsp), %ymm3
-vmovdqa 7392(%rsp), %ymm9
-vpaddw 7040(%rsp), %ymm3, %ymm3
-vpaddw 7744(%rsp), %ymm9, %ymm9
-vmovdqa 6720(%rsp), %ymm4
-vmovdqa 7424(%rsp), %ymm10
-vpaddw 7072(%rsp), %ymm4, %ymm4
-vpaddw 7776(%rsp), %ymm10, %ymm10
-vmovdqa 6752(%rsp), %ymm5
-vmovdqa 7456(%rsp), %ymm11
-vpaddw 7104(%rsp), %ymm5, %ymm5
-vpaddw 7808(%rsp), %ymm11, %ymm11
+vpsubw 8832(%r8), %ymm4, %ymm4
+vmovdqa %ymm4, 9024(%r8)
+vmovdqa 6592(%r8), %ymm0
+vmovdqa 7296(%r8), %ymm6
+vpaddw 6944(%r8), %ymm0, %ymm0
+vpaddw 7648(%r8), %ymm6, %ymm6
+vmovdqa 6624(%r8), %ymm1
+vmovdqa 7328(%r8), %ymm7
+vpaddw 6976(%r8), %ymm1, %ymm1
+vpaddw 7680(%r8), %ymm7, %ymm7
+vmovdqa 6656(%r8), %ymm2
+vmovdqa 7360(%r8), %ymm8
+vpaddw 7008(%r8), %ymm2, %ymm2
+vpaddw 7712(%r8), %ymm8, %ymm8
+vmovdqa 6688(%r8), %ymm3
+vmovdqa 7392(%r8), %ymm9
+vpaddw 7040(%r8), %ymm3, %ymm3
+vpaddw 7744(%r8), %ymm9, %ymm9
+vmovdqa 6720(%r8), %ymm4
+vmovdqa 7424(%r8), %ymm10
+vpaddw 7072(%r8), %ymm4, %ymm4
+vpaddw 7776(%r8), %ymm10, %ymm10
+vmovdqa 6752(%r8), %ymm5
+vmovdqa 7456(%r8), %ymm11
+vpaddw 7104(%r8), %ymm5, %ymm5
+vpaddw 7808(%r8), %ymm11, %ymm11
vpmullw %ymm0, %ymm6, %ymm12
-vmovdqa %ymm12, 5888(%rsp)
+vmovdqa %ymm12, 5888(%r8)
vpmullw %ymm0, %ymm7, %ymm13
vpmullw %ymm1, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 5920(%rsp)
+vmovdqa %ymm13, 5920(%r8)
vpmullw %ymm0, %ymm8, %ymm12
vpmullw %ymm1, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm2, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 5952(%rsp)
+vmovdqa %ymm12, 5952(%r8)
vpmullw %ymm0, %ymm9, %ymm13
vpmullw %ymm1, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3681,7 +3692,7 @@ vpmullw %ymm2, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm3, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 5984(%rsp)
+vmovdqa %ymm13, 5984(%r8)
vpmullw %ymm0, %ymm10, %ymm12
vpmullw %ymm1, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -3691,7 +3702,7 @@ vpmullw %ymm3, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6016(%rsp)
+vmovdqa %ymm12, 6016(%r8)
vpmullw %ymm0, %ymm11, %ymm13
vpmullw %ymm1, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3703,7 +3714,7 @@ vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm5, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6048(%rsp)
+vmovdqa %ymm13, 6048(%r8)
vpmullw %ymm1, %ymm11, %ymm12
vpmullw %ymm2, %ymm10, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -3713,7 +3724,7 @@ vpmullw %ymm4, %ymm8, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm5, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6080(%rsp)
+vmovdqa %ymm12, 6080(%r8)
vpmullw %ymm2, %ymm11, %ymm13
vpmullw %ymm3, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3721,51 +3732,51 @@ vpmullw %ymm4, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm5, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6112(%rsp)
+vmovdqa %ymm13, 6112(%r8)
vpmullw %ymm3, %ymm11, %ymm12
vpmullw %ymm4, %ymm10, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm5, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6144(%rsp)
+vmovdqa %ymm12, 6144(%r8)
vpmullw %ymm4, %ymm11, %ymm13
vpmullw %ymm5, %ymm10, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6176(%rsp)
+vmovdqa %ymm13, 6176(%r8)
vpmullw %ymm5, %ymm11, %ymm12
-vmovdqa %ymm12, 6208(%rsp)
-vmovdqa 6784(%rsp), %ymm0
-vmovdqa 7488(%rsp), %ymm6
-vpaddw 7136(%rsp), %ymm0, %ymm0
-vpaddw 7840(%rsp), %ymm6, %ymm6
-vmovdqa 6816(%rsp), %ymm1
-vmovdqa 7520(%rsp), %ymm7
-vpaddw 7168(%rsp), %ymm1, %ymm1
-vpaddw 7872(%rsp), %ymm7, %ymm7
-vmovdqa 6848(%rsp), %ymm2
-vmovdqa 7552(%rsp), %ymm8
-vpaddw 7200(%rsp), %ymm2, %ymm2
-vpaddw 7904(%rsp), %ymm8, %ymm8
-vmovdqa 6880(%rsp), %ymm3
-vmovdqa 7584(%rsp), %ymm9
-vpaddw 7232(%rsp), %ymm3, %ymm3
-vpaddw 7936(%rsp), %ymm9, %ymm9
-vmovdqa 6912(%rsp), %ymm4
-vmovdqa 7616(%rsp), %ymm10
-vpaddw 7264(%rsp), %ymm4, %ymm4
-vpaddw 7968(%rsp), %ymm10, %ymm10
+vmovdqa %ymm12, 6208(%r8)
+vmovdqa 6784(%r8), %ymm0
+vmovdqa 7488(%r8), %ymm6
+vpaddw 7136(%r8), %ymm0, %ymm0
+vpaddw 7840(%r8), %ymm6, %ymm6
+vmovdqa 6816(%r8), %ymm1
+vmovdqa 7520(%r8), %ymm7
+vpaddw 7168(%r8), %ymm1, %ymm1
+vpaddw 7872(%r8), %ymm7, %ymm7
+vmovdqa 6848(%r8), %ymm2
+vmovdqa 7552(%r8), %ymm8
+vpaddw 7200(%r8), %ymm2, %ymm2
+vpaddw 7904(%r8), %ymm8, %ymm8
+vmovdqa 6880(%r8), %ymm3
+vmovdqa 7584(%r8), %ymm9
+vpaddw 7232(%r8), %ymm3, %ymm3
+vpaddw 7936(%r8), %ymm9, %ymm9
+vmovdqa 6912(%r8), %ymm4
+vmovdqa 7616(%r8), %ymm10
+vpaddw 7264(%r8), %ymm4, %ymm4
+vpaddw 7968(%r8), %ymm10, %ymm10
vpmullw %ymm0, %ymm6, %ymm12
-vmovdqa %ymm12, 6272(%rsp)
+vmovdqa %ymm12, 6272(%r8)
vpmullw %ymm0, %ymm7, %ymm13
vpmullw %ymm1, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6304(%rsp)
+vmovdqa %ymm13, 6304(%r8)
vpmullw %ymm0, %ymm8, %ymm12
vpmullw %ymm1, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm2, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6336(%rsp)
+vmovdqa %ymm12, 6336(%r8)
vpmullw %ymm0, %ymm9, %ymm13
vpmullw %ymm1, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3773,7 +3784,7 @@ vpmullw %ymm2, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm3, %ymm6, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6368(%rsp)
+vmovdqa %ymm13, 6368(%r8)
vpmullw %ymm0, %ymm10, %ymm12
vpmullw %ymm1, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
@@ -3783,7 +3794,7 @@ vpmullw %ymm3, %ymm7, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm6, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6400(%rsp)
+vmovdqa %ymm12, 6400(%r8)
vpmullw %ymm1, %ymm10, %ymm13
vpmullw %ymm2, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
@@ -3791,39 +3802,39 @@ vpmullw %ymm3, %ymm8, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6432(%rsp)
+vmovdqa %ymm13, 6432(%r8)
vpmullw %ymm2, %ymm10, %ymm12
vpmullw %ymm3, %ymm9, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
vpmullw %ymm4, %ymm8, %ymm15
vpaddw %ymm12, %ymm15, %ymm12
-vmovdqa %ymm12, 6464(%rsp)
+vmovdqa %ymm12, 6464(%r8)
vpmullw %ymm3, %ymm10, %ymm13
vpmullw %ymm4, %ymm9, %ymm15
vpaddw %ymm13, %ymm15, %ymm13
-vmovdqa %ymm13, 6496(%rsp)
+vmovdqa %ymm13, 6496(%r8)
vpmullw %ymm4, %ymm10, %ymm12
-vmovdqa %ymm12, 6528(%rsp)
-vpaddw 6592(%rsp), %ymm0, %ymm0
-vpaddw 7296(%rsp), %ymm6, %ymm6
-vpaddw 6944(%rsp), %ymm0, %ymm0
-vpaddw 7648(%rsp), %ymm6, %ymm6
-vpaddw 6624(%rsp), %ymm1, %ymm1
-vpaddw 7328(%rsp), %ymm7, %ymm7
-vpaddw 6976(%rsp), %ymm1, %ymm1
-vpaddw 7680(%rsp), %ymm7, %ymm7
-vpaddw 6656(%rsp), %ymm2, %ymm2
-vpaddw 7360(%rsp), %ymm8, %ymm8
-vpaddw 7008(%rsp), %ymm2, %ymm2
-vpaddw 7712(%rsp), %ymm8, %ymm8
-vpaddw 6688(%rsp), %ymm3, %ymm3
-vpaddw 7392(%rsp), %ymm9, %ymm9
-vpaddw 7040(%rsp), %ymm3, %ymm3
-vpaddw 7744(%rsp), %ymm9, %ymm9
-vpaddw 6720(%rsp), %ymm4, %ymm4
-vpaddw 7424(%rsp), %ymm10, %ymm10
-vpaddw 7072(%rsp), %ymm4, %ymm4
-vpaddw 7776(%rsp), %ymm10, %ymm10
+vmovdqa %ymm12, 6528(%r8)
+vpaddw 6592(%r8), %ymm0, %ymm0
+vpaddw 7296(%r8), %ymm6, %ymm6
+vpaddw 6944(%r8), %ymm0, %ymm0
+vpaddw 7648(%r8), %ymm6, %ymm6
+vpaddw 6624(%r8), %ymm1, %ymm1
+vpaddw 7328(%r8), %ymm7, %ymm7
+vpaddw 6976(%r8), %ymm1, %ymm1
+vpaddw 7680(%r8), %ymm7, %ymm7
+vpaddw 6656(%r8), %ymm2, %ymm2
+vpaddw 7360(%r8), %ymm8, %ymm8
+vpaddw 7008(%r8), %ymm2, %ymm2
+vpaddw 7712(%r8), %ymm8, %ymm8
+vpaddw 6688(%r8), %ymm3, %ymm3
+vpaddw 7392(%r8), %ymm9, %ymm9
+vpaddw 7040(%r8), %ymm3, %ymm3
+vpaddw 7744(%r8), %ymm9, %ymm9
+vpaddw 6720(%r8), %ymm4, %ymm4
+vpaddw 7424(%r8), %ymm10, %ymm10
+vpaddw 7072(%r8), %ymm4, %ymm4
+vpaddw 7776(%r8), %ymm10, %ymm10
vpmullw %ymm0, %ymm11, %ymm12
vpmullw %ymm1, %ymm10, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
@@ -3835,9 +3846,9 @@ vpmullw %ymm4, %ymm7, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
vpmullw %ymm5, %ymm6, %ymm15
vpaddw %ymm15, %ymm12, %ymm12
-vpsubw 6048(%rsp), %ymm12, %ymm12
-vpsubw 6432(%rsp), %ymm12, %ymm12
-vmovdqa %ymm12, 6240(%rsp)
+vpsubw 6048(%r8), %ymm12, %ymm12
+vpsubw 6432(%r8), %ymm12, %ymm12
+vmovdqa %ymm12, 6240(%r8)
vpmullw %ymm5, %ymm7, %ymm12
vpmullw %ymm5, %ymm8, %ymm13
vpmullw %ymm5, %ymm9, %ymm14
@@ -3887,125 +3898,125 @@ vpmullw %ymm0, %ymm7, %ymm8
vpmullw %ymm1, %ymm6, %ymm5
vpaddw %ymm5, %ymm8, %ymm8
vpmullw %ymm0, %ymm6, %ymm7
-vmovdqa 6080(%rsp), %ymm0
-vpsubw 6272(%rsp), %ymm0, %ymm0
+vmovdqa 6080(%r8), %ymm0
+vpsubw 6272(%r8), %ymm0, %ymm0
vpsubw %ymm0, %ymm12, %ymm6
-vpsubw 6464(%rsp), %ymm6, %ymm6
-vmovdqa %ymm6, 6272(%rsp)
+vpsubw 6464(%r8), %ymm6, %ymm6
+vmovdqa %ymm6, 6272(%r8)
vpaddw %ymm7, %ymm0, %ymm0
-vpsubw 5888(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 6080(%rsp)
-vmovdqa 6112(%rsp), %ymm1
-vpsubw 6304(%rsp), %ymm1, %ymm1
+vpsubw 5888(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 6080(%r8)
+vmovdqa 6112(%r8), %ymm1
+vpsubw 6304(%r8), %ymm1, %ymm1
vpsubw %ymm1, %ymm13, %ymm7
-vpsubw 6496(%rsp), %ymm7, %ymm7
-vmovdqa %ymm7, 6304(%rsp)
+vpsubw 6496(%r8), %ymm7, %ymm7
+vmovdqa %ymm7, 6304(%r8)
vpaddw %ymm8, %ymm1, %ymm1
-vpsubw 5920(%rsp), %ymm1, %ymm1
-vmovdqa %ymm1, 6112(%rsp)
-vmovdqa 6144(%rsp), %ymm2
-vpsubw 6336(%rsp), %ymm2, %ymm2
+vpsubw 5920(%r8), %ymm1, %ymm1
+vmovdqa %ymm1, 6112(%r8)
+vmovdqa 6144(%r8), %ymm2
+vpsubw 6336(%r8), %ymm2, %ymm2
vpsubw %ymm2, %ymm14, %ymm8
-vpsubw 6528(%rsp), %ymm8, %ymm8
-vmovdqa %ymm8, 6336(%rsp)
+vpsubw 6528(%r8), %ymm8, %ymm8
+vmovdqa %ymm8, 6336(%r8)
vpaddw %ymm9, %ymm2, %ymm2
-vpsubw 5952(%rsp), %ymm2, %ymm2
-vmovdqa %ymm2, 6144(%rsp)
-vmovdqa 6176(%rsp), %ymm3
-vpsubw 6368(%rsp), %ymm3, %ymm3
+vpsubw 5952(%r8), %ymm2, %ymm2
+vmovdqa %ymm2, 6144(%r8)
+vmovdqa 6176(%r8), %ymm3
+vpsubw 6368(%r8), %ymm3, %ymm3
vpsubw %ymm3, %ymm15, %ymm9
-vmovdqa %ymm9, 6368(%rsp)
+vmovdqa %ymm9, 6368(%r8)
vpaddw %ymm10, %ymm3, %ymm3
-vpsubw 5984(%rsp), %ymm3, %ymm3
-vmovdqa %ymm3, 6176(%rsp)
-vmovdqa 6208(%rsp), %ymm4
-vpsubw 6400(%rsp), %ymm4, %ymm4
+vpsubw 5984(%r8), %ymm3, %ymm3
+vmovdqa %ymm3, 6176(%r8)
+vmovdqa 6208(%r8), %ymm4
+vpsubw 6400(%r8), %ymm4, %ymm4
vpaddw %ymm11, %ymm4, %ymm4
-vpsubw 6016(%rsp), %ymm4, %ymm4
-vmovdqa %ymm4, 6208(%rsp)
-vmovdqa 8352(%rsp), %ymm0
-vpsubw 8704(%rsp), %ymm0, %ymm0
-vmovdqa 6240(%rsp), %ymm1
+vpsubw 6016(%r8), %ymm4, %ymm4
+vmovdqa %ymm4, 6208(%r8)
+vmovdqa 8352(%r8), %ymm0
+vpsubw 8704(%r8), %ymm0, %ymm0
+vmovdqa 6240(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9056(%rsp), %ymm1, %ymm6
-vpsubw 8000(%rsp), %ymm0, %ymm0
-vpaddw 5888(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8352(%rsp)
-vmovdqa 8384(%rsp), %ymm0
-vpsubw 8736(%rsp), %ymm0, %ymm0
-vmovdqa 6272(%rsp), %ymm1
+vpsubw 9056(%r8), %ymm1, %ymm6
+vpsubw 8000(%r8), %ymm0, %ymm0
+vpaddw 5888(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8352(%r8)
+vmovdqa 8384(%r8), %ymm0
+vpsubw 8736(%r8), %ymm0, %ymm0
+vmovdqa 6272(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9088(%rsp), %ymm1, %ymm7
-vpsubw 8032(%rsp), %ymm0, %ymm0
-vpaddw 5920(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8384(%rsp)
-vmovdqa 8416(%rsp), %ymm0
-vpsubw 8768(%rsp), %ymm0, %ymm0
-vmovdqa 6304(%rsp), %ymm1
+vpsubw 9088(%r8), %ymm1, %ymm7
+vpsubw 8032(%r8), %ymm0, %ymm0
+vpaddw 5920(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8384(%r8)
+vmovdqa 8416(%r8), %ymm0
+vpsubw 8768(%r8), %ymm0, %ymm0
+vmovdqa 6304(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9120(%rsp), %ymm1, %ymm8
-vpsubw 8064(%rsp), %ymm0, %ymm0
-vpaddw 5952(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8416(%rsp)
-vmovdqa 8448(%rsp), %ymm0
-vpsubw 8800(%rsp), %ymm0, %ymm0
-vmovdqa 6336(%rsp), %ymm1
+vpsubw 9120(%r8), %ymm1, %ymm8
+vpsubw 8064(%r8), %ymm0, %ymm0
+vpaddw 5952(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8416(%r8)
+vmovdqa 8448(%r8), %ymm0
+vpsubw 8800(%r8), %ymm0, %ymm0
+vmovdqa 6336(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9152(%rsp), %ymm1, %ymm9
-vpsubw 8096(%rsp), %ymm0, %ymm0
-vpaddw 5984(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8448(%rsp)
-vmovdqa 8480(%rsp), %ymm0
-vpsubw 8832(%rsp), %ymm0, %ymm0
-vmovdqa 6368(%rsp), %ymm1
+vpsubw 9152(%r8), %ymm1, %ymm9
+vpsubw 8096(%r8), %ymm0, %ymm0
+vpaddw 5984(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8448(%r8)
+vmovdqa 8480(%r8), %ymm0
+vpsubw 8832(%r8), %ymm0, %ymm0
+vmovdqa 6368(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9184(%rsp), %ymm1, %ymm10
-vpsubw 8128(%rsp), %ymm0, %ymm0
-vpaddw 6016(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8480(%rsp)
-vmovdqa 8512(%rsp), %ymm0
-vpsubw 8864(%rsp), %ymm0, %ymm0
-vmovdqa 6400(%rsp), %ymm1
+vpsubw 9184(%r8), %ymm1, %ymm10
+vpsubw 8128(%r8), %ymm0, %ymm0
+vpaddw 6016(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8480(%r8)
+vmovdqa 8512(%r8), %ymm0
+vpsubw 8864(%r8), %ymm0, %ymm0
+vmovdqa 6400(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9216(%rsp), %ymm1, %ymm11
-vpsubw 8160(%rsp), %ymm0, %ymm0
-vpaddw 6048(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8512(%rsp)
-vmovdqa 8544(%rsp), %ymm0
-vpsubw 8896(%rsp), %ymm0, %ymm0
-vmovdqa 6432(%rsp), %ymm1
+vpsubw 9216(%r8), %ymm1, %ymm11
+vpsubw 8160(%r8), %ymm0, %ymm0
+vpaddw 6048(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8512(%r8)
+vmovdqa 8544(%r8), %ymm0
+vpsubw 8896(%r8), %ymm0, %ymm0
+vmovdqa 6432(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9248(%rsp), %ymm1, %ymm12
-vpsubw 8192(%rsp), %ymm0, %ymm0
-vpaddw 6080(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8544(%rsp)
-vmovdqa 8576(%rsp), %ymm0
-vpsubw 8928(%rsp), %ymm0, %ymm0
-vmovdqa 6464(%rsp), %ymm1
+vpsubw 9248(%r8), %ymm1, %ymm12
+vpsubw 8192(%r8), %ymm0, %ymm0
+vpaddw 6080(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8544(%r8)
+vmovdqa 8576(%r8), %ymm0
+vpsubw 8928(%r8), %ymm0, %ymm0
+vmovdqa 6464(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9280(%rsp), %ymm1, %ymm13
-vpsubw 8224(%rsp), %ymm0, %ymm0
-vpaddw 6112(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8576(%rsp)
-vmovdqa 8608(%rsp), %ymm0
-vpsubw 8960(%rsp), %ymm0, %ymm0
-vmovdqa 6496(%rsp), %ymm1
+vpsubw 9280(%r8), %ymm1, %ymm13
+vpsubw 8224(%r8), %ymm0, %ymm0
+vpaddw 6112(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8576(%r8)
+vmovdqa 8608(%r8), %ymm0
+vpsubw 8960(%r8), %ymm0, %ymm0
+vmovdqa 6496(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9312(%rsp), %ymm1, %ymm14
-vpsubw 8256(%rsp), %ymm0, %ymm0
-vpaddw 6144(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8608(%rsp)
-vmovdqa 8640(%rsp), %ymm0
-vpsubw 8992(%rsp), %ymm0, %ymm0
-vmovdqa 6528(%rsp), %ymm1
+vpsubw 9312(%r8), %ymm1, %ymm14
+vpsubw 8256(%r8), %ymm0, %ymm0
+vpaddw 6144(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8608(%r8)
+vmovdqa 8640(%r8), %ymm0
+vpsubw 8992(%r8), %ymm0, %ymm0
+vmovdqa 6528(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
-vpsubw 9344(%rsp), %ymm1, %ymm15
-vpsubw 8288(%rsp), %ymm0, %ymm0
-vpaddw 6176(%rsp), %ymm0, %ymm0
-vmovdqa %ymm0, 8640(%rsp)
-vmovdqa 6208(%rsp), %ymm0
-vpsubw 8320(%rsp), %ymm0, %ymm0
-vpsubw 9024(%rsp), %ymm0, %ymm0
+vpsubw 9344(%r8), %ymm1, %ymm15
+vpsubw 8288(%r8), %ymm0, %ymm0
+vpaddw 6176(%r8), %ymm0, %ymm0
+vmovdqa %ymm0, 8640(%r8)
+vmovdqa 6208(%r8), %ymm0
+vpsubw 8320(%r8), %ymm0, %ymm0
+vpsubw 9024(%r8), %ymm0, %ymm0
vpsubw 3488(%r10), %ymm0, %ymm0
vpsubw 4896(%r10), %ymm0, %ymm0
vmovdqa %ymm0, 4192(%r10)
@@ -4014,7 +4025,7 @@ vpsubw 4224(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm6, %ymm6
vpsubw 4928(%r10), %ymm6, %ymm6
vpsubw 2816(%r10), %ymm0, %ymm0
-vpaddw 8000(%rsp), %ymm0, %ymm0
+vpaddw 8000(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3520(%r10)
vmovdqa %ymm6, 4224(%r10)
vmovdqa 3552(%r10), %ymm0
@@ -4022,7 +4033,7 @@ vpsubw 4256(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm7, %ymm7
vpsubw 4960(%r10), %ymm7, %ymm7
vpsubw 2848(%r10), %ymm0, %ymm0
-vpaddw 8032(%rsp), %ymm0, %ymm0
+vpaddw 8032(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3552(%r10)
vmovdqa %ymm7, 4256(%r10)
vmovdqa 3584(%r10), %ymm0
@@ -4030,7 +4041,7 @@ vpsubw 4288(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm8, %ymm8
vpsubw 4992(%r10), %ymm8, %ymm8
vpsubw 2880(%r10), %ymm0, %ymm0
-vpaddw 8064(%rsp), %ymm0, %ymm0
+vpaddw 8064(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3584(%r10)
vmovdqa %ymm8, 4288(%r10)
vmovdqa 3616(%r10), %ymm0
@@ -4038,7 +4049,7 @@ vpsubw 4320(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm9, %ymm9
vpsubw 5024(%r10), %ymm9, %ymm9
vpsubw 2912(%r10), %ymm0, %ymm0
-vpaddw 8096(%rsp), %ymm0, %ymm0
+vpaddw 8096(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3616(%r10)
vmovdqa %ymm9, 4320(%r10)
vmovdqa 3648(%r10), %ymm0
@@ -4046,7 +4057,7 @@ vpsubw 4352(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm10, %ymm10
vpsubw 5056(%r10), %ymm10, %ymm10
vpsubw 2944(%r10), %ymm0, %ymm0
-vpaddw 8128(%rsp), %ymm0, %ymm0
+vpaddw 8128(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3648(%r10)
vmovdqa %ymm10, 4352(%r10)
vmovdqa 3680(%r10), %ymm0
@@ -4054,7 +4065,7 @@ vpsubw 4384(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm11, %ymm11
vpsubw 5088(%r10), %ymm11, %ymm11
vpsubw 2976(%r10), %ymm0, %ymm0
-vpaddw 8160(%rsp), %ymm0, %ymm0
+vpaddw 8160(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3680(%r10)
vmovdqa %ymm11, 4384(%r10)
vmovdqa 3712(%r10), %ymm0
@@ -4062,7 +4073,7 @@ vpsubw 4416(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm12, %ymm12
vpsubw 5120(%r10), %ymm12, %ymm12
vpsubw 3008(%r10), %ymm0, %ymm0
-vpaddw 8192(%rsp), %ymm0, %ymm0
+vpaddw 8192(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3712(%r10)
vmovdqa %ymm12, 4416(%r10)
vmovdqa 3744(%r10), %ymm0
@@ -4070,7 +4081,7 @@ vpsubw 4448(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm13, %ymm13
vpsubw 5152(%r10), %ymm13, %ymm13
vpsubw 3040(%r10), %ymm0, %ymm0
-vpaddw 8224(%rsp), %ymm0, %ymm0
+vpaddw 8224(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3744(%r10)
vmovdqa %ymm13, 4448(%r10)
vmovdqa 3776(%r10), %ymm0
@@ -4078,7 +4089,7 @@ vpsubw 4480(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm14, %ymm14
vpsubw 5184(%r10), %ymm14, %ymm14
vpsubw 3072(%r10), %ymm0, %ymm0
-vpaddw 8256(%rsp), %ymm0, %ymm0
+vpaddw 8256(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3776(%r10)
vmovdqa %ymm14, 4480(%r10)
vmovdqa 3808(%r10), %ymm0
@@ -4086,111 +4097,111 @@ vpsubw 4512(%r10), %ymm0, %ymm0
vpsubw %ymm0, %ymm15, %ymm15
vpsubw 5216(%r10), %ymm15, %ymm15
vpsubw 3104(%r10), %ymm0, %ymm0
-vpaddw 8288(%rsp), %ymm0, %ymm0
+vpaddw 8288(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3808(%r10)
vmovdqa %ymm15, 4512(%r10)
vmovdqa 3840(%r10), %ymm0
vpsubw 4544(%r10), %ymm0, %ymm0
-vmovdqa 9024(%rsp), %ymm1
+vmovdqa 9024(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5248(%r10), %ymm1, %ymm1
vpsubw 3136(%r10), %ymm0, %ymm0
-vpaddw 8320(%rsp), %ymm0, %ymm0
+vpaddw 8320(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3840(%r10)
vmovdqa %ymm1, 4544(%r10)
vmovdqa 3872(%r10), %ymm0
vpsubw 4576(%r10), %ymm0, %ymm0
-vmovdqa 9056(%rsp), %ymm1
+vmovdqa 9056(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5280(%r10), %ymm1, %ymm1
vpsubw 3168(%r10), %ymm0, %ymm0
-vpaddw 8352(%rsp), %ymm0, %ymm0
+vpaddw 8352(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3872(%r10)
vmovdqa %ymm1, 4576(%r10)
vmovdqa 3904(%r10), %ymm0
vpsubw 4608(%r10), %ymm0, %ymm0
-vmovdqa 9088(%rsp), %ymm1
+vmovdqa 9088(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5312(%r10), %ymm1, %ymm1
vpsubw 3200(%r10), %ymm0, %ymm0
-vpaddw 8384(%rsp), %ymm0, %ymm0
+vpaddw 8384(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3904(%r10)
vmovdqa %ymm1, 4608(%r10)
vmovdqa 3936(%r10), %ymm0
vpsubw 4640(%r10), %ymm0, %ymm0
-vmovdqa 9120(%rsp), %ymm1
+vmovdqa 9120(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5344(%r10), %ymm1, %ymm1
vpsubw 3232(%r10), %ymm0, %ymm0
-vpaddw 8416(%rsp), %ymm0, %ymm0
+vpaddw 8416(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3936(%r10)
vmovdqa %ymm1, 4640(%r10)
vmovdqa 3968(%r10), %ymm0
vpsubw 4672(%r10), %ymm0, %ymm0
-vmovdqa 9152(%rsp), %ymm1
+vmovdqa 9152(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5376(%r10), %ymm1, %ymm1
vpsubw 3264(%r10), %ymm0, %ymm0
-vpaddw 8448(%rsp), %ymm0, %ymm0
+vpaddw 8448(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 3968(%r10)
vmovdqa %ymm1, 4672(%r10)
vmovdqa 4000(%r10), %ymm0
vpsubw 4704(%r10), %ymm0, %ymm0
-vmovdqa 9184(%rsp), %ymm1
+vmovdqa 9184(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5408(%r10), %ymm1, %ymm1
vpsubw 3296(%r10), %ymm0, %ymm0
-vpaddw 8480(%rsp), %ymm0, %ymm0
+vpaddw 8480(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 4000(%r10)
vmovdqa %ymm1, 4704(%r10)
vmovdqa 4032(%r10), %ymm0
vpsubw 4736(%r10), %ymm0, %ymm0
-vmovdqa 9216(%rsp), %ymm1
+vmovdqa 9216(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5440(%r10), %ymm1, %ymm1
vpsubw 3328(%r10), %ymm0, %ymm0
-vpaddw 8512(%rsp), %ymm0, %ymm0
+vpaddw 8512(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 4032(%r10)
vmovdqa %ymm1, 4736(%r10)
vmovdqa 4064(%r10), %ymm0
vpsubw 4768(%r10), %ymm0, %ymm0
-vmovdqa 9248(%rsp), %ymm1
+vmovdqa 9248(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5472(%r10), %ymm1, %ymm1
vpsubw 3360(%r10), %ymm0, %ymm0
-vpaddw 8544(%rsp), %ymm0, %ymm0
+vpaddw 8544(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 4064(%r10)
vmovdqa %ymm1, 4768(%r10)
vmovdqa 4096(%r10), %ymm0
vpsubw 4800(%r10), %ymm0, %ymm0
-vmovdqa 9280(%rsp), %ymm1
+vmovdqa 9280(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5504(%r10), %ymm1, %ymm1
vpsubw 3392(%r10), %ymm0, %ymm0
-vpaddw 8576(%rsp), %ymm0, %ymm0
+vpaddw 8576(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 4096(%r10)
vmovdqa %ymm1, 4800(%r10)
vmovdqa 4128(%r10), %ymm0
vpsubw 4832(%r10), %ymm0, %ymm0
-vmovdqa 9312(%rsp), %ymm1
+vmovdqa 9312(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5536(%r10), %ymm1, %ymm1
vpsubw 3424(%r10), %ymm0, %ymm0
-vpaddw 8608(%rsp), %ymm0, %ymm0
+vpaddw 8608(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 4128(%r10)
vmovdqa %ymm1, 4832(%r10)
vmovdqa 4160(%r10), %ymm0
vpsubw 4864(%r10), %ymm0, %ymm0
-vmovdqa 9344(%rsp), %ymm1
+vmovdqa 9344(%r8), %ymm1
vpsubw %ymm0, %ymm1, %ymm1
vpsubw 5568(%r10), %ymm1, %ymm1
vpsubw 3456(%r10), %ymm0, %ymm0
-vpaddw 8640(%rsp), %ymm0, %ymm0
+vpaddw 8640(%r8), %ymm0, %ymm0
vmovdqa %ymm0, 4160(%r10)
vmovdqa %ymm1, 4864(%r10)
vpxor %ymm1, %ymm1, %ymm1
vmovdqa %ymm1, 5600(%r10)
-subq $32, %rsp
+subq $32, %r8
vmovdqa 2816(%r10), %ymm0
vmovdqa 2880(%r10), %ymm1
vmovdqa 2944(%r10), %ymm2
@@ -4231,7 +4242,7 @@ vpunpcklwd 3232(%r10), %ymm2, %ymm0
vpunpckhwd 3232(%r10), %ymm2, %ymm1
vpunpcklwd 3296(%r10), %ymm3, %ymm2
vpunpckhwd 3296(%r10), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -4283,7 +4294,7 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 2496(%r12)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 2688(%r12)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 1344(%r12)
vpermq $78, %ymm11, %ymm11
@@ -4329,7 +4340,7 @@ vpunpcklwd 3744(%r10), %ymm2, %ymm0
vpunpckhwd 3744(%r10), %ymm2, %ymm1
vpunpcklwd 3808(%r10), %ymm3, %ymm2
vpunpckhwd 3808(%r10), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -4381,7 +4392,7 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 2528(%r12)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 2720(%r12)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 1376(%r12)
vpermq $78, %ymm11, %ymm11
@@ -4427,7 +4438,7 @@ vpunpcklwd 4256(%r10), %ymm2, %ymm0
vpunpckhwd 4256(%r10), %ymm2, %ymm1
vpunpcklwd 4320(%r10), %ymm3, %ymm2
vpunpckhwd 4320(%r10), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -4479,7 +4490,7 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 2560(%r12)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 2752(%r12)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 1408(%r12)
vpermq $78, %ymm11, %ymm11
@@ -4525,7 +4536,7 @@ vpunpcklwd 4640(%r10), %ymm2, %ymm0
vpunpckhwd 4640(%r10), %ymm2, %ymm1
vpunpcklwd 4704(%r10), %ymm3, %ymm2
vpunpckhwd 4704(%r10), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -4577,7 +4588,7 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 2592(%r12)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 2784(%r12)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 1440(%r12)
vpermq $78, %ymm11, %ymm11
@@ -4623,7 +4634,7 @@ vpunpcklwd 5152(%r10), %ymm2, %ymm0
vpunpckhwd 5152(%r10), %ymm2, %ymm1
vpunpcklwd 5216(%r10), %ymm3, %ymm2
vpunpckhwd 5216(%r10), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -4675,7 +4686,7 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 2624(%r12)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 2816(%r12)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 1472(%r12)
vpermq $78, %ymm11, %ymm11
@@ -4721,7 +4732,7 @@ vpunpcklwd 5664(%r10), %ymm2, %ymm0
vpunpckhwd 5664(%r10), %ymm2, %ymm1
vpunpcklwd 5728(%r10), %ymm3, %ymm2
vpunpckhwd 5728(%r10), %ymm3, %ymm3
-vmovdqa %ymm11, 0(%rsp)
+vmovdqa %ymm11, 0(%r8)
vpunpckldq %ymm14, %ymm12, %ymm11
vpunpckhdq %ymm14, %ymm12, %ymm12
vpunpckldq %ymm15, %ymm13, %ymm14
@@ -4773,54 +4784,53 @@ vinserti128 $0, %xmm9, %ymm2, %ymm15
vmovdqa %ymm15, 2656(%r12)
vinserti128 $0, %xmm10, %ymm14, %ymm15
vmovdqa %ymm15, 2848(%r12)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa 0(%r8), %ymm11
vinserti128 $1, %xmm1, %ymm11, %ymm14
vmovdqa %ymm14, 1504(%r12)
vpermq $78, %ymm11, %ymm11
vinserti128 $0, %xmm11, %ymm1, %ymm1
vmovdqa %ymm1, 3040(%r12)
-addq $32, %rsp
+addq $32, %r8
add $1536, %rax
add $1536, %r11
add $3072, %r12
dec %ecx
jnz karatsuba_loop_4eced63f144beffcb0247f9c6f67d165
sub $12288, %r12
-add $9408, %rsp
-subq $2400, %rsp
+add $9408-2400, %r8
vpxor %ymm0, %ymm0, %ymm0
-vmovdqa %ymm0, 1792(%rsp)
-vmovdqa %ymm0, 1824(%rsp)
-vmovdqa %ymm0, 1856(%rsp)
-vmovdqa %ymm0, 1888(%rsp)
-vmovdqa %ymm0, 1920(%rsp)
-vmovdqa %ymm0, 1952(%rsp)
-vmovdqa %ymm0, 1984(%rsp)
-vmovdqa %ymm0, 2016(%rsp)
-vmovdqa %ymm0, 2048(%rsp)
-vmovdqa %ymm0, 2080(%rsp)
-vmovdqa %ymm0, 2112(%rsp)
-vmovdqa %ymm0, 2144(%rsp)
-vmovdqa %ymm0, 2176(%rsp)
-vmovdqa %ymm0, 2208(%rsp)
-vmovdqa %ymm0, 2240(%rsp)
-vmovdqa %ymm0, 2272(%rsp)
-vmovdqa %ymm0, 2304(%rsp)
-vmovdqa %ymm0, 2336(%rsp)
-vmovdqa %ymm0, 2368(%rsp)
-vmovdqa %ymm0, 2400(%rsp)
-vmovdqa %ymm0, 2432(%rsp)
-vmovdqa %ymm0, 2464(%rsp)
-vmovdqa %ymm0, 2496(%rsp)
-vmovdqa %ymm0, 2528(%rsp)
-vmovdqa %ymm0, 2560(%rsp)
-vmovdqa %ymm0, 2592(%rsp)
-vmovdqa %ymm0, 2624(%rsp)
-vmovdqa %ymm0, 2656(%rsp)
-vmovdqa %ymm0, 2688(%rsp)
-vmovdqa %ymm0, 2720(%rsp)
-vmovdqa %ymm0, 2752(%rsp)
-vmovdqa %ymm0, 2784(%rsp)
+vmovdqa %ymm0, 1792(%r8)
+vmovdqa %ymm0, 1824(%r8)
+vmovdqa %ymm0, 1856(%r8)
+vmovdqa %ymm0, 1888(%r8)
+vmovdqa %ymm0, 1920(%r8)
+vmovdqa %ymm0, 1952(%r8)
+vmovdqa %ymm0, 1984(%r8)
+vmovdqa %ymm0, 2016(%r8)
+vmovdqa %ymm0, 2048(%r8)
+vmovdqa %ymm0, 2080(%r8)
+vmovdqa %ymm0, 2112(%r8)
+vmovdqa %ymm0, 2144(%r8)
+vmovdqa %ymm0, 2176(%r8)
+vmovdqa %ymm0, 2208(%r8)
+vmovdqa %ymm0, 2240(%r8)
+vmovdqa %ymm0, 2272(%r8)
+vmovdqa %ymm0, 2304(%r8)
+vmovdqa %ymm0, 2336(%r8)
+vmovdqa %ymm0, 2368(%r8)
+vmovdqa %ymm0, 2400(%r8)
+vmovdqa %ymm0, 2432(%r8)
+vmovdqa %ymm0, 2464(%r8)
+vmovdqa %ymm0, 2496(%r8)
+vmovdqa %ymm0, 2528(%r8)
+vmovdqa %ymm0, 2560(%r8)
+vmovdqa %ymm0, 2592(%r8)
+vmovdqa %ymm0, 2624(%r8)
+vmovdqa %ymm0, 2656(%r8)
+vmovdqa %ymm0, 2688(%r8)
+vmovdqa %ymm0, 2720(%r8)
+vmovdqa %ymm0, 2752(%r8)
+vmovdqa %ymm0, 2784(%r8)
vmovdqa const729(%rip), %ymm15
vmovdqa const3_inv(%rip), %ymm14
vmovdqa const5_inv(%rip), %ymm13
@@ -4860,14 +4870,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 0(%r12), %ymm8
vmovdqa 864(%r12), %ymm9
-vmovdqa %ymm8, 0(%rsp)
-vmovdqa %ymm0, 32(%rsp)
-vmovdqa %ymm1, 64(%rsp)
-vmovdqa %ymm7, 96(%rsp)
-vmovdqa %ymm5, 128(%rsp)
-vmovdqa %ymm2, 160(%rsp)
-vmovdqa %ymm3, 192(%rsp)
-vmovdqa %ymm9, 224(%rsp)
+vmovdqa %ymm8, 0(%r8)
+vmovdqa %ymm0, 32(%r8)
+vmovdqa %ymm1, 64(%r8)
+vmovdqa %ymm7, 96(%r8)
+vmovdqa %ymm5, 128(%r8)
+vmovdqa %ymm2, 160(%r8)
+vmovdqa %ymm3, 192(%r8)
+vmovdqa %ymm9, 224(%r8)
vmovdqa 1824(%r12), %ymm0
vpsubw 1920(%r12), %ymm0, %ymm0
vmovdqa 2208(%r12), %ymm1
@@ -4903,14 +4913,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 1728(%r12), %ymm8
vmovdqa 2592(%r12), %ymm9
-vmovdqa %ymm8, 256(%rsp)
-vmovdqa %ymm0, 288(%rsp)
-vmovdqa %ymm1, 320(%rsp)
-vmovdqa %ymm7, 352(%rsp)
-vmovdqa %ymm5, 384(%rsp)
-vmovdqa %ymm2, 416(%rsp)
-vmovdqa %ymm3, 448(%rsp)
-vmovdqa %ymm9, 480(%rsp)
+vmovdqa %ymm8, 256(%r8)
+vmovdqa %ymm0, 288(%r8)
+vmovdqa %ymm1, 320(%r8)
+vmovdqa %ymm7, 352(%r8)
+vmovdqa %ymm5, 384(%r8)
+vmovdqa %ymm2, 416(%r8)
+vmovdqa %ymm3, 448(%r8)
+vmovdqa %ymm9, 480(%r8)
vmovdqa 3552(%r12), %ymm0
vpsubw 3648(%r12), %ymm0, %ymm0
vmovdqa 3936(%r12), %ymm1
@@ -4946,14 +4956,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 3456(%r12), %ymm8
vmovdqa 4320(%r12), %ymm9
-vmovdqa %ymm8, 512(%rsp)
-vmovdqa %ymm0, 544(%rsp)
-vmovdqa %ymm1, 576(%rsp)
-vmovdqa %ymm7, 608(%rsp)
-vmovdqa %ymm5, 640(%rsp)
-vmovdqa %ymm2, 672(%rsp)
-vmovdqa %ymm3, 704(%rsp)
-vmovdqa %ymm9, 736(%rsp)
+vmovdqa %ymm8, 512(%r8)
+vmovdqa %ymm0, 544(%r8)
+vmovdqa %ymm1, 576(%r8)
+vmovdqa %ymm7, 608(%r8)
+vmovdqa %ymm5, 640(%r8)
+vmovdqa %ymm2, 672(%r8)
+vmovdqa %ymm3, 704(%r8)
+vmovdqa %ymm9, 736(%r8)
vmovdqa 5280(%r12), %ymm0
vpsubw 5376(%r12), %ymm0, %ymm0
vmovdqa 5664(%r12), %ymm1
@@ -4989,14 +4999,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 5184(%r12), %ymm8
vmovdqa 6048(%r12), %ymm9
-vmovdqa %ymm8, 768(%rsp)
-vmovdqa %ymm0, 800(%rsp)
-vmovdqa %ymm1, 832(%rsp)
-vmovdqa %ymm7, 864(%rsp)
-vmovdqa %ymm5, 896(%rsp)
-vmovdqa %ymm2, 928(%rsp)
-vmovdqa %ymm3, 960(%rsp)
-vmovdqa %ymm9, 992(%rsp)
+vmovdqa %ymm8, 768(%r8)
+vmovdqa %ymm0, 800(%r8)
+vmovdqa %ymm1, 832(%r8)
+vmovdqa %ymm7, 864(%r8)
+vmovdqa %ymm5, 896(%r8)
+vmovdqa %ymm2, 928(%r8)
+vmovdqa %ymm3, 960(%r8)
+vmovdqa %ymm9, 992(%r8)
vmovdqa 7008(%r12), %ymm0
vpsubw 7104(%r12), %ymm0, %ymm0
vmovdqa 7392(%r12), %ymm1
@@ -5032,14 +5042,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 6912(%r12), %ymm8
vmovdqa 7776(%r12), %ymm9
-vmovdqa %ymm8, 1024(%rsp)
-vmovdqa %ymm0, 1056(%rsp)
-vmovdqa %ymm1, 1088(%rsp)
-vmovdqa %ymm7, 1120(%rsp)
-vmovdqa %ymm5, 1152(%rsp)
-vmovdqa %ymm2, 1184(%rsp)
-vmovdqa %ymm3, 1216(%rsp)
-vmovdqa %ymm9, 1248(%rsp)
+vmovdqa %ymm8, 1024(%r8)
+vmovdqa %ymm0, 1056(%r8)
+vmovdqa %ymm1, 1088(%r8)
+vmovdqa %ymm7, 1120(%r8)
+vmovdqa %ymm5, 1152(%r8)
+vmovdqa %ymm2, 1184(%r8)
+vmovdqa %ymm3, 1216(%r8)
+vmovdqa %ymm9, 1248(%r8)
vmovdqa 8736(%r12), %ymm0
vpsubw 8832(%r12), %ymm0, %ymm0
vmovdqa 9120(%r12), %ymm1
@@ -5075,14 +5085,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 8640(%r12), %ymm8
vmovdqa 9504(%r12), %ymm9
-vmovdqa %ymm8, 1280(%rsp)
-vmovdqa %ymm0, 1312(%rsp)
-vmovdqa %ymm1, 1344(%rsp)
-vmovdqa %ymm7, 1376(%rsp)
-vmovdqa %ymm5, 1408(%rsp)
-vmovdqa %ymm2, 1440(%rsp)
-vmovdqa %ymm3, 1472(%rsp)
-vmovdqa %ymm9, 1504(%rsp)
+vmovdqa %ymm8, 1280(%r8)
+vmovdqa %ymm0, 1312(%r8)
+vmovdqa %ymm1, 1344(%r8)
+vmovdqa %ymm7, 1376(%r8)
+vmovdqa %ymm5, 1408(%r8)
+vmovdqa %ymm2, 1440(%r8)
+vmovdqa %ymm3, 1472(%r8)
+vmovdqa %ymm9, 1504(%r8)
vmovdqa 10464(%r12), %ymm0
vpsubw 10560(%r12), %ymm0, %ymm0
vmovdqa 10848(%r12), %ymm1
@@ -5118,23 +5128,23 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 10368(%r12), %ymm8
vmovdqa 11232(%r12), %ymm9
-vmovdqa %ymm8, 1536(%rsp)
-vmovdqa %ymm0, 1568(%rsp)
-vmovdqa %ymm1, 1600(%rsp)
-vmovdqa %ymm7, 1632(%rsp)
-vmovdqa %ymm5, 1664(%rsp)
-vmovdqa %ymm2, 1696(%rsp)
-vmovdqa %ymm3, 1728(%rsp)
-vmovdqa %ymm9, 1760(%rsp)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa %ymm8, 1536(%r8)
+vmovdqa %ymm0, 1568(%r8)
+vmovdqa %ymm1, 1600(%r8)
+vmovdqa %ymm7, 1632(%r8)
+vmovdqa %ymm5, 1664(%r8)
+vmovdqa %ymm2, 1696(%r8)
+vmovdqa %ymm3, 1728(%r8)
+vmovdqa %ymm9, 1760(%r8)
+vmovdqa 0(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm10
vpunpckhwd const0(%rip), %ymm11, %ymm9
vpslld $1, %ymm10, %ymm10
vpslld $1, %ymm9, %ymm9
-vmovdqa 256(%rsp), %ymm8
+vmovdqa 256(%r8), %ymm8
vpunpcklwd const0(%rip), %ymm8, %ymm7
vpunpckhwd const0(%rip), %ymm8, %ymm8
-vmovdqa 512(%rsp), %ymm6
+vmovdqa 512(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm7, %ymm4
@@ -5148,7 +5158,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1536(%rsp), %ymm5
+vmovdqa 1536(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm8
vpunpckhwd const0(%rip), %ymm5, %ymm7
vpslld $1, %ymm8, %ymm8
@@ -5160,9 +5170,9 @@ vpsrld $1, %ymm3, %ymm3
vpand mask32_to_16(%rip), %ymm4, %ymm4
vpand mask32_to_16(%rip), %ymm3, %ymm3
vpackusdw %ymm3, %ymm4, %ymm3
-vmovdqa 768(%rsp), %ymm4
-vpaddw 1024(%rsp), %ymm4, %ymm7
-vpsubw 1024(%rsp), %ymm4, %ymm4
+vmovdqa 768(%r8), %ymm4
+vpaddw 1024(%r8), %ymm4, %ymm7
+vpsubw 1024(%r8), %ymm4, %ymm4
vpsrlw $2, %ymm4, %ymm4
vpsubw %ymm6, %ymm4, %ymm4
vpmullw %ymm14, %ymm4, %ymm4
@@ -5172,7 +5182,7 @@ vpsllw $7, %ymm5, %ymm7
vpsubw %ymm7, %ymm8, %ymm7
vpsrlw $3, %ymm7, %ymm7
vpsubw %ymm3, %ymm7, %ymm7
-vmovdqa 1280(%rsp), %ymm8
+vmovdqa 1280(%r8), %ymm8
vpsubw %ymm11, %ymm8, %ymm8
vpmullw %ymm15, %ymm5, %ymm9
vpsubw %ymm9, %ymm8, %ymm9
@@ -5197,7 +5207,7 @@ vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm10
vpor %ymm10, %ymm7, %ymm7
vpaddw %ymm7, %ymm11, %ymm11
-vmovdqa %xmm9, 2048(%rsp)
+vmovdqa %xmm9, 2048(%r8)
vpshufb shuf48_16(%rip), %ymm8, %ymm8
vpand mask3_5_3_5(%rip), %ymm8, %ymm9
vpand mask5_3_5_3(%rip), %ymm8, %ymm8
@@ -5205,7 +5215,7 @@ vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm10
vpor %ymm10, %ymm8, %ymm8
vpaddw %ymm8, %ymm6, %ymm6
-vmovdqa %xmm9, 2304(%rsp)
+vmovdqa %xmm9, 2304(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_3_5(%rip), %ymm5, %ymm9
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
@@ -5213,7 +5223,7 @@ vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm10
vpor %ymm10, %ymm5, %ymm5
vpaddw %ymm5, %ymm3, %ymm3
-vmovdqa %xmm9, 2560(%rsp)
+vmovdqa %xmm9, 2560(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 0(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -5222,15 +5232,15 @@ vpand mask_mod8192(%rip), %ymm3, %ymm3
vmovdqu %ymm3, 704(%rdi)
vpand mask_mod8192(%rip), %ymm4, %ymm4
vmovdqu %ymm4, 1056(%rdi)
-vmovdqa 32(%rsp), %ymm5
+vmovdqa 32(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm8
vpunpckhwd const0(%rip), %ymm5, %ymm7
vpslld $1, %ymm8, %ymm8
vpslld $1, %ymm7, %ymm7
-vmovdqa 288(%rsp), %ymm4
+vmovdqa 288(%r8), %ymm4
vpunpcklwd const0(%rip), %ymm4, %ymm3
vpunpckhwd const0(%rip), %ymm4, %ymm4
-vmovdqa 544(%rsp), %ymm6
+vmovdqa 544(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm3, %ymm9
@@ -5244,7 +5254,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1568(%rsp), %ymm11
+vmovdqa 1568(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm4
vpunpckhwd const0(%rip), %ymm11, %ymm3
vpslld $1, %ymm4, %ymm4
@@ -5256,9 +5266,9 @@ vpsrld $1, %ymm10, %ymm10
vpand mask32_to_16(%rip), %ymm9, %ymm9
vpand mask32_to_16(%rip), %ymm10, %ymm10
vpackusdw %ymm10, %ymm9, %ymm10
-vmovdqa 800(%rsp), %ymm9
-vpaddw 1056(%rsp), %ymm9, %ymm3
-vpsubw 1056(%rsp), %ymm9, %ymm9
+vmovdqa 800(%r8), %ymm9
+vpaddw 1056(%r8), %ymm9, %ymm3
+vpsubw 1056(%r8), %ymm9, %ymm9
vpsrlw $2, %ymm9, %ymm9
vpsubw %ymm6, %ymm9, %ymm9
vpmullw %ymm14, %ymm9, %ymm9
@@ -5268,7 +5278,7 @@ vpsllw $7, %ymm11, %ymm3
vpsubw %ymm3, %ymm4, %ymm3
vpsrlw $3, %ymm3, %ymm3
vpsubw %ymm10, %ymm3, %ymm3
-vmovdqa 1312(%rsp), %ymm4
+vmovdqa 1312(%r8), %ymm4
vpsubw %ymm5, %ymm4, %ymm4
vpmullw %ymm15, %ymm11, %ymm7
vpsubw %ymm7, %ymm4, %ymm7
@@ -5293,7 +5303,7 @@ vpermq $206, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm8
vpor %ymm8, %ymm3, %ymm3
vpaddw %ymm3, %ymm5, %ymm5
-vmovdqa %xmm7, 2080(%rsp)
+vmovdqa %xmm7, 2080(%r8)
vpshufb shuf48_16(%rip), %ymm4, %ymm4
vpand mask3_5_3_5(%rip), %ymm4, %ymm7
vpand mask5_3_5_3(%rip), %ymm4, %ymm4
@@ -5301,7 +5311,7 @@ vpermq $206, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm8
vpor %ymm8, %ymm4, %ymm4
vpaddw %ymm4, %ymm6, %ymm6
-vmovdqa %xmm7, 2336(%rsp)
+vmovdqa %xmm7, 2336(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_3_5(%rip), %ymm11, %ymm7
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
@@ -5309,7 +5319,7 @@ vpermq $206, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm8
vpor %ymm8, %ymm11, %ymm11
vpaddw %ymm11, %ymm10, %ymm10
-vmovdqa %xmm7, 2592(%rsp)
+vmovdqa %xmm7, 2592(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %ymm5, 88(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -5318,15 +5328,15 @@ vpand mask_mod8192(%rip), %ymm10, %ymm10
vmovdqu %ymm10, 792(%rdi)
vpand mask_mod8192(%rip), %ymm9, %ymm9
vmovdqu %ymm9, 1144(%rdi)
-vmovdqa 64(%rsp), %ymm11
+vmovdqa 64(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm4
vpunpckhwd const0(%rip), %ymm11, %ymm3
vpslld $1, %ymm4, %ymm4
vpslld $1, %ymm3, %ymm3
-vmovdqa 320(%rsp), %ymm9
+vmovdqa 320(%r8), %ymm9
vpunpcklwd const0(%rip), %ymm9, %ymm10
vpunpckhwd const0(%rip), %ymm9, %ymm9
-vmovdqa 576(%rsp), %ymm6
+vmovdqa 576(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm10, %ymm7
@@ -5340,7 +5350,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1600(%rsp), %ymm5
+vmovdqa 1600(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm9
vpunpckhwd const0(%rip), %ymm5, %ymm10
vpslld $1, %ymm9, %ymm9
@@ -5352,9 +5362,9 @@ vpsrld $1, %ymm8, %ymm8
vpand mask32_to_16(%rip), %ymm7, %ymm7
vpand mask32_to_16(%rip), %ymm8, %ymm8
vpackusdw %ymm8, %ymm7, %ymm8
-vmovdqa 832(%rsp), %ymm7
-vpaddw 1088(%rsp), %ymm7, %ymm10
-vpsubw 1088(%rsp), %ymm7, %ymm7
+vmovdqa 832(%r8), %ymm7
+vpaddw 1088(%r8), %ymm7, %ymm10
+vpsubw 1088(%r8), %ymm7, %ymm7
vpsrlw $2, %ymm7, %ymm7
vpsubw %ymm6, %ymm7, %ymm7
vpmullw %ymm14, %ymm7, %ymm7
@@ -5364,7 +5374,7 @@ vpsllw $7, %ymm5, %ymm10
vpsubw %ymm10, %ymm9, %ymm10
vpsrlw $3, %ymm10, %ymm10
vpsubw %ymm8, %ymm10, %ymm10
-vmovdqa 1344(%rsp), %ymm9
+vmovdqa 1344(%r8), %ymm9
vpsubw %ymm11, %ymm9, %ymm9
vpmullw %ymm15, %ymm5, %ymm3
vpsubw %ymm3, %ymm9, %ymm3
@@ -5389,7 +5399,7 @@ vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm4
vpor %ymm4, %ymm10, %ymm10
vpaddw %ymm10, %ymm11, %ymm11
-vmovdqa %xmm3, 2112(%rsp)
+vmovdqa %xmm3, 2112(%r8)
vpshufb shuf48_16(%rip), %ymm9, %ymm9
vpand mask3_5_3_5(%rip), %ymm9, %ymm3
vpand mask5_3_5_3(%rip), %ymm9, %ymm9
@@ -5397,7 +5407,7 @@ vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm4
vpor %ymm4, %ymm9, %ymm9
vpaddw %ymm9, %ymm6, %ymm6
-vmovdqa %xmm3, 2368(%rsp)
+vmovdqa %xmm3, 2368(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_3_5(%rip), %ymm5, %ymm3
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
@@ -5405,7 +5415,7 @@ vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm4
vpor %ymm4, %ymm5, %ymm5
vpaddw %ymm5, %ymm8, %ymm8
-vmovdqa %xmm3, 2624(%rsp)
+vmovdqa %xmm3, 2624(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 176(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -5414,15 +5424,15 @@ vpand mask_mod8192(%rip), %ymm8, %ymm8
vmovdqu %ymm8, 880(%rdi)
vpand mask_mod8192(%rip), %ymm7, %ymm7
vmovdqu %ymm7, 1232(%rdi)
-vmovdqa 96(%rsp), %ymm5
+vmovdqa 96(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm9
vpunpckhwd const0(%rip), %ymm5, %ymm10
vpslld $1, %ymm9, %ymm9
vpslld $1, %ymm10, %ymm10
-vmovdqa 352(%rsp), %ymm7
+vmovdqa 352(%r8), %ymm7
vpunpcklwd const0(%rip), %ymm7, %ymm8
vpunpckhwd const0(%rip), %ymm7, %ymm7
-vmovdqa 608(%rsp), %ymm6
+vmovdqa 608(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm8, %ymm3
@@ -5436,7 +5446,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1632(%rsp), %ymm11
+vmovdqa 1632(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm7
vpunpckhwd const0(%rip), %ymm11, %ymm8
vpslld $1, %ymm7, %ymm7
@@ -5448,9 +5458,9 @@ vpsrld $1, %ymm4, %ymm4
vpand mask32_to_16(%rip), %ymm3, %ymm3
vpand mask32_to_16(%rip), %ymm4, %ymm4
vpackusdw %ymm4, %ymm3, %ymm4
-vmovdqa 864(%rsp), %ymm3
-vpaddw 1120(%rsp), %ymm3, %ymm8
-vpsubw 1120(%rsp), %ymm3, %ymm3
+vmovdqa 864(%r8), %ymm3
+vpaddw 1120(%r8), %ymm3, %ymm8
+vpsubw 1120(%r8), %ymm3, %ymm3
vpsrlw $2, %ymm3, %ymm3
vpsubw %ymm6, %ymm3, %ymm3
vpmullw %ymm14, %ymm3, %ymm3
@@ -5460,7 +5470,7 @@ vpsllw $7, %ymm11, %ymm8
vpsubw %ymm8, %ymm7, %ymm8
vpsrlw $3, %ymm8, %ymm8
vpsubw %ymm4, %ymm8, %ymm8
-vmovdqa 1376(%rsp), %ymm7
+vmovdqa 1376(%r8), %ymm7
vpsubw %ymm5, %ymm7, %ymm7
vpmullw %ymm15, %ymm11, %ymm10
vpsubw %ymm10, %ymm7, %ymm10
@@ -5485,7 +5495,7 @@ vpermq $206, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm9
vpor %ymm9, %ymm8, %ymm8
vpaddw %ymm8, %ymm5, %ymm5
-vmovdqa %xmm10, 2144(%rsp)
+vmovdqa %xmm10, 2144(%r8)
vpshufb shuf48_16(%rip), %ymm7, %ymm7
vpand mask3_5_3_5(%rip), %ymm7, %ymm10
vpand mask5_3_5_3(%rip), %ymm7, %ymm7
@@ -5493,7 +5503,7 @@ vpermq $206, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm9
vpor %ymm9, %ymm7, %ymm7
vpaddw %ymm7, %ymm6, %ymm6
-vmovdqa %xmm10, 2400(%rsp)
+vmovdqa %xmm10, 2400(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_3_5(%rip), %ymm11, %ymm10
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
@@ -5501,7 +5511,7 @@ vpermq $206, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm9
vpor %ymm9, %ymm11, %ymm11
vpaddw %ymm11, %ymm4, %ymm4
-vmovdqa %xmm10, 2656(%rsp)
+vmovdqa %xmm10, 2656(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %ymm5, 264(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -5510,15 +5520,15 @@ vpand mask_mod8192(%rip), %ymm4, %ymm4
vmovdqu %ymm4, 968(%rdi)
vpand mask_mod8192(%rip), %ymm3, %ymm3
vmovdqu %ymm3, 1320(%rdi)
-vmovdqa 128(%rsp), %ymm11
+vmovdqa 128(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm7
vpunpckhwd const0(%rip), %ymm11, %ymm8
vpslld $1, %ymm7, %ymm7
vpslld $1, %ymm8, %ymm8
-vmovdqa 384(%rsp), %ymm3
+vmovdqa 384(%r8), %ymm3
vpunpcklwd const0(%rip), %ymm3, %ymm4
vpunpckhwd const0(%rip), %ymm3, %ymm3
-vmovdqa 640(%rsp), %ymm6
+vmovdqa 640(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm4, %ymm10
@@ -5532,7 +5542,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1664(%rsp), %ymm5
+vmovdqa 1664(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm3
vpunpckhwd const0(%rip), %ymm5, %ymm4
vpslld $1, %ymm3, %ymm3
@@ -5544,9 +5554,9 @@ vpsrld $1, %ymm9, %ymm9
vpand mask32_to_16(%rip), %ymm10, %ymm10
vpand mask32_to_16(%rip), %ymm9, %ymm9
vpackusdw %ymm9, %ymm10, %ymm9
-vmovdqa 896(%rsp), %ymm10
-vpaddw 1152(%rsp), %ymm10, %ymm4
-vpsubw 1152(%rsp), %ymm10, %ymm10
+vmovdqa 896(%r8), %ymm10
+vpaddw 1152(%r8), %ymm10, %ymm4
+vpsubw 1152(%r8), %ymm10, %ymm10
vpsrlw $2, %ymm10, %ymm10
vpsubw %ymm6, %ymm10, %ymm10
vpmullw %ymm14, %ymm10, %ymm10
@@ -5556,7 +5566,7 @@ vpsllw $7, %ymm5, %ymm4
vpsubw %ymm4, %ymm3, %ymm4
vpsrlw $3, %ymm4, %ymm4
vpsubw %ymm9, %ymm4, %ymm4
-vmovdqa 1408(%rsp), %ymm3
+vmovdqa 1408(%r8), %ymm3
vpsubw %ymm11, %ymm3, %ymm3
vpmullw %ymm15, %ymm5, %ymm8
vpsubw %ymm8, %ymm3, %ymm8
@@ -5590,7 +5600,7 @@ vmovdqu 0(%rdi), %ymm7
vpaddw %ymm10, %ymm7, %ymm7
vpand mask_mod8192(%rip), %ymm7, %ymm7
vmovdqu %ymm7, 0(%rdi)
-vmovdqa %xmm2, 1920(%rsp)
+vmovdqa %xmm2, 1920(%r8)
vpshufb shuf48_16(%rip), %ymm4, %ymm4
vpand mask3_5_3_5(%rip), %ymm4, %ymm2
vpand mask5_3_5_3(%rip), %ymm4, %ymm4
@@ -5598,7 +5608,7 @@ vpermq $206, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm7
vpor %ymm7, %ymm4, %ymm4
vpaddw %ymm4, %ymm11, %ymm11
-vmovdqa %xmm2, 2176(%rsp)
+vmovdqa %xmm2, 2176(%r8)
vpshufb shuf48_16(%rip), %ymm3, %ymm3
vpand mask3_5_3_5(%rip), %ymm3, %ymm2
vpand mask5_3_5_3(%rip), %ymm3, %ymm3
@@ -5606,7 +5616,7 @@ vpermq $206, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm7
vpor %ymm7, %ymm3, %ymm3
vpaddw %ymm3, %ymm6, %ymm6
-vmovdqa %xmm2, 2432(%rsp)
+vmovdqa %xmm2, 2432(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_3_5(%rip), %ymm5, %ymm2
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
@@ -5614,22 +5624,22 @@ vpermq $206, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm7
vpor %ymm7, %ymm5, %ymm5
vpaddw %ymm5, %ymm9, %ymm9
-vmovdqa %xmm2, 2688(%rsp)
+vmovdqa %xmm2, 2688(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 352(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
vmovdqu %ymm6, 704(%rdi)
vpand mask_mod8192(%rip), %ymm9, %ymm9
vmovdqu %ymm9, 1056(%rdi)
-vmovdqa 160(%rsp), %ymm5
+vmovdqa 160(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm3
vpunpckhwd const0(%rip), %ymm5, %ymm4
vpslld $1, %ymm3, %ymm3
vpslld $1, %ymm4, %ymm4
-vmovdqa 416(%rsp), %ymm10
+vmovdqa 416(%r8), %ymm10
vpunpcklwd const0(%rip), %ymm10, %ymm9
vpunpckhwd const0(%rip), %ymm10, %ymm10
-vmovdqa 672(%rsp), %ymm6
+vmovdqa 672(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm9, %ymm2
@@ -5643,7 +5653,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1696(%rsp), %ymm11
+vmovdqa 1696(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm10
vpunpckhwd const0(%rip), %ymm11, %ymm9
vpslld $1, %ymm10, %ymm10
@@ -5655,9 +5665,9 @@ vpsrld $1, %ymm7, %ymm7
vpand mask32_to_16(%rip), %ymm2, %ymm2
vpand mask32_to_16(%rip), %ymm7, %ymm7
vpackusdw %ymm7, %ymm2, %ymm7
-vmovdqa 928(%rsp), %ymm2
-vpaddw 1184(%rsp), %ymm2, %ymm9
-vpsubw 1184(%rsp), %ymm2, %ymm2
+vmovdqa 928(%r8), %ymm2
+vpaddw 1184(%r8), %ymm2, %ymm9
+vpsubw 1184(%r8), %ymm2, %ymm2
vpsrlw $2, %ymm2, %ymm2
vpsubw %ymm6, %ymm2, %ymm2
vpmullw %ymm14, %ymm2, %ymm2
@@ -5667,7 +5677,7 @@ vpsllw $7, %ymm11, %ymm9
vpsubw %ymm9, %ymm10, %ymm9
vpsrlw $3, %ymm9, %ymm9
vpsubw %ymm7, %ymm9, %ymm9
-vmovdqa 1440(%rsp), %ymm10
+vmovdqa 1440(%r8), %ymm10
vpsubw %ymm5, %ymm10, %ymm10
vpmullw %ymm15, %ymm11, %ymm4
vpsubw %ymm4, %ymm10, %ymm4
@@ -5701,7 +5711,7 @@ vmovdqu 88(%rdi), %ymm3
vpaddw %ymm2, %ymm3, %ymm3
vpand mask_mod8192(%rip), %ymm3, %ymm3
vmovdqu %ymm3, 88(%rdi)
-vmovdqa %xmm8, 1952(%rsp)
+vmovdqa %xmm8, 1952(%r8)
vpshufb shuf48_16(%rip), %ymm9, %ymm9
vpand mask3_5_3_5(%rip), %ymm9, %ymm8
vpand mask5_3_5_3(%rip), %ymm9, %ymm9
@@ -5709,7 +5719,7 @@ vpermq $206, %ymm8, %ymm8
vpand mask_keephigh(%rip), %ymm8, %ymm3
vpor %ymm3, %ymm9, %ymm9
vpaddw %ymm9, %ymm5, %ymm5
-vmovdqa %xmm8, 2208(%rsp)
+vmovdqa %xmm8, 2208(%r8)
vpshufb shuf48_16(%rip), %ymm10, %ymm10
vpand mask3_5_3_5(%rip), %ymm10, %ymm8
vpand mask5_3_5_3(%rip), %ymm10, %ymm10
@@ -5717,7 +5727,7 @@ vpermq $206, %ymm8, %ymm8
vpand mask_keephigh(%rip), %ymm8, %ymm3
vpor %ymm3, %ymm10, %ymm10
vpaddw %ymm10, %ymm6, %ymm6
-vmovdqa %xmm8, 2464(%rsp)
+vmovdqa %xmm8, 2464(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_3_5(%rip), %ymm11, %ymm8
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
@@ -5725,22 +5735,22 @@ vpermq $206, %ymm8, %ymm8
vpand mask_keephigh(%rip), %ymm8, %ymm3
vpor %ymm3, %ymm11, %ymm11
vpaddw %ymm11, %ymm7, %ymm7
-vmovdqa %xmm8, 2720(%rsp)
+vmovdqa %xmm8, 2720(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %ymm5, 440(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
vmovdqu %ymm6, 792(%rdi)
vpand mask_mod8192(%rip), %ymm7, %ymm7
vmovdqu %ymm7, 1144(%rdi)
-vmovdqa 192(%rsp), %ymm11
+vmovdqa 192(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm10
vpunpckhwd const0(%rip), %ymm11, %ymm9
vpslld $1, %ymm10, %ymm10
vpslld $1, %ymm9, %ymm9
-vmovdqa 448(%rsp), %ymm2
+vmovdqa 448(%r8), %ymm2
vpunpcklwd const0(%rip), %ymm2, %ymm7
vpunpckhwd const0(%rip), %ymm2, %ymm2
-vmovdqa 704(%rsp), %ymm6
+vmovdqa 704(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm7, %ymm8
@@ -5754,7 +5764,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1728(%rsp), %ymm5
+vmovdqa 1728(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm2
vpunpckhwd const0(%rip), %ymm5, %ymm7
vpslld $1, %ymm2, %ymm2
@@ -5766,9 +5776,9 @@ vpsrld $1, %ymm3, %ymm3
vpand mask32_to_16(%rip), %ymm8, %ymm8
vpand mask32_to_16(%rip), %ymm3, %ymm3
vpackusdw %ymm3, %ymm8, %ymm3
-vmovdqa 960(%rsp), %ymm8
-vpaddw 1216(%rsp), %ymm8, %ymm7
-vpsubw 1216(%rsp), %ymm8, %ymm8
+vmovdqa 960(%r8), %ymm8
+vpaddw 1216(%r8), %ymm8, %ymm7
+vpsubw 1216(%r8), %ymm8, %ymm8
vpsrlw $2, %ymm8, %ymm8
vpsubw %ymm6, %ymm8, %ymm8
vpmullw %ymm14, %ymm8, %ymm8
@@ -5778,7 +5788,7 @@ vpsllw $7, %ymm5, %ymm7
vpsubw %ymm7, %ymm2, %ymm7
vpsrlw $3, %ymm7, %ymm7
vpsubw %ymm3, %ymm7, %ymm7
-vmovdqa 1472(%rsp), %ymm2
+vmovdqa 1472(%r8), %ymm2
vpsubw %ymm11, %ymm2, %ymm2
vpmullw %ymm15, %ymm5, %ymm9
vpsubw %ymm9, %ymm2, %ymm9
@@ -5812,7 +5822,7 @@ vmovdqu 176(%rdi), %ymm10
vpaddw %ymm8, %ymm10, %ymm10
vpand mask_mod8192(%rip), %ymm10, %ymm10
vmovdqu %ymm10, 176(%rdi)
-vmovdqa %xmm4, 1984(%rsp)
+vmovdqa %xmm4, 1984(%r8)
vpshufb shuf48_16(%rip), %ymm7, %ymm7
vpand mask3_5_3_5(%rip), %ymm7, %ymm4
vpand mask5_3_5_3(%rip), %ymm7, %ymm7
@@ -5820,7 +5830,7 @@ vpermq $206, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm10
vpor %ymm10, %ymm7, %ymm7
vpaddw %ymm7, %ymm11, %ymm11
-vmovdqa %xmm4, 2240(%rsp)
+vmovdqa %xmm4, 2240(%r8)
vpshufb shuf48_16(%rip), %ymm2, %ymm2
vpand mask3_5_3_5(%rip), %ymm2, %ymm4
vpand mask5_3_5_3(%rip), %ymm2, %ymm2
@@ -5828,7 +5838,7 @@ vpermq $206, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm10
vpor %ymm10, %ymm2, %ymm2
vpaddw %ymm2, %ymm6, %ymm6
-vmovdqa %xmm4, 2496(%rsp)
+vmovdqa %xmm4, 2496(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_3_5(%rip), %ymm5, %ymm4
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
@@ -5836,22 +5846,22 @@ vpermq $206, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm10
vpor %ymm10, %ymm5, %ymm5
vpaddw %ymm5, %ymm3, %ymm3
-vmovdqa %xmm4, 2752(%rsp)
+vmovdqa %xmm4, 2752(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 528(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
vmovdqu %ymm6, 880(%rdi)
vpand mask_mod8192(%rip), %ymm3, %ymm3
vmovdqu %ymm3, 1232(%rdi)
-vmovdqa 224(%rsp), %ymm5
+vmovdqa 224(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm2
vpunpckhwd const0(%rip), %ymm5, %ymm7
vpslld $1, %ymm2, %ymm2
vpslld $1, %ymm7, %ymm7
-vmovdqa 480(%rsp), %ymm8
+vmovdqa 480(%r8), %ymm8
vpunpcklwd const0(%rip), %ymm8, %ymm3
vpunpckhwd const0(%rip), %ymm8, %ymm8
-vmovdqa 736(%rsp), %ymm6
+vmovdqa 736(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm3, %ymm4
@@ -5865,7 +5875,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1760(%rsp), %ymm11
+vmovdqa 1760(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm8
vpunpckhwd const0(%rip), %ymm11, %ymm3
vpslld $1, %ymm8, %ymm8
@@ -5877,9 +5887,9 @@ vpsrld $1, %ymm10, %ymm10
vpand mask32_to_16(%rip), %ymm4, %ymm4
vpand mask32_to_16(%rip), %ymm10, %ymm10
vpackusdw %ymm10, %ymm4, %ymm10
-vmovdqa 992(%rsp), %ymm4
-vpaddw 1248(%rsp), %ymm4, %ymm3
-vpsubw 1248(%rsp), %ymm4, %ymm4
+vmovdqa 992(%r8), %ymm4
+vpaddw 1248(%r8), %ymm4, %ymm3
+vpsubw 1248(%r8), %ymm4, %ymm4
vpsrlw $2, %ymm4, %ymm4
vpsubw %ymm6, %ymm4, %ymm4
vpmullw %ymm14, %ymm4, %ymm4
@@ -5889,7 +5899,7 @@ vpsllw $7, %ymm11, %ymm3
vpsubw %ymm3, %ymm8, %ymm3
vpsrlw $3, %ymm3, %ymm3
vpsubw %ymm10, %ymm3, %ymm3
-vmovdqa 1504(%rsp), %ymm8
+vmovdqa 1504(%r8), %ymm8
vpsubw %ymm5, %ymm8, %ymm8
vpmullw %ymm15, %ymm11, %ymm7
vpsubw %ymm7, %ymm8, %ymm7
@@ -5923,7 +5933,7 @@ vmovdqu 264(%rdi), %ymm2
vpaddw %ymm4, %ymm2, %ymm2
vpand mask_mod8192(%rip), %ymm2, %ymm2
vmovdqu %ymm2, 264(%rdi)
-vmovdqa %xmm9, 2016(%rsp)
+vmovdqa %xmm9, 2016(%r8)
vpshufb shuf48_16(%rip), %ymm3, %ymm3
vpand mask3_5_3_5(%rip), %ymm3, %ymm9
vpand mask5_3_5_3(%rip), %ymm3, %ymm3
@@ -5931,7 +5941,7 @@ vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm2
vpor %ymm2, %ymm3, %ymm3
vpaddw %ymm3, %ymm5, %ymm5
-vmovdqa %xmm9, 2272(%rsp)
+vmovdqa %xmm9, 2272(%r8)
vpshufb shuf48_16(%rip), %ymm8, %ymm8
vpand mask3_5_3_5(%rip), %ymm8, %ymm9
vpand mask5_3_5_3(%rip), %ymm8, %ymm8
@@ -5939,7 +5949,7 @@ vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm2
vpor %ymm2, %ymm8, %ymm8
vpaddw %ymm8, %ymm6, %ymm6
-vmovdqa %xmm9, 2528(%rsp)
+vmovdqa %xmm9, 2528(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_3_5(%rip), %ymm11, %ymm9
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
@@ -5947,7 +5957,7 @@ vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm2
vpor %ymm2, %ymm11, %ymm11
vpaddw %ymm11, %ymm10, %ymm10
-vmovdqa %xmm9, 2784(%rsp)
+vmovdqa %xmm9, 2784(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %ymm5, 616(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -5989,14 +5999,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 32(%r12), %ymm8
vmovdqa 896(%r12), %ymm9
-vmovdqa %ymm8, 0(%rsp)
-vmovdqa %ymm0, 32(%rsp)
-vmovdqa %ymm1, 64(%rsp)
-vmovdqa %ymm7, 96(%rsp)
-vmovdqa %ymm5, 128(%rsp)
-vmovdqa %ymm2, 160(%rsp)
-vmovdqa %ymm3, 192(%rsp)
-vmovdqa %ymm9, 224(%rsp)
+vmovdqa %ymm8, 0(%r8)
+vmovdqa %ymm0, 32(%r8)
+vmovdqa %ymm1, 64(%r8)
+vmovdqa %ymm7, 96(%r8)
+vmovdqa %ymm5, 128(%r8)
+vmovdqa %ymm2, 160(%r8)
+vmovdqa %ymm3, 192(%r8)
+vmovdqa %ymm9, 224(%r8)
vmovdqa 1856(%r12), %ymm0
vpsubw 1952(%r12), %ymm0, %ymm0
vmovdqa 2240(%r12), %ymm1
@@ -6032,14 +6042,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 1760(%r12), %ymm8
vmovdqa 2624(%r12), %ymm9
-vmovdqa %ymm8, 256(%rsp)
-vmovdqa %ymm0, 288(%rsp)
-vmovdqa %ymm1, 320(%rsp)
-vmovdqa %ymm7, 352(%rsp)
-vmovdqa %ymm5, 384(%rsp)
-vmovdqa %ymm2, 416(%rsp)
-vmovdqa %ymm3, 448(%rsp)
-vmovdqa %ymm9, 480(%rsp)
+vmovdqa %ymm8, 256(%r8)
+vmovdqa %ymm0, 288(%r8)
+vmovdqa %ymm1, 320(%r8)
+vmovdqa %ymm7, 352(%r8)
+vmovdqa %ymm5, 384(%r8)
+vmovdqa %ymm2, 416(%r8)
+vmovdqa %ymm3, 448(%r8)
+vmovdqa %ymm9, 480(%r8)
vmovdqa 3584(%r12), %ymm0
vpsubw 3680(%r12), %ymm0, %ymm0
vmovdqa 3968(%r12), %ymm1
@@ -6075,14 +6085,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 3488(%r12), %ymm8
vmovdqa 4352(%r12), %ymm9
-vmovdqa %ymm8, 512(%rsp)
-vmovdqa %ymm0, 544(%rsp)
-vmovdqa %ymm1, 576(%rsp)
-vmovdqa %ymm7, 608(%rsp)
-vmovdqa %ymm5, 640(%rsp)
-vmovdqa %ymm2, 672(%rsp)
-vmovdqa %ymm3, 704(%rsp)
-vmovdqa %ymm9, 736(%rsp)
+vmovdqa %ymm8, 512(%r8)
+vmovdqa %ymm0, 544(%r8)
+vmovdqa %ymm1, 576(%r8)
+vmovdqa %ymm7, 608(%r8)
+vmovdqa %ymm5, 640(%r8)
+vmovdqa %ymm2, 672(%r8)
+vmovdqa %ymm3, 704(%r8)
+vmovdqa %ymm9, 736(%r8)
vmovdqa 5312(%r12), %ymm0
vpsubw 5408(%r12), %ymm0, %ymm0
vmovdqa 5696(%r12), %ymm1
@@ -6118,14 +6128,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 5216(%r12), %ymm8
vmovdqa 6080(%r12), %ymm9
-vmovdqa %ymm8, 768(%rsp)
-vmovdqa %ymm0, 800(%rsp)
-vmovdqa %ymm1, 832(%rsp)
-vmovdqa %ymm7, 864(%rsp)
-vmovdqa %ymm5, 896(%rsp)
-vmovdqa %ymm2, 928(%rsp)
-vmovdqa %ymm3, 960(%rsp)
-vmovdqa %ymm9, 992(%rsp)
+vmovdqa %ymm8, 768(%r8)
+vmovdqa %ymm0, 800(%r8)
+vmovdqa %ymm1, 832(%r8)
+vmovdqa %ymm7, 864(%r8)
+vmovdqa %ymm5, 896(%r8)
+vmovdqa %ymm2, 928(%r8)
+vmovdqa %ymm3, 960(%r8)
+vmovdqa %ymm9, 992(%r8)
vmovdqa 7040(%r12), %ymm0
vpsubw 7136(%r12), %ymm0, %ymm0
vmovdqa 7424(%r12), %ymm1
@@ -6161,14 +6171,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 6944(%r12), %ymm8
vmovdqa 7808(%r12), %ymm9
-vmovdqa %ymm8, 1024(%rsp)
-vmovdqa %ymm0, 1056(%rsp)
-vmovdqa %ymm1, 1088(%rsp)
-vmovdqa %ymm7, 1120(%rsp)
-vmovdqa %ymm5, 1152(%rsp)
-vmovdqa %ymm2, 1184(%rsp)
-vmovdqa %ymm3, 1216(%rsp)
-vmovdqa %ymm9, 1248(%rsp)
+vmovdqa %ymm8, 1024(%r8)
+vmovdqa %ymm0, 1056(%r8)
+vmovdqa %ymm1, 1088(%r8)
+vmovdqa %ymm7, 1120(%r8)
+vmovdqa %ymm5, 1152(%r8)
+vmovdqa %ymm2, 1184(%r8)
+vmovdqa %ymm3, 1216(%r8)
+vmovdqa %ymm9, 1248(%r8)
vmovdqa 8768(%r12), %ymm0
vpsubw 8864(%r12), %ymm0, %ymm0
vmovdqa 9152(%r12), %ymm1
@@ -6204,14 +6214,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 8672(%r12), %ymm8
vmovdqa 9536(%r12), %ymm9
-vmovdqa %ymm8, 1280(%rsp)
-vmovdqa %ymm0, 1312(%rsp)
-vmovdqa %ymm1, 1344(%rsp)
-vmovdqa %ymm7, 1376(%rsp)
-vmovdqa %ymm5, 1408(%rsp)
-vmovdqa %ymm2, 1440(%rsp)
-vmovdqa %ymm3, 1472(%rsp)
-vmovdqa %ymm9, 1504(%rsp)
+vmovdqa %ymm8, 1280(%r8)
+vmovdqa %ymm0, 1312(%r8)
+vmovdqa %ymm1, 1344(%r8)
+vmovdqa %ymm7, 1376(%r8)
+vmovdqa %ymm5, 1408(%r8)
+vmovdqa %ymm2, 1440(%r8)
+vmovdqa %ymm3, 1472(%r8)
+vmovdqa %ymm9, 1504(%r8)
vmovdqa 10496(%r12), %ymm0
vpsubw 10592(%r12), %ymm0, %ymm0
vmovdqa 10880(%r12), %ymm1
@@ -6247,23 +6257,23 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 10400(%r12), %ymm8
vmovdqa 11264(%r12), %ymm9
-vmovdqa %ymm8, 1536(%rsp)
-vmovdqa %ymm0, 1568(%rsp)
-vmovdqa %ymm1, 1600(%rsp)
-vmovdqa %ymm7, 1632(%rsp)
-vmovdqa %ymm5, 1664(%rsp)
-vmovdqa %ymm2, 1696(%rsp)
-vmovdqa %ymm3, 1728(%rsp)
-vmovdqa %ymm9, 1760(%rsp)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa %ymm8, 1536(%r8)
+vmovdqa %ymm0, 1568(%r8)
+vmovdqa %ymm1, 1600(%r8)
+vmovdqa %ymm7, 1632(%r8)
+vmovdqa %ymm5, 1664(%r8)
+vmovdqa %ymm2, 1696(%r8)
+vmovdqa %ymm3, 1728(%r8)
+vmovdqa %ymm9, 1760(%r8)
+vmovdqa 0(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm8
vpunpckhwd const0(%rip), %ymm11, %ymm3
vpslld $1, %ymm8, %ymm8
vpslld $1, %ymm3, %ymm3
-vmovdqa 256(%rsp), %ymm4
+vmovdqa 256(%r8), %ymm4
vpunpcklwd const0(%rip), %ymm4, %ymm10
vpunpckhwd const0(%rip), %ymm4, %ymm4
-vmovdqa 512(%rsp), %ymm6
+vmovdqa 512(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm10, %ymm9
@@ -6277,7 +6287,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1536(%rsp), %ymm5
+vmovdqa 1536(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm4
vpunpckhwd const0(%rip), %ymm5, %ymm10
vpslld $1, %ymm4, %ymm4
@@ -6289,9 +6299,9 @@ vpsrld $1, %ymm2, %ymm2
vpand mask32_to_16(%rip), %ymm9, %ymm9
vpand mask32_to_16(%rip), %ymm2, %ymm2
vpackusdw %ymm2, %ymm9, %ymm2
-vmovdqa 768(%rsp), %ymm9
-vpaddw 1024(%rsp), %ymm9, %ymm10
-vpsubw 1024(%rsp), %ymm9, %ymm9
+vmovdqa 768(%r8), %ymm9
+vpaddw 1024(%r8), %ymm9, %ymm10
+vpsubw 1024(%r8), %ymm9, %ymm9
vpsrlw $2, %ymm9, %ymm9
vpsubw %ymm6, %ymm9, %ymm9
vpmullw %ymm14, %ymm9, %ymm9
@@ -6301,7 +6311,7 @@ vpsllw $7, %ymm5, %ymm10
vpsubw %ymm10, %ymm4, %ymm10
vpsrlw $3, %ymm10, %ymm10
vpsubw %ymm2, %ymm10, %ymm10
-vmovdqa 1280(%rsp), %ymm4
+vmovdqa 1280(%r8), %ymm4
vpsubw %ymm11, %ymm4, %ymm4
vpmullw %ymm15, %ymm5, %ymm3
vpsubw %ymm3, %ymm4, %ymm3
@@ -6325,27 +6335,27 @@ vpand mask5_3_5_3(%rip), %ymm10, %ymm10
vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm8
vpor %ymm8, %ymm10, %ymm10
-vpaddw 2048(%rsp), %ymm11, %ymm11
+vpaddw 2048(%r8), %ymm11, %ymm11
vpaddw %ymm10, %ymm11, %ymm11
-vmovdqa %xmm3, 2048(%rsp)
+vmovdqa %xmm3, 2048(%r8)
vpshufb shuf48_16(%rip), %ymm4, %ymm4
vpand mask3_5_3_5(%rip), %ymm4, %ymm3
vpand mask5_3_5_3(%rip), %ymm4, %ymm4
vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm8
vpor %ymm8, %ymm4, %ymm4
-vpaddw 2304(%rsp), %ymm6, %ymm6
+vpaddw 2304(%r8), %ymm6, %ymm6
vpaddw %ymm4, %ymm6, %ymm6
-vmovdqa %xmm3, 2304(%rsp)
+vmovdqa %xmm3, 2304(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_3_5(%rip), %ymm5, %ymm3
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm8
vpor %ymm8, %ymm5, %ymm5
-vpaddw 2560(%rsp), %ymm2, %ymm2
+vpaddw 2560(%r8), %ymm2, %ymm2
vpaddw %ymm5, %ymm2, %ymm2
-vmovdqa %xmm3, 2560(%rsp)
+vmovdqa %xmm3, 2560(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 32(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -6354,15 +6364,15 @@ vpand mask_mod8192(%rip), %ymm2, %ymm2
vmovdqu %ymm2, 736(%rdi)
vpand mask_mod8192(%rip), %ymm9, %ymm9
vmovdqu %ymm9, 1088(%rdi)
-vmovdqa 32(%rsp), %ymm5
+vmovdqa 32(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm4
vpunpckhwd const0(%rip), %ymm5, %ymm10
vpslld $1, %ymm4, %ymm4
vpslld $1, %ymm10, %ymm10
-vmovdqa 288(%rsp), %ymm9
+vmovdqa 288(%r8), %ymm9
vpunpcklwd const0(%rip), %ymm9, %ymm2
vpunpckhwd const0(%rip), %ymm9, %ymm9
-vmovdqa 544(%rsp), %ymm6
+vmovdqa 544(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm2, %ymm3
@@ -6376,7 +6386,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1568(%rsp), %ymm11
+vmovdqa 1568(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm9
vpunpckhwd const0(%rip), %ymm11, %ymm2
vpslld $1, %ymm9, %ymm9
@@ -6388,9 +6398,9 @@ vpsrld $1, %ymm8, %ymm8
vpand mask32_to_16(%rip), %ymm3, %ymm3
vpand mask32_to_16(%rip), %ymm8, %ymm8
vpackusdw %ymm8, %ymm3, %ymm8
-vmovdqa 800(%rsp), %ymm3
-vpaddw 1056(%rsp), %ymm3, %ymm2
-vpsubw 1056(%rsp), %ymm3, %ymm3
+vmovdqa 800(%r8), %ymm3
+vpaddw 1056(%r8), %ymm3, %ymm2
+vpsubw 1056(%r8), %ymm3, %ymm3
vpsrlw $2, %ymm3, %ymm3
vpsubw %ymm6, %ymm3, %ymm3
vpmullw %ymm14, %ymm3, %ymm3
@@ -6400,7 +6410,7 @@ vpsllw $7, %ymm11, %ymm2
vpsubw %ymm2, %ymm9, %ymm2
vpsrlw $3, %ymm2, %ymm2
vpsubw %ymm8, %ymm2, %ymm2
-vmovdqa 1312(%rsp), %ymm9
+vmovdqa 1312(%r8), %ymm9
vpsubw %ymm5, %ymm9, %ymm9
vpmullw %ymm15, %ymm11, %ymm10
vpsubw %ymm10, %ymm9, %ymm10
@@ -6424,27 +6434,27 @@ vpand mask5_3_5_3(%rip), %ymm2, %ymm2
vpermq $206, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm4
vpor %ymm4, %ymm2, %ymm2
-vpaddw 2080(%rsp), %ymm5, %ymm5
+vpaddw 2080(%r8), %ymm5, %ymm5
vpaddw %ymm2, %ymm5, %ymm5
-vmovdqa %xmm10, 2080(%rsp)
+vmovdqa %xmm10, 2080(%r8)
vpshufb shuf48_16(%rip), %ymm9, %ymm9
vpand mask3_5_3_5(%rip), %ymm9, %ymm10
vpand mask5_3_5_3(%rip), %ymm9, %ymm9
vpermq $206, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm4
vpor %ymm4, %ymm9, %ymm9
-vpaddw 2336(%rsp), %ymm6, %ymm6
+vpaddw 2336(%r8), %ymm6, %ymm6
vpaddw %ymm9, %ymm6, %ymm6
-vmovdqa %xmm10, 2336(%rsp)
+vmovdqa %xmm10, 2336(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_3_5(%rip), %ymm11, %ymm10
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
vpermq $206, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm4
vpor %ymm4, %ymm11, %ymm11
-vpaddw 2592(%rsp), %ymm8, %ymm8
+vpaddw 2592(%r8), %ymm8, %ymm8
vpaddw %ymm11, %ymm8, %ymm8
-vmovdqa %xmm10, 2592(%rsp)
+vmovdqa %xmm10, 2592(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %ymm5, 120(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -6453,15 +6463,15 @@ vpand mask_mod8192(%rip), %ymm8, %ymm8
vmovdqu %ymm8, 824(%rdi)
vpand mask_mod8192(%rip), %ymm3, %ymm3
vmovdqu %ymm3, 1176(%rdi)
-vmovdqa 64(%rsp), %ymm11
+vmovdqa 64(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm9
vpunpckhwd const0(%rip), %ymm11, %ymm2
vpslld $1, %ymm9, %ymm9
vpslld $1, %ymm2, %ymm2
-vmovdqa 320(%rsp), %ymm3
+vmovdqa 320(%r8), %ymm3
vpunpcklwd const0(%rip), %ymm3, %ymm8
vpunpckhwd const0(%rip), %ymm3, %ymm3
-vmovdqa 576(%rsp), %ymm6
+vmovdqa 576(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm8, %ymm10
@@ -6475,7 +6485,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1600(%rsp), %ymm5
+vmovdqa 1600(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm3
vpunpckhwd const0(%rip), %ymm5, %ymm8
vpslld $1, %ymm3, %ymm3
@@ -6487,9 +6497,9 @@ vpsrld $1, %ymm4, %ymm4
vpand mask32_to_16(%rip), %ymm10, %ymm10
vpand mask32_to_16(%rip), %ymm4, %ymm4
vpackusdw %ymm4, %ymm10, %ymm4
-vmovdqa 832(%rsp), %ymm10
-vpaddw 1088(%rsp), %ymm10, %ymm8
-vpsubw 1088(%rsp), %ymm10, %ymm10
+vmovdqa 832(%r8), %ymm10
+vpaddw 1088(%r8), %ymm10, %ymm8
+vpsubw 1088(%r8), %ymm10, %ymm10
vpsrlw $2, %ymm10, %ymm10
vpsubw %ymm6, %ymm10, %ymm10
vpmullw %ymm14, %ymm10, %ymm10
@@ -6499,7 +6509,7 @@ vpsllw $7, %ymm5, %ymm8
vpsubw %ymm8, %ymm3, %ymm8
vpsrlw $3, %ymm8, %ymm8
vpsubw %ymm4, %ymm8, %ymm8
-vmovdqa 1344(%rsp), %ymm3
+vmovdqa 1344(%r8), %ymm3
vpsubw %ymm11, %ymm3, %ymm3
vpmullw %ymm15, %ymm5, %ymm2
vpsubw %ymm2, %ymm3, %ymm2
@@ -6523,27 +6533,27 @@ vpand mask5_3_5_3(%rip), %ymm8, %ymm8
vpermq $206, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm9
vpor %ymm9, %ymm8, %ymm8
-vpaddw 2112(%rsp), %ymm11, %ymm11
+vpaddw 2112(%r8), %ymm11, %ymm11
vpaddw %ymm8, %ymm11, %ymm11
-vmovdqa %xmm2, 2112(%rsp)
+vmovdqa %xmm2, 2112(%r8)
vpshufb shuf48_16(%rip), %ymm3, %ymm3
vpand mask3_5_3_5(%rip), %ymm3, %ymm2
vpand mask5_3_5_3(%rip), %ymm3, %ymm3
vpermq $206, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm9
vpor %ymm9, %ymm3, %ymm3
-vpaddw 2368(%rsp), %ymm6, %ymm6
+vpaddw 2368(%r8), %ymm6, %ymm6
vpaddw %ymm3, %ymm6, %ymm6
-vmovdqa %xmm2, 2368(%rsp)
+vmovdqa %xmm2, 2368(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_3_5(%rip), %ymm5, %ymm2
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
vpermq $206, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm9
vpor %ymm9, %ymm5, %ymm5
-vpaddw 2624(%rsp), %ymm4, %ymm4
+vpaddw 2624(%r8), %ymm4, %ymm4
vpaddw %ymm5, %ymm4, %ymm4
-vmovdqa %xmm2, 2624(%rsp)
+vmovdqa %xmm2, 2624(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 208(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -6552,15 +6562,15 @@ vpand mask_mod8192(%rip), %ymm4, %ymm4
vmovdqu %ymm4, 912(%rdi)
vpand mask_mod8192(%rip), %ymm10, %ymm10
vmovdqu %ymm10, 1264(%rdi)
-vmovdqa 96(%rsp), %ymm5
+vmovdqa 96(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm3
vpunpckhwd const0(%rip), %ymm5, %ymm8
vpslld $1, %ymm3, %ymm3
vpslld $1, %ymm8, %ymm8
-vmovdqa 352(%rsp), %ymm10
+vmovdqa 352(%r8), %ymm10
vpunpcklwd const0(%rip), %ymm10, %ymm4
vpunpckhwd const0(%rip), %ymm10, %ymm10
-vmovdqa 608(%rsp), %ymm6
+vmovdqa 608(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm4, %ymm2
@@ -6574,7 +6584,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1632(%rsp), %ymm11
+vmovdqa 1632(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm10
vpunpckhwd const0(%rip), %ymm11, %ymm4
vpslld $1, %ymm10, %ymm10
@@ -6586,9 +6596,9 @@ vpsrld $1, %ymm9, %ymm9
vpand mask32_to_16(%rip), %ymm2, %ymm2
vpand mask32_to_16(%rip), %ymm9, %ymm9
vpackusdw %ymm9, %ymm2, %ymm9
-vmovdqa 864(%rsp), %ymm2
-vpaddw 1120(%rsp), %ymm2, %ymm4
-vpsubw 1120(%rsp), %ymm2, %ymm2
+vmovdqa 864(%r8), %ymm2
+vpaddw 1120(%r8), %ymm2, %ymm4
+vpsubw 1120(%r8), %ymm2, %ymm2
vpsrlw $2, %ymm2, %ymm2
vpsubw %ymm6, %ymm2, %ymm2
vpmullw %ymm14, %ymm2, %ymm2
@@ -6598,7 +6608,7 @@ vpsllw $7, %ymm11, %ymm4
vpsubw %ymm4, %ymm10, %ymm4
vpsrlw $3, %ymm4, %ymm4
vpsubw %ymm9, %ymm4, %ymm4
-vmovdqa 1376(%rsp), %ymm10
+vmovdqa 1376(%r8), %ymm10
vpsubw %ymm5, %ymm10, %ymm10
vpmullw %ymm15, %ymm11, %ymm8
vpsubw %ymm8, %ymm10, %ymm8
@@ -6622,27 +6632,27 @@ vpand mask5_3_5_3(%rip), %ymm4, %ymm4
vpermq $206, %ymm8, %ymm8
vpand mask_keephigh(%rip), %ymm8, %ymm3
vpor %ymm3, %ymm4, %ymm4
-vpaddw 2144(%rsp), %ymm5, %ymm5
+vpaddw 2144(%r8), %ymm5, %ymm5
vpaddw %ymm4, %ymm5, %ymm5
-vmovdqa %xmm8, 2144(%rsp)
+vmovdqa %xmm8, 2144(%r8)
vpshufb shuf48_16(%rip), %ymm10, %ymm10
vpand mask3_5_3_5(%rip), %ymm10, %ymm8
vpand mask5_3_5_3(%rip), %ymm10, %ymm10
vpermq $206, %ymm8, %ymm8
vpand mask_keephigh(%rip), %ymm8, %ymm3
vpor %ymm3, %ymm10, %ymm10
-vpaddw 2400(%rsp), %ymm6, %ymm6
+vpaddw 2400(%r8), %ymm6, %ymm6
vpaddw %ymm10, %ymm6, %ymm6
-vmovdqa %xmm8, 2400(%rsp)
+vmovdqa %xmm8, 2400(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_3_5(%rip), %ymm11, %ymm8
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
vpermq $206, %ymm8, %ymm8
vpand mask_keephigh(%rip), %ymm8, %ymm3
vpor %ymm3, %ymm11, %ymm11
-vpaddw 2656(%rsp), %ymm9, %ymm9
+vpaddw 2656(%r8), %ymm9, %ymm9
vpaddw %ymm11, %ymm9, %ymm9
-vmovdqa %xmm8, 2656(%rsp)
+vmovdqa %xmm8, 2656(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %ymm5, 296(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -6651,15 +6661,15 @@ vpand mask_mod8192(%rip), %ymm9, %ymm9
vmovdqu %ymm9, 1000(%rdi)
vpand mask_mod8192(%rip), %ymm2, %ymm2
vmovdqu %ymm2, 1352(%rdi)
-vmovdqa 128(%rsp), %ymm11
+vmovdqa 128(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm10
vpunpckhwd const0(%rip), %ymm11, %ymm4
vpslld $1, %ymm10, %ymm10
vpslld $1, %ymm4, %ymm4
-vmovdqa 384(%rsp), %ymm2
+vmovdqa 384(%r8), %ymm2
vpunpcklwd const0(%rip), %ymm2, %ymm9
vpunpckhwd const0(%rip), %ymm2, %ymm2
-vmovdqa 640(%rsp), %ymm6
+vmovdqa 640(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm9, %ymm8
@@ -6673,7 +6683,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1664(%rsp), %ymm5
+vmovdqa 1664(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm2
vpunpckhwd const0(%rip), %ymm5, %ymm9
vpslld $1, %ymm2, %ymm2
@@ -6685,9 +6695,9 @@ vpsrld $1, %ymm3, %ymm3
vpand mask32_to_16(%rip), %ymm8, %ymm8
vpand mask32_to_16(%rip), %ymm3, %ymm3
vpackusdw %ymm3, %ymm8, %ymm3
-vmovdqa 896(%rsp), %ymm8
-vpaddw 1152(%rsp), %ymm8, %ymm9
-vpsubw 1152(%rsp), %ymm8, %ymm8
+vmovdqa 896(%r8), %ymm8
+vpaddw 1152(%r8), %ymm8, %ymm9
+vpsubw 1152(%r8), %ymm8, %ymm8
vpsrlw $2, %ymm8, %ymm8
vpsubw %ymm6, %ymm8, %ymm8
vpmullw %ymm14, %ymm8, %ymm8
@@ -6697,7 +6707,7 @@ vpsllw $7, %ymm5, %ymm9
vpsubw %ymm9, %ymm2, %ymm9
vpsrlw $3, %ymm9, %ymm9
vpsubw %ymm3, %ymm9, %ymm9
-vmovdqa 1408(%rsp), %ymm2
+vmovdqa 1408(%r8), %ymm2
vpsubw %ymm11, %ymm2, %ymm2
vpmullw %ymm15, %ymm5, %ymm4
vpsubw %ymm4, %ymm2, %ymm4
@@ -6728,53 +6738,53 @@ vpermq $206, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm10
vpor %ymm10, %ymm8, %ymm8
vmovdqu 32(%rdi), %ymm10
-vpaddw 1920(%rsp), %ymm10, %ymm10
+vpaddw 1920(%r8), %ymm10, %ymm10
vpaddw %ymm8, %ymm10, %ymm10
vpand mask_mod8192(%rip), %ymm10, %ymm10
vmovdqu %ymm10, 32(%rdi)
-vmovdqa %xmm7, 1920(%rsp)
+vmovdqa %xmm7, 1920(%r8)
vpshufb shuf48_16(%rip), %ymm9, %ymm9
vpand mask3_5_3_5(%rip), %ymm9, %ymm7
vpand mask5_3_5_3(%rip), %ymm9, %ymm9
vpermq $206, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm10
vpor %ymm10, %ymm9, %ymm9
-vpaddw 2176(%rsp), %ymm11, %ymm11
+vpaddw 2176(%r8), %ymm11, %ymm11
vpaddw %ymm9, %ymm11, %ymm11
-vmovdqa %xmm7, 2176(%rsp)
+vmovdqa %xmm7, 2176(%r8)
vpshufb shuf48_16(%rip), %ymm2, %ymm2
vpand mask3_5_3_5(%rip), %ymm2, %ymm7
vpand mask5_3_5_3(%rip), %ymm2, %ymm2
vpermq $206, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm10
vpor %ymm10, %ymm2, %ymm2
-vpaddw 2432(%rsp), %ymm6, %ymm6
+vpaddw 2432(%r8), %ymm6, %ymm6
vpaddw %ymm2, %ymm6, %ymm6
-vmovdqa %xmm7, 2432(%rsp)
+vmovdqa %xmm7, 2432(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_3_5(%rip), %ymm5, %ymm7
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
vpermq $206, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm10
vpor %ymm10, %ymm5, %ymm5
-vpaddw 2688(%rsp), %ymm3, %ymm3
+vpaddw 2688(%r8), %ymm3, %ymm3
vpaddw %ymm5, %ymm3, %ymm3
-vmovdqa %xmm7, 2688(%rsp)
+vmovdqa %xmm7, 2688(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 384(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
vmovdqu %ymm6, 736(%rdi)
vpand mask_mod8192(%rip), %ymm3, %ymm3
vmovdqu %ymm3, 1088(%rdi)
-vmovdqa 160(%rsp), %ymm5
+vmovdqa 160(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm2
vpunpckhwd const0(%rip), %ymm5, %ymm9
vpslld $1, %ymm2, %ymm2
vpslld $1, %ymm9, %ymm9
-vmovdqa 416(%rsp), %ymm8
+vmovdqa 416(%r8), %ymm8
vpunpcklwd const0(%rip), %ymm8, %ymm3
vpunpckhwd const0(%rip), %ymm8, %ymm8
-vmovdqa 672(%rsp), %ymm6
+vmovdqa 672(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm3, %ymm7
@@ -6788,7 +6798,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1696(%rsp), %ymm11
+vmovdqa 1696(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm8
vpunpckhwd const0(%rip), %ymm11, %ymm3
vpslld $1, %ymm8, %ymm8
@@ -6800,9 +6810,9 @@ vpsrld $1, %ymm10, %ymm10
vpand mask32_to_16(%rip), %ymm7, %ymm7
vpand mask32_to_16(%rip), %ymm10, %ymm10
vpackusdw %ymm10, %ymm7, %ymm10
-vmovdqa 928(%rsp), %ymm7
-vpaddw 1184(%rsp), %ymm7, %ymm3
-vpsubw 1184(%rsp), %ymm7, %ymm7
+vmovdqa 928(%r8), %ymm7
+vpaddw 1184(%r8), %ymm7, %ymm3
+vpsubw 1184(%r8), %ymm7, %ymm7
vpsrlw $2, %ymm7, %ymm7
vpsubw %ymm6, %ymm7, %ymm7
vpmullw %ymm14, %ymm7, %ymm7
@@ -6812,7 +6822,7 @@ vpsllw $7, %ymm11, %ymm3
vpsubw %ymm3, %ymm8, %ymm3
vpsrlw $3, %ymm3, %ymm3
vpsubw %ymm10, %ymm3, %ymm3
-vmovdqa 1440(%rsp), %ymm8
+vmovdqa 1440(%r8), %ymm8
vpsubw %ymm5, %ymm8, %ymm8
vpmullw %ymm15, %ymm11, %ymm9
vpsubw %ymm9, %ymm8, %ymm9
@@ -6843,53 +6853,53 @@ vpermq $206, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm2
vpor %ymm2, %ymm7, %ymm7
vmovdqu 120(%rdi), %ymm2
-vpaddw 1952(%rsp), %ymm2, %ymm2
+vpaddw 1952(%r8), %ymm2, %ymm2
vpaddw %ymm7, %ymm2, %ymm2
vpand mask_mod8192(%rip), %ymm2, %ymm2
vmovdqu %ymm2, 120(%rdi)
-vmovdqa %xmm4, 1952(%rsp)
+vmovdqa %xmm4, 1952(%r8)
vpshufb shuf48_16(%rip), %ymm3, %ymm3
vpand mask3_5_3_5(%rip), %ymm3, %ymm4
vpand mask5_3_5_3(%rip), %ymm3, %ymm3
vpermq $206, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm2
vpor %ymm2, %ymm3, %ymm3
-vpaddw 2208(%rsp), %ymm5, %ymm5
+vpaddw 2208(%r8), %ymm5, %ymm5
vpaddw %ymm3, %ymm5, %ymm5
-vmovdqa %xmm4, 2208(%rsp)
+vmovdqa %xmm4, 2208(%r8)
vpshufb shuf48_16(%rip), %ymm8, %ymm8
vpand mask3_5_3_5(%rip), %ymm8, %ymm4
vpand mask5_3_5_3(%rip), %ymm8, %ymm8
vpermq $206, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm2
vpor %ymm2, %ymm8, %ymm8
-vpaddw 2464(%rsp), %ymm6, %ymm6
+vpaddw 2464(%r8), %ymm6, %ymm6
vpaddw %ymm8, %ymm6, %ymm6
-vmovdqa %xmm4, 2464(%rsp)
+vmovdqa %xmm4, 2464(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_3_5(%rip), %ymm11, %ymm4
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
vpermq $206, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm2
vpor %ymm2, %ymm11, %ymm11
-vpaddw 2720(%rsp), %ymm10, %ymm10
+vpaddw 2720(%r8), %ymm10, %ymm10
vpaddw %ymm11, %ymm10, %ymm10
-vmovdqa %xmm4, 2720(%rsp)
+vmovdqa %xmm4, 2720(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %ymm5, 472(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
vmovdqu %ymm6, 824(%rdi)
vpand mask_mod8192(%rip), %ymm10, %ymm10
vmovdqu %ymm10, 1176(%rdi)
-vmovdqa 192(%rsp), %ymm11
+vmovdqa 192(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm8
vpunpckhwd const0(%rip), %ymm11, %ymm3
vpslld $1, %ymm8, %ymm8
vpslld $1, %ymm3, %ymm3
-vmovdqa 448(%rsp), %ymm7
+vmovdqa 448(%r8), %ymm7
vpunpcklwd const0(%rip), %ymm7, %ymm10
vpunpckhwd const0(%rip), %ymm7, %ymm7
-vmovdqa 704(%rsp), %ymm6
+vmovdqa 704(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm10, %ymm4
@@ -6903,7 +6913,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1728(%rsp), %ymm5
+vmovdqa 1728(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm7
vpunpckhwd const0(%rip), %ymm5, %ymm10
vpslld $1, %ymm7, %ymm7
@@ -6915,9 +6925,9 @@ vpsrld $1, %ymm2, %ymm2
vpand mask32_to_16(%rip), %ymm4, %ymm4
vpand mask32_to_16(%rip), %ymm2, %ymm2
vpackusdw %ymm2, %ymm4, %ymm2
-vmovdqa 960(%rsp), %ymm4
-vpaddw 1216(%rsp), %ymm4, %ymm10
-vpsubw 1216(%rsp), %ymm4, %ymm4
+vmovdqa 960(%r8), %ymm4
+vpaddw 1216(%r8), %ymm4, %ymm10
+vpsubw 1216(%r8), %ymm4, %ymm4
vpsrlw $2, %ymm4, %ymm4
vpsubw %ymm6, %ymm4, %ymm4
vpmullw %ymm14, %ymm4, %ymm4
@@ -6927,7 +6937,7 @@ vpsllw $7, %ymm5, %ymm10
vpsubw %ymm10, %ymm7, %ymm10
vpsrlw $3, %ymm10, %ymm10
vpsubw %ymm2, %ymm10, %ymm10
-vmovdqa 1472(%rsp), %ymm7
+vmovdqa 1472(%r8), %ymm7
vpsubw %ymm11, %ymm7, %ymm7
vpmullw %ymm15, %ymm5, %ymm3
vpsubw %ymm3, %ymm7, %ymm3
@@ -6958,53 +6968,53 @@ vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm8
vpor %ymm8, %ymm4, %ymm4
vmovdqu 208(%rdi), %ymm8
-vpaddw 1984(%rsp), %ymm8, %ymm8
+vpaddw 1984(%r8), %ymm8, %ymm8
vpaddw %ymm4, %ymm8, %ymm8
vpand mask_mod8192(%rip), %ymm8, %ymm8
vmovdqu %ymm8, 208(%rdi)
-vmovdqa %xmm9, 1984(%rsp)
+vmovdqa %xmm9, 1984(%r8)
vpshufb shuf48_16(%rip), %ymm10, %ymm10
vpand mask3_5_3_5(%rip), %ymm10, %ymm9
vpand mask5_3_5_3(%rip), %ymm10, %ymm10
vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm8
vpor %ymm8, %ymm10, %ymm10
-vpaddw 2240(%rsp), %ymm11, %ymm11
+vpaddw 2240(%r8), %ymm11, %ymm11
vpaddw %ymm10, %ymm11, %ymm11
-vmovdqa %xmm9, 2240(%rsp)
+vmovdqa %xmm9, 2240(%r8)
vpshufb shuf48_16(%rip), %ymm7, %ymm7
vpand mask3_5_3_5(%rip), %ymm7, %ymm9
vpand mask5_3_5_3(%rip), %ymm7, %ymm7
vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm8
vpor %ymm8, %ymm7, %ymm7
-vpaddw 2496(%rsp), %ymm6, %ymm6
+vpaddw 2496(%r8), %ymm6, %ymm6
vpaddw %ymm7, %ymm6, %ymm6
-vmovdqa %xmm9, 2496(%rsp)
+vmovdqa %xmm9, 2496(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_3_5(%rip), %ymm5, %ymm9
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
vpermq $206, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm8
vpor %ymm8, %ymm5, %ymm5
-vpaddw 2752(%rsp), %ymm2, %ymm2
+vpaddw 2752(%r8), %ymm2, %ymm2
vpaddw %ymm5, %ymm2, %ymm2
-vmovdqa %xmm9, 2752(%rsp)
+vmovdqa %xmm9, 2752(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 560(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
vmovdqu %ymm6, 912(%rdi)
vpand mask_mod8192(%rip), %ymm2, %ymm2
vmovdqu %ymm2, 1264(%rdi)
-vmovdqa 224(%rsp), %ymm5
+vmovdqa 224(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm7
vpunpckhwd const0(%rip), %ymm5, %ymm10
vpslld $1, %ymm7, %ymm7
vpslld $1, %ymm10, %ymm10
-vmovdqa 480(%rsp), %ymm4
+vmovdqa 480(%r8), %ymm4
vpunpcklwd const0(%rip), %ymm4, %ymm2
vpunpckhwd const0(%rip), %ymm4, %ymm4
-vmovdqa 736(%rsp), %ymm6
+vmovdqa 736(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm2, %ymm9
@@ -7018,7 +7028,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1760(%rsp), %ymm11
+vmovdqa 1760(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm4
vpunpckhwd const0(%rip), %ymm11, %ymm2
vpslld $1, %ymm4, %ymm4
@@ -7030,9 +7040,9 @@ vpsrld $1, %ymm8, %ymm8
vpand mask32_to_16(%rip), %ymm9, %ymm9
vpand mask32_to_16(%rip), %ymm8, %ymm8
vpackusdw %ymm8, %ymm9, %ymm8
-vmovdqa 992(%rsp), %ymm9
-vpaddw 1248(%rsp), %ymm9, %ymm2
-vpsubw 1248(%rsp), %ymm9, %ymm9
+vmovdqa 992(%r8), %ymm9
+vpaddw 1248(%r8), %ymm9, %ymm2
+vpsubw 1248(%r8), %ymm9, %ymm9
vpsrlw $2, %ymm9, %ymm9
vpsubw %ymm6, %ymm9, %ymm9
vpmullw %ymm14, %ymm9, %ymm9
@@ -7042,7 +7052,7 @@ vpsllw $7, %ymm11, %ymm2
vpsubw %ymm2, %ymm4, %ymm2
vpsrlw $3, %ymm2, %ymm2
vpsubw %ymm8, %ymm2, %ymm2
-vmovdqa 1504(%rsp), %ymm4
+vmovdqa 1504(%r8), %ymm4
vpsubw %ymm5, %ymm4, %ymm4
vpmullw %ymm15, %ymm11, %ymm10
vpsubw %ymm10, %ymm4, %ymm10
@@ -7073,38 +7083,38 @@ vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm7
vpor %ymm7, %ymm9, %ymm9
vmovdqu 296(%rdi), %ymm7
-vpaddw 2016(%rsp), %ymm7, %ymm7
+vpaddw 2016(%r8), %ymm7, %ymm7
vpaddw %ymm9, %ymm7, %ymm7
vpand mask_mod8192(%rip), %ymm7, %ymm7
vmovdqu %ymm7, 296(%rdi)
-vmovdqa %xmm3, 2016(%rsp)
+vmovdqa %xmm3, 2016(%r8)
vpshufb shuf48_16(%rip), %ymm2, %ymm2
vpand mask3_5_3_5(%rip), %ymm2, %ymm3
vpand mask5_3_5_3(%rip), %ymm2, %ymm2
vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm7
vpor %ymm7, %ymm2, %ymm2
-vpaddw 2272(%rsp), %ymm5, %ymm5
+vpaddw 2272(%r8), %ymm5, %ymm5
vpaddw %ymm2, %ymm5, %ymm5
-vmovdqa %xmm3, 2272(%rsp)
+vmovdqa %xmm3, 2272(%r8)
vpshufb shuf48_16(%rip), %ymm4, %ymm4
vpand mask3_5_3_5(%rip), %ymm4, %ymm3
vpand mask5_3_5_3(%rip), %ymm4, %ymm4
vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm7
vpor %ymm7, %ymm4, %ymm4
-vpaddw 2528(%rsp), %ymm6, %ymm6
+vpaddw 2528(%r8), %ymm6, %ymm6
vpaddw %ymm4, %ymm6, %ymm6
-vmovdqa %xmm3, 2528(%rsp)
+vmovdqa %xmm3, 2528(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_3_5(%rip), %ymm11, %ymm3
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
vpermq $206, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm7
vpor %ymm7, %ymm11, %ymm11
-vpaddw 2784(%rsp), %ymm8, %ymm8
+vpaddw 2784(%r8), %ymm8, %ymm8
vpaddw %ymm11, %ymm8, %ymm8
-vmovdqa %xmm3, 2784(%rsp)
+vmovdqa %xmm3, 2784(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %ymm5, 648(%rdi)
vpand mask_mod8192(%rip), %ymm6, %ymm6
@@ -7146,14 +7156,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 64(%r12), %ymm8
vmovdqa 928(%r12), %ymm9
-vmovdqa %ymm8, 0(%rsp)
-vmovdqa %ymm0, 32(%rsp)
-vmovdqa %ymm1, 64(%rsp)
-vmovdqa %ymm7, 96(%rsp)
-vmovdqa %ymm5, 128(%rsp)
-vmovdqa %ymm2, 160(%rsp)
-vmovdqa %ymm3, 192(%rsp)
-vmovdqa %ymm9, 224(%rsp)
+vmovdqa %ymm8, 0(%r8)
+vmovdqa %ymm0, 32(%r8)
+vmovdqa %ymm1, 64(%r8)
+vmovdqa %ymm7, 96(%r8)
+vmovdqa %ymm5, 128(%r8)
+vmovdqa %ymm2, 160(%r8)
+vmovdqa %ymm3, 192(%r8)
+vmovdqa %ymm9, 224(%r8)
vmovdqa 1888(%r12), %ymm0
vpsubw 1984(%r12), %ymm0, %ymm0
vmovdqa 2272(%r12), %ymm1
@@ -7189,14 +7199,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 1792(%r12), %ymm8
vmovdqa 2656(%r12), %ymm9
-vmovdqa %ymm8, 256(%rsp)
-vmovdqa %ymm0, 288(%rsp)
-vmovdqa %ymm1, 320(%rsp)
-vmovdqa %ymm7, 352(%rsp)
-vmovdqa %ymm5, 384(%rsp)
-vmovdqa %ymm2, 416(%rsp)
-vmovdqa %ymm3, 448(%rsp)
-vmovdqa %ymm9, 480(%rsp)
+vmovdqa %ymm8, 256(%r8)
+vmovdqa %ymm0, 288(%r8)
+vmovdqa %ymm1, 320(%r8)
+vmovdqa %ymm7, 352(%r8)
+vmovdqa %ymm5, 384(%r8)
+vmovdqa %ymm2, 416(%r8)
+vmovdqa %ymm3, 448(%r8)
+vmovdqa %ymm9, 480(%r8)
vmovdqa 3616(%r12), %ymm0
vpsubw 3712(%r12), %ymm0, %ymm0
vmovdqa 4000(%r12), %ymm1
@@ -7232,14 +7242,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 3520(%r12), %ymm8
vmovdqa 4384(%r12), %ymm9
-vmovdqa %ymm8, 512(%rsp)
-vmovdqa %ymm0, 544(%rsp)
-vmovdqa %ymm1, 576(%rsp)
-vmovdqa %ymm7, 608(%rsp)
-vmovdqa %ymm5, 640(%rsp)
-vmovdqa %ymm2, 672(%rsp)
-vmovdqa %ymm3, 704(%rsp)
-vmovdqa %ymm9, 736(%rsp)
+vmovdqa %ymm8, 512(%r8)
+vmovdqa %ymm0, 544(%r8)
+vmovdqa %ymm1, 576(%r8)
+vmovdqa %ymm7, 608(%r8)
+vmovdqa %ymm5, 640(%r8)
+vmovdqa %ymm2, 672(%r8)
+vmovdqa %ymm3, 704(%r8)
+vmovdqa %ymm9, 736(%r8)
vmovdqa 5344(%r12), %ymm0
vpsubw 5440(%r12), %ymm0, %ymm0
vmovdqa 5728(%r12), %ymm1
@@ -7275,14 +7285,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 5248(%r12), %ymm8
vmovdqa 6112(%r12), %ymm9
-vmovdqa %ymm8, 768(%rsp)
-vmovdqa %ymm0, 800(%rsp)
-vmovdqa %ymm1, 832(%rsp)
-vmovdqa %ymm7, 864(%rsp)
-vmovdqa %ymm5, 896(%rsp)
-vmovdqa %ymm2, 928(%rsp)
-vmovdqa %ymm3, 960(%rsp)
-vmovdqa %ymm9, 992(%rsp)
+vmovdqa %ymm8, 768(%r8)
+vmovdqa %ymm0, 800(%r8)
+vmovdqa %ymm1, 832(%r8)
+vmovdqa %ymm7, 864(%r8)
+vmovdqa %ymm5, 896(%r8)
+vmovdqa %ymm2, 928(%r8)
+vmovdqa %ymm3, 960(%r8)
+vmovdqa %ymm9, 992(%r8)
vmovdqa 7072(%r12), %ymm0
vpsubw 7168(%r12), %ymm0, %ymm0
vmovdqa 7456(%r12), %ymm1
@@ -7318,14 +7328,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 6976(%r12), %ymm8
vmovdqa 7840(%r12), %ymm9
-vmovdqa %ymm8, 1024(%rsp)
-vmovdqa %ymm0, 1056(%rsp)
-vmovdqa %ymm1, 1088(%rsp)
-vmovdqa %ymm7, 1120(%rsp)
-vmovdqa %ymm5, 1152(%rsp)
-vmovdqa %ymm2, 1184(%rsp)
-vmovdqa %ymm3, 1216(%rsp)
-vmovdqa %ymm9, 1248(%rsp)
+vmovdqa %ymm8, 1024(%r8)
+vmovdqa %ymm0, 1056(%r8)
+vmovdqa %ymm1, 1088(%r8)
+vmovdqa %ymm7, 1120(%r8)
+vmovdqa %ymm5, 1152(%r8)
+vmovdqa %ymm2, 1184(%r8)
+vmovdqa %ymm3, 1216(%r8)
+vmovdqa %ymm9, 1248(%r8)
vmovdqa 8800(%r12), %ymm0
vpsubw 8896(%r12), %ymm0, %ymm0
vmovdqa 9184(%r12), %ymm1
@@ -7361,14 +7371,14 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 8704(%r12), %ymm8
vmovdqa 9568(%r12), %ymm9
-vmovdqa %ymm8, 1280(%rsp)
-vmovdqa %ymm0, 1312(%rsp)
-vmovdqa %ymm1, 1344(%rsp)
-vmovdqa %ymm7, 1376(%rsp)
-vmovdqa %ymm5, 1408(%rsp)
-vmovdqa %ymm2, 1440(%rsp)
-vmovdqa %ymm3, 1472(%rsp)
-vmovdqa %ymm9, 1504(%rsp)
+vmovdqa %ymm8, 1280(%r8)
+vmovdqa %ymm0, 1312(%r8)
+vmovdqa %ymm1, 1344(%r8)
+vmovdqa %ymm7, 1376(%r8)
+vmovdqa %ymm5, 1408(%r8)
+vmovdqa %ymm2, 1440(%r8)
+vmovdqa %ymm3, 1472(%r8)
+vmovdqa %ymm9, 1504(%r8)
vmovdqa 10528(%r12), %ymm0
vpsubw 10624(%r12), %ymm0, %ymm0
vmovdqa 10912(%r12), %ymm1
@@ -7404,23 +7414,23 @@ vpsubw %ymm0, %ymm7, %ymm7
vpaddw %ymm4, %ymm7, %ymm7
vmovdqa 10432(%r12), %ymm8
vmovdqa 11296(%r12), %ymm9
-vmovdqa %ymm8, 1536(%rsp)
-vmovdqa %ymm0, 1568(%rsp)
-vmovdqa %ymm1, 1600(%rsp)
-vmovdqa %ymm7, 1632(%rsp)
-vmovdqa %ymm5, 1664(%rsp)
-vmovdqa %ymm2, 1696(%rsp)
-vmovdqa %ymm3, 1728(%rsp)
-vmovdqa %ymm9, 1760(%rsp)
-vmovdqa 0(%rsp), %ymm11
+vmovdqa %ymm8, 1536(%r8)
+vmovdqa %ymm0, 1568(%r8)
+vmovdqa %ymm1, 1600(%r8)
+vmovdqa %ymm7, 1632(%r8)
+vmovdqa %ymm5, 1664(%r8)
+vmovdqa %ymm2, 1696(%r8)
+vmovdqa %ymm3, 1728(%r8)
+vmovdqa %ymm9, 1760(%r8)
+vmovdqa 0(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm4
vpunpckhwd const0(%rip), %ymm11, %ymm2
vpslld $1, %ymm4, %ymm4
vpslld $1, %ymm2, %ymm2
-vmovdqa 256(%rsp), %ymm9
+vmovdqa 256(%r8), %ymm9
vpunpcklwd const0(%rip), %ymm9, %ymm8
vpunpckhwd const0(%rip), %ymm9, %ymm9
-vmovdqa 512(%rsp), %ymm6
+vmovdqa 512(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm8, %ymm3
@@ -7434,7 +7444,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1536(%rsp), %ymm5
+vmovdqa 1536(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm9
vpunpckhwd const0(%rip), %ymm5, %ymm8
vpslld $1, %ymm9, %ymm9
@@ -7446,9 +7456,9 @@ vpsrld $1, %ymm7, %ymm7
vpand mask32_to_16(%rip), %ymm3, %ymm3
vpand mask32_to_16(%rip), %ymm7, %ymm7
vpackusdw %ymm7, %ymm3, %ymm7
-vmovdqa 768(%rsp), %ymm3
-vpaddw 1024(%rsp), %ymm3, %ymm8
-vpsubw 1024(%rsp), %ymm3, %ymm3
+vmovdqa 768(%r8), %ymm3
+vpaddw 1024(%r8), %ymm3, %ymm8
+vpsubw 1024(%r8), %ymm3, %ymm3
vpsrlw $2, %ymm3, %ymm3
vpsubw %ymm6, %ymm3, %ymm3
vpmullw %ymm14, %ymm3, %ymm3
@@ -7458,7 +7468,7 @@ vpsllw $7, %ymm5, %ymm8
vpsubw %ymm8, %ymm9, %ymm8
vpsrlw $3, %ymm8, %ymm8
vpsubw %ymm7, %ymm8, %ymm8
-vmovdqa 1280(%rsp), %ymm9
+vmovdqa 1280(%r8), %ymm9
vpsubw %ymm11, %ymm9, %ymm9
vpmullw %ymm15, %ymm5, %ymm2
vpsubw %ymm2, %ymm9, %ymm2
@@ -7482,27 +7492,27 @@ vpand mask5_3_5_3(%rip), %ymm8, %ymm8
vpermq $139, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm4
vpor %ymm4, %ymm8, %ymm8
-vpaddw 2048(%rsp), %ymm11, %ymm11
+vpaddw 2048(%r8), %ymm11, %ymm11
vpaddw %ymm8, %ymm11, %ymm11
-vmovdqa %xmm2, 2048(%rsp)
+vmovdqa %xmm2, 2048(%r8)
vpshufb shuf48_16(%rip), %ymm9, %ymm9
vpand mask3_5_4_3_1(%rip), %ymm9, %ymm2
vpand mask5_3_5_3(%rip), %ymm9, %ymm9
vpermq $139, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm4
vpor %ymm4, %ymm9, %ymm9
-vpaddw 2304(%rsp), %ymm6, %ymm6
+vpaddw 2304(%r8), %ymm6, %ymm6
vpaddw %ymm9, %ymm6, %ymm6
-vmovdqa %xmm2, 2304(%rsp)
+vmovdqa %xmm2, 2304(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_4_3_1(%rip), %ymm5, %ymm2
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
vpermq $139, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm4
vpor %ymm4, %ymm5, %ymm5
-vpaddw 2560(%rsp), %ymm7, %ymm7
+vpaddw 2560(%r8), %ymm7, %ymm7
vpaddw %ymm5, %ymm7, %ymm7
-vmovdqa %xmm2, 2560(%rsp)
+vmovdqa %xmm2, 2560(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %xmm11, 64(%rdi)
vextracti128 $1, %ymm11, %xmm11
@@ -7519,15 +7529,15 @@ vpand mask_mod8192(%rip), %ymm3, %ymm3
vmovdqu %xmm3, 1120(%rdi)
vextracti128 $1, %ymm3, %xmm3
vmovq %xmm3, 1136(%rdi)
-vmovdqa 32(%rsp), %ymm5
+vmovdqa 32(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm9
vpunpckhwd const0(%rip), %ymm5, %ymm8
vpslld $1, %ymm9, %ymm9
vpslld $1, %ymm8, %ymm8
-vmovdqa 288(%rsp), %ymm3
+vmovdqa 288(%r8), %ymm3
vpunpcklwd const0(%rip), %ymm3, %ymm7
vpunpckhwd const0(%rip), %ymm3, %ymm3
-vmovdqa 544(%rsp), %ymm6
+vmovdqa 544(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm7, %ymm2
@@ -7541,7 +7551,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1568(%rsp), %ymm11
+vmovdqa 1568(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm3
vpunpckhwd const0(%rip), %ymm11, %ymm7
vpslld $1, %ymm3, %ymm3
@@ -7553,9 +7563,9 @@ vpsrld $1, %ymm4, %ymm4
vpand mask32_to_16(%rip), %ymm2, %ymm2
vpand mask32_to_16(%rip), %ymm4, %ymm4
vpackusdw %ymm4, %ymm2, %ymm4
-vmovdqa 800(%rsp), %ymm2
-vpaddw 1056(%rsp), %ymm2, %ymm7
-vpsubw 1056(%rsp), %ymm2, %ymm2
+vmovdqa 800(%r8), %ymm2
+vpaddw 1056(%r8), %ymm2, %ymm7
+vpsubw 1056(%r8), %ymm2, %ymm2
vpsrlw $2, %ymm2, %ymm2
vpsubw %ymm6, %ymm2, %ymm2
vpmullw %ymm14, %ymm2, %ymm2
@@ -7565,7 +7575,7 @@ vpsllw $7, %ymm11, %ymm7
vpsubw %ymm7, %ymm3, %ymm7
vpsrlw $3, %ymm7, %ymm7
vpsubw %ymm4, %ymm7, %ymm7
-vmovdqa 1312(%rsp), %ymm3
+vmovdqa 1312(%r8), %ymm3
vpsubw %ymm5, %ymm3, %ymm3
vpmullw %ymm15, %ymm11, %ymm8
vpsubw %ymm8, %ymm3, %ymm8
@@ -7589,27 +7599,27 @@ vpand mask5_3_5_3(%rip), %ymm7, %ymm7
vpermq $139, %ymm8, %ymm8
vpand mask_keephigh(%rip), %ymm8, %ymm9
vpor %ymm9, %ymm7, %ymm7
-vpaddw 2080(%rsp), %ymm5, %ymm5
+vpaddw 2080(%r8), %ymm5, %ymm5
vpaddw %ymm7, %ymm5, %ymm5
-vmovdqa %xmm8, 2080(%rsp)
+vmovdqa %xmm8, 2080(%r8)
vpshufb shuf48_16(%rip), %ymm3, %ymm3
vpand mask3_5_4_3_1(%rip), %ymm3, %ymm8
vpand mask5_3_5_3(%rip), %ymm3, %ymm3
vpermq $139, %ymm8, %ymm8
vpand mask_keephigh(%rip), %ymm8, %ymm9
vpor %ymm9, %ymm3, %ymm3
-vpaddw 2336(%rsp), %ymm6, %ymm6
+vpaddw 2336(%r8), %ymm6, %ymm6
vpaddw %ymm3, %ymm6, %ymm6
-vmovdqa %xmm8, 2336(%rsp)
+vmovdqa %xmm8, 2336(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_4_3_1(%rip), %ymm11, %ymm8
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
vpermq $139, %ymm8, %ymm8
vpand mask_keephigh(%rip), %ymm8, %ymm9
vpor %ymm9, %ymm11, %ymm11
-vpaddw 2592(%rsp), %ymm4, %ymm4
+vpaddw 2592(%r8), %ymm4, %ymm4
vpaddw %ymm11, %ymm4, %ymm4
-vmovdqa %xmm8, 2592(%rsp)
+vmovdqa %xmm8, 2592(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %xmm5, 152(%rdi)
vextracti128 $1, %ymm5, %xmm5
@@ -7626,15 +7636,15 @@ vpand mask_mod8192(%rip), %ymm2, %ymm2
vmovdqu %xmm2, 1208(%rdi)
vextracti128 $1, %ymm2, %xmm2
vmovq %xmm2, 1224(%rdi)
-vmovdqa 64(%rsp), %ymm11
+vmovdqa 64(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm3
vpunpckhwd const0(%rip), %ymm11, %ymm7
vpslld $1, %ymm3, %ymm3
vpslld $1, %ymm7, %ymm7
-vmovdqa 320(%rsp), %ymm2
+vmovdqa 320(%r8), %ymm2
vpunpcklwd const0(%rip), %ymm2, %ymm4
vpunpckhwd const0(%rip), %ymm2, %ymm2
-vmovdqa 576(%rsp), %ymm6
+vmovdqa 576(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm4, %ymm8
@@ -7648,7 +7658,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1600(%rsp), %ymm5
+vmovdqa 1600(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm2
vpunpckhwd const0(%rip), %ymm5, %ymm4
vpslld $1, %ymm2, %ymm2
@@ -7660,9 +7670,9 @@ vpsrld $1, %ymm9, %ymm9
vpand mask32_to_16(%rip), %ymm8, %ymm8
vpand mask32_to_16(%rip), %ymm9, %ymm9
vpackusdw %ymm9, %ymm8, %ymm9
-vmovdqa 832(%rsp), %ymm8
-vpaddw 1088(%rsp), %ymm8, %ymm4
-vpsubw 1088(%rsp), %ymm8, %ymm8
+vmovdqa 832(%r8), %ymm8
+vpaddw 1088(%r8), %ymm8, %ymm4
+vpsubw 1088(%r8), %ymm8, %ymm8
vpsrlw $2, %ymm8, %ymm8
vpsubw %ymm6, %ymm8, %ymm8
vpmullw %ymm14, %ymm8, %ymm8
@@ -7672,7 +7682,7 @@ vpsllw $7, %ymm5, %ymm4
vpsubw %ymm4, %ymm2, %ymm4
vpsrlw $3, %ymm4, %ymm4
vpsubw %ymm9, %ymm4, %ymm4
-vmovdqa 1344(%rsp), %ymm2
+vmovdqa 1344(%r8), %ymm2
vpsubw %ymm11, %ymm2, %ymm2
vpmullw %ymm15, %ymm5, %ymm7
vpsubw %ymm7, %ymm2, %ymm7
@@ -7696,27 +7706,27 @@ vpand mask5_3_5_3(%rip), %ymm4, %ymm4
vpermq $139, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm3
vpor %ymm3, %ymm4, %ymm4
-vpaddw 2112(%rsp), %ymm11, %ymm11
+vpaddw 2112(%r8), %ymm11, %ymm11
vpaddw %ymm4, %ymm11, %ymm11
-vmovdqa %xmm7, 2112(%rsp)
+vmovdqa %xmm7, 2112(%r8)
vpshufb shuf48_16(%rip), %ymm2, %ymm2
vpand mask3_5_4_3_1(%rip), %ymm2, %ymm7
vpand mask5_3_5_3(%rip), %ymm2, %ymm2
vpermq $139, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm3
vpor %ymm3, %ymm2, %ymm2
-vpaddw 2368(%rsp), %ymm6, %ymm6
+vpaddw 2368(%r8), %ymm6, %ymm6
vpaddw %ymm2, %ymm6, %ymm6
-vmovdqa %xmm7, 2368(%rsp)
+vmovdqa %xmm7, 2368(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_4_3_1(%rip), %ymm5, %ymm7
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
vpermq $139, %ymm7, %ymm7
vpand mask_keephigh(%rip), %ymm7, %ymm3
vpor %ymm3, %ymm5, %ymm5
-vpaddw 2624(%rsp), %ymm9, %ymm9
+vpaddw 2624(%r8), %ymm9, %ymm9
vpaddw %ymm5, %ymm9, %ymm9
-vmovdqa %xmm7, 2624(%rsp)
+vmovdqa %xmm7, 2624(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %xmm11, 240(%rdi)
vextracti128 $1, %ymm11, %xmm11
@@ -7733,15 +7743,15 @@ vpand mask_mod8192(%rip), %ymm8, %ymm8
vmovdqu %xmm8, 1296(%rdi)
vextracti128 $1, %ymm8, %xmm8
vmovq %xmm8, 1312(%rdi)
-vmovdqa 96(%rsp), %ymm5
+vmovdqa 96(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm2
vpunpckhwd const0(%rip), %ymm5, %ymm4
vpslld $1, %ymm2, %ymm2
vpslld $1, %ymm4, %ymm4
-vmovdqa 352(%rsp), %ymm8
+vmovdqa 352(%r8), %ymm8
vpunpcklwd const0(%rip), %ymm8, %ymm9
vpunpckhwd const0(%rip), %ymm8, %ymm8
-vmovdqa 608(%rsp), %ymm6
+vmovdqa 608(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm9, %ymm7
@@ -7755,7 +7765,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1632(%rsp), %ymm11
+vmovdqa 1632(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm8
vpunpckhwd const0(%rip), %ymm11, %ymm9
vpslld $1, %ymm8, %ymm8
@@ -7767,9 +7777,9 @@ vpsrld $1, %ymm3, %ymm3
vpand mask32_to_16(%rip), %ymm7, %ymm7
vpand mask32_to_16(%rip), %ymm3, %ymm3
vpackusdw %ymm3, %ymm7, %ymm3
-vmovdqa 864(%rsp), %ymm7
-vpaddw 1120(%rsp), %ymm7, %ymm9
-vpsubw 1120(%rsp), %ymm7, %ymm7
+vmovdqa 864(%r8), %ymm7
+vpaddw 1120(%r8), %ymm7, %ymm9
+vpsubw 1120(%r8), %ymm7, %ymm7
vpsrlw $2, %ymm7, %ymm7
vpsubw %ymm6, %ymm7, %ymm7
vpmullw %ymm14, %ymm7, %ymm7
@@ -7779,7 +7789,7 @@ vpsllw $7, %ymm11, %ymm9
vpsubw %ymm9, %ymm8, %ymm9
vpsrlw $3, %ymm9, %ymm9
vpsubw %ymm3, %ymm9, %ymm9
-vmovdqa 1376(%rsp), %ymm8
+vmovdqa 1376(%r8), %ymm8
vpsubw %ymm5, %ymm8, %ymm8
vpmullw %ymm15, %ymm11, %ymm4
vpsubw %ymm4, %ymm8, %ymm4
@@ -7803,60 +7813,60 @@ vpand mask5_3_5_3(%rip), %ymm9, %ymm9
vpermq $139, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm2
vpor %ymm2, %ymm9, %ymm9
-vpaddw 2144(%rsp), %ymm5, %ymm5
+vpaddw 2144(%r8), %ymm5, %ymm5
vpaddw %ymm9, %ymm5, %ymm5
-vmovdqa %xmm4, 2144(%rsp)
+vmovdqa %xmm4, 2144(%r8)
vpshufb shuf48_16(%rip), %ymm8, %ymm8
vpand mask3_5_4_3_1(%rip), %ymm8, %ymm4
vpand mask5_3_5_3(%rip), %ymm8, %ymm8
vpermq $139, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm2
vpor %ymm2, %ymm8, %ymm8
-vpaddw 2400(%rsp), %ymm6, %ymm6
+vpaddw 2400(%r8), %ymm6, %ymm6
vpaddw %ymm8, %ymm6, %ymm6
-vmovdqa %xmm4, 2400(%rsp)
+vmovdqa %xmm4, 2400(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_4_3_1(%rip), %ymm11, %ymm4
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
vpermq $139, %ymm4, %ymm4
vpand mask_keephigh(%rip), %ymm4, %ymm2
vpor %ymm2, %ymm11, %ymm11
-vpaddw 2656(%rsp), %ymm3, %ymm3
+vpaddw 2656(%r8), %ymm3, %ymm3
vpaddw %ymm11, %ymm3, %ymm3
-vmovdqa %xmm4, 2656(%rsp)
+vmovdqa %xmm4, 2656(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %xmm5, 328(%rdi)
vextracti128 $1, %ymm5, %xmm5
vmovq %xmm5, 344(%rdi)
vpshufb shufmin1_mask3(%rip), %ymm5, %ymm5
-vmovdqa %xmm5, 1792(%rsp)
+vmovdqa %xmm5, 1792(%r8)
vpand mask_mod8192(%rip), %ymm6, %ymm6
vmovdqu %xmm6, 680(%rdi)
vextracti128 $1, %ymm6, %xmm6
vmovq %xmm6, 696(%rdi)
vpshufb shufmin1_mask3(%rip), %ymm6, %ymm6
-vmovdqa %xmm6, 1824(%rsp)
+vmovdqa %xmm6, 1824(%r8)
vpand mask_mod8192(%rip), %ymm3, %ymm3
vmovdqu %xmm3, 1032(%rdi)
vextracti128 $1, %ymm3, %xmm3
vmovq %xmm3, 1048(%rdi)
vpshufb shufmin1_mask3(%rip), %ymm3, %ymm3
-vmovdqa %xmm3, 1856(%rsp)
+vmovdqa %xmm3, 1856(%r8)
vpand mask_mod8192(%rip), %ymm7, %ymm7
vmovdqu %xmm7, 1384(%rdi)
vextracti128 $1, %ymm7, %xmm7
vpextrw $0, %xmm7, 1400(%rdi)
vpshufb shufmin1_mask3(%rip), %ymm7, %ymm7
-vmovdqa %xmm7, 1888(%rsp)
-vmovdqa 128(%rsp), %ymm11
+vmovdqa %xmm7, 1888(%r8)
+vmovdqa 128(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm8
vpunpckhwd const0(%rip), %ymm11, %ymm9
vpslld $1, %ymm8, %ymm8
vpslld $1, %ymm9, %ymm9
-vmovdqa 384(%rsp), %ymm7
+vmovdqa 384(%r8), %ymm7
vpunpcklwd const0(%rip), %ymm7, %ymm3
vpunpckhwd const0(%rip), %ymm7, %ymm7
-vmovdqa 640(%rsp), %ymm6
+vmovdqa 640(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm3, %ymm4
@@ -7870,7 +7880,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1664(%rsp), %ymm5
+vmovdqa 1664(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm7
vpunpckhwd const0(%rip), %ymm5, %ymm3
vpslld $1, %ymm7, %ymm7
@@ -7882,9 +7892,9 @@ vpsrld $1, %ymm2, %ymm2
vpand mask32_to_16(%rip), %ymm4, %ymm4
vpand mask32_to_16(%rip), %ymm2, %ymm2
vpackusdw %ymm2, %ymm4, %ymm2
-vmovdqa 896(%rsp), %ymm4
-vpaddw 1152(%rsp), %ymm4, %ymm3
-vpsubw 1152(%rsp), %ymm4, %ymm4
+vmovdqa 896(%r8), %ymm4
+vpaddw 1152(%r8), %ymm4, %ymm3
+vpsubw 1152(%r8), %ymm4, %ymm4
vpsrlw $2, %ymm4, %ymm4
vpsubw %ymm6, %ymm4, %ymm4
vpmullw %ymm14, %ymm4, %ymm4
@@ -7894,7 +7904,7 @@ vpsllw $7, %ymm5, %ymm3
vpsubw %ymm3, %ymm7, %ymm3
vpsrlw $3, %ymm3, %ymm3
vpsubw %ymm2, %ymm3, %ymm3
-vmovdqa 1408(%rsp), %ymm7
+vmovdqa 1408(%r8), %ymm7
vpsubw %ymm11, %ymm7, %ymm7
vpmullw %ymm15, %ymm5, %ymm9
vpsubw %ymm9, %ymm7, %ymm9
@@ -7925,40 +7935,40 @@ vpermq $139, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm8
vpor %ymm8, %ymm4, %ymm4
vmovdqu 64(%rdi), %ymm8
-vpaddw 1920(%rsp), %ymm8, %ymm8
+vpaddw 1920(%r8), %ymm8, %ymm8
vpaddw %ymm4, %ymm8, %ymm8
vpand mask_mod8192(%rip), %ymm8, %ymm8
vmovdqu %xmm8, 64(%rdi)
vextracti128 $1, %ymm8, %xmm8
vmovq %xmm8, 80(%rdi)
-vmovdqa %xmm10, 1920(%rsp)
+vmovdqa %xmm10, 1920(%r8)
vpshufb shuf48_16(%rip), %ymm3, %ymm3
vpand mask3_5_4_3_1(%rip), %ymm3, %ymm10
vpand mask5_3_5_3(%rip), %ymm3, %ymm3
vpermq $139, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm8
vpor %ymm8, %ymm3, %ymm3
-vpaddw 2176(%rsp), %ymm11, %ymm11
+vpaddw 2176(%r8), %ymm11, %ymm11
vpaddw %ymm3, %ymm11, %ymm11
-vmovdqa %xmm10, 2176(%rsp)
+vmovdqa %xmm10, 2176(%r8)
vpshufb shuf48_16(%rip), %ymm7, %ymm7
vpand mask3_5_4_3_1(%rip), %ymm7, %ymm10
vpand mask5_3_5_3(%rip), %ymm7, %ymm7
vpermq $139, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm8
vpor %ymm8, %ymm7, %ymm7
-vpaddw 2432(%rsp), %ymm6, %ymm6
+vpaddw 2432(%r8), %ymm6, %ymm6
vpaddw %ymm7, %ymm6, %ymm6
-vmovdqa %xmm10, 2432(%rsp)
+vmovdqa %xmm10, 2432(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_4_3_1(%rip), %ymm5, %ymm10
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
vpermq $139, %ymm10, %ymm10
vpand mask_keephigh(%rip), %ymm10, %ymm8
vpor %ymm8, %ymm5, %ymm5
-vpaddw 2688(%rsp), %ymm2, %ymm2
+vpaddw 2688(%r8), %ymm2, %ymm2
vpaddw %ymm5, %ymm2, %ymm2
-vmovdqa %xmm10, 2688(%rsp)
+vmovdqa %xmm10, 2688(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %xmm11, 416(%rdi)
vextracti128 $1, %ymm11, %xmm11
@@ -7971,15 +7981,15 @@ vpand mask_mod8192(%rip), %ymm2, %ymm2
vmovdqu %xmm2, 1120(%rdi)
vextracti128 $1, %ymm2, %xmm2
vmovq %xmm2, 1136(%rdi)
-vmovdqa 160(%rsp), %ymm5
+vmovdqa 160(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm7
vpunpckhwd const0(%rip), %ymm5, %ymm3
vpslld $1, %ymm7, %ymm7
vpslld $1, %ymm3, %ymm3
-vmovdqa 416(%rsp), %ymm4
+vmovdqa 416(%r8), %ymm4
vpunpcklwd const0(%rip), %ymm4, %ymm2
vpunpckhwd const0(%rip), %ymm4, %ymm4
-vmovdqa 672(%rsp), %ymm6
+vmovdqa 672(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm2, %ymm10
@@ -7993,7 +8003,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1696(%rsp), %ymm11
+vmovdqa 1696(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm4
vpunpckhwd const0(%rip), %ymm11, %ymm2
vpslld $1, %ymm4, %ymm4
@@ -8005,9 +8015,9 @@ vpsrld $1, %ymm8, %ymm8
vpand mask32_to_16(%rip), %ymm10, %ymm10
vpand mask32_to_16(%rip), %ymm8, %ymm8
vpackusdw %ymm8, %ymm10, %ymm8
-vmovdqa 928(%rsp), %ymm10
-vpaddw 1184(%rsp), %ymm10, %ymm2
-vpsubw 1184(%rsp), %ymm10, %ymm10
+vmovdqa 928(%r8), %ymm10
+vpaddw 1184(%r8), %ymm10, %ymm2
+vpsubw 1184(%r8), %ymm10, %ymm10
vpsrlw $2, %ymm10, %ymm10
vpsubw %ymm6, %ymm10, %ymm10
vpmullw %ymm14, %ymm10, %ymm10
@@ -8017,7 +8027,7 @@ vpsllw $7, %ymm11, %ymm2
vpsubw %ymm2, %ymm4, %ymm2
vpsrlw $3, %ymm2, %ymm2
vpsubw %ymm8, %ymm2, %ymm2
-vmovdqa 1440(%rsp), %ymm4
+vmovdqa 1440(%r8), %ymm4
vpsubw %ymm5, %ymm4, %ymm4
vpmullw %ymm15, %ymm11, %ymm3
vpsubw %ymm3, %ymm4, %ymm3
@@ -8048,40 +8058,40 @@ vpermq $139, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm7
vpor %ymm7, %ymm10, %ymm10
vmovdqu 152(%rdi), %ymm7
-vpaddw 1952(%rsp), %ymm7, %ymm7
+vpaddw 1952(%r8), %ymm7, %ymm7
vpaddw %ymm10, %ymm7, %ymm7
vpand mask_mod8192(%rip), %ymm7, %ymm7
vmovdqu %xmm7, 152(%rdi)
vextracti128 $1, %ymm7, %xmm7
vmovq %xmm7, 168(%rdi)
-vmovdqa %xmm9, 1952(%rsp)
+vmovdqa %xmm9, 1952(%r8)
vpshufb shuf48_16(%rip), %ymm2, %ymm2
vpand mask3_5_4_3_1(%rip), %ymm2, %ymm9
vpand mask5_3_5_3(%rip), %ymm2, %ymm2
vpermq $139, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm7
vpor %ymm7, %ymm2, %ymm2
-vpaddw 2208(%rsp), %ymm5, %ymm5
+vpaddw 2208(%r8), %ymm5, %ymm5
vpaddw %ymm2, %ymm5, %ymm5
-vmovdqa %xmm9, 2208(%rsp)
+vmovdqa %xmm9, 2208(%r8)
vpshufb shuf48_16(%rip), %ymm4, %ymm4
vpand mask3_5_4_3_1(%rip), %ymm4, %ymm9
vpand mask5_3_5_3(%rip), %ymm4, %ymm4
vpermq $139, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm7
vpor %ymm7, %ymm4, %ymm4
-vpaddw 2464(%rsp), %ymm6, %ymm6
+vpaddw 2464(%r8), %ymm6, %ymm6
vpaddw %ymm4, %ymm6, %ymm6
-vmovdqa %xmm9, 2464(%rsp)
+vmovdqa %xmm9, 2464(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_4_3_1(%rip), %ymm11, %ymm9
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
vpermq $139, %ymm9, %ymm9
vpand mask_keephigh(%rip), %ymm9, %ymm7
vpor %ymm7, %ymm11, %ymm11
-vpaddw 2720(%rsp), %ymm8, %ymm8
+vpaddw 2720(%r8), %ymm8, %ymm8
vpaddw %ymm11, %ymm8, %ymm8
-vmovdqa %xmm9, 2720(%rsp)
+vmovdqa %xmm9, 2720(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %xmm5, 504(%rdi)
vextracti128 $1, %ymm5, %xmm5
@@ -8094,15 +8104,15 @@ vpand mask_mod8192(%rip), %ymm8, %ymm8
vmovdqu %xmm8, 1208(%rdi)
vextracti128 $1, %ymm8, %xmm8
vmovq %xmm8, 1224(%rdi)
-vmovdqa 192(%rsp), %ymm11
+vmovdqa 192(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm4
vpunpckhwd const0(%rip), %ymm11, %ymm2
vpslld $1, %ymm4, %ymm4
vpslld $1, %ymm2, %ymm2
-vmovdqa 448(%rsp), %ymm10
+vmovdqa 448(%r8), %ymm10
vpunpcklwd const0(%rip), %ymm10, %ymm8
vpunpckhwd const0(%rip), %ymm10, %ymm10
-vmovdqa 704(%rsp), %ymm6
+vmovdqa 704(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm5
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm5, %ymm8, %ymm9
@@ -8116,7 +8126,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm5, %ymm5
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm5, %ymm6
-vmovdqa 1728(%rsp), %ymm5
+vmovdqa 1728(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm10
vpunpckhwd const0(%rip), %ymm5, %ymm8
vpslld $1, %ymm10, %ymm10
@@ -8128,9 +8138,9 @@ vpsrld $1, %ymm7, %ymm7
vpand mask32_to_16(%rip), %ymm9, %ymm9
vpand mask32_to_16(%rip), %ymm7, %ymm7
vpackusdw %ymm7, %ymm9, %ymm7
-vmovdqa 960(%rsp), %ymm9
-vpaddw 1216(%rsp), %ymm9, %ymm8
-vpsubw 1216(%rsp), %ymm9, %ymm9
+vmovdqa 960(%r8), %ymm9
+vpaddw 1216(%r8), %ymm9, %ymm8
+vpsubw 1216(%r8), %ymm9, %ymm9
vpsrlw $2, %ymm9, %ymm9
vpsubw %ymm6, %ymm9, %ymm9
vpmullw %ymm14, %ymm9, %ymm9
@@ -8140,7 +8150,7 @@ vpsllw $7, %ymm5, %ymm8
vpsubw %ymm8, %ymm10, %ymm8
vpsrlw $3, %ymm8, %ymm8
vpsubw %ymm7, %ymm8, %ymm8
-vmovdqa 1472(%rsp), %ymm10
+vmovdqa 1472(%r8), %ymm10
vpsubw %ymm11, %ymm10, %ymm10
vpmullw %ymm15, %ymm5, %ymm2
vpsubw %ymm2, %ymm10, %ymm2
@@ -8171,40 +8181,40 @@ vpermq $139, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm4
vpor %ymm4, %ymm9, %ymm9
vmovdqu 240(%rdi), %ymm4
-vpaddw 1984(%rsp), %ymm4, %ymm4
+vpaddw 1984(%r8), %ymm4, %ymm4
vpaddw %ymm9, %ymm4, %ymm4
vpand mask_mod8192(%rip), %ymm4, %ymm4
vmovdqu %xmm4, 240(%rdi)
vextracti128 $1, %ymm4, %xmm4
vmovq %xmm4, 256(%rdi)
-vmovdqa %xmm3, 1984(%rsp)
+vmovdqa %xmm3, 1984(%r8)
vpshufb shuf48_16(%rip), %ymm8, %ymm8
vpand mask3_5_4_3_1(%rip), %ymm8, %ymm3
vpand mask5_3_5_3(%rip), %ymm8, %ymm8
vpermq $139, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm4
vpor %ymm4, %ymm8, %ymm8
-vpaddw 2240(%rsp), %ymm11, %ymm11
+vpaddw 2240(%r8), %ymm11, %ymm11
vpaddw %ymm8, %ymm11, %ymm11
-vmovdqa %xmm3, 2240(%rsp)
+vmovdqa %xmm3, 2240(%r8)
vpshufb shuf48_16(%rip), %ymm10, %ymm10
vpand mask3_5_4_3_1(%rip), %ymm10, %ymm3
vpand mask5_3_5_3(%rip), %ymm10, %ymm10
vpermq $139, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm4
vpor %ymm4, %ymm10, %ymm10
-vpaddw 2496(%rsp), %ymm6, %ymm6
+vpaddw 2496(%r8), %ymm6, %ymm6
vpaddw %ymm10, %ymm6, %ymm6
-vmovdqa %xmm3, 2496(%rsp)
+vmovdqa %xmm3, 2496(%r8)
vpshufb shuf48_16(%rip), %ymm5, %ymm5
vpand mask3_5_4_3_1(%rip), %ymm5, %ymm3
vpand mask5_3_5_3(%rip), %ymm5, %ymm5
vpermq $139, %ymm3, %ymm3
vpand mask_keephigh(%rip), %ymm3, %ymm4
vpor %ymm4, %ymm5, %ymm5
-vpaddw 2752(%rsp), %ymm7, %ymm7
+vpaddw 2752(%r8), %ymm7, %ymm7
vpaddw %ymm5, %ymm7, %ymm7
-vmovdqa %xmm3, 2752(%rsp)
+vmovdqa %xmm3, 2752(%r8)
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %xmm11, 592(%rdi)
vextracti128 $1, %ymm11, %xmm11
@@ -8217,15 +8227,15 @@ vpand mask_mod8192(%rip), %ymm7, %ymm7
vmovdqu %xmm7, 1296(%rdi)
vextracti128 $1, %ymm7, %xmm7
vmovq %xmm7, 1312(%rdi)
-vmovdqa 224(%rsp), %ymm5
+vmovdqa 224(%r8), %ymm5
vpunpcklwd const0(%rip), %ymm5, %ymm10
vpunpckhwd const0(%rip), %ymm5, %ymm8
vpslld $1, %ymm10, %ymm10
vpslld $1, %ymm8, %ymm8
-vmovdqa 480(%rsp), %ymm9
+vmovdqa 480(%r8), %ymm9
vpunpcklwd const0(%rip), %ymm9, %ymm7
vpunpckhwd const0(%rip), %ymm9, %ymm9
-vmovdqa 736(%rsp), %ymm6
+vmovdqa 736(%r8), %ymm6
vpunpcklwd const0(%rip), %ymm6, %ymm11
vpunpckhwd const0(%rip), %ymm6, %ymm6
vpaddd %ymm11, %ymm7, %ymm3
@@ -8239,7 +8249,7 @@ vpsrld $1, %ymm6, %ymm6
vpand mask32_to_16(%rip), %ymm11, %ymm11
vpand mask32_to_16(%rip), %ymm6, %ymm6
vpackusdw %ymm6, %ymm11, %ymm6
-vmovdqa 1760(%rsp), %ymm11
+vmovdqa 1760(%r8), %ymm11
vpunpcklwd const0(%rip), %ymm11, %ymm9
vpunpckhwd const0(%rip), %ymm11, %ymm7
vpslld $1, %ymm9, %ymm9
@@ -8251,9 +8261,9 @@ vpsrld $1, %ymm4, %ymm4
vpand mask32_to_16(%rip), %ymm3, %ymm3
vpand mask32_to_16(%rip), %ymm4, %ymm4
vpackusdw %ymm4, %ymm3, %ymm4
-vmovdqa 992(%rsp), %ymm3
-vpaddw 1248(%rsp), %ymm3, %ymm7
-vpsubw 1248(%rsp), %ymm3, %ymm3
+vmovdqa 992(%r8), %ymm3
+vpaddw 1248(%r8), %ymm3, %ymm7
+vpsubw 1248(%r8), %ymm3, %ymm3
vpsrlw $2, %ymm3, %ymm3
vpsubw %ymm6, %ymm3, %ymm3
vpmullw %ymm14, %ymm3, %ymm3
@@ -8263,7 +8273,7 @@ vpsllw $7, %ymm11, %ymm7
vpsubw %ymm7, %ymm9, %ymm7
vpsrlw $3, %ymm7, %ymm7
vpsubw %ymm4, %ymm7, %ymm7
-vmovdqa 1504(%rsp), %ymm9
+vmovdqa 1504(%r8), %ymm9
vpsubw %ymm5, %ymm9, %ymm9
vpmullw %ymm15, %ymm11, %ymm8
vpsubw %ymm8, %ymm9, %ymm8
@@ -8283,16 +8293,29 @@ vpmullw %ymm13, %ymm9, %ymm9
vpsubw %ymm9, %ymm6, %ymm6
vextracti128 $1, %ymm4, %xmm8
vpshufb shufmin1_mask3(%rip), %ymm8, %ymm8
-vmovdqa %ymm8, 2816(%rsp)
+vmovdqa %ymm8, 2816(%r8)
vextracti128 $1, %ymm3, %xmm8
vpshufb shufmin1_mask3(%rip), %ymm8, %ymm8
-vmovdqa %ymm8, 2848(%rsp)
+vmovdqa %ymm8, 2848(%r8)
vextracti128 $1, %ymm7, %xmm8
vpshufb shufmin1_mask3(%rip), %ymm8, %ymm8
-vmovdqa %ymm8, 2880(%rsp)
+vmovdqa %ymm8, 2880(%r8)
vmovdqu 680(%rdi), %ymm8
vmovdqu 1032(%rdi), %ymm10
-vmovdqu 1384(%rdi), %ymm2
+
+# Only 18 bytes can be read at 1384, but vmovdqu reads 32.
+# Copy 18 bytes to the red zone and zero pad to 32 bytes.
+xor %r9, %r9
+movq %r9, -16(%rsp)
+movq %r9, -8(%rsp)
+movq 1384(%rdi), %r9
+movq %r9, -32(%rsp)
+movq 1384+8(%rdi), %r9
+movq %r9, -24(%rsp)
+movw 1384+16(%rdi), %r9w
+movw %r9w, -16(%rsp)
+vmovdqu -32(%rsp), %ymm2
+
vpaddw %ymm5, %ymm8, %ymm5
vpaddw %ymm6, %ymm10, %ymm6
vpaddw %ymm4, %ymm2, %ymm4
@@ -8303,42 +8326,42 @@ vpermq $139, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm10
vpor %ymm10, %ymm3, %ymm3
vmovdqu 328(%rdi), %ymm10
-vpaddw 2016(%rsp), %ymm10, %ymm10
+vpaddw 2016(%r8), %ymm10, %ymm10
vpaddw %ymm3, %ymm10, %ymm10
vpand mask_mod8192(%rip), %ymm10, %ymm10
vmovdqu %xmm10, 328(%rdi)
vextracti128 $1, %ymm10, %xmm10
vmovq %xmm10, 344(%rdi)
vpshufb shufmin1_mask3(%rip), %ymm10, %ymm10
-vmovdqa %xmm10, 1792(%rsp)
-vmovdqa %xmm2, 2016(%rsp)
+vmovdqa %xmm10, 1792(%r8)
+vmovdqa %xmm2, 2016(%r8)
vpshufb shuf48_16(%rip), %ymm7, %ymm7
vpand mask3_5_4_3_1(%rip), %ymm7, %ymm2
vpand mask5_3_5_3(%rip), %ymm7, %ymm7
vpermq $139, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm10
vpor %ymm10, %ymm7, %ymm7
-vpaddw 2272(%rsp), %ymm5, %ymm5
+vpaddw 2272(%r8), %ymm5, %ymm5
vpaddw %ymm7, %ymm5, %ymm5
-vmovdqa %xmm2, 2272(%rsp)
+vmovdqa %xmm2, 2272(%r8)
vpshufb shuf48_16(%rip), %ymm9, %ymm9
vpand mask3_5_4_3_1(%rip), %ymm9, %ymm2
vpand mask5_3_5_3(%rip), %ymm9, %ymm9
vpermq $139, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm10
vpor %ymm10, %ymm9, %ymm9
-vpaddw 2528(%rsp), %ymm6, %ymm6
+vpaddw 2528(%r8), %ymm6, %ymm6
vpaddw %ymm9, %ymm6, %ymm6
-vmovdqa %xmm2, 2528(%rsp)
+vmovdqa %xmm2, 2528(%r8)
vpshufb shuf48_16(%rip), %ymm11, %ymm11
vpand mask3_5_4_3_1(%rip), %ymm11, %ymm2
vpand mask5_3_5_3(%rip), %ymm11, %ymm11
vpermq $139, %ymm2, %ymm2
vpand mask_keephigh(%rip), %ymm2, %ymm10
vpor %ymm10, %ymm11, %ymm11
-vpaddw 2784(%rsp), %ymm4, %ymm4
+vpaddw 2784(%r8), %ymm4, %ymm4
vpaddw %ymm11, %ymm4, %ymm4
-vmovdqa %xmm2, 2784(%rsp)
+vmovdqa %xmm2, 2784(%r8)
vpand mask_mod8192(%rip), %ymm5, %ymm5
vmovdqu %xmm5, 680(%rdi)
vextracti128 $1, %ymm5, %xmm5
@@ -8352,108 +8375,107 @@ vmovdqu %xmm4, 1384(%rdi)
vextracti128 $1, %ymm4, %xmm4
vpextrw $0, %xmm4, 1400(%rdi)
vmovdqu 0(%rdi), %ymm11
-vpaddw 1888(%rsp), %ymm11, %ymm11
-vpaddw 2816(%rsp), %ymm11, %ymm11
+vpaddw 1888(%r8), %ymm11, %ymm11
+vpaddw 2816(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 0(%rdi)
vmovdqu 352(%rdi), %ymm11
-vpaddw 2528(%rsp), %ymm11, %ymm11
-vpaddw 2848(%rsp), %ymm11, %ymm11
+vpaddw 2528(%r8), %ymm11, %ymm11
+vpaddw 2848(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 352(%rdi)
vmovdqu 704(%rdi), %ymm11
-vpaddw 2784(%rsp), %ymm11, %ymm11
-vpaddw 2880(%rsp), %ymm11, %ymm11
+vpaddw 2784(%r8), %ymm11, %ymm11
+vpaddw 2880(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 704(%rdi)
vmovdqu 88(%rdi), %ymm11
-vpaddw 2048(%rsp), %ymm11, %ymm11
-vpaddw 1920(%rsp), %ymm11, %ymm11
+vpaddw 2048(%r8), %ymm11, %ymm11
+vpaddw 1920(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 88(%rdi)
vmovdqu 440(%rdi), %ymm11
-vpaddw 2304(%rsp), %ymm11, %ymm11
+vpaddw 2304(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 440(%rdi)
vmovdqu 792(%rdi), %ymm11
-vpaddw 2560(%rsp), %ymm11, %ymm11
+vpaddw 2560(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 792(%rdi)
vmovdqu 176(%rdi), %ymm11
-vpaddw 2080(%rsp), %ymm11, %ymm11
-vpaddw 1952(%rsp), %ymm11, %ymm11
+vpaddw 2080(%r8), %ymm11, %ymm11
+vpaddw 1952(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 176(%rdi)
vmovdqu 528(%rdi), %ymm11
-vpaddw 2336(%rsp), %ymm11, %ymm11
+vpaddw 2336(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 528(%rdi)
vmovdqu 880(%rdi), %ymm11
-vpaddw 2592(%rsp), %ymm11, %ymm11
+vpaddw 2592(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 880(%rdi)
vmovdqu 264(%rdi), %ymm11
-vpaddw 2112(%rsp), %ymm11, %ymm11
-vpaddw 1984(%rsp), %ymm11, %ymm11
+vpaddw 2112(%r8), %ymm11, %ymm11
+vpaddw 1984(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 264(%rdi)
vmovdqu 616(%rdi), %ymm11
-vpaddw 2368(%rsp), %ymm11, %ymm11
+vpaddw 2368(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 616(%rdi)
vmovdqu 968(%rdi), %ymm11
-vpaddw 2624(%rsp), %ymm11, %ymm11
+vpaddw 2624(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 968(%rdi)
vmovdqu 352(%rdi), %ymm11
-vpaddw 2144(%rsp), %ymm11, %ymm11
+vpaddw 2144(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 352(%rdi)
vmovdqu 704(%rdi), %ymm11
-vpaddw 2400(%rsp), %ymm11, %ymm11
+vpaddw 2400(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 704(%rdi)
vmovdqu 1056(%rdi), %ymm11
-vpaddw 2656(%rsp), %ymm11, %ymm11
+vpaddw 2656(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 1056(%rdi)
vmovdqu 440(%rdi), %ymm11
-vpaddw 2176(%rsp), %ymm11, %ymm11
+vpaddw 2176(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 440(%rdi)
vmovdqu 792(%rdi), %ymm11
-vpaddw 2432(%rsp), %ymm11, %ymm11
+vpaddw 2432(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 792(%rdi)
vmovdqu 1144(%rdi), %ymm11
-vpaddw 2688(%rsp), %ymm11, %ymm11
+vpaddw 2688(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 1144(%rdi)
vmovdqu 528(%rdi), %ymm11
-vpaddw 2208(%rsp), %ymm11, %ymm11
+vpaddw 2208(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 528(%rdi)
vmovdqu 880(%rdi), %ymm11
-vpaddw 2464(%rsp), %ymm11, %ymm11
+vpaddw 2464(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 880(%rdi)
vmovdqu 1232(%rdi), %ymm11
-vpaddw 2720(%rsp), %ymm11, %ymm11
+vpaddw 2720(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 1232(%rdi)
vmovdqu 616(%rdi), %ymm11
-vpaddw 2240(%rsp), %ymm11, %ymm11
+vpaddw 2240(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 616(%rdi)
vmovdqu 968(%rdi), %ymm11
-vpaddw 2496(%rsp), %ymm11, %ymm11
+vpaddw 2496(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 968(%rdi)
vmovdqu 1320(%rdi), %ymm11
-vpaddw 2752(%rsp), %ymm11, %ymm11
+vpaddw 2752(%r8), %ymm11, %ymm11
vpand mask_mod8192(%rip), %ymm11, %ymm11
vmovdqu %ymm11, 1320(%rdi)
-mov %r8, %rsp
pop %r12
.cfi_restore r12
pop %rbp
diff --git a/deps/boringssl/src/crypto/hrss/hrss.c b/deps/boringssl/src/crypto/hrss/hrss.c
index 67ff4c1..0247001 100644
--- a/deps/boringssl/src/crypto/hrss/hrss.c
+++ b/deps/boringssl/src/crypto/hrss/hrss.c
@@ -22,6 +22,7 @@
#include <openssl/cpu.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
+#include <openssl/rand.h>
#include <openssl/sha.h>
#if defined(_MSC_VER)
@@ -939,6 +940,34 @@ OPENSSL_UNUSED static void poly_print(const struct poly *p) {
printf("]\n");
}
+// POLY_MUL_SCRATCH contains space for the working variables needed by
+// |poly_mul|. The contents afterwards may be discarded, but the object may also
+// be reused with future |poly_mul| calls to save heap allocations.
+//
+// This object must have 32-byte alignment.
+struct POLY_MUL_SCRATCH {
+ union {
+ // This is used by |poly_mul_novec|.
+ struct {
+ uint16_t prod[2 * N];
+ uint16_t scratch[1318];
+ } novec;
+
+#if defined(HRSS_HAVE_VECTOR_UNIT)
+ // This is used by |poly_mul_vec|.
+ struct {
+ vec_t prod[VECS_PER_POLY * 2];
+ vec_t scratch[172];
+ } vec;
+#endif
+
+#if defined(POLY_RQ_MUL_ASM)
+ // This is the space used by |poly_Rq_mul|.
+ uint8_t rq[POLY_MUL_RQ_SCRATCH_SPACE];
+#endif
+ } u;
+};
+
#if defined(HRSS_HAVE_VECTOR_UNIT)
// poly_mul_vec_aux is a recursive function that multiplies |n| words from |a|
@@ -1184,8 +1213,8 @@ static void poly_mul_vec_aux(vec_t *restrict out, vec_t *restrict scratch,
}
// poly_mul_vec sets |*out| to |x|×|y| mod (𝑥^n - 1).
-static void poly_mul_vec(struct poly *out, const struct poly *x,
- const struct poly *y) {
+static void poly_mul_vec(struct POLY_MUL_SCRATCH *scratch, struct poly *out,
+ const struct poly *x, const struct poly *y) {
OPENSSL_memset((uint16_t *)&x->v[N], 0, 3 * sizeof(uint16_t));
OPENSSL_memset((uint16_t *)&y->v[N], 0, 3 * sizeof(uint16_t));
@@ -1194,9 +1223,9 @@ static void poly_mul_vec(struct poly *out, const struct poly *x,
OPENSSL_STATIC_ASSERT(alignof(struct poly) == alignof(vec_t),
"struct poly has incorrect alignment");
- vec_t prod[VECS_PER_POLY * 2];
- vec_t scratch[172];
- poly_mul_vec_aux(prod, scratch, x->vectors, y->vectors, VECS_PER_POLY);
+ vec_t *const prod = scratch->u.vec.prod;
+ vec_t *const aux_scratch = scratch->u.vec.scratch;
+ poly_mul_vec_aux(prod, aux_scratch, x->vectors, y->vectors, VECS_PER_POLY);
// |prod| needs to be reduced mod (𝑥^n - 1), which just involves adding the
// upper-half to the lower-half. However, N is 701, which isn't a multiple of
@@ -1273,11 +1302,11 @@ static void poly_mul_novec_aux(uint16_t *out, uint16_t *scratch,
}
// poly_mul_novec sets |*out| to |x|×|y| mod (𝑥^n - 1).
-static void poly_mul_novec(struct poly *out, const struct poly *x,
- const struct poly *y) {
- uint16_t prod[2 * N];
- uint16_t scratch[1318];
- poly_mul_novec_aux(prod, scratch, x->v, y->v, N);
+static void poly_mul_novec(struct POLY_MUL_SCRATCH *scratch, struct poly *out,
+ const struct poly *x, const struct poly *y) {
+ uint16_t *const prod = scratch->u.novec.prod;
+ uint16_t *const aux_scratch = scratch->u.novec.scratch;
+ poly_mul_novec_aux(prod, aux_scratch, x->v, y->v, N);
for (size_t i = 0; i < N; i++) {
out->v[i] = prod[i] + prod[i + N];
@@ -1285,25 +1314,25 @@ static void poly_mul_novec(struct poly *out, const struct poly *x,
OPENSSL_memset(&out->v[N], 0, 3 * sizeof(uint16_t));
}
-static void poly_mul(struct poly *r, const struct poly *a,
- const struct poly *b) {
+static void poly_mul(struct POLY_MUL_SCRATCH *scratch, struct poly *r,
+ const struct poly *a, const struct poly *b) {
#if defined(POLY_RQ_MUL_ASM)
const int has_avx2 = (OPENSSL_ia32cap_P[2] & (1 << 5)) != 0;
if (has_avx2) {
- poly_Rq_mul(r->v, a->v, b->v);
+ poly_Rq_mul(r->v, a->v, b->v, scratch->u.rq);
return;
}
#endif
#if defined(HRSS_HAVE_VECTOR_UNIT)
if (vec_capable()) {
- poly_mul_vec(r, a, b);
+ poly_mul_vec(scratch, r, a, b);
return;
}
#endif
// Fallback, non-vector case.
- poly_mul_novec(r, a, b);
+ poly_mul_novec(scratch, r, a, b);
}
// poly_mul_x_minus_1 sets |p| to |p|×(𝑥 - 1) mod (𝑥^n - 1).
@@ -1548,7 +1577,8 @@ static void poly_invert_mod2(struct poly *out, const struct poly *in) {
}
// poly_invert sets |*out| to |in^-1| (i.e. such that |*out|×|in| = 1 mod Φ(N)).
-static void poly_invert(struct poly *out, const struct poly *in) {
+static void poly_invert(struct POLY_MUL_SCRATCH *scratch, struct poly *out,
+ const struct poly *in) {
// Inversion mod Q, which is done based on the result of inverting mod
// 2. See [NTRUTN14] paper, bottom of page two.
struct poly a, *b, tmp;
@@ -1565,9 +1595,9 @@ static void poly_invert(struct poly *out, const struct poly *in) {
// We are working mod Q=2**13 and we need to iterate ceil(log_2(13))
// times, which is four.
for (unsigned i = 0; i < 4; i++) {
- poly_mul(&tmp, &a, b);
+ poly_mul(scratch, &tmp, &a, b);
tmp.v[0] += 2;
- poly_mul(b, b, &tmp);
+ poly_mul(scratch, b, b, &tmp);
}
}
@@ -1871,9 +1901,7 @@ static struct public_key *public_key_from_external(
sizeof(struct HRSS_public_key) >= sizeof(struct public_key) + 15,
"HRSS public key too small");
- uintptr_t p = (uintptr_t)ext;
- p = (p + 15) & ~15;
- return (struct public_key *)p;
+ return align_pointer(ext->opaque, 16);
}
// private_key_from_external does the same thing as |public_key_from_external|,
@@ -1885,151 +1913,219 @@ static struct private_key *private_key_from_external(
sizeof(struct HRSS_private_key) >= sizeof(struct private_key) + 15,
"HRSS private key too small");
- uintptr_t p = (uintptr_t)ext;
- p = (p + 15) & ~15;
- return (struct private_key *)p;
+ return align_pointer(ext->opaque, 16);
}
-void HRSS_generate_key(
+// malloc_align32 returns a pointer to |size| bytes of 32-byte-aligned heap and
+// sets |*out_ptr| to a value that can be passed to |OPENSSL_free| to release
+// it. It returns NULL if out of memory.
+static void *malloc_align32(void **out_ptr, size_t size) {
+ void *ptr = OPENSSL_malloc(size + 31);
+ if (!ptr) {
+ *out_ptr = NULL;
+ return NULL;
+ }
+
+ *out_ptr = ptr;
+ return align_pointer(ptr, 32);
+}
+
+int HRSS_generate_key(
struct HRSS_public_key *out_pub, struct HRSS_private_key *out_priv,
const uint8_t in[HRSS_SAMPLE_BYTES + HRSS_SAMPLE_BYTES + 32]) {
struct public_key *pub = public_key_from_external(out_pub);
struct private_key *priv = private_key_from_external(out_priv);
+ struct vars {
+ struct POLY_MUL_SCRATCH scratch;
+ struct poly f;
+ struct poly pg_phi1;
+ struct poly pfg_phi1;
+ struct poly pfg_phi1_inverse;
+ };
+
+ void *malloc_ptr;
+ struct vars *const vars = malloc_align32(&malloc_ptr, sizeof(struct vars));
+ if (!vars) {
+ // If the caller ignores the return value the output will still be safe.
+ // The private key output is randomised in case it's later passed to
+ // |HRSS_encap|.
+ memset(out_pub, 0, sizeof(struct HRSS_public_key));
+ RAND_bytes((uint8_t*) out_priv, sizeof(struct HRSS_private_key));
+ return 0;
+ }
+
OPENSSL_memcpy(priv->hmac_key, in + 2 * HRSS_SAMPLE_BYTES,
sizeof(priv->hmac_key));
- struct poly f;
- poly_short_sample_plus(&f, in);
- poly3_from_poly(&priv->f, &f);
+ poly_short_sample_plus(&vars->f, in);
+ poly3_from_poly(&priv->f, &vars->f);
HRSS_poly3_invert(&priv->f_inverse, &priv->f);
// pg_phi1 is p (i.e. 3) × g × Φ(1) (i.e. 𝑥-1).
- struct poly pg_phi1;
- poly_short_sample_plus(&pg_phi1, in + HRSS_SAMPLE_BYTES);
+ poly_short_sample_plus(&vars->pg_phi1, in + HRSS_SAMPLE_BYTES);
for (unsigned i = 0; i < N; i++) {
- pg_phi1.v[i] *= 3;
+ vars->pg_phi1.v[i] *= 3;
}
- poly_mul_x_minus_1(&pg_phi1);
+ poly_mul_x_minus_1(&vars->pg_phi1);
- struct poly pfg_phi1;
- poly_mul(&pfg_phi1, &f, &pg_phi1);
+ poly_mul(&vars->scratch, &vars->pfg_phi1, &vars->f, &vars->pg_phi1);
- struct poly pfg_phi1_inverse;
- poly_invert(&pfg_phi1_inverse, &pfg_phi1);
+ poly_invert(&vars->scratch, &vars->pfg_phi1_inverse, &vars->pfg_phi1);
- poly_mul(&pub->ph, &pfg_phi1_inverse, &pg_phi1);
- poly_mul(&pub->ph, &pub->ph, &pg_phi1);
+ poly_mul(&vars->scratch, &pub->ph, &vars->pfg_phi1_inverse, &vars->pg_phi1);
+ poly_mul(&vars->scratch, &pub->ph, &pub->ph, &vars->pg_phi1);
poly_clamp(&pub->ph);
- poly_mul(&priv->ph_inverse, &pfg_phi1_inverse, &f);
- poly_mul(&priv->ph_inverse, &priv->ph_inverse, &f);
+ poly_mul(&vars->scratch, &priv->ph_inverse, &vars->pfg_phi1_inverse,
+ &vars->f);
+ poly_mul(&vars->scratch, &priv->ph_inverse, &priv->ph_inverse, &vars->f);
poly_clamp(&priv->ph_inverse);
+
+ OPENSSL_free(malloc_ptr);
+ return 1;
}
static const char kSharedKey[] = "shared key";
-void HRSS_encap(uint8_t out_ciphertext[POLY_BYTES],
- uint8_t out_shared_key[32],
- const struct HRSS_public_key *in_pub,
- const uint8_t in[HRSS_SAMPLE_BYTES + HRSS_SAMPLE_BYTES]) {
+int HRSS_encap(uint8_t out_ciphertext[POLY_BYTES], uint8_t out_shared_key[32],
+ const struct HRSS_public_key *in_pub,
+ const uint8_t in[HRSS_SAMPLE_BYTES + HRSS_SAMPLE_BYTES]) {
const struct public_key *pub =
public_key_from_external((struct HRSS_public_key *)in_pub);
- struct poly m, r, m_lifted;
- poly_short_sample(&m, in);
- poly_short_sample(&r, in + HRSS_SAMPLE_BYTES);
- poly_lift(&m_lifted, &m);
- struct poly prh_plus_m;
- poly_mul(&prh_plus_m, &r, &pub->ph);
+ struct vars {
+ struct POLY_MUL_SCRATCH scratch;
+ struct poly m, r, m_lifted;
+ struct poly prh_plus_m;
+ SHA256_CTX hash_ctx;
+ uint8_t m_bytes[HRSS_POLY3_BYTES];
+ uint8_t r_bytes[HRSS_POLY3_BYTES];
+ };
+
+ void *malloc_ptr;
+ struct vars *const vars = malloc_align32(&malloc_ptr, sizeof(struct vars));
+ if (!vars) {
+ // If the caller ignores the return value the output will still be safe.
+ // The private key output is randomised in case it's used to encrypt and
+ // transmit something.
+ memset(out_ciphertext, 0, POLY_BYTES);
+ RAND_bytes(out_shared_key, 32);
+ return 0;
+ }
+
+ poly_short_sample(&vars->m, in);
+ poly_short_sample(&vars->r, in + HRSS_SAMPLE_BYTES);
+ poly_lift(&vars->m_lifted, &vars->m);
+
+ poly_mul(&vars->scratch, &vars->prh_plus_m, &vars->r, &pub->ph);
for (unsigned i = 0; i < N; i++) {
- prh_plus_m.v[i] += m_lifted.v[i];
+ vars->prh_plus_m.v[i] += vars->m_lifted.v[i];
}
- poly_marshal(out_ciphertext, &prh_plus_m);
+ poly_marshal(out_ciphertext, &vars->prh_plus_m);
+
+ poly_marshal_mod3(vars->m_bytes, &vars->m);
+ poly_marshal_mod3(vars->r_bytes, &vars->r);
- uint8_t m_bytes[HRSS_POLY3_BYTES], r_bytes[HRSS_POLY3_BYTES];
- poly_marshal_mod3(m_bytes, &m);
- poly_marshal_mod3(r_bytes, &r);
+ SHA256_Init(&vars->hash_ctx);
+ SHA256_Update(&vars->hash_ctx, kSharedKey, sizeof(kSharedKey));
+ SHA256_Update(&vars->hash_ctx, vars->m_bytes, sizeof(vars->m_bytes));
+ SHA256_Update(&vars->hash_ctx, vars->r_bytes, sizeof(vars->r_bytes));
+ SHA256_Update(&vars->hash_ctx, out_ciphertext, POLY_BYTES);
+ SHA256_Final(out_shared_key, &vars->hash_ctx);
- SHA256_CTX hash_ctx;
- SHA256_Init(&hash_ctx);
- SHA256_Update(&hash_ctx, kSharedKey, sizeof(kSharedKey));
- SHA256_Update(&hash_ctx, m_bytes, sizeof(m_bytes));
- SHA256_Update(&hash_ctx, r_bytes, sizeof(r_bytes));
- SHA256_Update(&hash_ctx, out_ciphertext, POLY_BYTES);
- SHA256_Final(out_shared_key, &hash_ctx);
+ OPENSSL_free(malloc_ptr);
+ return 1;
}
-void HRSS_decap(uint8_t out_shared_key[HRSS_KEY_BYTES],
+int HRSS_decap(uint8_t out_shared_key[HRSS_KEY_BYTES],
const struct HRSS_private_key *in_priv,
const uint8_t *ciphertext, size_t ciphertext_len) {
const struct private_key *priv =
private_key_from_external((struct HRSS_private_key *)in_priv);
+ struct vars {
+ struct POLY_MUL_SCRATCH scratch;
+ uint8_t masked_key[SHA256_CBLOCK];
+ SHA256_CTX hash_ctx;
+ struct poly c;
+ struct poly f, cf;
+ struct poly3 cf3, m3;
+ struct poly m, m_lifted;
+ struct poly r;
+ struct poly3 r3;
+ uint8_t expected_ciphertext[HRSS_CIPHERTEXT_BYTES];
+ uint8_t m_bytes[HRSS_POLY3_BYTES];
+ uint8_t r_bytes[HRSS_POLY3_BYTES];
+ uint8_t shared_key[32];
+ };
+
+ void *malloc_ptr;
+ struct vars *const vars = malloc_align32(&malloc_ptr, sizeof(struct vars));
+ if (!vars) {
+ // If the caller ignores the return value the output will still be safe.
+ // The private key output is randomised in case it's used to encrypt and
+ // transmit something.
+ RAND_bytes(out_shared_key, HRSS_KEY_BYTES);
+ return 0;
+ }
+
// This is HMAC, expanded inline rather than using the |HMAC| function so that
// we can avoid dealing with possible allocation failures and so keep this
// function infallible.
- uint8_t masked_key[SHA256_CBLOCK];
- OPENSSL_STATIC_ASSERT(sizeof(priv->hmac_key) <= sizeof(masked_key),
+ OPENSSL_STATIC_ASSERT(sizeof(priv->hmac_key) <= sizeof(vars->masked_key),
"HRSS HMAC key larger than SHA-256 block size");
for (size_t i = 0; i < sizeof(priv->hmac_key); i++) {
- masked_key[i] = priv->hmac_key[i] ^ 0x36;
+ vars->masked_key[i] = priv->hmac_key[i] ^ 0x36;
}
- OPENSSL_memset(masked_key + sizeof(priv->hmac_key), 0x36,
- sizeof(masked_key) - sizeof(priv->hmac_key));
+ OPENSSL_memset(vars->masked_key + sizeof(priv->hmac_key), 0x36,
+ sizeof(vars->masked_key) - sizeof(priv->hmac_key));
- SHA256_CTX hash_ctx;
- SHA256_Init(&hash_ctx);
- SHA256_Update(&hash_ctx, masked_key, sizeof(masked_key));
- SHA256_Update(&hash_ctx, ciphertext, ciphertext_len);
+ SHA256_Init(&vars->hash_ctx);
+ SHA256_Update(&vars->hash_ctx, vars->masked_key, sizeof(vars->masked_key));
+ SHA256_Update(&vars->hash_ctx, ciphertext, ciphertext_len);
uint8_t inner_digest[SHA256_DIGEST_LENGTH];
- SHA256_Final(inner_digest, &hash_ctx);
+ SHA256_Final(inner_digest, &vars->hash_ctx);
for (size_t i = 0; i < sizeof(priv->hmac_key); i++) {
- masked_key[i] ^= (0x5c ^ 0x36);
+ vars->masked_key[i] ^= (0x5c ^ 0x36);
}
- OPENSSL_memset(masked_key + sizeof(priv->hmac_key), 0x5c,
- sizeof(masked_key) - sizeof(priv->hmac_key));
+ OPENSSL_memset(vars->masked_key + sizeof(priv->hmac_key), 0x5c,
+ sizeof(vars->masked_key) - sizeof(priv->hmac_key));
- SHA256_Init(&hash_ctx);
- SHA256_Update(&hash_ctx, masked_key, sizeof(masked_key));
- SHA256_Update(&hash_ctx, inner_digest, sizeof(inner_digest));
+ SHA256_Init(&vars->hash_ctx);
+ SHA256_Update(&vars->hash_ctx, vars->masked_key, sizeof(vars->masked_key));
+ SHA256_Update(&vars->hash_ctx, inner_digest, sizeof(inner_digest));
OPENSSL_STATIC_ASSERT(HRSS_KEY_BYTES == SHA256_DIGEST_LENGTH,
"HRSS shared key length incorrect");
- SHA256_Final(out_shared_key, &hash_ctx);
+ SHA256_Final(out_shared_key, &vars->hash_ctx);
- struct poly c;
// If the ciphertext is publicly invalid then a random shared key is still
// returned to simply the logic of the caller, but this path is not constant
// time.
if (ciphertext_len != HRSS_CIPHERTEXT_BYTES ||
- !poly_unmarshal(&c, ciphertext)) {
- return;
+ !poly_unmarshal(&vars->c, ciphertext)) {
+ goto out;
}
- struct poly f, cf;
- struct poly3 cf3, m3;
- poly_from_poly3(&f, &priv->f);
- poly_mul(&cf, &c, &f);
- poly3_from_poly(&cf3, &cf);
+ poly_from_poly3(&vars->f, &priv->f);
+ poly_mul(&vars->scratch, &vars->cf, &vars->c, &vars->f);
+ poly3_from_poly(&vars->cf3, &vars->cf);
// Note that cf3 is not reduced mod Φ(N). That reduction is deferred.
- HRSS_poly3_mul(&m3, &cf3, &priv->f_inverse);
+ HRSS_poly3_mul(&vars->m3, &vars->cf3, &priv->f_inverse);
- struct poly m, m_lifted;
- poly_from_poly3(&m, &m3);
- poly_lift(&m_lifted, &m);
+ poly_from_poly3(&vars->m, &vars->m3);
+ poly_lift(&vars->m_lifted, &vars->m);
- struct poly r;
for (unsigned i = 0; i < N; i++) {
- r.v[i] = c.v[i] - m_lifted.v[i];
+ vars->r.v[i] = vars->c.v[i] - vars->m_lifted.v[i];
}
- poly_mul(&r, &r, &priv->ph_inverse);
- poly_mod_phiN(&r);
- poly_clamp(&r);
+ poly_mul(&vars->scratch, &vars->r, &vars->r, &priv->ph_inverse);
+ poly_mod_phiN(&vars->r);
+ poly_clamp(&vars->r);
- struct poly3 r3;
- crypto_word_t ok = poly3_from_poly_checked(&r3, &r);
+ crypto_word_t ok = poly3_from_poly_checked(&vars->r3, &vars->r);
// [NTRUCOMP] section 5.1 includes ReEnc2 and a proof that it's valid. Rather
// than do an expensive |poly_mul|, it rebuilds |c'| from |c - lift(m)|
@@ -2054,32 +2150,34 @@ void HRSS_decap(uint8_t out_shared_key[HRSS_KEY_BYTES],
// The |poly_marshal| here then is just confirming that |poly_unmarshal| is
// strict and could be omitted.
- uint8_t expected_ciphertext[HRSS_CIPHERTEXT_BYTES];
OPENSSL_STATIC_ASSERT(HRSS_CIPHERTEXT_BYTES == POLY_BYTES,
"ciphertext is the wrong size");
- assert(ciphertext_len == sizeof(expected_ciphertext));
- poly_marshal(expected_ciphertext, &c);
-
- uint8_t m_bytes[HRSS_POLY3_BYTES];
- uint8_t r_bytes[HRSS_POLY3_BYTES];
- poly_marshal_mod3(m_bytes, &m);
- poly_marshal_mod3(r_bytes, &r);
-
- ok &= constant_time_is_zero_w(CRYPTO_memcmp(ciphertext, expected_ciphertext,
- sizeof(expected_ciphertext)));
-
- uint8_t shared_key[32];
- SHA256_Init(&hash_ctx);
- SHA256_Update(&hash_ctx, kSharedKey, sizeof(kSharedKey));
- SHA256_Update(&hash_ctx, m_bytes, sizeof(m_bytes));
- SHA256_Update(&hash_ctx, r_bytes, sizeof(r_bytes));
- SHA256_Update(&hash_ctx, expected_ciphertext, sizeof(expected_ciphertext));
- SHA256_Final(shared_key, &hash_ctx);
-
- for (unsigned i = 0; i < sizeof(shared_key); i++) {
+ assert(ciphertext_len == sizeof(vars->expected_ciphertext));
+ poly_marshal(vars->expected_ciphertext, &vars->c);
+
+ poly_marshal_mod3(vars->m_bytes, &vars->m);
+ poly_marshal_mod3(vars->r_bytes, &vars->r);
+
+ ok &= constant_time_is_zero_w(
+ CRYPTO_memcmp(ciphertext, vars->expected_ciphertext,
+ sizeof(vars->expected_ciphertext)));
+
+ SHA256_Init(&vars->hash_ctx);
+ SHA256_Update(&vars->hash_ctx, kSharedKey, sizeof(kSharedKey));
+ SHA256_Update(&vars->hash_ctx, vars->m_bytes, sizeof(vars->m_bytes));
+ SHA256_Update(&vars->hash_ctx, vars->r_bytes, sizeof(vars->r_bytes));
+ SHA256_Update(&vars->hash_ctx, vars->expected_ciphertext,
+ sizeof(vars->expected_ciphertext));
+ SHA256_Final(vars->shared_key, &vars->hash_ctx);
+
+ for (unsigned i = 0; i < sizeof(vars->shared_key); i++) {
out_shared_key[i] =
- constant_time_select_8(ok, shared_key[i], out_shared_key[i]);
+ constant_time_select_8(ok, vars->shared_key[i], out_shared_key[i]);
}
+
+out:
+ OPENSSL_free(malloc_ptr);
+ return 1;
}
void HRSS_marshal_public_key(uint8_t out[HRSS_PUBLIC_KEY_BYTES],
diff --git a/deps/boringssl/src/crypto/hrss/hrss_test.cc b/deps/boringssl/src/crypto/hrss/hrss_test.cc
index 66b9047..7adbe9e 100644
--- a/deps/boringssl/src/crypto/hrss/hrss_test.cc
+++ b/deps/boringssl/src/crypto/hrss/hrss_test.cc
@@ -143,7 +143,7 @@ TEST(HRSS, Basic) {
HRSS_public_key pub;
HRSS_private_key priv;
- HRSS_generate_key(&pub, &priv, generate_key_entropy);
+ ASSERT_TRUE(HRSS_generate_key(&pub, &priv, generate_key_entropy));
uint8_t encap_entropy[HRSS_ENCAP_BYTES];
for (unsigned i = 0; i < sizeof(encap_entropy); i++) {
@@ -157,10 +157,10 @@ TEST(HRSS, Basic) {
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES];
uint8_t shared_key[HRSS_KEY_BYTES];
- HRSS_encap(ciphertext, shared_key, &pub2, encap_entropy);
+ ASSERT_TRUE(HRSS_encap(ciphertext, shared_key, &pub2, encap_entropy));
uint8_t shared_key2[HRSS_KEY_BYTES];
- HRSS_decap(shared_key2, &priv, ciphertext, sizeof(ciphertext));
+ ASSERT_TRUE(HRSS_decap(shared_key2, &priv, ciphertext, sizeof(ciphertext)));
EXPECT_EQ(Bytes(shared_key), Bytes(shared_key2));
}
@@ -173,7 +173,7 @@ TEST(HRSS, Random) {
HRSS_public_key pub;
HRSS_private_key priv;
- HRSS_generate_key(&pub, &priv, generate_key_entropy);
+ ASSERT_TRUE(HRSS_generate_key(&pub, &priv, generate_key_entropy));
for (unsigned j = 0; j < 10; j++) {
uint8_t encap_entropy[HRSS_ENCAP_BYTES];
@@ -182,10 +182,11 @@ TEST(HRSS, Random) {
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES];
uint8_t shared_key[HRSS_KEY_BYTES];
- HRSS_encap(ciphertext, shared_key, &pub, encap_entropy);
+ ASSERT_TRUE(HRSS_encap(ciphertext, shared_key, &pub, encap_entropy));
uint8_t shared_key2[HRSS_KEY_BYTES];
- HRSS_decap(shared_key2, &priv, ciphertext, sizeof(ciphertext));
+ ASSERT_TRUE(
+ HRSS_decap(shared_key2, &priv, ciphertext, sizeof(ciphertext)));
EXPECT_EQ(Bytes(shared_key), Bytes(shared_key2));
uint32_t offset;
@@ -193,7 +194,8 @@ TEST(HRSS, Random) {
uint8_t bit;
RAND_bytes(&bit, sizeof(bit));
ciphertext[offset % sizeof(ciphertext)] ^= (1 << (bit & 7));
- HRSS_decap(shared_key2, &priv, ciphertext, sizeof(ciphertext));
+ ASSERT_TRUE(
+ HRSS_decap(shared_key2, &priv, ciphertext, sizeof(ciphertext)));
EXPECT_NE(Bytes(shared_key), Bytes(shared_key2));
}
}
@@ -216,7 +218,7 @@ TEST(HRSS, Golden) {
HRSS_private_key priv;
OPENSSL_memset(&pub, 0, sizeof(pub));
OPENSSL_memset(&priv, 0, sizeof(priv));
- HRSS_generate_key(&pub, &priv, generate_key_entropy);
+ ASSERT_TRUE(HRSS_generate_key(&pub, &priv, generate_key_entropy));
static const uint8_t kExpectedPub[HRSS_PUBLIC_KEY_BYTES] = {
0x4a, 0x21, 0x39, 0x7c, 0xb4, 0xa6, 0x58, 0x15, 0x35, 0x77, 0xe4, 0x2a,
@@ -325,7 +327,7 @@ TEST(HRSS, Golden) {
}
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES];
uint8_t shared_key[HRSS_KEY_BYTES];
- HRSS_encap(ciphertext, shared_key, &pub, encap_entropy);
+ ASSERT_TRUE(HRSS_encap(ciphertext, shared_key, &pub, encap_entropy));
static const uint8_t kExpectedCiphertext[HRSS_CIPHERTEXT_BYTES] = {
0xe0, 0xc0, 0x77, 0xeb, 0x7a, 0x48, 0x7d, 0x74, 0x4e, 0x4f, 0x6d, 0xb9,
@@ -433,13 +435,13 @@ TEST(HRSS, Golden) {
};
EXPECT_EQ(Bytes(shared_key), Bytes(kExpectedSharedKey));
- HRSS_decap(shared_key, &priv, ciphertext, sizeof(ciphertext));
+ ASSERT_TRUE(HRSS_decap(shared_key, &priv, ciphertext, sizeof(ciphertext)));
EXPECT_EQ(Bytes(shared_key, sizeof(shared_key)),
Bytes(kExpectedSharedKey, sizeof(kExpectedSharedKey)));
// Corrupt the ciphertext and ensure that the failure key is constant.
ciphertext[50] ^= 4;
- HRSS_decap(shared_key, &priv, ciphertext, sizeof(ciphertext));
+ ASSERT_TRUE(HRSS_decap(shared_key, &priv, ciphertext, sizeof(ciphertext)));
static const uint8_t kExpectedFailureKey[HRSS_KEY_BYTES] = {
0x13, 0xf7, 0xed, 0x51, 0x00, 0xbc, 0xca, 0x29, 0xdf, 0xb0, 0xd0,
@@ -460,6 +462,23 @@ TEST(HRSS, ABI) {
alignas(16) uint16_t r[N + 3];
alignas(16) uint16_t a[N + 3] = {0};
alignas(16) uint16_t b[N + 3] = {0};
- CHECK_ABI(poly_Rq_mul, r, a, b);
+
+ uint8_t kCanary[256];
+ OPENSSL_STATIC_ASSERT(sizeof(kCanary) % 32 == 0, "needed for alignment");
+ memset(kCanary, 42, sizeof(kCanary));
+ alignas(32) uint8_t
+ scratch[sizeof(kCanary) + POLY_MUL_RQ_SCRATCH_SPACE + sizeof(kCanary)];
+ OPENSSL_memcpy(scratch, kCanary, sizeof(kCanary));
+ OPENSSL_memcpy(scratch + sizeof(kCanary) + POLY_MUL_RQ_SCRATCH_SPACE, kCanary,
+ sizeof(kCanary));
+
+ // The function should not touch more than |POLY_MUL_RQ_SCRATCH_SPACE| bytes
+ // of |scratch|.
+ CHECK_ABI(poly_Rq_mul, r, a, b, &scratch[sizeof(kCanary)]);
+
+ EXPECT_EQ(Bytes(scratch, sizeof(kCanary)), Bytes(kCanary));
+ EXPECT_EQ(Bytes(scratch + sizeof(kCanary) + POLY_MUL_RQ_SCRATCH_SPACE,
+ sizeof(kCanary)),
+ Bytes(kCanary));
}
#endif // POLY_RQ_MUL_ASM && SUPPORTS_ABI_TEST
diff --git a/deps/boringssl/src/crypto/hrss/internal.h b/deps/boringssl/src/crypto/hrss/internal.h
index c0d9bd2..340b2e0 100644
--- a/deps/boringssl/src/crypto/hrss/internal.h
+++ b/deps/boringssl/src/crypto/hrss/internal.h
@@ -47,10 +47,17 @@ OPENSSL_EXPORT void HRSS_poly3_invert(struct poly3 *out,
#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_SMALL) && \
defined(OPENSSL_X86_64) && defined(OPENSSL_LINUX)
#define POLY_RQ_MUL_ASM
+// POLY_MUL_RQ_SCRATCH_SPACE is the number of bytes of scratch space needed
+// by the assembly function poly_Rq_mul.
+#define POLY_MUL_RQ_SCRATCH_SPACE (6144 + 6144 + 12288 + 512 + 9408 + 32)
+
// poly_Rq_mul is defined in assembly. Inputs and outputs must be 16-byte-
// aligned.
-extern void poly_Rq_mul(uint16_t r[N + 3], const uint16_t a[N + 3],
- const uint16_t b[N + 3]);
+extern void poly_Rq_mul(
+ uint16_t r[N + 3], const uint16_t a[N + 3], const uint16_t b[N + 3],
+ // The following should be `scratch[POLY_MUL_RQ_SCRATCH_SPACE]` but
+ // GCC 11.1 has a bug with unions that breaks that.
+ uint8_t scratch[]);
#endif
diff --git a/deps/boringssl/src/crypto/internal.h b/deps/boringssl/src/crypto/internal.h
index edba9f9..03bb779 100644
--- a/deps/boringssl/src/crypto/internal.h
+++ b/deps/boringssl/src/crypto/internal.h
@@ -109,6 +109,7 @@
#ifndef OPENSSL_HEADER_CRYPTO_INTERNAL_H
#define OPENSSL_HEADER_CRYPTO_INTERNAL_H
+#include <openssl/crypto.h>
#include <openssl/ex_data.h>
#include <openssl/stack.h>
#include <openssl/thread.h>
@@ -208,6 +209,9 @@ typedef __uint128_t uint128_t;
#define OPENSSL_SSE2
#endif
+
+// Pointer utility functions.
+
// buffers_alias returns one if |a| and |b| alias and zero otherwise.
static inline int buffers_alias(const uint8_t *a, size_t a_len,
const uint8_t *b, size_t b_len) {
@@ -220,6 +224,23 @@ static inline int buffers_alias(const uint8_t *a, size_t a_len,
return a_u + a_len > b_u && b_u + b_len > a_u;
}
+// align_pointer returns |ptr|, advanced to |alignment|. |alignment| must be a
+// power of two, and |ptr| must have at least |alignment - 1| bytes of scratch
+// space.
+static inline void *align_pointer(void *ptr, size_t alignment) {
+ // |alignment| must be a power of two.
+ assert(alignment != 0 && (alignment & (alignment - 1)) == 0);
+ // Instead of aligning |ptr| as a |uintptr_t| and casting back, compute the
+ // offset and advance in pointer space. C guarantees that casting from pointer
+ // to |uintptr_t| and back gives the same pointer, but general
+ // integer-to-pointer conversions are implementation-defined. GCC does define
+ // it in the useful way, but this makes fewer assumptions.
+ uintptr_t offset = (0u - (uintptr_t)ptr) & (alignment - 1);
+ ptr = (char *)ptr + offset;
+ assert(((uintptr_t)ptr & (alignment - 1)) == 0);
+ return ptr;
+}
+
// Constant-time utility functions.
//
@@ -470,6 +491,13 @@ OPENSSL_EXPORT void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void));
// Reference counting.
+// Automatically enable C11 atomics if implemented.
+#if !defined(OPENSSL_C11_ATOMIC) && defined(OPENSSL_THREADS) && \
+ !defined(__STDC_NO_ATOMICS__) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 201112L
+#define OPENSSL_C11_ATOMIC
+#endif
+
// CRYPTO_REFCOUNT_MAX is the value at which the reference count saturates.
#define CRYPTO_REFCOUNT_MAX 0xffffffff
@@ -607,6 +635,7 @@ BSSL_NAMESPACE_END
typedef enum {
OPENSSL_THREAD_LOCAL_ERR = 0,
OPENSSL_THREAD_LOCAL_RAND,
+ OPENSSL_THREAD_LOCAL_FIPS_COUNTERS,
OPENSSL_THREAD_LOCAL_TEST,
NUM_OPENSSL_THREAD_LOCALS,
} thread_local_data_t;
@@ -811,6 +840,58 @@ static inline void *OPENSSL_memset(void *dst, int c, size_t n) {
return memset(dst, c, n);
}
+
+// Loads and stores.
+//
+// The following functions load and store sized integers with the specified
+// endianness. They use |memcpy|, and so avoid alignment or strict aliasing
+// requirements on the input and output pointers.
+
+static inline uint32_t CRYPTO_load_u32_le(const void *in) {
+ uint32_t v;
+ OPENSSL_memcpy(&v, in, sizeof(v));
+ return v;
+}
+
+static inline void CRYPTO_store_u32_le(void *out, uint32_t v) {
+ OPENSSL_memcpy(out, &v, sizeof(v));
+}
+
+static inline uint32_t CRYPTO_load_u32_be(const void *in) {
+ uint32_t v;
+ OPENSSL_memcpy(&v, in, sizeof(v));
+ return CRYPTO_bswap4(v);
+}
+
+static inline void CRYPTO_store_u32_be(void *out, uint32_t v) {
+ v = CRYPTO_bswap4(v);
+ OPENSSL_memcpy(out, &v, sizeof(v));
+}
+
+static inline uint64_t CRYPTO_load_u64_be(const void *ptr) {
+ uint64_t ret;
+ OPENSSL_memcpy(&ret, ptr, sizeof(ret));
+ return CRYPTO_bswap8(ret);
+}
+
+static inline void CRYPTO_store_u64_be(void *out, uint64_t v) {
+ v = CRYPTO_bswap8(v);
+ OPENSSL_memcpy(out, &v, sizeof(v));
+}
+
+static inline crypto_word_t CRYPTO_load_word_le(const void *in) {
+ crypto_word_t v;
+ OPENSSL_memcpy(&v, in, sizeof(v));
+ return v;
+}
+
+static inline void CRYPTO_store_word_le(void *out, crypto_word_t v) {
+ OPENSSL_memcpy(out, &v, sizeof(v));
+}
+
+
+// FIPS functions.
+
#if defined(BORINGSSL_FIPS)
// BORINGSSL_FIPS_abort is called when a FIPS power-on or continuous test
// fails. It prevents any further cryptographic operations by the current
@@ -826,6 +907,11 @@ void BORINGSSL_FIPS_abort(void) __attribute__((noreturn));
int boringssl_fips_self_test(const uint8_t *module_hash,
size_t module_hash_len);
+#if defined(BORINGSSL_FIPS_COUNTERS)
+void boringssl_fips_inc_counter(enum fips_counter_t counter);
+#else
+OPENSSL_INLINE void boringssl_fips_inc_counter(enum fips_counter_t counter) {}
+#endif
#if defined(__cplusplus)
} // extern C
diff --git a/deps/boringssl/src/crypto/lhash/internal.h b/deps/boringssl/src/crypto/lhash/internal.h
new file mode 100644
index 0000000..64dca1d
--- /dev/null
+++ b/deps/boringssl/src/crypto/lhash/internal.h
@@ -0,0 +1,253 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_LHASH_INTERNAL_H
+#define OPENSSL_HEADER_LHASH_INTERNAL_H
+
+#include <openssl/lhash.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+// lhash is a traditional, chaining hash table that automatically expands and
+// contracts as needed. One should not use the lh_* functions directly, rather
+// use the type-safe macro wrappers:
+//
+// A hash table of a specific type of object has type |LHASH_OF(type)|. This
+// can be defined (once) with |DEFINE_LHASH_OF(type)| and declared where needed
+// with |DECLARE_LHASH_OF(type)|. For example:
+//
+// struct foo {
+// int bar;
+// };
+//
+// DEFINE_LHASH_OF(struct foo)
+//
+// Although note that the hash table will contain /pointers/ to |foo|.
+//
+// A macro will be defined for each of the |OPENSSL_lh_*| functions below. For
+// |LHASH_OF(foo)|, the macros would be |lh_foo_new|, |lh_foo_num_items| etc.
+
+
+// lhash_cmp_func is a comparison function that returns a value equal, or not
+// equal, to zero depending on whether |*a| is equal, or not equal to |*b|,
+// respectively. Note the difference between this and |stack_cmp_func| in that
+// this takes pointers to the objects directly.
+//
+// This function's actual type signature is int (*)(const T*, const T*). The
+// low-level |lh_*| functions will be passed a type-specific wrapper to call it
+// correctly.
+typedef int (*lhash_cmp_func)(const void *a, const void *b);
+typedef int (*lhash_cmp_func_helper)(lhash_cmp_func func, const void *a,
+ const void *b);
+
+// lhash_hash_func is a function that maps an object to a uniformly distributed
+// uint32_t.
+//
+// This function's actual type signature is uint32_t (*)(const T*). The
+// low-level |lh_*| functions will be passed a type-specific wrapper to call it
+// correctly.
+typedef uint32_t (*lhash_hash_func)(const void *a);
+typedef uint32_t (*lhash_hash_func_helper)(lhash_hash_func func, const void *a);
+
+typedef struct lhash_st _LHASH;
+
+// OPENSSL_lh_new returns a new, empty hash table or NULL on error.
+OPENSSL_EXPORT _LHASH *OPENSSL_lh_new(lhash_hash_func hash,
+ lhash_cmp_func comp);
+
+// OPENSSL_lh_free frees the hash table itself but none of the elements. See
+// |OPENSSL_lh_doall|.
+OPENSSL_EXPORT void OPENSSL_lh_free(_LHASH *lh);
+
+// OPENSSL_lh_num_items returns the number of items in |lh|.
+OPENSSL_EXPORT size_t OPENSSL_lh_num_items(const _LHASH *lh);
+
+// OPENSSL_lh_retrieve finds an element equal to |data| in the hash table and
+// returns it. If no such element exists, it returns NULL.
+OPENSSL_EXPORT void *OPENSSL_lh_retrieve(const _LHASH *lh, const void *data,
+ lhash_hash_func_helper call_hash_func,
+ lhash_cmp_func_helper call_cmp_func);
+
+// OPENSSL_lh_retrieve_key finds an element matching |key|, given the specified
+// hash and comparison function. This differs from |OPENSSL_lh_retrieve| in that
+// the key may be a different type than the values stored in |lh|. |key_hash|
+// and |cmp_key| must be compatible with the functions passed into
+// |OPENSSL_lh_new|.
+OPENSSL_EXPORT void *OPENSSL_lh_retrieve_key(const _LHASH *lh, const void *key,
+ uint32_t key_hash,
+ int (*cmp_key)(const void *key,
+ const void *value));
+
+// OPENSSL_lh_insert inserts |data| into the hash table. If an existing element
+// is equal to |data| (with respect to the comparison function) then |*old_data|
+// will be set to that value and it will be replaced. Otherwise, or in the
+// event of an error, |*old_data| will be set to NULL. It returns one on
+// success or zero in the case of an allocation error.
+OPENSSL_EXPORT int OPENSSL_lh_insert(_LHASH *lh, void **old_data, void *data,
+ lhash_hash_func_helper call_hash_func,
+ lhash_cmp_func_helper call_cmp_func);
+
+// OPENSSL_lh_delete removes an element equal to |data| from the hash table and
+// returns it. If no such element is found, it returns NULL.
+OPENSSL_EXPORT void *OPENSSL_lh_delete(_LHASH *lh, const void *data,
+ lhash_hash_func_helper call_hash_func,
+ lhash_cmp_func_helper call_cmp_func);
+
+// OPENSSL_lh_doall_arg calls |func| on each element of the hash table and also
+// passes |arg| as the second argument.
+// TODO(fork): rename this
+OPENSSL_EXPORT void OPENSSL_lh_doall_arg(_LHASH *lh,
+ void (*func)(void *, void *),
+ void *arg);
+
+#define DEFINE_LHASH_OF(type) \
+ DECLARE_LHASH_OF(type) \
+ \
+ typedef int (*lhash_##type##_cmp_func)(const type *, const type *); \
+ typedef uint32_t (*lhash_##type##_hash_func)(const type *); \
+ \
+ OPENSSL_INLINE int lh_##type##_call_cmp_func(lhash_cmp_func func, \
+ const void *a, const void *b) { \
+ return ((lhash_##type##_cmp_func)func)((const type *)a, (const type *)b); \
+ } \
+ \
+ OPENSSL_INLINE uint32_t lh_##type##_call_hash_func(lhash_hash_func func, \
+ const void *a) { \
+ return ((lhash_##type##_hash_func)func)((const type *)a); \
+ } \
+ \
+ OPENSSL_INLINE LHASH_OF(type) *lh_##type##_new( \
+ lhash_##type##_hash_func hash, lhash_##type##_cmp_func comp) { \
+ return (LHASH_OF(type) *)OPENSSL_lh_new((lhash_hash_func)hash, \
+ (lhash_cmp_func)comp); \
+ } \
+ \
+ OPENSSL_INLINE void lh_##type##_free(LHASH_OF(type) *lh) { \
+ OPENSSL_lh_free((_LHASH *)lh); \
+ } \
+ \
+ OPENSSL_INLINE size_t lh_##type##_num_items(const LHASH_OF(type) *lh) { \
+ return OPENSSL_lh_num_items((const _LHASH *)lh); \
+ } \
+ \
+ OPENSSL_INLINE type *lh_##type##_retrieve(const LHASH_OF(type) *lh, \
+ const type *data) { \
+ return (type *)OPENSSL_lh_retrieve((const _LHASH *)lh, data, \
+ lh_##type##_call_hash_func, \
+ lh_##type##_call_cmp_func); \
+ } \
+ \
+ typedef struct { \
+ int (*cmp_key)(const void *key, const type *value); \
+ const void *key; \
+ } LHASH_CMP_KEY_##type; \
+ \
+ OPENSSL_INLINE int lh_##type##_call_cmp_key(const void *key, \
+ const void *value) { \
+ const LHASH_CMP_KEY_##type *cb = (const LHASH_CMP_KEY_##type *)key; \
+ return cb->cmp_key(cb->key, (const type *)value); \
+ } \
+ \
+ OPENSSL_INLINE type *lh_##type##_retrieve_key( \
+ const LHASH_OF(type) *lh, const void *key, uint32_t key_hash, \
+ int (*cmp_key)(const void *key, const type *value)) { \
+ LHASH_CMP_KEY_##type cb = {cmp_key, key}; \
+ return (type *)OPENSSL_lh_retrieve_key((const _LHASH *)lh, &cb, key_hash, \
+ lh_##type##_call_cmp_key); \
+ } \
+ \
+ OPENSSL_INLINE int lh_##type##_insert(LHASH_OF(type) *lh, type **old_data, \
+ type *data) { \
+ void *old_data_void = NULL; \
+ int ret = OPENSSL_lh_insert((_LHASH *)lh, &old_data_void, data, \
+ lh_##type##_call_hash_func, \
+ lh_##type##_call_cmp_func); \
+ *old_data = (type *)old_data_void; \
+ return ret; \
+ } \
+ \
+ OPENSSL_INLINE type *lh_##type##_delete(LHASH_OF(type) *lh, \
+ const type *data) { \
+ return (type *)OPENSSL_lh_delete((_LHASH *)lh, data, \
+ lh_##type##_call_hash_func, \
+ lh_##type##_call_cmp_func); \
+ } \
+ \
+ typedef struct { \
+ void (*doall_arg)(type *, void *); \
+ void *arg; \
+ } LHASH_DOALL_##type; \
+ \
+ OPENSSL_INLINE void lh_##type##_call_doall_arg(void *value, void *arg) { \
+ const LHASH_DOALL_##type *cb = (const LHASH_DOALL_##type *)arg; \
+ cb->doall_arg((type *)value, cb->arg); \
+ } \
+ \
+ OPENSSL_INLINE void lh_##type##_doall_arg( \
+ LHASH_OF(type) *lh, void (*func)(type *, void *), void *arg) { \
+ LHASH_DOALL_##type cb = {func, arg}; \
+ OPENSSL_lh_doall_arg((_LHASH *)lh, lh_##type##_call_doall_arg, &cb); \
+ }
+
+
+#if defined(__cplusplus)
+} // extern C
+#endif
+
+#endif // OPENSSL_HEADER_LHASH_INTERNAL_H
diff --git a/deps/boringssl/src/crypto/lhash/lhash.c b/deps/boringssl/src/crypto/lhash/lhash.c
index 98ee60a..4a95a2e 100644
--- a/deps/boringssl/src/crypto/lhash/lhash.c
+++ b/deps/boringssl/src/crypto/lhash/lhash.c
@@ -62,6 +62,7 @@
#include <openssl/mem.h>
+#include "internal.h"
#include "../internal.h"
@@ -73,6 +74,16 @@ static const size_t kMinNumBuckets = 16;
static const size_t kMaxAverageChainLength = 2;
static const size_t kMinAverageChainLength = 1;
+// lhash_item_st is an element of a hash chain. It points to the opaque data
+// for this element and to the next item in the chain. The linked-list is NULL
+// terminated.
+typedef struct lhash_item_st {
+ void *data;
+ struct lhash_item_st *next;
+ // hash contains the cached, hash value of |data|.
+ uint32_t hash;
+} LHASH_ITEM;
+
struct lhash_st {
// num_items contains the total number of items in the hash table.
size_t num_items;
@@ -92,7 +103,7 @@ struct lhash_st {
lhash_hash_func hash;
};
-_LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp) {
+_LHASH *OPENSSL_lh_new(lhash_hash_func hash, lhash_cmp_func comp) {
_LHASH *ret = OPENSSL_malloc(sizeof(_LHASH));
if (ret == NULL) {
return NULL;
@@ -112,7 +123,7 @@ _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp) {
return ret;
}
-void lh_free(_LHASH *lh) {
+void OPENSSL_lh_free(_LHASH *lh) {
if (lh == NULL) {
return;
}
@@ -129,7 +140,7 @@ void lh_free(_LHASH *lh) {
OPENSSL_free(lh);
}
-size_t lh_num_items(const _LHASH *lh) { return lh->num_items; }
+size_t OPENSSL_lh_num_items(const _LHASH *lh) { return lh->num_items; }
// get_next_ptr_and_hash returns a pointer to the pointer that points to the
// item equal to |data|. In other words, it searches for an item equal to |data|
@@ -175,16 +186,18 @@ static LHASH_ITEM **get_next_ptr_by_key(const _LHASH *lh, const void *key,
return ret;
}
-void *lh_retrieve(const _LHASH *lh, const void *data,
- lhash_hash_func_helper call_hash_func,
- lhash_cmp_func_helper call_cmp_func) {
+void *OPENSSL_lh_retrieve(const _LHASH *lh, const void *data,
+ lhash_hash_func_helper call_hash_func,
+ lhash_cmp_func_helper call_cmp_func) {
LHASH_ITEM **next_ptr =
get_next_ptr_and_hash(lh, NULL, data, call_hash_func, call_cmp_func);
return *next_ptr == NULL ? NULL : (*next_ptr)->data;
}
-void *lh_retrieve_key(const _LHASH *lh, const void *key, uint32_t key_hash,
- int (*cmp_key)(const void *key, const void *value)) {
+void *OPENSSL_lh_retrieve_key(const _LHASH *lh, const void *key,
+ uint32_t key_hash,
+ int (*cmp_key)(const void *key,
+ const void *value)) {
LHASH_ITEM **next_ptr = get_next_ptr_by_key(lh, key, key_hash, cmp_key);
return *next_ptr == NULL ? NULL : (*next_ptr)->data;
}
@@ -252,9 +265,9 @@ static void lh_maybe_resize(_LHASH *lh) {
}
}
-int lh_insert(_LHASH *lh, void **old_data, void *data,
- lhash_hash_func_helper call_hash_func,
- lhash_cmp_func_helper call_cmp_func) {
+int OPENSSL_lh_insert(_LHASH *lh, void **old_data, void *data,
+ lhash_hash_func_helper call_hash_func,
+ lhash_cmp_func_helper call_cmp_func) {
uint32_t hash;
LHASH_ITEM **next_ptr, *item;
@@ -287,9 +300,9 @@ int lh_insert(_LHASH *lh, void **old_data, void *data,
return 1;
}
-void *lh_delete(_LHASH *lh, const void *data,
- lhash_hash_func_helper call_hash_func,
- lhash_cmp_func_helper call_cmp_func) {
+void *OPENSSL_lh_delete(_LHASH *lh, const void *data,
+ lhash_hash_func_helper call_hash_func,
+ lhash_cmp_func_helper call_cmp_func) {
LHASH_ITEM **next_ptr, *item, *ret;
next_ptr =
@@ -311,7 +324,7 @@ void *lh_delete(_LHASH *lh, const void *data,
return ret;
}
-void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) {
+void OPENSSL_lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) {
if (lh == NULL) {
return;
}
@@ -338,11 +351,3 @@ void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) {
// resizing is done here.
lh_maybe_resize(lh);
}
-
-uint32_t lh_strhash(const char *c) {
- if (c == NULL) {
- return 0;
- }
-
- return OPENSSL_hash32(c, strlen(c));
-}
diff --git a/deps/boringssl/src/crypto/lhash/lhash_test.cc b/deps/boringssl/src/crypto/lhash/lhash_test.cc
index 885d3c7..6b4bfad 100644
--- a/deps/boringssl/src/crypto/lhash/lhash_test.cc
+++ b/deps/boringssl/src/crypto/lhash/lhash_test.cc
@@ -25,8 +25,12 @@
#include <utility>
#include <vector>
+#include <openssl/mem.h>
+
#include <gtest/gtest.h>
+#include "internal.h"
+
DEFINE_LHASH_OF(char)
@@ -58,7 +62,7 @@ static const char *Lookup(
TEST(LHashTest, Basic) {
std::unique_ptr<LHASH_OF(char), FreeLHASH_OF_char> lh(
- lh_char_new(lh_strhash, strcmp));
+ lh_char_new(OPENSSL_strhash, strcmp));
ASSERT_TRUE(lh);
// lh is expected to store a canonical instance of each string. dummy_lh
@@ -90,15 +94,6 @@ TEST(LHashTest, Basic) {
&actual);
std::sort(actual.begin(), actual.end());
EXPECT_EQ(expected, actual);
-
- // Also test |lh_*_doall|.
- actual.clear();
- static ValueList *global_actual_list;
- global_actual_list = &actual;
- lh_char_doall(lh.get(),
- [](char *ptr) { global_actual_list->push_back(ptr); });
- std::sort(actual.begin(), actual.end());
- EXPECT_EQ(expected, actual);
}
enum Action {
@@ -116,7 +111,7 @@ TEST(LHashTest, Basic) {
// Do the same lookup with |lh_char_retrieve_key|.
value = lh_char_retrieve_key(
- lh.get(), &key, lh_strhash(key.get()),
+ lh.get(), &key, OPENSSL_strhash(key.get()),
[](const void *key_ptr, const char *data) -> int {
const char *key_data =
reinterpret_cast<const std::unique_ptr<char[]> *>(key_ptr)
diff --git a/deps/boringssl/src/crypto/mem.c b/deps/boringssl/src/crypto/mem.c
index 0491f15..4ccc263 100644
--- a/deps/boringssl/src/crypto/mem.c
+++ b/deps/boringssl/src/crypto/mem.c
@@ -93,20 +93,38 @@ static void __asan_unpoison_memory_region(const void *addr, size_t size) {}
#define WEAK_SYMBOL_FUNC(rettype, name, args) static rettype(*name) args = NULL;
#endif
+#if defined(BORINGSSL_SDALLOCX)
// sdallocx is a sized |free| function. By passing the size (which we happen to
-// always know in BoringSSL), the malloc implementation can save work. We cannot
-// depend on |sdallocx| being available, however, so it's a weak symbol.
+// always know in BoringSSL), the malloc implementation can save work.
//
-// This will always be safe, but will only be overridden if the malloc
-// implementation is statically linked with BoringSSL. So, if |sdallocx| is
-// provided in, say, libc.so, we still won't use it because that's dynamically
-// linked. This isn't an ideal result, but its helps in some cases.
-WEAK_SYMBOL_FUNC(void, sdallocx, (void *ptr, size_t size, int flags));
+// This is guarded by BORINGSSL_SDALLOCX, rather than being a weak symbol,
+// because it can work poorly if there are two malloc implementations in the
+// address space. (Which probably isn't valid, ODR etc, but
+// https://github.com/grpc/grpc/issues/25450). In that situation, |malloc| can
+// come from one allocator but |sdallocx| from another and crashes quickly
+// result. We can't match |sdallocx| with |mallocx| because tcmalloc only
+// provides the former, so a mismatch can still happen.
+void sdallocx(void *ptr, size_t size, int flags);
+#endif
// The following three functions can be defined to override default heap
// allocation and freeing. If defined, it is the responsibility of
// |OPENSSL_memory_free| to zero out the memory before returning it to the
// system. |OPENSSL_memory_free| will not be passed NULL pointers.
+//
+// WARNING: These functions are called on every allocation and free in
+// BoringSSL across the entire process. They may be called by any code in the
+// process which calls BoringSSL, including in process initializers and thread
+// destructors. When called, BoringSSL may hold pthreads locks. Any other code
+// in the process which, directly or indirectly, calls BoringSSL may be on the
+// call stack and may itself be using arbitrary synchronization primitives.
+//
+// As a result, these functions may not have the usual programming environment
+// available to most C or C++ code. In particular, they may not call into
+// BoringSSL, or any library which depends on BoringSSL. Any synchronization
+// primitives used must tolerate every other synchronization primitive linked
+// into the process, including pthreads locks. Failing to meet these constraints
+// may result in deadlocks, crashes, or memory corruption.
WEAK_SYMBOL_FUNC(void*, OPENSSL_memory_alloc, (size_t size));
WEAK_SYMBOL_FUNC(void, OPENSSL_memory_free, (void *ptr));
WEAK_SYMBOL_FUNC(size_t, OPENSSL_memory_get_size, (void *ptr));
@@ -148,11 +166,11 @@ void OPENSSL_free(void *orig_ptr) {
size_t size = *(size_t *)ptr;
OPENSSL_cleanse(ptr, size + OPENSSL_MALLOC_PREFIX);
- if (sdallocx) {
- sdallocx(ptr, size + OPENSSL_MALLOC_PREFIX, 0 /* flags */);
- } else {
- free(ptr);
- }
+#if defined(BORINGSSL_SDALLOCX)
+ sdallocx(ptr, size + OPENSSL_MALLOC_PREFIX, 0 /* flags */);
+#else
+ free(ptr);
+#endif
}
void *OPENSSL_realloc(void *orig_ptr, size_t new_size) {
@@ -233,6 +251,8 @@ uint32_t OPENSSL_hash32(const void *ptr, size_t len) {
return h;
}
+uint32_t OPENSSL_strhash(const char *s) { return OPENSSL_hash32(s, strlen(s)); }
+
size_t OPENSSL_strnlen(const char *s, size_t len) {
for (size_t i = 0; i < len; i++) {
if (s[i] == 0) {
@@ -308,22 +328,15 @@ int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) {
}
char *OPENSSL_strndup(const char *str, size_t size) {
- char *ret;
- size_t alloc_size;
-
- if (str == NULL) {
- return NULL;
- }
-
size = OPENSSL_strnlen(str, size);
- alloc_size = size + 1;
+ size_t alloc_size = size + 1;
if (alloc_size < size) {
// overflow
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE);
return NULL;
}
- ret = OPENSSL_malloc(alloc_size);
+ char *ret = OPENSSL_malloc(alloc_size);
if (ret == NULL) {
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE);
return NULL;
diff --git a/deps/boringssl/src/crypto/obj/obj.c b/deps/boringssl/src/crypto/obj/obj.c
index 3bf1abf..958625d 100644
--- a/deps/boringssl/src/crypto/obj/obj.c
+++ b/deps/boringssl/src/crypto/obj/obj.c
@@ -67,8 +67,12 @@
#include <openssl/mem.h>
#include <openssl/thread.h>
-#include "obj_dat.h"
+#include "../asn1/internal.h"
#include "../internal.h"
+#include "../lhash/internal.h"
+
+// obj_data.h must be included after the definition of |ASN1_OBJECT|.
+#include "obj_dat.h"
DEFINE_LHASH_OF(ASN1_OBJECT)
@@ -338,12 +342,12 @@ OPENSSL_EXPORT int OBJ_nid2cbb(CBB *out, int nid) {
return 1;
}
-const ASN1_OBJECT *OBJ_nid2obj(int nid) {
+ASN1_OBJECT *OBJ_nid2obj(int nid) {
if (nid >= 0 && nid < NUM_NID) {
if (nid != NID_undef && kObjects[nid].nid == NID_undef) {
goto err;
}
- return &kObjects[nid];
+ return (ASN1_OBJECT *)&kObjects[nid];
}
CRYPTO_STATIC_MUTEX_lock_read(&global_added_lock);
@@ -411,7 +415,7 @@ ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) {
}
if (nid != NID_undef) {
- return (ASN1_OBJECT*) OBJ_nid2obj(nid);
+ return OBJ_nid2obj(nid);
}
}
@@ -484,7 +488,7 @@ static int cmp_data(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
}
static uint32_t hash_short_name(const ASN1_OBJECT *obj) {
- return lh_strhash(obj->sn);
+ return OPENSSL_strhash(obj->sn);
}
static int cmp_short_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
@@ -492,7 +496,7 @@ static int cmp_short_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
}
static uint32_t hash_long_name(const ASN1_OBJECT *obj) {
- return lh_strhash(obj->ln);
+ return OPENSSL_strhash(obj->ln);
}
static int cmp_long_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
diff --git a/deps/boringssl/src/crypto/obj/obj_test.cc b/deps/boringssl/src/crypto/obj/obj_test.cc
index e623843..08796e2 100644
--- a/deps/boringssl/src/crypto/obj/obj_test.cc
+++ b/deps/boringssl/src/crypto/obj/obj_test.cc
@@ -75,14 +75,16 @@ TEST(ObjTest, TestSignatureAlgorithms) {
static bool ExpectObj2Txt(const uint8_t *der, size_t der_len,
bool always_return_oid, const char *expected) {
- ASN1_OBJECT obj;
- OPENSSL_memset(&obj, 0, sizeof(obj));
- obj.data = der;
- obj.length = static_cast<int>(der_len);
+ bssl::UniquePtr<ASN1_OBJECT> obj(
+ ASN1_OBJECT_create(NID_undef, der, static_cast<int>(der_len),
+ /*sn=*/nullptr, /*ln=*/nullptr));
+ if (!obj) {
+ return false;
+ }
int expected_len = static_cast<int>(strlen(expected));
- int len = OBJ_obj2txt(nullptr, 0, &obj, always_return_oid);
+ int len = OBJ_obj2txt(nullptr, 0, obj.get(), always_return_oid);
if (len != expected_len) {
fprintf(stderr,
"OBJ_obj2txt of %s with out_len = 0 returned %d, wanted %d.\n",
@@ -92,7 +94,7 @@ static bool ExpectObj2Txt(const uint8_t *der, size_t der_len,
char short_buf[1];
OPENSSL_memset(short_buf, 0xff, sizeof(short_buf));
- len = OBJ_obj2txt(short_buf, sizeof(short_buf), &obj, always_return_oid);
+ len = OBJ_obj2txt(short_buf, sizeof(short_buf), obj.get(), always_return_oid);
if (len != expected_len) {
fprintf(stderr,
"OBJ_obj2txt of %s with out_len = 1 returned %d, wanted %d.\n",
@@ -109,7 +111,7 @@ static bool ExpectObj2Txt(const uint8_t *der, size_t der_len,
}
char buf[256];
- len = OBJ_obj2txt(buf, sizeof(buf), &obj, always_return_oid);
+ len = OBJ_obj2txt(buf, sizeof(buf), obj.get(), always_return_oid);
if (len != expected_len) {
fprintf(stderr,
"OBJ_obj2txt of %s with out_len = 256 returned %d, wanted %d.\n",
@@ -166,17 +168,14 @@ TEST(ObjTest, TestObj2Txt) {
ASSERT_TRUE(ExpectObj2Txt(nullptr, 0, false /* return name */, ""));
ASSERT_TRUE(ExpectObj2Txt(nullptr, 0, true /* don't return name */, ""));
- ASN1_OBJECT obj;
- OPENSSL_memset(&obj, 0, sizeof(obj));
-
// kNonMinimalOID is kBasicConstraints with the final component non-minimally
// encoded.
- static const uint8_t kNonMinimalOID[] = {
- 0x55, 0x1d, 0x80, 0x13,
- };
- obj.data = kNonMinimalOID;
- obj.length = sizeof(kNonMinimalOID);
- ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, &obj, 0));
+ static const uint8_t kNonMinimalOID[] = {0x55, 0x1d, 0x80, 0x13};
+ bssl::UniquePtr<ASN1_OBJECT> obj(
+ ASN1_OBJECT_create(NID_undef, kNonMinimalOID, sizeof(kNonMinimalOID),
+ /*sn=*/nullptr, /*ln=*/nullptr));
+ ASSERT_TRUE(obj);
+ ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, obj.get(), 0));
// kOverflowOID is the DER representation of
// 1.2.840.113554.4.1.72585.18446744073709551616. (The final value is 2^64.)
@@ -184,16 +183,16 @@ TEST(ObjTest, TestObj2Txt) {
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09,
0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
};
- obj.data = kOverflowOID;
- obj.length = sizeof(kOverflowOID);
- ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, &obj, 0));
+ obj.reset(ASN1_OBJECT_create(NID_undef, kOverflowOID, sizeof(kOverflowOID),
+ /*sn=*/nullptr, /*ln=*/nullptr));
+ ASSERT_TRUE(obj);
+ ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, obj.get(), 0));
// kInvalidOID is a mis-encoded version of kBasicConstraints with the final
// octet having the high bit set.
- static const uint8_t kInvalidOID[] = {
- 0x55, 0x1d, 0x93,
- };
- obj.data = kInvalidOID;
- obj.length = sizeof(kInvalidOID);
- ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, &obj, 0));
+ static const uint8_t kInvalidOID[] = {0x55, 0x1d, 0x93};
+ obj.reset(ASN1_OBJECT_create(NID_undef, kInvalidOID, sizeof(kInvalidOID),
+ /*sn=*/nullptr, /*ln=*/nullptr));
+ ASSERT_TRUE(obj);
+ ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, obj.get(), 0));
}
diff --git a/deps/boringssl/src/crypto/pem/pem_all.c b/deps/boringssl/src/crypto/pem/pem_all.c
index 6b40883..e419774 100644
--- a/deps/boringssl/src/crypto/pem/pem_all.c
+++ b/deps/boringssl/src/crypto/pem/pem_all.c
@@ -157,8 +157,6 @@ RSA *PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **rsa, pem_password_cb *cb,
return pkey_get_rsa(pktmp, rsa);
}
-#ifndef OPENSSL_NO_FP_API
-
RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **rsa, pem_password_cb *cb, void *u)
{
EVP_PKEY *pktmp;
@@ -166,8 +164,6 @@ RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **rsa, pem_password_cb *cb, void *u)
return pkey_get_rsa(pktmp, rsa);
}
-#endif
-
IMPLEMENT_PEM_write_cb_const(RSAPrivateKey, RSA, PEM_STRING_RSA,
RSAPrivateKey)
@@ -205,7 +201,6 @@ IMPLEMENT_PEM_write_cb_const(DSAPrivateKey, DSA, PEM_STRING_DSA,
DSAPrivateKey)
IMPLEMENT_PEM_rw(DSA_PUBKEY, DSA, PEM_STRING_PUBLIC, DSA_PUBKEY)
-# ifndef OPENSSL_NO_FP_API
DSA *PEM_read_DSAPrivateKey(FILE *fp, DSA **dsa, pem_password_cb *cb, void *u)
{
EVP_PKEY *pktmp;
@@ -213,8 +208,6 @@ DSA *PEM_read_DSAPrivateKey(FILE *fp, DSA **dsa, pem_password_cb *cb, void *u)
return pkey_get_dsa(pktmp, dsa); /* will free pktmp */
}
-# endif
-
IMPLEMENT_PEM_rw_const(DSAparams, DSA, PEM_STRING_DSAPARAMS, DSAparams)
#endif
static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey)
@@ -245,7 +238,6 @@ IMPLEMENT_PEM_write_cb(ECPrivateKey, EC_KEY, PEM_STRING_ECPRIVATEKEY,
ECPrivateKey)
IMPLEMENT_PEM_rw(EC_PUBKEY, EC_KEY, PEM_STRING_PUBLIC, EC_PUBKEY)
-#ifndef OPENSSL_NO_FP_API
EC_KEY *PEM_read_ECPrivateKey(FILE *fp, EC_KEY **eckey, pem_password_cb *cb,
void *u)
{
@@ -254,7 +246,6 @@ EC_KEY *PEM_read_ECPrivateKey(FILE *fp, EC_KEY **eckey, pem_password_cb *cb,
return pkey_get_eckey(pktmp, eckey); /* will free pktmp */
}
-#endif
IMPLEMENT_PEM_write_const(DHparams, DH, PEM_STRING_DHPARAMS, DHparams)
diff --git a/deps/boringssl/src/crypto/pem/pem_info.c b/deps/boringssl/src/crypto/pem/pem_info.c
index 1cda35b..3a1d0cc 100644
--- a/deps/boringssl/src/crypto/pem/pem_info.c
+++ b/deps/boringssl/src/crypto/pem/pem_info.c
@@ -70,7 +70,6 @@
#include <openssl/rsa.h>
#include <openssl/x509.h>
-#ifndef OPENSSL_NO_FP_API
STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
pem_password_cb *cb, void *u)
{
@@ -83,7 +82,6 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
BIO_free(b);
return ret;
}
-#endif
enum parse_result_t {
parse_ok,
diff --git a/deps/boringssl/src/crypto/pem/pem_lib.c b/deps/boringssl/src/crypto/pem/pem_lib.c
index 00c0e0a..747d694 100644
--- a/deps/boringssl/src/crypto/pem/pem_lib.c
+++ b/deps/boringssl/src/crypto/pem/pem_lib.c
@@ -117,7 +117,6 @@ void PEM_dek_info(char *buf, const char *type, int len, char *str)
buf[j + i * 2 + 1] = '\0';
}
-#ifndef OPENSSL_NO_FP_API
void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
pem_password_cb *cb, void *u)
{
@@ -130,7 +129,6 @@ void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
BIO_free(b);
return ret;
}
-#endif
static int check_pem(const char *nm, const char *name)
{
@@ -252,7 +250,6 @@ int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
return ret;
}
-#ifndef OPENSSL_NO_FP_API
int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
void *x, const EVP_CIPHER *enc, unsigned char *kstr,
int klen, pem_password_cb *callback, void *u)
@@ -266,7 +263,6 @@ int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
BIO_free(b);
return ret;
}
-#endif
int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
void *x, const EVP_CIPHER *enc, unsigned char *kstr,
@@ -507,7 +503,6 @@ static int load_iv(char **fromp, unsigned char *to, int num)
return (1);
}
-#ifndef OPENSSL_NO_FP_API
int PEM_write(FILE *fp, const char *name, const char *header,
const unsigned char *data, long len)
{
@@ -520,7 +515,6 @@ int PEM_write(FILE *fp, const char *name, const char *header,
BIO_free(b);
return (ret);
}
-#endif
int PEM_write_bio(BIO *bp, const char *name, const char *header,
const unsigned char *data, long len)
@@ -578,7 +572,6 @@ int PEM_write_bio(BIO *bp, const char *name, const char *header,
return (0);
}
-#ifndef OPENSSL_NO_FP_API
int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
long *len)
{
@@ -591,7 +584,6 @@ int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
BIO_free(b);
return (ret);
}
-#endif
int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
long *len)
diff --git a/deps/boringssl/src/crypto/pem/pem_pk8.c b/deps/boringssl/src/crypto/pem/pem_pk8.c
index 819a329..8a1f040 100644
--- a/deps/boringssl/src/crypto/pem/pem_pk8.c
+++ b/deps/boringssl/src/crypto/pem/pem_pk8.c
@@ -190,7 +190,6 @@ EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
return ret;
}
-#ifndef OPENSSL_NO_FP_API
int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
char *kstr, int klen, pem_password_cb *cb, void *u)
@@ -248,7 +247,6 @@ EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb,
return ret;
}
-#endif
IMPLEMENT_PEM_rw(PKCS8, X509_SIG, PEM_STRING_PKCS8, X509_SIG)
diff --git a/deps/boringssl/src/crypto/pem/pem_pkey.c b/deps/boringssl/src/crypto/pem/pem_pkey.c
index 5776535..48d8c96 100644
--- a/deps/boringssl/src/crypto/pem/pem_pkey.c
+++ b/deps/boringssl/src/crypto/pem/pem_pkey.c
@@ -150,7 +150,6 @@ int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, (char *)kstr, klen, cb, u);
}
-#ifndef OPENSSL_NO_FP_API
EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb,
void *u)
{
@@ -178,7 +177,6 @@ int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
return ret;
}
-#endif
/* Transparently read in PKCS#3 or X9.42 DH parameters */
@@ -203,7 +201,6 @@ DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u)
return ret;
}
-#ifndef OPENSSL_NO_FP_API
DH *PEM_read_DHparams(FILE *fp, DH **x, pem_password_cb *cb, void *u)
{
BIO *b = BIO_new_fp(fp, BIO_NOCLOSE);
@@ -215,4 +212,3 @@ DH *PEM_read_DHparams(FILE *fp, DH **x, pem_password_cb *cb, void *u)
BIO_free(b);
return ret;
}
-#endif
diff --git a/deps/boringssl/src/crypto/pkcs7/pkcs7_test.cc b/deps/boringssl/src/crypto/pkcs7/pkcs7_test.cc
index 948b44f..8e14603 100644
--- a/deps/boringssl/src/crypto/pkcs7/pkcs7_test.cc
+++ b/deps/boringssl/src/crypto/pkcs7/pkcs7_test.cc
@@ -17,6 +17,7 @@
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/mem.h>
+#include <openssl/pem.h>
#include <openssl/pkcs7.h>
#include <openssl/stack.h>
#include <openssl/x509.h>
@@ -492,6 +493,9 @@ static void TestCertReparse(const uint8_t *der_bytes, size_t der_len) {
ASSERT_TRUE(PKCS7_get_certificates(certs2.get(), &pkcs7));
EXPECT_EQ(0u, CBS_len(&pkcs7));
+ // PKCS#7 stores certificates in a SET OF, so |PKCS7_bundle_certificates| may
+ // not preserve the original order. All of our test inputs are already sorted,
+ // but this check should be relaxed if we add others.
ASSERT_EQ(sk_X509_num(certs.get()), sk_X509_num(certs2.get()));
for (size_t i = 0; i < sk_X509_num(certs.get()); i++) {
X509 *a = sk_X509_value(certs.get(), i);
@@ -574,6 +578,9 @@ static void TestCRLReparse(const uint8_t *der_bytes, size_t der_len) {
ASSERT_TRUE(PKCS7_get_CRLs(crls2.get(), &pkcs7));
EXPECT_EQ(0u, CBS_len(&pkcs7));
+ // PKCS#7 stores CRLs in a SET OF, so |PKCS7_bundle_CRLs| may not preserve the
+ // original order. All of our test inputs are already sorted, but this check
+ // should be relaxed if we add others.
ASSERT_EQ(sk_X509_CRL_num(crls.get()), sk_X509_CRL_num(crls.get()));
for (size_t i = 0; i < sk_X509_CRL_num(crls.get()); i++) {
X509_CRL *a = sk_X509_CRL_value(crls.get(), i);
@@ -656,3 +663,115 @@ TEST(PKCS7Test, PEMCerts) {
TEST(PKCS7Test, PEMCRLs) {
TestPEMCRLs(kPEMCRL);
}
+
+// Test that we output certificates in the canonical DER order.
+TEST(PKCS7Test, SortCerts) {
+ // kPKCS7NSS contains three certificates in the canonical DER order.
+ CBS pkcs7;
+ CBS_init(&pkcs7, kPKCS7NSS, sizeof(kPKCS7NSS));
+ bssl::UniquePtr<STACK_OF(X509)> certs(sk_X509_new_null());
+ ASSERT_TRUE(certs);
+ ASSERT_TRUE(PKCS7_get_certificates(certs.get(), &pkcs7));
+ ASSERT_EQ(3u, sk_X509_num(certs.get()));
+
+ X509 *cert1 = sk_X509_value(certs.get(), 0);
+ X509 *cert2 = sk_X509_value(certs.get(), 1);
+ X509 *cert3 = sk_X509_value(certs.get(), 2);
+
+ auto check_order = [&](X509 *new_cert1, X509 *new_cert2, X509 *new_cert3) {
+ // Bundle the certificates in the new order.
+ bssl::UniquePtr<STACK_OF(X509)> new_certs(sk_X509_new_null());
+ ASSERT_TRUE(new_certs);
+ ASSERT_TRUE(bssl::PushToStack(new_certs.get(), bssl::UpRef(new_cert1)));
+ ASSERT_TRUE(bssl::PushToStack(new_certs.get(), bssl::UpRef(new_cert2)));
+ ASSERT_TRUE(bssl::PushToStack(new_certs.get(), bssl::UpRef(new_cert3)));
+ bssl::ScopedCBB cbb;
+ ASSERT_TRUE(CBB_init(cbb.get(), sizeof(kPKCS7NSS)));
+ ASSERT_TRUE(PKCS7_bundle_certificates(cbb.get(), new_certs.get()));
+
+ // The bundle should be sorted back to the original order.
+ CBS cbs;
+ CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get()));
+ bssl::UniquePtr<STACK_OF(X509)> result(sk_X509_new_null());
+ ASSERT_TRUE(result);
+ ASSERT_TRUE(PKCS7_get_certificates(result.get(), &cbs));
+ ASSERT_EQ(sk_X509_num(certs.get()), sk_X509_num(result.get()));
+ for (size_t i = 0; i < sk_X509_num(certs.get()); i++) {
+ X509 *a = sk_X509_value(certs.get(), i);
+ X509 *b = sk_X509_value(result.get(), i);
+ EXPECT_EQ(0, X509_cmp(a, b));
+ }
+ };
+
+ check_order(cert1, cert2, cert3);
+ check_order(cert3, cert2, cert1);
+ check_order(cert2, cert3, cert1);
+}
+
+// Test that we output CRLs in the canonical DER order.
+TEST(PKCS7Test, SortCRLs) {
+ static const char kCRL1[] = R"(
+-----BEGIN X509 CRL-----
+MIIBpzCBkAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ
+Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoA4wDDAKBgNV
+HRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAnrBKKgvd9x9zwK9rtUvVeFeJ7+LN
+ZEAc+a5oxpPNEsJx6hXoApYEbzXMxuWBQoCs5iEBycSGudct21L+MVf27M38KrWo
+eOkq0a2siqViQZO2Fb/SUFR0k9zb8xl86Zf65lgPplALun0bV/HT7MJcl04Tc4os
+dsAReBs5nqTGNEd5AlC1iKHvQZkM//MD51DspKnDpsDiUVi54h9C1SpfZmX8H2Vv
+diyu0fZ/bPAM3VAGawatf/SyWfBMyKpoPXEG39oAzmjjOj8en82psn7m474IGaho
+/vBbhl1ms5qQiLYPjm4YELtnXQoFyC72tBjbdFd/ZE9k4CNKDbxFUXFbkw==
+-----END X509 CRL-----
+)";
+ static const char kCRL2[] = R"(
+-----BEGIN X509 CRL-----
+MIIBvjCBpwIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ
+Qm9yaW5nU1NMFw0xNjA5MjYxNTEyNDRaFw0xNjEwMjYxNTEyNDRaMBUwEwICEAAX
+DTE2MDkyNjE1MTIyNlqgDjAMMAoGA1UdFAQDAgECMA0GCSqGSIb3DQEBCwUAA4IB
+AQCUGaM4DcWzlQKrcZvI8TMeR8BpsvQeo5BoI/XZu2a8h//PyRyMwYeaOM+3zl0d
+sjgCT8b3C1FPgT+P2Lkowv7rJ+FHJRNQkogr+RuqCSPTq65ha4WKlRGWkMFybzVH
+NloxC+aU3lgp/NlX9yUtfqYmJek1CDrOOGPrAEAwj1l/BUeYKNGqfBWYJQtPJu+5
+OaSvIYGpETCZJscUWODmLEb/O3DM438vLvxonwGqXqS0KX37+CHpUlyhnSovxXxp
+Pz4aF+L7OtczxL0GYtD2fR9B7TDMqsNmHXgQrixvvOY7MUdLGbd4RfJL3yA53hyO
+xzfKY2TzxLiOmctG0hXFkH5J
+-----END X509 CRL-----
+)";
+
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kCRL1, strlen(kCRL1)));
+ ASSERT_TRUE(bio);
+ bssl::UniquePtr<X509_CRL> crl1(
+ PEM_read_bio_X509_CRL(bio.get(), nullptr, nullptr, nullptr));
+ ASSERT_TRUE(crl1);
+ bio.reset(BIO_new_mem_buf(kCRL2, strlen(kCRL2)));
+ ASSERT_TRUE(bio);
+ bssl::UniquePtr<X509_CRL> crl2(
+ PEM_read_bio_X509_CRL(bio.get(), nullptr, nullptr, nullptr));
+ ASSERT_TRUE(crl2);
+
+ // DER's SET OF ordering sorts by tag, then length, so |crl1| comes before
+ // |crl2|.
+ auto check_order = [&](X509_CRL *new_crl1, X509_CRL *new_crl2) {
+ // Bundle the CRLs in the new order.
+ bssl::UniquePtr<STACK_OF(X509_CRL)> new_crls(sk_X509_CRL_new_null());
+ ASSERT_TRUE(new_crls);
+ ASSERT_TRUE(bssl::PushToStack(new_crls.get(), bssl::UpRef(new_crl1)));
+ ASSERT_TRUE(bssl::PushToStack(new_crls.get(), bssl::UpRef(new_crl2)));
+ bssl::ScopedCBB cbb;
+ ASSERT_TRUE(CBB_init(cbb.get(), 64));
+ ASSERT_TRUE(PKCS7_bundle_CRLs(cbb.get(), new_crls.get()));
+
+ // The bundle should be sorted back to the original order.
+ CBS cbs;
+ CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get()));
+ bssl::UniquePtr<STACK_OF(X509_CRL)> result(sk_X509_CRL_new_null());
+ ASSERT_TRUE(result);
+ ASSERT_TRUE(PKCS7_get_CRLs(result.get(), &cbs));
+ ASSERT_EQ(2u, sk_X509_CRL_num(result.get()));
+ EXPECT_EQ(0, X509_CRL_cmp(crl1.get(), sk_X509_CRL_value(result.get(), 0)));
+ EXPECT_EQ(0, X509_CRL_cmp(crl2.get(), sk_X509_CRL_value(result.get(), 1)));
+ };
+
+ check_order(crl1.get(), crl2.get());
+ check_order(crl2.get(), crl1.get());
+}
diff --git a/deps/boringssl/src/crypto/pkcs7/pkcs7_x509.c b/deps/boringssl/src/crypto/pkcs7/pkcs7_x509.c
index 107bdea..3f1526c 100644
--- a/deps/boringssl/src/crypto/pkcs7/pkcs7_x509.c
+++ b/deps/boringssl/src/crypto/pkcs7/pkcs7_x509.c
@@ -192,7 +192,8 @@ static int pkcs7_bundle_certificates_cb(CBB *out, const void *arg) {
}
}
- return CBB_flush(out);
+ // |certificates| is a implicitly-tagged SET OF.
+ return CBB_flush_asn1_set_of(&certificates) && CBB_flush(out);
}
int PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) {
@@ -222,7 +223,8 @@ static int pkcs7_bundle_crls_cb(CBB *out, const void *arg) {
}
}
- return CBB_flush(out);
+ // |crl_data| is a implicitly-tagged SET OF.
+ return CBB_flush_asn1_set_of(&crl_data) && CBB_flush(out);
}
int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls) {
@@ -235,7 +237,7 @@ static PKCS7 *pkcs7_new(CBS *cbs) {
return NULL;
}
OPENSSL_memset(ret, 0, sizeof(PKCS7));
- ret->type = (ASN1_OBJECT *)OBJ_nid2obj(NID_pkcs7_signed);
+ ret->type = OBJ_nid2obj(NID_pkcs7_signed);
ret->d.sign = OPENSSL_malloc(sizeof(PKCS7_SIGNED));
if (ret->d.sign == NULL) {
goto err;
diff --git a/deps/boringssl/src/crypto/pkcs8/pkcs12_test.cc b/deps/boringssl/src/crypto/pkcs8/pkcs12_test.cc
index d345006..e67630d 100644
--- a/deps/boringssl/src/crypto/pkcs8/pkcs12_test.cc
+++ b/deps/boringssl/src/crypto/pkcs8/pkcs12_test.cc
@@ -28,1457 +28,19 @@
#include "../test/test_util.h"
-// kPKCS12DER contains sample PKCS#12 data generated by OpenSSL with:
-// openssl pkcs12 -export -inkey key.pem -in cacert.pem
-static const uint8_t kOpenSSL[] = {
- 0x30, 0x82, 0x09, 0xa1, 0x02, 0x01, 0x03, 0x30, 0x82, 0x09, 0x67, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
- 0x09, 0x58, 0x04, 0x82, 0x09, 0x54, 0x30, 0x82, 0x09, 0x50, 0x30, 0x82,
- 0x04, 0x07, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x06, 0xa0, 0x82, 0x03, 0xf8, 0x30, 0x82, 0x03, 0xf4, 0x02, 0x01, 0x00,
- 0x30, 0x82, 0x03, 0xed, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x31, 0x24, 0xca,
- 0x7d, 0xc3, 0x25, 0x3e, 0xdc, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x03,
- 0xc0, 0x55, 0xe7, 0x7f, 0x9c, 0xd6, 0x0c, 0xd2, 0x69, 0x1d, 0x6e, 0x8b,
- 0xb8, 0x07, 0xec, 0x4a, 0xe7, 0x06, 0x67, 0xd1, 0x24, 0x1b, 0xd5, 0x68,
- 0x13, 0x3d, 0xd7, 0x56, 0x5e, 0x15, 0x40, 0xdb, 0xda, 0x88, 0x36, 0xc9,
- 0x02, 0x96, 0xb5, 0xb5, 0xf7, 0x81, 0xef, 0x88, 0x1d, 0x66, 0x62, 0xa8,
- 0x83, 0xf7, 0x91, 0xb1, 0x26, 0x1f, 0x9b, 0x25, 0x78, 0x0a, 0x04, 0xb1,
- 0xc0, 0x93, 0x48, 0xa2, 0xf0, 0x51, 0x4f, 0x2b, 0xf8, 0x03, 0x67, 0x61,
- 0x1b, 0xed, 0x29, 0xfe, 0x3f, 0xdd, 0x83, 0xa3, 0x93, 0x75, 0xa7, 0xd9,
- 0x37, 0x5b, 0xa7, 0xc9, 0xf4, 0x52, 0x86, 0xd2, 0x3f, 0xca, 0x61, 0x5c,
- 0x1e, 0xf9, 0x07, 0x7d, 0xbd, 0xda, 0x76, 0x8a, 0x03, 0x8e, 0x12, 0x4e,
- 0x8f, 0x68, 0x6e, 0x72, 0x6e, 0xf0, 0xbe, 0x22, 0xc7, 0x9d, 0x97, 0x7c,
- 0x45, 0xc0, 0xaa, 0x31, 0xe1, 0x55, 0x81, 0xb3, 0xec, 0x98, 0x94, 0xac,
- 0xf7, 0x15, 0x9b, 0x42, 0x49, 0x8c, 0x2a, 0x29, 0x7a, 0x25, 0x92, 0x64,
- 0x92, 0xbd, 0x4e, 0x5c, 0xec, 0xff, 0x61, 0xbb, 0x8e, 0x5c, 0xc8, 0xdb,
- 0xba, 0x97, 0x30, 0xf4, 0x55, 0x9e, 0x1b, 0xfa, 0xbe, 0x2a, 0x90, 0xcf,
- 0xe8, 0xc0, 0x9d, 0xb0, 0x0e, 0x24, 0x61, 0xe7, 0x3a, 0xb7, 0x7f, 0xda,
- 0x63, 0xaa, 0x2a, 0x4a, 0xa6, 0x91, 0x52, 0xa6, 0x76, 0xc9, 0xbe, 0x9f,
- 0x1b, 0x1d, 0xa4, 0x09, 0x5b, 0x0f, 0xd1, 0x64, 0x4e, 0xdf, 0x0c, 0x44,
- 0x59, 0x3a, 0xef, 0x9a, 0xd8, 0x22, 0xa2, 0x5f, 0x80, 0xb5, 0x4f, 0xbe,
- 0x84, 0x23, 0xe3, 0x74, 0x77, 0x3c, 0x9e, 0x27, 0x64, 0xac, 0x65, 0xf4,
- 0xbb, 0x34, 0xb7, 0xa4, 0xfe, 0x02, 0x1a, 0x88, 0x05, 0x3b, 0x4b, 0xb8,
- 0xd8, 0xb9, 0x26, 0x69, 0x22, 0x97, 0x3d, 0x93, 0x9b, 0xe8, 0x72, 0xaa,
- 0x4d, 0x8f, 0x76, 0x51, 0x12, 0x59, 0x58, 0xf1, 0x1a, 0xa3, 0xdb, 0x5d,
- 0xbc, 0xea, 0x84, 0x19, 0x55, 0x4f, 0x00, 0xfb, 0xe2, 0x57, 0x47, 0xca,
- 0xea, 0xbe, 0x8f, 0x85, 0x8b, 0x1c, 0x27, 0x8d, 0x81, 0x70, 0x7f, 0xf1,
- 0x56, 0x58, 0xe1, 0x26, 0x94, 0xd8, 0x2f, 0xde, 0xac, 0xc8, 0xac, 0xbf,
- 0xc3, 0xc6, 0x67, 0xa6, 0xf4, 0x6c, 0xec, 0x20, 0x3c, 0xbc, 0x9d, 0xd9,
- 0xd0, 0xa1, 0x4e, 0x8c, 0x11, 0x19, 0x2b, 0xb3, 0xa1, 0xdf, 0x6a, 0x8f,
- 0xa2, 0xc3, 0xcc, 0xf6, 0xbd, 0x09, 0x7a, 0x96, 0x61, 0x20, 0xd4, 0x06,
- 0x99, 0x4c, 0x6f, 0x23, 0x9b, 0x4c, 0xcc, 0x73, 0x8b, 0x42, 0x48, 0x99,
- 0x45, 0x8f, 0xcb, 0xc8, 0x46, 0x1a, 0xfb, 0x51, 0x03, 0x6a, 0xf2, 0x22,
- 0x85, 0x88, 0x9d, 0x61, 0x8b, 0x16, 0x33, 0xf4, 0xf7, 0x9b, 0xc8, 0x21,
- 0x4f, 0xb1, 0xcd, 0x30, 0xfc, 0x29, 0x88, 0x12, 0xdc, 0xd4, 0x30, 0x4c,
- 0xb9, 0xad, 0x34, 0xde, 0x01, 0xf8, 0xc1, 0x12, 0xa7, 0x4d, 0xc7, 0x31,
- 0x99, 0x2b, 0x45, 0x88, 0x06, 0x34, 0x69, 0x6e, 0x6d, 0x34, 0xd8, 0xdd,
- 0x0a, 0x3d, 0x59, 0x74, 0x36, 0x31, 0x6a, 0xed, 0x91, 0x3b, 0x5b, 0x88,
- 0x43, 0x46, 0x3f, 0x67, 0x66, 0xe4, 0xde, 0x52, 0xb4, 0xbf, 0x7b, 0x3d,
- 0x54, 0x79, 0xaf, 0x8d, 0xf5, 0x0a, 0x80, 0xfd, 0xeb, 0x31, 0x24, 0xbc,
- 0x24, 0xd7, 0x21, 0x9f, 0x87, 0xab, 0xbd, 0x75, 0x2c, 0x13, 0x13, 0x96,
- 0xab, 0x76, 0xfb, 0xb2, 0x44, 0xd0, 0xd2, 0x19, 0xf1, 0x95, 0x9a, 0x91,
- 0xbf, 0x7a, 0x7b, 0x76, 0x95, 0x72, 0xa9, 0x16, 0xfc, 0x3e, 0xa9, 0x4e,
- 0x01, 0x15, 0x3d, 0x43, 0x73, 0xa3, 0x8b, 0xef, 0x48, 0xad, 0x11, 0xbd,
- 0x53, 0xd3, 0x0c, 0x15, 0x15, 0x1a, 0xb4, 0x3a, 0xe0, 0x7f, 0x9a, 0xa1,
- 0x36, 0x47, 0x72, 0x92, 0xf0, 0xdf, 0xb0, 0xe2, 0xbc, 0x35, 0xd4, 0x32,
- 0x6b, 0x37, 0x69, 0x4f, 0x47, 0x9a, 0xe2, 0x35, 0x8a, 0x31, 0x60, 0xed,
- 0x80, 0x57, 0xe2, 0x9d, 0x58, 0x9c, 0x7f, 0x46, 0xd2, 0x54, 0x0e, 0x28,
- 0x53, 0x8b, 0x1f, 0x46, 0x34, 0x22, 0xac, 0x71, 0xc7, 0xca, 0x0f, 0xb4,
- 0xb7, 0x7a, 0xfc, 0x34, 0x57, 0xa5, 0x86, 0x8d, 0x66, 0x5c, 0xc7, 0x3a,
- 0xdb, 0xf8, 0x79, 0x3a, 0x8a, 0xf6, 0xa2, 0x1e, 0x09, 0xc9, 0x10, 0xe9,
- 0x93, 0x3a, 0xc5, 0xed, 0xb2, 0xca, 0xbb, 0x66, 0xf1, 0x9d, 0xc9, 0x9c,
- 0x42, 0x75, 0x64, 0x3e, 0xe4, 0x12, 0x2b, 0x67, 0xf8, 0xbf, 0x2b, 0x98,
- 0x5d, 0xb6, 0xa0, 0xba, 0x79, 0x98, 0xe0, 0x47, 0x5c, 0x77, 0x85, 0x4e,
- 0x26, 0x71, 0xfe, 0xab, 0x5c, 0xa8, 0x32, 0x93, 0xec, 0xd0, 0x26, 0x90,
- 0xe4, 0xda, 0x2f, 0x34, 0x8a, 0x50, 0xb8, 0x3b, 0x7b, 0x4c, 0x5f, 0xa9,
- 0x3e, 0x8a, 0xa8, 0xf3, 0xc0, 0xb7, 0x50, 0x0b, 0x77, 0x4e, 0x8c, 0xa0,
- 0xaf, 0xdb, 0x59, 0xe7, 0xac, 0xd1, 0x34, 0x4e, 0x62, 0x47, 0x2e, 0x1e,
- 0x5e, 0xb4, 0xc9, 0x64, 0xf8, 0x0f, 0xf4, 0xf8, 0xb6, 0x9a, 0xe3, 0x7e,
- 0xcf, 0xb7, 0xee, 0x11, 0x14, 0x52, 0x89, 0x3b, 0x27, 0x98, 0xfc, 0x95,
- 0xa7, 0xad, 0xbf, 0x61, 0x34, 0xad, 0x1a, 0x24, 0x2a, 0x48, 0x66, 0x65,
- 0x75, 0x9c, 0x59, 0xc0, 0x4f, 0x5f, 0x3d, 0x5a, 0x8c, 0xee, 0xd0, 0xb1,
- 0x17, 0x6d, 0x34, 0x46, 0x37, 0xa0, 0xba, 0x71, 0xac, 0x77, 0x73, 0x29,
- 0xa3, 0x37, 0x4f, 0x02, 0xd3, 0x7f, 0x0e, 0xe8, 0xce, 0xff, 0x80, 0x11,
- 0x45, 0x42, 0x03, 0x5a, 0x87, 0xaa, 0xff, 0x25, 0x12, 0x1f, 0x43, 0x19,
- 0x3e, 0xa9, 0x62, 0x96, 0x0c, 0x6f, 0x33, 0x88, 0x5c, 0xaa, 0xf9, 0xe2,
- 0xb4, 0xb9, 0xf7, 0x55, 0xae, 0xb5, 0x76, 0x57, 0x47, 0x83, 0xe3, 0xfa,
- 0x05, 0xda, 0x86, 0x02, 0x97, 0xb4, 0x60, 0xae, 0x59, 0xd5, 0x6c, 0xc1,
- 0x33, 0xe1, 0x36, 0x36, 0x94, 0x79, 0x9e, 0xad, 0xa3, 0x2d, 0xbc, 0xb5,
- 0xa2, 0xeb, 0xdd, 0xcd, 0xcb, 0x48, 0x42, 0x15, 0xb8, 0xe6, 0x0e, 0x76,
- 0x5b, 0x57, 0x74, 0x24, 0xe6, 0x89, 0xc4, 0xe8, 0x08, 0xa9, 0xfe, 0xb3,
- 0x23, 0xa6, 0xca, 0x72, 0xe2, 0xe4, 0xcb, 0xc1, 0x4a, 0xd1, 0x1d, 0xb9,
- 0x5e, 0x36, 0x97, 0x19, 0x7c, 0x15, 0x48, 0xf1, 0x2d, 0xeb, 0xec, 0xad,
- 0x52, 0x6f, 0x2f, 0xe1, 0x19, 0xcf, 0xcf, 0x98, 0x13, 0x0d, 0xcc, 0xb2,
- 0xa6, 0x8a, 0xda, 0x93, 0x24, 0x3d, 0x5d, 0x83, 0xfe, 0x8d, 0x9e, 0x47,
- 0xd8, 0x6e, 0x8d, 0x06, 0x52, 0x7d, 0x46, 0x84, 0x04, 0x69, 0x34, 0x61,
- 0x04, 0x50, 0x1f, 0x86, 0x92, 0x94, 0xe9, 0x0b, 0x13, 0x5b, 0xf6, 0x16,
- 0x81, 0xeb, 0xfa, 0xf1, 0xbb, 0x04, 0x68, 0x17, 0xca, 0x35, 0x6f, 0xba,
- 0x4e, 0x4c, 0x33, 0xce, 0xf4, 0x26, 0xb7, 0x74, 0xab, 0xa5, 0xd0, 0xaa,
- 0x0d, 0x85, 0x11, 0x30, 0x58, 0x62, 0xdf, 0x48, 0xc7, 0xdf, 0xc9, 0x38,
- 0x9e, 0x6f, 0x96, 0x23, 0x2f, 0xc1, 0xd4, 0x8d, 0x65, 0x9b, 0x46, 0x5f,
- 0x9c, 0xea, 0x26, 0x60, 0xb5, 0x95, 0x85, 0x71, 0x18, 0xc3, 0xf4, 0x54,
- 0x61, 0xca, 0xfe, 0x55, 0x3b, 0xbe, 0x81, 0xaf, 0xd9, 0x3a, 0x27, 0xe9,
- 0x1c, 0x30, 0x82, 0x05, 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x05, 0x32, 0x04, 0x82, 0x05, 0x2e,
- 0x30, 0x82, 0x05, 0x2a, 0x30, 0x82, 0x05, 0x26, 0x06, 0x0b, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x04,
- 0xee, 0x30, 0x82, 0x04, 0xea, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0xd9,
- 0x68, 0xcb, 0x08, 0x16, 0xc8, 0x93, 0x57, 0x02, 0x02, 0x08, 0x00, 0x04,
- 0x82, 0x04, 0xc8, 0x7c, 0xdb, 0xa6, 0x1e, 0x33, 0xa4, 0xc6, 0x4e, 0x13,
- 0x22, 0x7a, 0x1f, 0xc6, 0x82, 0xab, 0x93, 0x5f, 0xf0, 0xa4, 0xe4, 0x40,
- 0xac, 0xdf, 0x16, 0xec, 0x8d, 0x1f, 0xd9, 0xe4, 0x03, 0xd6, 0xc9, 0xc4,
- 0x1d, 0xfd, 0xa3, 0xe3, 0xba, 0xfc, 0xcb, 0xd0, 0x47, 0x65, 0x0c, 0x6e,
- 0x5d, 0xfc, 0xd2, 0xd4, 0x63, 0xa7, 0x93, 0xf6, 0x8a, 0x44, 0x8c, 0xfe,
- 0x84, 0xd8, 0x0d, 0xa6, 0x16, 0x22, 0xe1, 0x65, 0x10, 0x5e, 0x18, 0x44,
- 0x58, 0x2f, 0xc7, 0x64, 0x74, 0x5f, 0xcf, 0x73, 0x34, 0xe1, 0x4b, 0xe4,
- 0xb3, 0x5b, 0xdb, 0x81, 0x4b, 0x1c, 0x38, 0x72, 0xa6, 0xc5, 0xeb, 0x56,
- 0x9b, 0xc7, 0xe3, 0x3d, 0x54, 0x6e, 0x05, 0x2c, 0xd3, 0x57, 0xc9, 0x4f,
- 0x80, 0x1e, 0xd7, 0xd8, 0x26, 0x6a, 0xcb, 0x79, 0x46, 0x70, 0xfc, 0x45,
- 0xa7, 0x79, 0xab, 0x01, 0x03, 0xb6, 0xb1, 0x44, 0x41, 0xd9, 0x73, 0x37,
- 0xaa, 0xd7, 0xf9, 0x44, 0x93, 0xaf, 0xbb, 0xb5, 0x77, 0xeb, 0x2b, 0x20,
- 0x2e, 0xbd, 0xea, 0x2f, 0xde, 0xa6, 0x2f, 0xd6, 0xac, 0x74, 0xa5, 0x34,
- 0xfb, 0xdf, 0xf7, 0x02, 0xa2, 0x20, 0x15, 0xc8, 0x61, 0x72, 0xbb, 0x7f,
- 0x04, 0xf6, 0x0f, 0xf8, 0x7e, 0xc3, 0xe6, 0xab, 0x2a, 0xe6, 0xd8, 0xe1,
- 0x0d, 0x5a, 0x3c, 0xc0, 0x58, 0xae, 0xf8, 0x1b, 0x15, 0x3c, 0x7b, 0x7f,
- 0xf5, 0x9f, 0xec, 0xf7, 0x3f, 0x30, 0x4f, 0x3d, 0x6c, 0x44, 0xdd, 0x0e,
- 0x4c, 0x2c, 0x93, 0x68, 0x43, 0x31, 0xa8, 0x97, 0x4b, 0xf6, 0x66, 0x71,
- 0x2a, 0x52, 0x3e, 0x3a, 0xe6, 0x72, 0x8a, 0xe6, 0xe3, 0xc8, 0xff, 0x65,
- 0x68, 0x1a, 0x46, 0x21, 0xb3, 0xf0, 0x46, 0x7c, 0x0c, 0x65, 0xd1, 0x8e,
- 0xa4, 0x91, 0x11, 0x5c, 0x93, 0xeb, 0xeb, 0xae, 0x46, 0xf4, 0xbb, 0xf8,
- 0xf3, 0x7e, 0x20, 0x30, 0xf8, 0xcd, 0x19, 0xcd, 0x54, 0x0a, 0x7f, 0x4f,
- 0xe8, 0xac, 0xa9, 0xac, 0x72, 0x96, 0x80, 0x45, 0x2a, 0x4a, 0x63, 0x90,
- 0x01, 0x19, 0xd0, 0x7e, 0x26, 0x53, 0x2d, 0xc4, 0x20, 0xa5, 0x1f, 0x89,
- 0x67, 0x0f, 0xd9, 0x75, 0x51, 0x0a, 0xf1, 0xd4, 0xfd, 0x2e, 0xbe, 0xe6,
- 0x94, 0x3b, 0x6c, 0x8c, 0xe3, 0x0f, 0x5f, 0xce, 0x58, 0x48, 0xde, 0x8d,
- 0xeb, 0xd3, 0xe1, 0x0a, 0xcd, 0xdf, 0x34, 0x4d, 0xd1, 0x5b, 0xab, 0x41,
- 0x41, 0x6b, 0xeb, 0xa1, 0x2f, 0x01, 0x4a, 0x72, 0x2e, 0xf4, 0x5e, 0x44,
- 0x76, 0xc7, 0xe6, 0x16, 0xb9, 0xfb, 0x10, 0x37, 0x00, 0x2d, 0xc6, 0x3b,
- 0x17, 0x72, 0x21, 0xdb, 0xac, 0x86, 0x7b, 0xf5, 0x70, 0x3f, 0x73, 0xa3,
- 0xce, 0x0e, 0x20, 0xbb, 0x59, 0x4c, 0x23, 0xc2, 0xe8, 0x22, 0x22, 0xe0,
- 0x02, 0x0d, 0xe4, 0xa2, 0x3f, 0x55, 0x9d, 0xc0, 0xeb, 0x9a, 0xc4, 0xf3,
- 0xaa, 0xb8, 0xf1, 0x73, 0xec, 0x47, 0xe8, 0x2d, 0x6b, 0xa1, 0x40, 0x94,
- 0xf6, 0x07, 0xb9, 0x6f, 0x03, 0x5a, 0x78, 0xe5, 0x59, 0x41, 0x1a, 0xc7,
- 0xcd, 0x43, 0x10, 0x20, 0x28, 0x95, 0xe0, 0x2a, 0x6f, 0xf2, 0xf8, 0x12,
- 0xd6, 0x13, 0x7f, 0x37, 0x3d, 0x38, 0xa7, 0x22, 0x91, 0xc6, 0xe3, 0x52,
- 0xde, 0xd8, 0xbf, 0x78, 0x9a, 0xa4, 0xf7, 0xc0, 0x8c, 0xbf, 0x81, 0x28,
- 0x20, 0xb8, 0x01, 0xde, 0xb5, 0x6b, 0x0a, 0x56, 0x12, 0x5c, 0x62, 0x1d,
- 0xaf, 0xb7, 0xf2, 0x74, 0x66, 0x0a, 0x7a, 0xc4, 0x9f, 0x1e, 0xc2, 0xa8,
- 0x4c, 0xd6, 0x76, 0x6d, 0x74, 0x35, 0x37, 0x12, 0x5c, 0x95, 0xee, 0x98,
- 0x1d, 0xe2, 0x91, 0xde, 0x13, 0x08, 0xd0, 0x59, 0x4d, 0x62, 0x92, 0x69,
- 0x1b, 0xf7, 0x21, 0x45, 0xaf, 0x83, 0xf8, 0x64, 0xf0, 0xfb, 0x92, 0x9d,
- 0xa1, 0xd9, 0x61, 0x5e, 0x00, 0xc8, 0x1a, 0x6e, 0x6a, 0x2d, 0xad, 0xa8,
- 0x1b, 0x0e, 0xaf, 0xea, 0xb2, 0xae, 0x1c, 0x89, 0xc7, 0x4d, 0x2c, 0x0f,
- 0x4d, 0x8d, 0x78, 0x8d, 0x15, 0x9d, 0x4c, 0x90, 0x52, 0xa1, 0xa9, 0xd8,
- 0xb2, 0x66, 0xb9, 0xb1, 0x46, 0x0a, 0x69, 0x86, 0x2b, 0x0f, 0xb2, 0x41,
- 0xce, 0xe8, 0x8e, 0x49, 0x97, 0x08, 0x0b, 0x70, 0x97, 0xcb, 0xa4, 0x33,
- 0x3f, 0x83, 0x6b, 0x6c, 0x17, 0xce, 0xd8, 0xd5, 0x9b, 0xd4, 0x55, 0x9b,
- 0x99, 0xe1, 0xba, 0x61, 0x31, 0x36, 0x79, 0x31, 0x5f, 0xa1, 0x8c, 0xa9,
- 0x77, 0x42, 0xaa, 0x8c, 0x45, 0x6e, 0xb6, 0x90, 0x08, 0xe8, 0x2e, 0xc4,
- 0x72, 0x69, 0x42, 0xca, 0xa2, 0xd4, 0x8a, 0x2c, 0x37, 0xe1, 0xde, 0xb8,
- 0x98, 0x36, 0xeb, 0xcc, 0x58, 0x0c, 0x24, 0xad, 0xab, 0x62, 0x44, 0x6d,
- 0x80, 0xd5, 0xce, 0x2e, 0x4a, 0x3e, 0xa5, 0xc5, 0x34, 0xf8, 0x32, 0x26,
- 0x2a, 0x56, 0xa4, 0xdd, 0xe9, 0x92, 0x06, 0xad, 0xe8, 0x85, 0x77, 0x6b,
- 0xf1, 0x1b, 0xeb, 0xac, 0x77, 0x19, 0x1c, 0x6a, 0xb7, 0xef, 0x28, 0x70,
- 0x87, 0x92, 0x33, 0xdd, 0xaa, 0x30, 0xc1, 0xa0, 0x93, 0x64, 0x18, 0xa2,
- 0x91, 0x7f, 0xf7, 0xc4, 0xa5, 0x16, 0x93, 0xb3, 0x5b, 0xd8, 0x53, 0x28,
- 0xc5, 0x5e, 0xb1, 0xce, 0x97, 0xbc, 0xb6, 0x65, 0xa8, 0x53, 0xcd, 0xf4,
- 0x4d, 0x6b, 0xea, 0x6f, 0x6f, 0xa5, 0x1c, 0xf1, 0x0f, 0xcb, 0x04, 0x25,
- 0x4a, 0xfe, 0x7d, 0xfc, 0xa3, 0xbd, 0x41, 0xd3, 0x96, 0x6a, 0x8b, 0xad,
- 0xd4, 0xaa, 0x0a, 0x76, 0xea, 0x3b, 0xab, 0x39, 0x55, 0xa3, 0x89, 0x9f,
- 0xf6, 0xf5, 0x9b, 0x9c, 0x83, 0xf8, 0x28, 0x50, 0xdf, 0x31, 0x74, 0x83,
- 0xdb, 0xf1, 0x0f, 0x4c, 0x35, 0x6a, 0xe5, 0x64, 0x2e, 0xb9, 0x77, 0x3d,
- 0xdd, 0xff, 0xa3, 0xa7, 0x90, 0x79, 0xc6, 0x5b, 0x01, 0x16, 0x38, 0xa8,
- 0x22, 0xa3, 0x14, 0x13, 0xed, 0xd0, 0x89, 0x0d, 0x1f, 0x3a, 0x41, 0x4c,
- 0x57, 0x79, 0xfc, 0x1d, 0xdf, 0xad, 0x1a, 0x11, 0x15, 0x31, 0x7e, 0xdb,
- 0x99, 0x3a, 0x6c, 0xde, 0x94, 0x9a, 0x45, 0x4c, 0xfb, 0xa5, 0xa5, 0x31,
- 0xee, 0xe3, 0x09, 0x13, 0x6d, 0xfd, 0x19, 0x37, 0x3f, 0xf6, 0xed, 0x8f,
- 0x0c, 0xce, 0x4b, 0xd1, 0xe1, 0x3d, 0xfb, 0x85, 0x00, 0x84, 0x19, 0xeb,
- 0xa2, 0x63, 0x1d, 0x2b, 0x2d, 0x21, 0xee, 0x08, 0x5a, 0x6d, 0xb0, 0xb1,
- 0xd6, 0x81, 0x00, 0xb6, 0xd0, 0x09, 0x90, 0xb4, 0x84, 0x17, 0xd9, 0x2a,
- 0x3c, 0x1d, 0x53, 0xc6, 0xc1, 0x8b, 0xda, 0xae, 0x0c, 0x0a, 0x3e, 0x1c,
- 0x8a, 0xc4, 0xd6, 0x97, 0x5d, 0x48, 0xe7, 0x79, 0x80, 0x78, 0xaa, 0xde,
- 0x17, 0x60, 0x5d, 0x28, 0x15, 0x3a, 0x42, 0xb7, 0x85, 0xc8, 0x60, 0x93,
- 0x28, 0xb0, 0x4e, 0xc9, 0xf7, 0x46, 0xe7, 0xfc, 0x4e, 0x9f, 0x9f, 0x12,
- 0xdf, 0xcb, 0x6e, 0x0c, 0xaf, 0x71, 0xda, 0xb7, 0xec, 0x3d, 0x46, 0xf3,
- 0x35, 0x41, 0x42, 0xd8, 0x27, 0x92, 0x99, 0x1c, 0x4d, 0xc9, 0x3c, 0xe9,
- 0x0e, 0xcb, 0x3f, 0x57, 0x65, 0x77, 0x0d, 0xdd, 0xff, 0xea, 0x70, 0x35,
- 0xcc, 0xf5, 0x38, 0x1b, 0x57, 0xdf, 0x6d, 0xcb, 0xfd, 0x13, 0x39, 0xd6,
- 0x04, 0xe2, 0xf1, 0xc2, 0xd9, 0xea, 0x8c, 0x9f, 0xfb, 0xb5, 0xfc, 0xe6,
- 0xa9, 0xaa, 0x0f, 0x43, 0xc9, 0x9c, 0x91, 0xe4, 0x21, 0xaf, 0x37, 0x14,
- 0x78, 0x46, 0xe1, 0x29, 0x41, 0x0c, 0x4e, 0xf5, 0x93, 0x1d, 0xf8, 0x33,
- 0x47, 0x6f, 0x9d, 0x8b, 0xf3, 0x27, 0xd4, 0xbb, 0xf6, 0xae, 0xfa, 0xa5,
- 0x8b, 0x41, 0x8f, 0xb4, 0xd7, 0x2f, 0xc1, 0x27, 0xea, 0x70, 0x55, 0x1d,
- 0xe2, 0xd8, 0x0c, 0x4a, 0x5e, 0x7c, 0x87, 0xa4, 0x0e, 0x84, 0x07, 0xd3,
- 0x38, 0x67, 0x2c, 0x55, 0x11, 0xfd, 0x1e, 0xda, 0x4d, 0x66, 0x01, 0x12,
- 0x0c, 0x1b, 0x7c, 0x7c, 0x5c, 0x82, 0x21, 0x35, 0x65, 0x5c, 0x7a, 0xd2,
- 0x66, 0xc2, 0x2b, 0x5e, 0xb8, 0xb1, 0xcb, 0xdf, 0x59, 0xc9, 0x31, 0xb7,
- 0x17, 0x26, 0x96, 0x5e, 0x6f, 0x1c, 0x62, 0x3d, 0x8d, 0x88, 0xf1, 0xd1,
- 0x01, 0x3e, 0xf9, 0x6f, 0xb9, 0x77, 0xdc, 0xee, 0xee, 0x78, 0x59, 0xef,
- 0xcf, 0x3a, 0x87, 0x88, 0xa2, 0xea, 0xfd, 0x0a, 0xa9, 0xa9, 0x3e, 0x0c,
- 0xf8, 0x7f, 0x97, 0x32, 0x17, 0xc2, 0x97, 0xcb, 0xa4, 0x9b, 0xae, 0x5d,
- 0xe7, 0x39, 0x2b, 0x2b, 0xa8, 0xe6, 0x7b, 0x51, 0x75, 0x1f, 0x53, 0x54,
- 0x37, 0xf4, 0x00, 0xa4, 0xb0, 0xa0, 0x93, 0xb4, 0x33, 0xe7, 0xae, 0x28,
- 0xc0, 0x2d, 0x3a, 0xb3, 0xaa, 0xd7, 0x3c, 0x76, 0x44, 0x4b, 0xbb, 0x6a,
- 0x67, 0x98, 0xce, 0xf8, 0x15, 0x13, 0x67, 0x79, 0x3c, 0x15, 0x09, 0xb7,
- 0x22, 0xc0, 0xec, 0x07, 0x8a, 0xfd, 0x44, 0xcb, 0x99, 0xbd, 0xdc, 0xd5,
- 0x53, 0x4c, 0x97, 0x1b, 0x46, 0xaf, 0xc0, 0x6c, 0x06, 0x01, 0x93, 0x8a,
- 0x50, 0x51, 0x6a, 0xe4, 0x5c, 0x0a, 0x52, 0x81, 0x3b, 0x75, 0xed, 0xa2,
- 0x97, 0xa6, 0x5c, 0x55, 0x63, 0xee, 0xfb, 0x33, 0x82, 0x10, 0xa8, 0x21,
- 0x1a, 0x8d, 0xc8, 0xe1, 0x52, 0x68, 0x38, 0x88, 0x2f, 0xae, 0x2b, 0x22,
- 0x7a, 0x9b, 0x0c, 0x19, 0x73, 0x6f, 0x91, 0xc7, 0xfa, 0x95, 0x61, 0x28,
- 0x74, 0x73, 0x70, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x14, 0x74,
- 0x2d, 0x52, 0x8e, 0x0d, 0x0c, 0x06, 0x6c, 0x32, 0x64, 0xd3, 0x7e, 0x33,
- 0x31, 0x68, 0x8b, 0x28, 0x1a, 0x75, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09,
- 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x22,
- 0x8e, 0xff, 0x5a, 0x78, 0xec, 0x2c, 0x21, 0xa2, 0x48, 0xb7, 0x63, 0x88,
- 0x10, 0x47, 0x1c, 0xc0, 0xd3, 0xec, 0x5a, 0x04, 0x08, 0xb3, 0x2e, 0x21,
- 0xfd, 0x82, 0x14, 0xd8, 0x5c, 0x02, 0x02, 0x08, 0x00,
-};
-
-// kNSS is the result of importing the OpenSSL example PKCS#12 into Chrome and
-// then exporting it again.
-static const uint8_t kNSS[] = {
- 0x30, 0x80, 0x02, 0x01, 0x03, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x82,
- 0x09, 0xef, 0x30, 0x80, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x82, 0x05,
- 0x77, 0x30, 0x82, 0x05, 0x73, 0x30, 0x82, 0x05, 0x6f, 0x06, 0x0b, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82,
- 0x04, 0xf6, 0x30, 0x82, 0x04, 0xf2, 0x30, 0x24, 0x06, 0x0a, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x16, 0x04, 0x10,
- 0xac, 0x71, 0x8a, 0x7c, 0x89, 0xcf, 0xa8, 0xb0, 0xd6, 0xd1, 0x07, 0xf0,
- 0x83, 0x4f, 0x7a, 0xd0, 0x02, 0x02, 0x07, 0xd0, 0x04, 0x82, 0x04, 0xc8,
- 0xea, 0x51, 0x2c, 0x61, 0xaa, 0x9d, 0xf3, 0x90, 0xe1, 0x38, 0x45, 0xb0,
- 0x5f, 0xfd, 0xe2, 0x04, 0x65, 0xe6, 0xff, 0x87, 0xb6, 0x78, 0x69, 0xb0,
- 0xcb, 0x14, 0xe9, 0x99, 0x39, 0xe3, 0xe5, 0x70, 0x84, 0x57, 0x68, 0xf7,
- 0x28, 0xb9, 0x75, 0xa6, 0xfb, 0x16, 0x72, 0xe1, 0x34, 0xb8, 0x3b, 0x61,
- 0x51, 0x89, 0x18, 0x94, 0x40, 0xef, 0x73, 0xda, 0xdb, 0xd7, 0xb7, 0x44,
- 0x73, 0x8f, 0x16, 0x84, 0xa2, 0x99, 0xa6, 0x05, 0x5e, 0x74, 0xae, 0xe2,
- 0xcf, 0x3e, 0x99, 0xca, 0xcd, 0x76, 0x36, 0x77, 0x59, 0xec, 0x25, 0x59,
- 0x3d, 0x4b, 0x45, 0xa5, 0x4e, 0x7b, 0x7a, 0xc9, 0x8b, 0xde, 0x4f, 0x70,
- 0x6d, 0xb1, 0xa8, 0xf3, 0xb6, 0xb5, 0xe7, 0x67, 0x3f, 0xe9, 0x64, 0xb8,
- 0x49, 0xf4, 0x11, 0x94, 0x9d, 0x1c, 0xb0, 0xa5, 0xfb, 0xb3, 0x61, 0xd4,
- 0xf3, 0xa7, 0x68, 0x66, 0xd7, 0xa4, 0xf0, 0xcd, 0xc8, 0x40, 0x4f, 0x3e,
- 0xa7, 0x26, 0x40, 0x76, 0x64, 0xa1, 0x4e, 0xf1, 0x91, 0xc2, 0xa3, 0xef,
- 0xbc, 0xcd, 0x42, 0xe5, 0xd2, 0x6f, 0xff, 0xfe, 0x4d, 0x33, 0x01, 0xb4,
- 0x99, 0x63, 0x1b, 0xd3, 0x01, 0x55, 0x00, 0xa6, 0x23, 0x9b, 0xa9, 0x17,
- 0x09, 0x38, 0x32, 0x18, 0x36, 0xbc, 0x20, 0x02, 0xfe, 0x7b, 0xec, 0xd3,
- 0x4c, 0x7d, 0xc9, 0xc9, 0xce, 0x66, 0x3b, 0x34, 0x6e, 0xea, 0xf9, 0xb1,
- 0x1a, 0x83, 0xa3, 0x3c, 0x8d, 0xc7, 0x79, 0xc9, 0xff, 0x6b, 0x1d, 0x35,
- 0xf6, 0x2a, 0x3d, 0x3b, 0x83, 0x16, 0x64, 0xcf, 0x9f, 0x7c, 0x31, 0x02,
- 0xda, 0x37, 0x1a, 0x16, 0x49, 0xdc, 0xd9, 0x70, 0xae, 0x99, 0x2c, 0xc7,
- 0x01, 0xba, 0x42, 0xab, 0xe9, 0x4d, 0xa4, 0x78, 0x2c, 0xbd, 0xa0, 0xf1,
- 0xb7, 0xcf, 0xdd, 0xc1, 0xdb, 0x8f, 0x04, 0x87, 0x0b, 0x47, 0x4f, 0xd5,
- 0xd5, 0xe7, 0xfc, 0x6e, 0x42, 0xd5, 0x91, 0x4d, 0x7b, 0x1b, 0x5c, 0x3c,
- 0x02, 0x70, 0xdb, 0x05, 0x91, 0xaf, 0x35, 0x43, 0x05, 0xc2, 0x6d, 0xcf,
- 0x59, 0x23, 0xfc, 0xc4, 0xf6, 0x67, 0xf1, 0x84, 0x61, 0x4a, 0xb6, 0x4c,
- 0x15, 0x15, 0xa3, 0xea, 0x8f, 0x13, 0x15, 0xe3, 0xd2, 0xb5, 0x50, 0xc8,
- 0xae, 0xc8, 0x5c, 0x03, 0xb5, 0x63, 0x93, 0xaa, 0x10, 0xd7, 0x56, 0x0d,
- 0x6e, 0x13, 0x45, 0x8f, 0xec, 0x17, 0x5c, 0x5c, 0x73, 0x91, 0x5f, 0x6c,
- 0xaf, 0x11, 0x13, 0x32, 0x5e, 0x14, 0xf9, 0xaf, 0xaf, 0x43, 0x04, 0x60,
- 0x93, 0x42, 0x30, 0xa6, 0x75, 0xc0, 0x83, 0xd2, 0x4c, 0xa5, 0x0a, 0x16,
- 0x39, 0xef, 0x3f, 0xf7, 0x9d, 0x23, 0x19, 0xb9, 0xcd, 0xd8, 0x7c, 0x6e,
- 0xee, 0x6d, 0x2e, 0xff, 0x5a, 0xf3, 0xb9, 0xab, 0xe5, 0x64, 0xdc, 0xc2,
- 0x67, 0x30, 0x73, 0x19, 0x2d, 0xea, 0xd2, 0x19, 0x1f, 0x1f, 0xe0, 0xd9,
- 0xac, 0xc9, 0xdb, 0x38, 0x74, 0x5e, 0x31, 0x47, 0x2e, 0x9e, 0x2b, 0xcc,
- 0xb9, 0xe4, 0x29, 0xf8, 0xb2, 0xbf, 0x1b, 0xbc, 0x68, 0x96, 0x79, 0xcf,
- 0xaf, 0xf2, 0x1f, 0x57, 0x3f, 0x74, 0xc4, 0x71, 0x63, 0xb4, 0xe8, 0xbe,
- 0x58, 0xdb, 0x28, 0x62, 0xb5, 0x79, 0x8b, 0xe4, 0xd0, 0x96, 0xd0, 0xda,
- 0x0f, 0xd2, 0x70, 0x93, 0x2f, 0x71, 0xe0, 0x9f, 0x28, 0xb7, 0x52, 0x38,
- 0x9c, 0xcb, 0x8b, 0x2a, 0x8e, 0xbf, 0x0e, 0x3d, 0x60, 0x05, 0x0a, 0x91,
- 0x5b, 0xb5, 0x78, 0x10, 0x31, 0x00, 0x80, 0x31, 0x2d, 0xd7, 0xb0, 0x88,
- 0xc7, 0xd9, 0x58, 0xc6, 0xfc, 0x3b, 0xf4, 0xee, 0xec, 0xba, 0x05, 0xae,
- 0xae, 0xff, 0xcf, 0xd0, 0x71, 0xc6, 0xe7, 0xf3, 0x8b, 0x64, 0x50, 0x7a,
- 0x09, 0x93, 0x0f, 0x34, 0x59, 0x2d, 0xde, 0x4b, 0x1d, 0x86, 0x49, 0xff,
- 0x63, 0x76, 0x28, 0x6b, 0x52, 0x1b, 0x46, 0x06, 0x18, 0x90, 0x1c, 0x2d,
- 0xc5, 0x03, 0xcc, 0x00, 0x4d, 0xb7, 0xb2, 0x12, 0xc5, 0xf9, 0xb4, 0xa4,
- 0x6a, 0x36, 0x62, 0x46, 0x34, 0x2a, 0xf0, 0x11, 0xa3, 0xd6, 0x80, 0x21,
- 0xbf, 0x3b, 0xfd, 0xc5, 0x25, 0xa0, 0x4d, 0xc0, 0x2e, 0xc0, 0xf1, 0x7b,
- 0x96, 0x11, 0x64, 0x8e, 0xb9, 0xdb, 0x89, 0x4e, 0x33, 0x89, 0xf5, 0xc6,
- 0xfc, 0x2b, 0x99, 0xf5, 0xc2, 0x04, 0x83, 0x15, 0x47, 0xa8, 0xa5, 0xc1,
- 0x4a, 0xe4, 0x76, 0xab, 0x3e, 0xf0, 0x9b, 0xb7, 0x8d, 0x46, 0xd3, 0x52,
- 0x9b, 0xbd, 0xfd, 0x2b, 0xba, 0x73, 0x5d, 0x23, 0x67, 0x68, 0xe1, 0x76,
- 0x6f, 0x56, 0x2b, 0x17, 0xe4, 0x7e, 0x9a, 0xfd, 0x05, 0x48, 0x39, 0xc9,
- 0xcf, 0xa5, 0x83, 0xf7, 0x90, 0x9c, 0xa4, 0x28, 0x57, 0x40, 0xe9, 0xd4,
- 0x4b, 0x1a, 0x4b, 0x6f, 0x65, 0x14, 0xca, 0x43, 0xc1, 0x3f, 0x7c, 0xec,
- 0x82, 0x47, 0x0e, 0x64, 0x8b, 0x6f, 0x8c, 0xb2, 0xf0, 0x6d, 0xeb, 0x6f,
- 0x71, 0x8f, 0xcc, 0x2d, 0x60, 0x2b, 0xc3, 0x9f, 0x13, 0x94, 0xc7, 0x23,
- 0x02, 0xf5, 0xe6, 0xdf, 0x2d, 0xa9, 0xdb, 0xa9, 0xf3, 0xee, 0xe9, 0x3f,
- 0x2a, 0x69, 0x24, 0x6b, 0x78, 0xff, 0x6a, 0xd7, 0xe4, 0x69, 0x8c, 0x17,
- 0xd5, 0xc1, 0x36, 0x1a, 0xca, 0x77, 0xb0, 0xb5, 0x6b, 0x96, 0x4a, 0xb5,
- 0x0e, 0x4d, 0x0b, 0xd6, 0xd9, 0x78, 0xc5, 0xbf, 0xe3, 0x59, 0xfe, 0x63,
- 0xe3, 0xd3, 0x3c, 0x9a, 0xfa, 0xd7, 0x69, 0x5b, 0xef, 0xd3, 0xa4, 0xa3,
- 0xb9, 0x1f, 0x5c, 0x40, 0x20, 0x95, 0x38, 0x2d, 0xf5, 0x04, 0x0c, 0x2c,
- 0x79, 0x77, 0xc1, 0xb6, 0xcc, 0x74, 0x3c, 0x66, 0xf1, 0xc6, 0x65, 0xab,
- 0x4d, 0x68, 0x41, 0x16, 0x71, 0x51, 0xb9, 0x1b, 0xcb, 0xa7, 0x6d, 0xe0,
- 0x70, 0xa9, 0xfa, 0x65, 0x6b, 0x7b, 0x1e, 0xc5, 0xdf, 0xe2, 0x4c, 0x96,
- 0x44, 0x6b, 0x24, 0xa1, 0x15, 0x8e, 0xe7, 0x9b, 0x1f, 0x51, 0xef, 0xd7,
- 0x65, 0x5f, 0xcd, 0x74, 0x7f, 0x2d, 0x5c, 0xba, 0xba, 0x20, 0x32, 0x8d,
- 0x1c, 0xf1, 0x5a, 0xed, 0x21, 0xad, 0x78, 0x7b, 0x59, 0x58, 0xe4, 0xf6,
- 0xa7, 0x10, 0x35, 0xca, 0x5d, 0x86, 0x1a, 0x68, 0xba, 0x1c, 0x3c, 0x1c,
- 0x23, 0x79, 0x8b, 0x9f, 0xda, 0x5c, 0xd1, 0x5a, 0xa9, 0xc8, 0xf6, 0xc9,
- 0xdf, 0x21, 0x5a, 0x98, 0xdc, 0xf4, 0xb9, 0x02, 0x97, 0x2c, 0x10, 0x60,
- 0xc9, 0xb5, 0xea, 0x75, 0x0b, 0xd9, 0x8a, 0xa4, 0x86, 0x92, 0xbe, 0xf5,
- 0xd8, 0xc7, 0x6b, 0x13, 0x8b, 0xbb, 0xca, 0x5f, 0xe4, 0x8b, 0xce, 0xb5,
- 0x27, 0xae, 0x53, 0xed, 0xef, 0x37, 0xa6, 0x81, 0x8f, 0x70, 0x25, 0x18,
- 0x93, 0x06, 0x8c, 0x18, 0xcd, 0x7a, 0x1a, 0x8d, 0xfc, 0xde, 0x6f, 0x30,
- 0xdb, 0x41, 0xb6, 0x42, 0x14, 0x54, 0xf8, 0xcd, 0xc6, 0xf8, 0x0f, 0x82,
- 0x17, 0xfa, 0x8d, 0xba, 0x80, 0x81, 0x6a, 0xf7, 0x02, 0x97, 0x00, 0x78,
- 0xd6, 0x5b, 0xc9, 0xba, 0xd1, 0x99, 0xef, 0x8e, 0x48, 0x6c, 0x35, 0x10,
- 0x5b, 0xf1, 0x9b, 0x93, 0x4f, 0xbd, 0x7d, 0x27, 0x9e, 0xc7, 0x86, 0xb2,
- 0x8f, 0x6a, 0x91, 0x59, 0x2d, 0x14, 0xab, 0x1b, 0x34, 0x6e, 0xfa, 0x25,
- 0x5e, 0x14, 0xc7, 0xef, 0x3d, 0x0f, 0x13, 0xf9, 0x45, 0x4b, 0x90, 0xbc,
- 0xd8, 0x51, 0x42, 0x95, 0x25, 0x9b, 0x1b, 0x7c, 0xaf, 0x3b, 0x60, 0x21,
- 0x4c, 0x5f, 0x7c, 0x63, 0x4b, 0x45, 0xa6, 0xdc, 0xfd, 0x32, 0xf3, 0x06,
- 0x61, 0x11, 0x2d, 0x27, 0xde, 0x19, 0x38, 0x63, 0xf9, 0x70, 0xd1, 0x82,
- 0x8e, 0xc7, 0x99, 0xe1, 0x96, 0x9b, 0x54, 0x93, 0x64, 0x5f, 0xd1, 0x62,
- 0x9c, 0x37, 0x10, 0x1a, 0x8a, 0x82, 0x8d, 0x2a, 0x93, 0x95, 0x22, 0xc9,
- 0x21, 0xf5, 0xce, 0x21, 0xbb, 0x7c, 0x17, 0xee, 0x20, 0xa0, 0x73, 0xaa,
- 0x69, 0x78, 0x4e, 0x0d, 0x2c, 0x2c, 0x96, 0x23, 0xdc, 0x07, 0x16, 0xbd,
- 0xe7, 0xd5, 0x49, 0xcc, 0x44, 0xd1, 0x9d, 0xd7, 0xa3, 0x01, 0x60, 0xa0,
- 0xe0, 0x41, 0x63, 0x28, 0x8a, 0x43, 0xdb, 0x4f, 0x25, 0x5b, 0x27, 0x52,
- 0x4a, 0xee, 0x42, 0x43, 0x9a, 0xef, 0x33, 0x43, 0x70, 0xda, 0x64, 0x57,
- 0x49, 0x0c, 0x7f, 0xfd, 0xc7, 0x88, 0x26, 0x94, 0x10, 0xcc, 0x05, 0x1d,
- 0x54, 0x95, 0xea, 0x4e, 0x65, 0x28, 0x03, 0xbc, 0xa2, 0x62, 0xd2, 0xce,
- 0x60, 0x34, 0xf9, 0xdb, 0x26, 0xb5, 0xe6, 0x9b, 0x55, 0x2c, 0x8f, 0x30,
- 0x3a, 0x94, 0x9a, 0x15, 0x79, 0x22, 0x75, 0x4d, 0x1b, 0x91, 0xe0, 0x5b,
- 0xdb, 0xd1, 0x15, 0x7f, 0xcc, 0xc6, 0x88, 0xb5, 0x00, 0x3f, 0x5d, 0x84,
- 0x2e, 0x68, 0xde, 0x6f, 0x41, 0x5b, 0x4e, 0xe7, 0xdf, 0xe6, 0x3b, 0x7e,
- 0xf2, 0xdd, 0xfc, 0x01, 0xf2, 0x1b, 0x52, 0xba, 0xc4, 0x51, 0xae, 0x8f,
- 0xa0, 0x55, 0x12, 0x81, 0x57, 0xe0, 0x58, 0x5e, 0xea, 0xd7, 0x85, 0xfb,
- 0x19, 0x8b, 0xb7, 0x24, 0x29, 0x94, 0xa7, 0xfc, 0xed, 0x17, 0xaa, 0x32,
- 0x50, 0x11, 0xb3, 0x7a, 0x43, 0x3a, 0xc0, 0x2b, 0x82, 0x9c, 0x85, 0xd9,
- 0xd0, 0xdb, 0x21, 0x71, 0x83, 0xb4, 0x30, 0x14, 0xec, 0xfc, 0x8d, 0x32,
- 0xd6, 0xa2, 0x36, 0x5e, 0x3b, 0xe9, 0x12, 0x0c, 0x95, 0xd6, 0x0c, 0x0c,
- 0x31, 0x66, 0x30, 0x3f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x09, 0x14, 0x31, 0x32, 0x1e, 0x30, 0x00, 0x49, 0x00, 0x6e, 0x00,
- 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00,
- 0x20, 0x00, 0x57, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x69, 0x00,
- 0x74, 0x00, 0x73, 0x00, 0x20, 0x00, 0x50, 0x00, 0x74, 0x00, 0x79, 0x00,
- 0x20, 0x00, 0x4c, 0x00, 0x74, 0x00, 0x64, 0x30, 0x23, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14,
- 0x14, 0x74, 0x2d, 0x52, 0x8e, 0x0d, 0x0c, 0x06, 0x6c, 0x32, 0x64, 0xd3,
- 0x7e, 0x33, 0x31, 0x68, 0x8b, 0x28, 0x1a, 0x75, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x06, 0xa0, 0x80, 0x30, 0x80, 0x02, 0x01, 0x00, 0x30, 0x80,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30,
- 0x24, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01,
- 0x06, 0x30, 0x16, 0x04, 0x10, 0x9d, 0x1b, 0x68, 0x8e, 0x11, 0xc2, 0xb2,
- 0xd6, 0xd0, 0xe9, 0x5a, 0x9e, 0x96, 0xc1, 0x8c, 0xa6, 0x02, 0x02, 0x07,
- 0xd0, 0xa0, 0x80, 0x04, 0x82, 0x03, 0xf8, 0x1d, 0xce, 0x13, 0x70, 0x7a,
- 0x6b, 0x0a, 0x12, 0x2d, 0x01, 0x84, 0x63, 0x5c, 0x07, 0x82, 0x23, 0xf8,
- 0x8a, 0x5e, 0x53, 0x8f, 0xc8, 0xb4, 0x87, 0x1a, 0xa2, 0x98, 0xdb, 0xc6,
- 0x26, 0xca, 0xbb, 0x20, 0x24, 0xad, 0xac, 0xdf, 0xbe, 0x73, 0x6d, 0x97,
- 0x4b, 0x6e, 0x5b, 0x45, 0xd2, 0x84, 0xd4, 0xa4, 0x82, 0xd0, 0xce, 0x40,
- 0x13, 0x4c, 0x6d, 0x4d, 0x2e, 0xc1, 0x96, 0x95, 0x01, 0x64, 0xf3, 0xf0,
- 0x5f, 0x06, 0x06, 0xea, 0xf7, 0x84, 0x8f, 0xb3, 0xb0, 0x6e, 0x7c, 0x9b,
- 0x71, 0x73, 0xb9, 0xcd, 0xac, 0x72, 0xf6, 0xa0, 0x23, 0xda, 0x9b, 0x9f,
- 0xec, 0x16, 0xef, 0x33, 0xd4, 0xd0, 0x4d, 0x20, 0xf0, 0x75, 0xa9, 0x73,
- 0xf4, 0x31, 0xc7, 0x57, 0xb8, 0x0d, 0x9d, 0x85, 0x7c, 0xee, 0x3a, 0x24,
- 0x7b, 0x74, 0xa0, 0x5c, 0xad, 0xde, 0x5e, 0x05, 0x1e, 0xeb, 0x02, 0x78,
- 0x12, 0xb4, 0xb9, 0xc6, 0xe5, 0xc5, 0x99, 0xbc, 0x05, 0x62, 0x5b, 0x10,
- 0x52, 0x08, 0x00, 0x9e, 0x73, 0xac, 0xe4, 0x1d, 0xdb, 0xb8, 0xbf, 0x48,
- 0x03, 0x28, 0x05, 0x3c, 0x61, 0x1a, 0x8b, 0x4c, 0xd7, 0x5f, 0x8c, 0xb4,
- 0xcd, 0x91, 0x1c, 0x0b, 0xf4, 0x55, 0xd4, 0x1c, 0x42, 0x4a, 0xd4, 0xf5,
- 0x15, 0x38, 0xd9, 0x06, 0xfc, 0x49, 0xf6, 0xe5, 0xa7, 0x09, 0x5d, 0x01,
- 0xbd, 0xc3, 0xd1, 0x09, 0x9f, 0x5d, 0x0c, 0x19, 0x43, 0xd0, 0xfa, 0x25,
- 0x17, 0xad, 0x2a, 0xbf, 0x89, 0x63, 0x06, 0xa8, 0x02, 0x03, 0xe4, 0xfe,
- 0x19, 0x08, 0x70, 0xa1, 0x74, 0x74, 0xb6, 0xb6, 0x0f, 0x19, 0x4d, 0x54,
- 0xa5, 0xb2, 0xd7, 0x37, 0x3b, 0x17, 0xc0, 0x5d, 0xc2, 0x8a, 0xf1, 0xcc,
- 0xed, 0xef, 0x65, 0xc8, 0xca, 0xbe, 0x02, 0xd4, 0x9b, 0x1e, 0xef, 0xc9,
- 0xe0, 0x91, 0x82, 0xb0, 0xe0, 0x50, 0xc7, 0xa0, 0xcc, 0x01, 0x6d, 0x55,
- 0xe5, 0x67, 0x99, 0x65, 0x13, 0xe4, 0xd2, 0x90, 0x91, 0xf3, 0x76, 0x0b,
- 0x6a, 0x2d, 0x19, 0xaf, 0x61, 0xb3, 0x7f, 0x4c, 0x04, 0xfe, 0x68, 0xf6,
- 0xb3, 0x56, 0xd8, 0xf3, 0x34, 0xd7, 0x04, 0x0a, 0x31, 0xc8, 0x37, 0xdf,
- 0xac, 0xd8, 0x91, 0x80, 0x8a, 0x30, 0x12, 0x22, 0x80, 0xd7, 0x24, 0xcf,
- 0x70, 0xaf, 0x56, 0xaf, 0x81, 0xfe, 0x63, 0xf1, 0xea, 0x57, 0x4c, 0xf2,
- 0xdb, 0x30, 0x50, 0x92, 0xc1, 0xeb, 0x04, 0x9a, 0xdf, 0xf5, 0x74, 0x57,
- 0x5b, 0x58, 0xc2, 0x4e, 0x6b, 0x11, 0xf3, 0xe1, 0xb3, 0x0f, 0x56, 0x35,
- 0x04, 0xf8, 0x50, 0x1d, 0x7e, 0xe6, 0x99, 0xa2, 0x48, 0xdb, 0xea, 0x62,
- 0x4f, 0x98, 0xc2, 0xef, 0xbf, 0x7f, 0x94, 0xc0, 0x36, 0xc0, 0xf3, 0x27,
- 0xfe, 0xe2, 0x17, 0x1e, 0x91, 0x7d, 0x96, 0xa9, 0x2b, 0x71, 0x51, 0xc3,
- 0x59, 0x2d, 0x11, 0x50, 0x1e, 0xcb, 0xce, 0xff, 0x04, 0x4d, 0x16, 0xf5,
- 0xc2, 0xd4, 0x1f, 0xdd, 0x7f, 0x5a, 0xfd, 0x1d, 0xe9, 0x63, 0x52, 0x44,
- 0x76, 0x5f, 0x91, 0xfd, 0xe8, 0xdf, 0x0a, 0x69, 0x0d, 0xd3, 0x64, 0x91,
- 0xea, 0xdd, 0x03, 0x4f, 0x42, 0xa5, 0xe9, 0xa1, 0x70, 0x05, 0xf3, 0x22,
- 0x8e, 0xad, 0x70, 0x1a, 0x3e, 0x94, 0x42, 0x06, 0xe7, 0x47, 0x37, 0x3d,
- 0xf5, 0xda, 0x3e, 0x2a, 0x3a, 0xc0, 0x23, 0xd9, 0x4a, 0x26, 0x69, 0x13,
- 0xa6, 0x93, 0x7c, 0xf2, 0xaf, 0x04, 0x5e, 0x9b, 0x88, 0xc7, 0x77, 0xd0,
- 0x93, 0xab, 0x1b, 0xbd, 0x3d, 0x69, 0x90, 0xab, 0x41, 0xa9, 0xbc, 0x84,
- 0x18, 0x4d, 0x29, 0x02, 0xc1, 0xf8, 0xff, 0x63, 0x18, 0x24, 0x74, 0x8f,
- 0x7e, 0x44, 0x33, 0xaf, 0x88, 0x8b, 0x93, 0x5b, 0x9a, 0xae, 0x6b, 0x08,
- 0xa2, 0x82, 0x5d, 0xf3, 0xbe, 0x61, 0xc3, 0xf0, 0x2d, 0x31, 0x4c, 0xb5,
- 0xb5, 0x91, 0x0f, 0xfa, 0x81, 0x61, 0xad, 0xfc, 0xba, 0x91, 0xeb, 0x3b,
- 0x9d, 0x22, 0x41, 0x45, 0x0e, 0x8e, 0x24, 0xc7, 0x1c, 0x81, 0x95, 0xa8,
- 0x7b, 0x64, 0xed, 0xa5, 0xec, 0x5a, 0x68, 0x3c, 0x85, 0x8d, 0x92, 0xb7,
- 0x24, 0x0f, 0xed, 0xf5, 0xc6, 0x31, 0x61, 0xdc, 0xef, 0xa7, 0xcb, 0x8f,
- 0xda, 0x43, 0x05, 0x42, 0xf6, 0x9e, 0xbc, 0x1b, 0x9a, 0xa1, 0xe8, 0x1d,
- 0x8d, 0x42, 0xdb, 0x80, 0x83, 0x55, 0x52, 0x2b, 0x95, 0x00, 0x05, 0x82,
- 0x84, 0xc3, 0x54, 0x23, 0x8e, 0x1d, 0x00, 0xa2, 0x16, 0x3e, 0xce, 0x3d,
- 0xcc, 0x9e, 0xb8, 0x4c, 0x59, 0xb2, 0x12, 0xa2, 0x23, 0xc1, 0x46, 0x50,
- 0x86, 0xae, 0x75, 0x7e, 0x49, 0x38, 0x77, 0x94, 0xf0, 0x27, 0xd8, 0x17,
- 0x38, 0x8c, 0xe0, 0x73, 0x00, 0xfb, 0xaf, 0xbf, 0xe8, 0xed, 0x85, 0x58,
- 0x3e, 0xb4, 0x88, 0x04, 0xc8, 0x22, 0x1b, 0xb4, 0x75, 0xa2, 0xc4, 0xdd,
- 0x06, 0xd2, 0x83, 0x42, 0x21, 0x57, 0xfc, 0xd8, 0xae, 0x9c, 0x0e, 0xd8,
- 0x6a, 0x70, 0xd1, 0xeb, 0x44, 0x9c, 0xb7, 0x37, 0x04, 0x05, 0xf5, 0x17,
- 0xbe, 0xf3, 0x56, 0x1b, 0x06, 0x36, 0x1c, 0x59, 0x7b, 0x65, 0x8d, 0xbb,
- 0xbe, 0x22, 0x9a, 0x70, 0xa3, 0xe9, 0x60, 0x1a, 0xc9, 0xdd, 0x81, 0x3c,
- 0x2d, 0x4e, 0xc0, 0x8a, 0xe5, 0x91, 0xa7, 0xc1, 0x80, 0x07, 0x47, 0x7a,
- 0x74, 0x4f, 0x3e, 0x4a, 0xdc, 0xb2, 0xcc, 0xff, 0x37, 0x66, 0x05, 0xcb,
- 0xd6, 0xe9, 0x90, 0xf5, 0xef, 0x2b, 0x7e, 0xa7, 0x66, 0x51, 0xcb, 0x48,
- 0xb3, 0x8a, 0x6f, 0x06, 0xba, 0x8b, 0x3d, 0x35, 0x36, 0xdf, 0x0e, 0x40,
- 0xe5, 0xa1, 0xe3, 0xdd, 0x89, 0xab, 0x64, 0x9c, 0x01, 0x15, 0x9e, 0x93,
- 0xea, 0xf9, 0x4f, 0x9e, 0xf5, 0x8b, 0xf2, 0xc2, 0xbb, 0xe5, 0xc3, 0xa3,
- 0xe3, 0x13, 0x63, 0x4f, 0x7d, 0x20, 0xe4, 0x66, 0x96, 0x84, 0x8d, 0xd4,
- 0xca, 0x72, 0x52, 0xdc, 0xb8, 0x93, 0xd4, 0xa5, 0x3e, 0x6e, 0x42, 0x56,
- 0x80, 0x46, 0x77, 0x86, 0x49, 0xfe, 0xf3, 0xb4, 0x5b, 0x37, 0xfc, 0xb8,
- 0x0c, 0xd7, 0x63, 0xac, 0x3c, 0x6f, 0xf0, 0xbe, 0xbe, 0xb4, 0x13, 0xe7,
- 0x34, 0xe5, 0x06, 0xbf, 0x17, 0x48, 0x6e, 0xc0, 0x26, 0x94, 0xdd, 0xed,
- 0xf4, 0xda, 0x97, 0x25, 0xab, 0xd6, 0x9b, 0xc3, 0x8c, 0xeb, 0x17, 0x09,
- 0xfc, 0x03, 0x5a, 0x2f, 0x19, 0x85, 0x50, 0xc4, 0xe6, 0x35, 0x71, 0x94,
- 0xad, 0xc5, 0xcf, 0x08, 0xcf, 0x69, 0x3b, 0xc3, 0x31, 0xec, 0xf1, 0xfa,
- 0x80, 0x66, 0x8f, 0x14, 0xde, 0x56, 0x21, 0x12, 0x9b, 0x0c, 0xdf, 0x92,
- 0x48, 0x06, 0xce, 0xdb, 0xeb, 0x28, 0x54, 0x27, 0x8b, 0xa9, 0xef, 0x0c,
- 0xf4, 0xa0, 0xcc, 0x84, 0x59, 0x60, 0xed, 0x18, 0x65, 0xca, 0x67, 0x0c,
- 0xd1, 0x1f, 0xcf, 0x59, 0x4b, 0xce, 0x07, 0x27, 0x08, 0x6a, 0xea, 0x53,
- 0xdc, 0x47, 0xb3, 0x4e, 0xe4, 0x0b, 0xff, 0x9a, 0x7d, 0x6b, 0x0d, 0x2f,
- 0x2d, 0x60, 0xd7, 0x8b, 0x22, 0xf5, 0x30, 0x43, 0x09, 0xe6, 0xdf, 0x01,
- 0x03, 0x27, 0x2d, 0xb5, 0x74, 0x52, 0x5d, 0x08, 0xc7, 0x5a, 0x44, 0x25,
- 0x0f, 0x2c, 0x14, 0x8f, 0x48, 0xea, 0x18, 0x99, 0xd1, 0xcc, 0xc5, 0xdc,
- 0x65, 0xa5, 0x3d, 0x25, 0x94, 0xa9, 0xc7, 0xad, 0x3e, 0xa4, 0xf6, 0xe6,
- 0xbd, 0xa7, 0x70, 0xd4, 0xdc, 0x9b, 0x26, 0xcb, 0x31, 0x70, 0xaf, 0x3e,
- 0xa4, 0xb6, 0x8d, 0x21, 0x31, 0x67, 0x35, 0x35, 0x86, 0x67, 0xd1, 0x02,
- 0x6c, 0x36, 0x76, 0xc9, 0x20, 0xf6, 0x0f, 0x30, 0x41, 0x83, 0x19, 0xf5,
- 0xe1, 0x33, 0x90, 0xbc, 0x7b, 0x8c, 0x9b, 0x8a, 0x68, 0x30, 0x9e, 0xed,
- 0xf4, 0x88, 0xc9, 0x04, 0x08, 0x2b, 0xb0, 0x0f, 0xae, 0xc7, 0xe0, 0x6e,
- 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39, 0x30, 0x21, 0x30,
- 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
- 0xe0, 0xf7, 0xa1, 0x1b, 0xf6, 0x3f, 0x05, 0xad, 0x55, 0x6a, 0x20, 0x4c,
- 0x71, 0xca, 0x62, 0x47, 0x13, 0x28, 0xd5, 0x05, 0x04, 0x10, 0x3e, 0x87,
- 0x2d, 0x96, 0xea, 0x80, 0x4b, 0xab, 0x3a, 0xb9, 0xee, 0x09, 0x65, 0x28,
- 0xbc, 0x8d, 0x02, 0x02, 0x07, 0xd0, 0x00, 0x00,
-};
-
-// kWindows is a dummy key and certificate exported from the certificate
-// manager on Windows 7.
-static const uint8_t kWindows[] = {
- 0x30, 0x82, 0x0a, 0x02, 0x02, 0x01, 0x03, 0x30, 0x82, 0x09, 0xbe, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
- 0x09, 0xaf, 0x04, 0x82, 0x09, 0xab, 0x30, 0x82, 0x09, 0xa7, 0x30, 0x82,
- 0x06, 0x08, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x01, 0xa0, 0x82, 0x05, 0xf9, 0x04, 0x82, 0x05, 0xf5, 0x30, 0x82, 0x05,
- 0xf1, 0x30, 0x82, 0x05, 0xed, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x04, 0xfe, 0x30, 0x82,
- 0x04, 0xfa, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0xb7, 0x20, 0x55, 0x5a,
- 0x4d, 0x3f, 0x0e, 0x89, 0x02, 0x02, 0x07, 0xd0, 0x04, 0x82, 0x04, 0xd8,
- 0x3a, 0xcc, 0xd6, 0xcb, 0x4d, 0x54, 0xc0, 0x04, 0x56, 0x10, 0xcc, 0x49,
- 0xe4, 0xe0, 0x10, 0x73, 0xfb, 0x1a, 0xdd, 0x1d, 0x4f, 0x6e, 0x55, 0xe3,
- 0xa4, 0xab, 0xf9, 0x26, 0xaa, 0x42, 0x54, 0xa0, 0xd1, 0xf0, 0x8d, 0xbf,
- 0x71, 0x7d, 0x18, 0x00, 0x17, 0xb3, 0xb7, 0x63, 0x50, 0x8d, 0x2c, 0xeb,
- 0x2f, 0xe3, 0xc3, 0xbf, 0x93, 0xc8, 0x46, 0x48, 0x99, 0x47, 0xe2, 0x3b,
- 0x8d, 0x71, 0x01, 0x5f, 0x59, 0x5b, 0x61, 0x7e, 0x1f, 0x0c, 0x6e, 0x3e,
- 0xc4, 0x74, 0x99, 0x98, 0x30, 0xff, 0x37, 0x7b, 0x30, 0x19, 0xb5, 0xfc,
- 0x69, 0x94, 0x5f, 0x79, 0x69, 0x34, 0xda, 0xb5, 0x21, 0xcf, 0xfe, 0x72,
- 0x87, 0xe8, 0x7d, 0x29, 0x7e, 0x27, 0x25, 0x90, 0x80, 0x98, 0xdd, 0x8d,
- 0xbf, 0x42, 0xb0, 0x10, 0xd8, 0x7d, 0x6d, 0xfe, 0x6f, 0x0d, 0x61, 0x09,
- 0xfd, 0xb2, 0x9b, 0xeb, 0xbf, 0x1c, 0xca, 0x33, 0xbc, 0x4e, 0x19, 0x52,
- 0x55, 0x53, 0xb4, 0xa5, 0x98, 0x6c, 0xa3, 0x3b, 0xf8, 0xa4, 0x8d, 0x79,
- 0xcf, 0x40, 0xf2, 0x89, 0x09, 0x3c, 0x38, 0xab, 0xae, 0xf4, 0x09, 0x3b,
- 0xb6, 0xcb, 0xdd, 0xd7, 0xad, 0xe0, 0x5a, 0x71, 0x64, 0xc9, 0x0f, 0x18,
- 0xac, 0x3c, 0x12, 0xd4, 0x22, 0x54, 0x24, 0x1a, 0xa5, 0x35, 0x78, 0x99,
- 0x09, 0x4a, 0x18, 0x95, 0x23, 0xb9, 0xf7, 0x89, 0x3f, 0x13, 0x43, 0x1f,
- 0x8d, 0x76, 0x6b, 0x04, 0xdb, 0x64, 0xf4, 0x8e, 0xf5, 0x50, 0xa0, 0xae,
- 0x1c, 0x8c, 0xc8, 0xf3, 0xde, 0xf3, 0x11, 0x2d, 0xfe, 0x76, 0xf0, 0xac,
- 0x46, 0x54, 0x23, 0x03, 0x49, 0xfa, 0x73, 0xcd, 0xe0, 0xa1, 0x6c, 0x66,
- 0x4d, 0x1b, 0x99, 0x57, 0x3d, 0x61, 0x61, 0xeb, 0x61, 0x40, 0xc7, 0xd6,
- 0x41, 0xbe, 0x63, 0x21, 0x1e, 0x7e, 0xb5, 0x0e, 0x94, 0x93, 0x37, 0x41,
- 0xe8, 0x91, 0x06, 0xd7, 0xa3, 0x33, 0x78, 0x17, 0x17, 0x59, 0x78, 0x8f,
- 0xaf, 0xed, 0xf9, 0x90, 0xfb, 0xb6, 0xc8, 0xa9, 0x0b, 0x10, 0x1a, 0xf1,
- 0xab, 0x10, 0x11, 0xbc, 0x7f, 0xa5, 0x2d, 0x34, 0x7d, 0x7b, 0xaf, 0xc8,
- 0xb2, 0x00, 0x6b, 0xd4, 0xbb, 0x25, 0x9b, 0xc7, 0x14, 0x8b, 0x50, 0x0a,
- 0xd5, 0x2c, 0x1f, 0xa0, 0x5f, 0x07, 0x1d, 0x5e, 0x1a, 0xa4, 0x4b, 0x85,
- 0xb2, 0xa6, 0xe2, 0xdd, 0xb7, 0xda, 0x11, 0x25, 0x51, 0xbf, 0x72, 0x50,
- 0x53, 0xa1, 0x3d, 0xfa, 0x1d, 0x34, 0x75, 0xdd, 0x7a, 0xe0, 0x90, 0x56,
- 0x14, 0xc3, 0xe8, 0x0b, 0xea, 0x32, 0x5f, 0x92, 0xfc, 0x2e, 0x4d, 0x0e,
- 0xfe, 0xba, 0x1a, 0x00, 0x6d, 0x8f, 0x75, 0xac, 0x49, 0x4c, 0x79, 0x03,
- 0x2e, 0xf2, 0xcc, 0x8e, 0x96, 0x27, 0x3c, 0x59, 0x28, 0x7f, 0x52, 0x8d,
- 0xc3, 0x3b, 0x24, 0x68, 0xff, 0xbb, 0xd0, 0x4e, 0xdf, 0xc4, 0x91, 0x32,
- 0x14, 0x5e, 0x43, 0x73, 0xd8, 0x56, 0x65, 0xe1, 0x48, 0x89, 0xe4, 0x33,
- 0xef, 0x4b, 0x51, 0x50, 0xf2, 0x53, 0xe7, 0xae, 0x7d, 0xb6, 0x8c, 0x80,
- 0xee, 0x8d, 0x9e, 0x24, 0x1a, 0xdd, 0x95, 0x7d, 0x22, 0x58, 0x76, 0xf8,
- 0xbb, 0x63, 0x36, 0x17, 0xdc, 0xc6, 0x3e, 0xb8, 0xe9, 0x1f, 0xd8, 0xe0,
- 0x06, 0x18, 0x1b, 0x3c, 0x45, 0xcb, 0xe1, 0x5a, 0x41, 0xe5, 0x32, 0xa3,
- 0x85, 0x1b, 0xff, 0xe0, 0x5e, 0x28, 0xee, 0xe9, 0x05, 0xc7, 0xc8, 0x47,
- 0x85, 0xe8, 0x13, 0x7f, 0x1b, 0xda, 0xd7, 0x3e, 0x8e, 0xb8, 0xa3, 0x96,
- 0x34, 0x19, 0x3b, 0x0c, 0x88, 0x26, 0x38, 0xe7, 0x65, 0xf6, 0x03, 0x4f,
- 0xc8, 0x37, 0x6e, 0x2f, 0x5e, 0x5d, 0xcd, 0xa3, 0x29, 0x37, 0xe8, 0x86,
- 0x84, 0x66, 0x37, 0x84, 0xa0, 0x49, 0x4e, 0x8f, 0x3b, 0x1a, 0x42, 0x9f,
- 0x62, 0x1f, 0x2b, 0x97, 0xc9, 0x18, 0x21, 0xd2, 0xa5, 0xcd, 0x8f, 0xa4,
- 0x03, 0xf8, 0x82, 0x1e, 0xb8, 0x3e, 0x6b, 0x54, 0x29, 0x75, 0x5f, 0x80,
- 0xe6, 0x8f, 0x2f, 0x65, 0xb0, 0x6b, 0xbb, 0x18, 0x6e, 0x0d, 0x32, 0x62,
- 0x8c, 0x97, 0x48, 0xd3, 0xaa, 0xf2, 0x5e, 0xb8, 0x25, 0xbc, 0xb5, 0x22,
- 0x4a, 0xac, 0xcf, 0xdc, 0x8b, 0x48, 0xfc, 0x95, 0xf2, 0x17, 0x21, 0x1e,
- 0xda, 0x13, 0xd3, 0x1b, 0xe2, 0x37, 0xd5, 0xbf, 0x92, 0xe4, 0x81, 0xf5,
- 0x98, 0x57, 0x51, 0x14, 0xda, 0x80, 0x7d, 0x4a, 0x6a, 0xce, 0x17, 0xaf,
- 0xdb, 0xc3, 0x2e, 0x84, 0x3b, 0x1e, 0x02, 0x51, 0x4a, 0xc1, 0x25, 0x8c,
- 0x5a, 0x20, 0x56, 0xee, 0xec, 0x59, 0xcf, 0xd7, 0x3e, 0x5f, 0x39, 0x9f,
- 0xbf, 0x4d, 0x4e, 0x94, 0xb1, 0x1d, 0x83, 0x70, 0xc0, 0xab, 0xff, 0xfa,
- 0x7c, 0x2e, 0x5b, 0xfb, 0x57, 0x3f, 0x60, 0xb8, 0xf3, 0x36, 0x5f, 0xbf,
- 0x6a, 0x8c, 0x6f, 0xe0, 0x34, 0xe8, 0x75, 0x26, 0xc2, 0x1e, 0x22, 0x64,
- 0x0e, 0x43, 0xc1, 0x93, 0xe6, 0x8a, 0x2e, 0xe9, 0xd9, 0xe0, 0x9f, 0x56,
- 0x50, 0x8a, 0xbd, 0x68, 0xf6, 0x57, 0x63, 0x55, 0xbb, 0xe7, 0xfe, 0x22,
- 0xca, 0xdc, 0x85, 0x38, 0x39, 0xc8, 0x66, 0x02, 0x28, 0x0f, 0xe0, 0x1c,
- 0xd6, 0x0f, 0x5d, 0x6a, 0x0b, 0xd8, 0xe5, 0x6a, 0xeb, 0x54, 0xb2, 0xe0,
- 0x02, 0x6f, 0xe2, 0x42, 0x89, 0x66, 0xc2, 0xd5, 0xc6, 0xe2, 0xb2, 0x04,
- 0x6d, 0x8a, 0x2b, 0x48, 0xc2, 0x51, 0x07, 0x8e, 0xf3, 0x91, 0x0b, 0xb7,
- 0x55, 0x6e, 0xbb, 0xbf, 0x11, 0x5a, 0xcb, 0x2c, 0xb3, 0x1e, 0x61, 0xd3,
- 0xdb, 0x90, 0xad, 0xba, 0x10, 0x96, 0xe2, 0x16, 0xf4, 0x0c, 0x47, 0xbd,
- 0x64, 0x66, 0x7a, 0x17, 0x63, 0xb9, 0x02, 0xcb, 0x53, 0x7a, 0x35, 0x92,
- 0x74, 0xc3, 0x2a, 0x7d, 0xc5, 0x11, 0x18, 0x2f, 0xa3, 0x62, 0x2c, 0xc0,
- 0x87, 0xd3, 0xd3, 0xba, 0xcb, 0xe0, 0x86, 0x9b, 0x4b, 0xc5, 0x59, 0x98,
- 0x7e, 0x32, 0x96, 0x55, 0xc1, 0x3d, 0x5a, 0xcd, 0x90, 0x2d, 0xf8, 0xb7,
- 0xa8, 0xba, 0xce, 0x89, 0x64, 0xa6, 0xf3, 0x1b, 0x11, 0x2e, 0x12, 0x99,
- 0x4d, 0x34, 0x45, 0x13, 0x66, 0xb7, 0x69, 0x7b, 0xc5, 0x79, 0xf5, 0x6b,
- 0xc2, 0x1d, 0xc8, 0x3f, 0x09, 0x18, 0x0a, 0xfc, 0xf7, 0xaf, 0x98, 0xc2,
- 0xc7, 0xcc, 0x85, 0x29, 0xc6, 0x22, 0x7a, 0x77, 0xab, 0xb5, 0xac, 0xf7,
- 0x9e, 0x70, 0x8e, 0x7f, 0x3c, 0xf1, 0xbd, 0xd9, 0x7a, 0x92, 0x84, 0xc5,
- 0xb8, 0x56, 0xc3, 0xcb, 0xf7, 0x25, 0xad, 0xda, 0x0e, 0x1c, 0xe4, 0x68,
- 0x66, 0x83, 0x91, 0x78, 0xf1, 0xe7, 0x8c, 0xaa, 0x45, 0xb6, 0x85, 0x74,
- 0x9b, 0x08, 0xff, 0xac, 0x38, 0x55, 0xa5, 0x6a, 0xea, 0x2e, 0x75, 0x71,
- 0xd3, 0xa2, 0xdc, 0x1c, 0xc0, 0xc7, 0x0b, 0xa9, 0xd5, 0x7e, 0xf9, 0x63,
- 0x82, 0x87, 0xb7, 0x81, 0x01, 0xb9, 0x31, 0xdf, 0x41, 0x35, 0x0e, 0xe2,
- 0x1f, 0x48, 0xbf, 0x60, 0xce, 0xb0, 0xb4, 0x38, 0xa5, 0xb4, 0x76, 0xa3,
- 0x80, 0x1f, 0x93, 0x57, 0xf2, 0x05, 0x81, 0x42, 0xd1, 0xae, 0x56, 0x6d,
- 0xc5, 0x4c, 0xab, 0xa6, 0x24, 0x2a, 0x02, 0x3b, 0xb1, 0xc4, 0x75, 0xcf,
- 0x15, 0x90, 0xb5, 0xf2, 0xe7, 0x10, 0x69, 0xa0, 0xe3, 0xc4, 0xe6, 0x52,
- 0x63, 0x14, 0xb4, 0x15, 0x91, 0x8e, 0xba, 0x7a, 0xad, 0x2d, 0x9b, 0x24,
- 0x74, 0x36, 0x31, 0xca, 0xcb, 0x4b, 0x5a, 0xbf, 0xd3, 0x4e, 0xb4, 0xc1,
- 0x48, 0x44, 0x74, 0x2f, 0x83, 0xe4, 0x39, 0x3d, 0x90, 0x2d, 0x32, 0x12,
- 0xf7, 0xfa, 0xd3, 0xe3, 0xdb, 0x4f, 0xe6, 0xe7, 0x20, 0x2c, 0x57, 0xc0,
- 0xf9, 0x80, 0xe1, 0xdc, 0x1c, 0xf2, 0x05, 0x54, 0x35, 0xf6, 0xbd, 0xfb,
- 0xbd, 0xc5, 0xb2, 0x82, 0x32, 0x63, 0x32, 0xca, 0xf4, 0xf7, 0x14, 0x92,
- 0x87, 0x8a, 0x45, 0x37, 0x56, 0x93, 0xda, 0x4f, 0x04, 0x59, 0x03, 0x24,
- 0x93, 0x1a, 0x0b, 0x4e, 0xdb, 0x58, 0xbf, 0xda, 0x2a, 0x0e, 0x7e, 0x98,
- 0x6c, 0x0c, 0xeb, 0x21, 0xf9, 0xbf, 0x9b, 0x1f, 0xc0, 0xef, 0xd3, 0xea,
- 0xcb, 0x99, 0x5e, 0x14, 0x3e, 0x10, 0xfa, 0xad, 0x38, 0xf7, 0x68, 0x9f,
- 0xa3, 0xcc, 0xdf, 0xe5, 0x31, 0x91, 0x98, 0xde, 0x74, 0x5f, 0x7b, 0xce,
- 0xe4, 0x54, 0xd9, 0x51, 0xec, 0xf5, 0x4b, 0x17, 0x5f, 0x99, 0x4c, 0xf8,
- 0x00, 0xe0, 0x10, 0x09, 0x07, 0x64, 0xae, 0x61, 0x3b, 0x60, 0xa3, 0x89,
- 0x38, 0xc4, 0x80, 0xf2, 0x1e, 0x11, 0x26, 0x78, 0x72, 0x05, 0x97, 0x27,
- 0xba, 0x83, 0x33, 0x1b, 0x14, 0x4b, 0xc0, 0xc8, 0xb0, 0xcc, 0x0a, 0x9b,
- 0x3e, 0x4c, 0xde, 0x12, 0x07, 0x11, 0xd5, 0xf0, 0xc0, 0xdd, 0x70, 0x3d,
- 0xd8, 0x7a, 0xf7, 0xa2, 0xf2, 0x70, 0xad, 0x54, 0xce, 0x67, 0x41, 0x12,
- 0x29, 0x1f, 0xe1, 0x49, 0x5f, 0x4c, 0x77, 0x41, 0x7c, 0x74, 0x25, 0x9c,
- 0x91, 0xd1, 0x0d, 0xa5, 0x9a, 0xb8, 0x56, 0x4c, 0x01, 0xc0, 0x77, 0x51,
- 0x14, 0xc8, 0x92, 0x40, 0x9a, 0xbd, 0x7f, 0x3b, 0x9b, 0x17, 0xbb, 0x80,
- 0x6e, 0x50, 0x64, 0x31, 0xed, 0xe2, 0x22, 0x9f, 0x96, 0x8e, 0xe2, 0x4e,
- 0x54, 0x6e, 0x36, 0x35, 0xfc, 0xf2, 0xed, 0xfc, 0x56, 0x63, 0xdb, 0x89,
- 0x19, 0x99, 0xf8, 0x47, 0xff, 0xce, 0x35, 0xd2, 0x86, 0x63, 0xbc, 0xe4,
- 0x8c, 0x5d, 0x12, 0x94, 0x31, 0x81, 0xdb, 0x30, 0x13, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x06, 0x04, 0x04,
- 0x01, 0x00, 0x00, 0x00, 0x30, 0x57, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x09, 0x14, 0x31, 0x4a, 0x1e, 0x48, 0x00, 0x65, 0x00,
- 0x65, 0x00, 0x36, 0x00, 0x64, 0x00, 0x38, 0x00, 0x38, 0x00, 0x30, 0x00,
- 0x35, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x36, 0x00, 0x64, 0x00, 0x39, 0x00,
- 0x2d, 0x00, 0x34, 0x00, 0x32, 0x00, 0x65, 0x00, 0x32, 0x00, 0x2d, 0x00,
- 0x38, 0x00, 0x62, 0x00, 0x36, 0x00, 0x38, 0x00, 0x2d, 0x00, 0x66, 0x00,
- 0x65, 0x00, 0x61, 0x00, 0x62, 0x00, 0x35, 0x00, 0x65, 0x00, 0x66, 0x00,
- 0x32, 0x00, 0x38, 0x00, 0x32, 0x00, 0x37, 0x00, 0x30, 0x30, 0x6b, 0x06,
- 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x11, 0x01, 0x31, 0x5e,
- 0x1e, 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f,
- 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x20, 0x00, 0x45,
- 0x00, 0x6e, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65,
- 0x00, 0x64, 0x00, 0x20, 0x00, 0x43, 0x00, 0x72, 0x00, 0x79, 0x00, 0x70,
- 0x00, 0x74, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x72, 0x00, 0x61, 0x00, 0x70,
- 0x00, 0x68, 0x00, 0x69, 0x00, 0x63, 0x00, 0x20, 0x00, 0x50, 0x00, 0x72,
- 0x00, 0x6f, 0x00, 0x76, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72,
- 0x00, 0x20, 0x00, 0x76, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x30, 0x30, 0x82,
- 0x03, 0x97, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x06, 0xa0, 0x82, 0x03, 0x88, 0x30, 0x82, 0x03, 0x84, 0x02, 0x01, 0x00,
- 0x30, 0x82, 0x03, 0x7d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x92, 0x16, 0x6d,
- 0x6d, 0x68, 0xd3, 0xb0, 0xc1, 0x02, 0x02, 0x07, 0xd0, 0x80, 0x82, 0x03,
- 0x50, 0xee, 0x76, 0xe8, 0x60, 0xbf, 0xca, 0x3c, 0x2d, 0xe5, 0x29, 0x22,
- 0xf6, 0x33, 0xc3, 0x50, 0x6a, 0xdb, 0xf3, 0x58, 0x3c, 0xd9, 0x7c, 0xd8,
- 0xf9, 0x83, 0x89, 0x17, 0xa8, 0x1b, 0x6b, 0x09, 0xc1, 0x99, 0x49, 0xb0,
- 0x43, 0x06, 0xc6, 0x42, 0x4b, 0x7c, 0x85, 0x4b, 0xe6, 0x69, 0x38, 0x91,
- 0xce, 0x3d, 0x3c, 0x97, 0xd5, 0x14, 0x4f, 0x15, 0x5a, 0x81, 0x4d, 0x77,
- 0x40, 0xe0, 0xe1, 0x1c, 0x69, 0x3f, 0x1d, 0x65, 0x68, 0xb3, 0x98, 0x95,
- 0x30, 0x6c, 0xb0, 0x70, 0x93, 0x0c, 0xce, 0xec, 0xaf, 0x57, 0xc6, 0x9c,
- 0x34, 0xb4, 0x2b, 0xaf, 0xc3, 0x5e, 0x70, 0x87, 0x17, 0xe8, 0xc9, 0x54,
- 0x06, 0xb5, 0xb7, 0x83, 0xff, 0x46, 0x2b, 0xb6, 0x6a, 0x66, 0x2f, 0x6d,
- 0x0f, 0x96, 0x53, 0x66, 0x65, 0xb8, 0x7b, 0x48, 0x55, 0x83, 0xd3, 0xc4,
- 0x16, 0x93, 0xde, 0x72, 0x59, 0xf1, 0x9a, 0xab, 0xd5, 0xd5, 0xcb, 0x24,
- 0xa6, 0x4a, 0x4e, 0x57, 0xf3, 0x6e, 0xca, 0xb1, 0xeb, 0x7d, 0xdb, 0x02,
- 0xd2, 0x79, 0x89, 0xef, 0xa2, 0x8b, 0xee, 0x6f, 0xdc, 0x5e, 0x65, 0xa5,
- 0x09, 0x33, 0x51, 0xb5, 0x21, 0xc8, 0xc6, 0xab, 0xed, 0xd5, 0x50, 0x93,
- 0x39, 0x71, 0x97, 0xd3, 0x2c, 0xdd, 0xaf, 0xb1, 0xc6, 0x9b, 0x4b, 0x69,
- 0x98, 0xae, 0xaf, 0x21, 0xa0, 0x8a, 0x90, 0x25, 0xe0, 0xf4, 0x8c, 0xf2,
- 0xc3, 0x4f, 0x64, 0xb6, 0xc6, 0x64, 0x90, 0xff, 0x95, 0x0a, 0xcc, 0x8c,
- 0xf4, 0x86, 0x80, 0x53, 0x8d, 0x51, 0x0b, 0xcd, 0x45, 0x4f, 0xcf, 0x7c,
- 0xc6, 0xdf, 0x08, 0x5e, 0xa7, 0xdf, 0x4f, 0xcf, 0x84, 0xde, 0xb8, 0x4d,
- 0x73, 0x40, 0x06, 0xbe, 0x33, 0x82, 0xe8, 0x41, 0x1b, 0x9a, 0xc3, 0x5b,
- 0xb6, 0xf3, 0xfc, 0x32, 0x98, 0xcc, 0xcc, 0x5e, 0xd5, 0xb7, 0x86, 0x0f,
- 0xc8, 0x59, 0x72, 0xcb, 0x9a, 0xc5, 0x3c, 0x50, 0xb8, 0x25, 0xb8, 0x87,
- 0x3e, 0x49, 0xd4, 0x2d, 0x2f, 0x50, 0x35, 0xeb, 0xb8, 0x10, 0xa7, 0xea,
- 0xb1, 0xe2, 0x0c, 0x6a, 0x84, 0x2c, 0xe2, 0x7a, 0x26, 0xef, 0x7e, 0x6b,
- 0x1e, 0x47, 0x6e, 0x98, 0xc0, 0x3f, 0x92, 0x24, 0xe7, 0x88, 0xf9, 0x18,
- 0x78, 0x37, 0x8a, 0x54, 0xa6, 0x2b, 0x5b, 0xf0, 0xc7, 0xe2, 0x98, 0xa4,
- 0xa6, 0x2e, 0xc3, 0x6a, 0x75, 0x66, 0x51, 0xe8, 0x0d, 0x90, 0xfd, 0xa7,
- 0xec, 0x22, 0xb3, 0x7d, 0x9d, 0x0c, 0xfe, 0x72, 0x7f, 0x98, 0xf6, 0x86,
- 0x30, 0xd3, 0x7c, 0xee, 0xa5, 0xc5, 0x20, 0x89, 0x79, 0x04, 0x8e, 0xa8,
- 0xb6, 0x94, 0x70, 0x4e, 0x75, 0xe5, 0xa0, 0xae, 0x8c, 0x7f, 0x72, 0x4c,
- 0xd5, 0x9f, 0xd2, 0x56, 0x0d, 0xb2, 0x28, 0x45, 0x99, 0xf8, 0x40, 0xd4,
- 0x3f, 0x42, 0x4a, 0x0c, 0x92, 0x23, 0xe1, 0x17, 0xaf, 0x68, 0xa6, 0x0f,
- 0x1d, 0x32, 0x0d, 0xf8, 0x08, 0x8e, 0xdc, 0x79, 0x68, 0xf0, 0xfe, 0x0b,
- 0xda, 0x94, 0x2d, 0xa6, 0xa7, 0x76, 0x7e, 0xd6, 0xca, 0xec, 0x7c, 0x37,
- 0x52, 0x4f, 0x77, 0xcf, 0xa3, 0xcf, 0x8a, 0xfe, 0x89, 0xd9, 0x3e, 0xbc,
- 0xb5, 0x06, 0xa0, 0x21, 0x91, 0x89, 0x77, 0x84, 0x85, 0x43, 0x2a, 0x65,
- 0xec, 0x75, 0x4d, 0x0d, 0x1c, 0x79, 0x0f, 0x61, 0xca, 0x3e, 0x62, 0xbb,
- 0x41, 0xf9, 0x4c, 0x5c, 0x3b, 0xde, 0x33, 0x8e, 0xdf, 0x51, 0x72, 0x93,
- 0xca, 0xa6, 0xc7, 0x16, 0xe5, 0xb3, 0x22, 0xb6, 0x2e, 0xbf, 0xae, 0x1d,
- 0x91, 0x1d, 0x49, 0x96, 0xa3, 0x25, 0xd4, 0xce, 0x6f, 0xf0, 0xfb, 0xb7,
- 0xf5, 0x4a, 0x24, 0x03, 0x54, 0x4b, 0x7f, 0x0b, 0xb4, 0x31, 0xb4, 0x33,
- 0xb7, 0x40, 0xf0, 0xd5, 0x4c, 0xee, 0xe3, 0x4b, 0x12, 0x8c, 0xc9, 0xa7,
- 0x06, 0xb1, 0x02, 0x5a, 0x14, 0x6f, 0xe2, 0x3b, 0x68, 0x9b, 0x3d, 0xfc,
- 0x83, 0x4a, 0xcc, 0xb5, 0x77, 0xe7, 0xf0, 0x1b, 0x52, 0xce, 0x60, 0x89,
- 0xe2, 0x45, 0x76, 0xaa, 0x76, 0x70, 0xc2, 0xfd, 0x21, 0x8f, 0x1d, 0x67,
- 0x1a, 0x4c, 0xe8, 0x81, 0x2b, 0x2e, 0xa9, 0x56, 0x0a, 0x27, 0x0f, 0x81,
- 0xba, 0x5c, 0x4f, 0xfa, 0x6e, 0x7e, 0x33, 0x7d, 0x78, 0xed, 0xd2, 0xe3,
- 0x24, 0xae, 0x24, 0xb2, 0x1b, 0x62, 0x71, 0x0e, 0x73, 0xfe, 0x8a, 0x3b,
- 0x98, 0x0d, 0x82, 0x8e, 0x8d, 0x0f, 0xb3, 0xe2, 0x65, 0x87, 0xeb, 0x36,
- 0x91, 0x4d, 0x8a, 0xfb, 0x22, 0x7a, 0x23, 0x2c, 0xe1, 0xb6, 0x94, 0xb6,
- 0x90, 0x94, 0xcc, 0x0c, 0x7d, 0x02, 0x36, 0x56, 0xda, 0x45, 0x20, 0x90,
- 0x48, 0xdb, 0xa4, 0xf5, 0x27, 0xac, 0x22, 0x49, 0x25, 0xaa, 0xd8, 0xa7,
- 0x79, 0x38, 0x80, 0xc0, 0x95, 0xc7, 0xd1, 0x5c, 0x17, 0x7c, 0xa7, 0xec,
- 0xd2, 0x63, 0xc6, 0xc6, 0x55, 0xfe, 0x78, 0x99, 0x06, 0x2c, 0x6e, 0x4f,
- 0xfe, 0xd1, 0x5b, 0x8c, 0x2f, 0xa1, 0x42, 0x03, 0x26, 0x5a, 0x5e, 0xda,
- 0xef, 0x43, 0xd2, 0x0e, 0xf9, 0x5f, 0xdb, 0x1d, 0x9c, 0xd1, 0xcb, 0x65,
- 0x84, 0x26, 0xed, 0x91, 0x8f, 0x16, 0xb4, 0x1c, 0xc0, 0xb3, 0x8d, 0x79,
- 0xae, 0x9b, 0xcb, 0x36, 0x6d, 0xcd, 0x67, 0x1f, 0x87, 0x11, 0x2a, 0x7c,
- 0xb1, 0x8c, 0xfb, 0x06, 0xab, 0xd2, 0xd6, 0x2a, 0xe3, 0x45, 0x6c, 0xa5,
- 0xc0, 0x19, 0x6b, 0xfc, 0xc3, 0xb7, 0x54, 0x35, 0xda, 0xdf, 0x12, 0x97,
- 0x5c, 0xac, 0x59, 0xb4, 0x42, 0x25, 0xef, 0x04, 0xf7, 0x4c, 0xdb, 0x74,
- 0xb9, 0x68, 0x8f, 0xee, 0x37, 0x0a, 0xc6, 0x21, 0x86, 0x0f, 0x6f, 0x8e,
- 0xab, 0xd5, 0x7b, 0x38, 0x5e, 0x5f, 0x7d, 0xb9, 0x5a, 0xcb, 0xce, 0xa0,
- 0x56, 0x37, 0x13, 0x71, 0x4b, 0xba, 0x43, 0x7c, 0xc0, 0xb7, 0x7f, 0x32,
- 0xd7, 0x46, 0x27, 0x58, 0xfc, 0xdb, 0xb5, 0x64, 0x20, 0x3b, 0x20, 0x85,
- 0x79, 0xa8, 0x9a, 0x22, 0xaf, 0x29, 0x86, 0xc5, 0x9d, 0x23, 0x96, 0x52,
- 0xca, 0xc7, 0x9d, 0x92, 0x26, 0xe5, 0x3a, 0x60, 0xd6, 0xad, 0x8d, 0x5a,
- 0xd9, 0x29, 0xbe, 0xd5, 0x5c, 0x3a, 0x77, 0xda, 0x34, 0xe2, 0x76, 0xcb,
- 0x98, 0xa4, 0xf3, 0x33, 0xf1, 0x68, 0x20, 0x83, 0x95, 0x0b, 0x8d, 0x93,
- 0x59, 0x02, 0x0c, 0x8f, 0xe4, 0xc4, 0xb0, 0xe7, 0x61, 0x0d, 0xf9, 0x80,
- 0x20, 0x58, 0x40, 0xea, 0xb7, 0x0b, 0x1b, 0xad, 0xe3, 0x30, 0x3b, 0x30,
- 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14,
- 0x2d, 0x77, 0x79, 0x79, 0x90, 0x41, 0x75, 0xf4, 0x4a, 0x7f, 0xf7, 0x15,
- 0x94, 0x28, 0x62, 0xf7, 0x69, 0xd4, 0x44, 0x27, 0x04, 0x14, 0x2b, 0x2f,
- 0xd9, 0x24, 0xc3, 0x8a, 0x34, 0xbb, 0x52, 0x52, 0x7b, 0xf6, 0x0e, 0x7b,
- 0xfe, 0x3a, 0x66, 0x47, 0x40, 0x49, 0x02, 0x02, 0x07, 0xd0,
-};
-
-// kPBES2WithSHA1 is a PKCS#12 file using PBES2 and HMAC-SHA-1 created with:
-// openssl pkcs12 -export -inkey key.pem -in cert.pem -keypbe AES-128-CBC -certpbe AES-128-CBC
-//
-// This was generated with an older OpenSSL, which used hmacWithSHA1 as the PRF.
-// (There is currently no way to specify the PRF in the pkcs12 command.)
-static const uint8_t kPBES2WithSHA1[] = {
- 0x30, 0x82, 0x0a, 0x03, 0x02, 0x01, 0x03, 0x30, 0x82, 0x09, 0xc9, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
- 0x09, 0xba, 0x04, 0x82, 0x09, 0xb6, 0x30, 0x82, 0x09, 0xb2, 0x30, 0x82,
- 0x04, 0x34, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x06, 0xa0, 0x82, 0x04, 0x25, 0x30, 0x82, 0x04, 0x21, 0x02, 0x01, 0x00,
- 0x30, 0x82, 0x04, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x01, 0x30, 0x49, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x05, 0x0d, 0x30, 0x3c, 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, 0x30, 0x0e, 0x04, 0x08, 0xdb,
- 0x48, 0xe6, 0x98, 0x09, 0x8f, 0x6e, 0x2d, 0x02, 0x02, 0x08, 0x00, 0x30,
- 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02,
- 0x04, 0x10, 0xee, 0xb3, 0x10, 0xe5, 0x21, 0x85, 0x03, 0x3e, 0x69, 0xad,
- 0xdf, 0x78, 0xa7, 0xd8, 0xac, 0xf1, 0x80, 0x82, 0x03, 0xc0, 0xcb, 0x58,
- 0x11, 0x28, 0x1d, 0xbc, 0x3c, 0x8c, 0xe7, 0x7b, 0x15, 0x67, 0x30, 0xf3,
- 0x2b, 0x94, 0x10, 0x8c, 0xbe, 0xfd, 0xaa, 0x11, 0xd7, 0x99, 0xee, 0x21,
- 0xb6, 0x1b, 0x4f, 0x53, 0xcb, 0x44, 0xff, 0x4f, 0xbf, 0xf6, 0x43, 0x3d,
- 0x12, 0xe6, 0x09, 0xe8, 0x05, 0xdd, 0x2f, 0xc5, 0x39, 0xde, 0x0c, 0x88,
- 0xe8, 0x4e, 0x89, 0x8f, 0x5f, 0xdf, 0x23, 0x50, 0xe6, 0xb7, 0xba, 0x1a,
- 0xdd, 0x1c, 0x63, 0x51, 0x0e, 0x71, 0xb7, 0xf7, 0x39, 0x3c, 0xd4, 0xe7,
- 0x52, 0x50, 0xc5, 0xd7, 0xbf, 0x65, 0x94, 0x72, 0x97, 0x2a, 0xb9, 0x68,
- 0xc2, 0xbd, 0x0c, 0x97, 0x02, 0x74, 0x23, 0x7f, 0x11, 0x6b, 0xea, 0xb4,
- 0xe4, 0x2f, 0xf0, 0x8b, 0x91, 0x5c, 0xdb, 0xae, 0x10, 0xbf, 0x89, 0xbc,
- 0x62, 0xef, 0x99, 0xbf, 0x07, 0x59, 0x58, 0x12, 0xef, 0xaf, 0xe6, 0xcd,
- 0x30, 0x27, 0xe4, 0xab, 0x44, 0xf7, 0xf9, 0x14, 0xb2, 0x5d, 0xfa, 0x97,
- 0xe6, 0x9a, 0xed, 0x85, 0x60, 0x86, 0xd9, 0xb0, 0xd7, 0xa4, 0xe4, 0x00,
- 0xa8, 0xee, 0xbb, 0xfc, 0x0d, 0xe8, 0x58, 0x7a, 0xca, 0x02, 0x1d, 0x02,
- 0xab, 0xbd, 0x16, 0x50, 0x4f, 0xfc, 0x60, 0xde, 0x48, 0xb1, 0x7f, 0xea,
- 0xba, 0x45, 0x7b, 0x29, 0xfe, 0x8e, 0xed, 0x48, 0xd2, 0x31, 0x64, 0xda,
- 0x89, 0x84, 0x6f, 0xd1, 0xd2, 0xb1, 0x7b, 0x97, 0x19, 0x38, 0x16, 0xd9,
- 0x3f, 0xd6, 0xdb, 0x6f, 0xab, 0x56, 0x34, 0xca, 0x34, 0x9c, 0x57, 0x41,
- 0x6e, 0x87, 0x85, 0x2a, 0xa8, 0xfb, 0xe9, 0xf6, 0x3d, 0xb6, 0x83, 0x7b,
- 0x02, 0xc9, 0xbe, 0xf1, 0xbb, 0x8e, 0xe5, 0x68, 0xae, 0xaa, 0xe1, 0x25,
- 0x8d, 0x1f, 0x1f, 0x52, 0x45, 0x3e, 0xef, 0x33, 0xd8, 0x58, 0xd9, 0x48,
- 0xd4, 0xb5, 0xe1, 0x53, 0x21, 0xb5, 0xbd, 0xd4, 0x63, 0x1f, 0xbf, 0xe4,
- 0x30, 0x5e, 0xc3, 0x63, 0xce, 0xdc, 0x12, 0x8c, 0xc7, 0x0c, 0xea, 0x3b,
- 0xf3, 0x0b, 0x38, 0x8d, 0xcc, 0x9b, 0xe7, 0xa0, 0x14, 0x5e, 0x48, 0x9c,
- 0x74, 0x86, 0x8e, 0x2b, 0x77, 0x80, 0xbb, 0x85, 0xa6, 0xd4, 0x25, 0x6e,
- 0x75, 0x07, 0x59, 0xd6, 0x88, 0x00, 0x35, 0x03, 0x5a, 0xb0, 0x86, 0x7e,
- 0x01, 0xa7, 0x77, 0x74, 0x13, 0xfa, 0x9f, 0x2d, 0xe3, 0x90, 0xda, 0x68,
- 0x23, 0x36, 0x0b, 0x62, 0x21, 0x76, 0xda, 0x6c, 0x05, 0x35, 0x80, 0xfc,
- 0xee, 0x5f, 0x3c, 0xac, 0x60, 0x2a, 0x9c, 0x6e, 0x4c, 0xaa, 0xa3, 0xd1,
- 0xdf, 0x2c, 0x7e, 0x0e, 0xc0, 0xa0, 0x84, 0xe4, 0xb2, 0x33, 0x1f, 0x8c,
- 0xcb, 0x74, 0x31, 0x18, 0x5b, 0x0b, 0x18, 0x41, 0xc6, 0x87, 0x13, 0xa2,
- 0xad, 0x1d, 0x43, 0x5e, 0x67, 0xd0, 0x31, 0xf5, 0x61, 0x7c, 0x3d, 0x16,
- 0x55, 0x01, 0x94, 0x45, 0xa4, 0x50, 0x0f, 0xb1, 0x1b, 0x81, 0x51, 0xa7,
- 0x92, 0xae, 0xa3, 0x6d, 0x4e, 0x55, 0x46, 0x37, 0x98, 0xe1, 0xe4, 0x5c,
- 0x29, 0x79, 0xc9, 0x76, 0x0a, 0xb5, 0x9d, 0x1b, 0x8a, 0xf6, 0xab, 0xeb,
- 0x69, 0x6e, 0x17, 0x88, 0xeb, 0x82, 0xfa, 0x78, 0x2f, 0x8c, 0x30, 0xfd,
- 0xf1, 0x74, 0xcd, 0x53, 0x78, 0x27, 0x43, 0x82, 0x05, 0x37, 0x07, 0xb3,
- 0x4c, 0x89, 0x9d, 0x00, 0x1d, 0x73, 0xad, 0x0f, 0xcd, 0x63, 0xbe, 0x9b,
- 0xa9, 0x50, 0xa5, 0x43, 0x74, 0x86, 0x87, 0xbc, 0xd9, 0x97, 0x66, 0x84,
- 0x35, 0x3e, 0x67, 0xce, 0x92, 0x2c, 0x78, 0xc7, 0x88, 0x19, 0x6a, 0x1c,
- 0xa8, 0x93, 0x0b, 0x79, 0x21, 0xe5, 0x39, 0x1b, 0x00, 0x68, 0x2a, 0x0b,
- 0xac, 0x6a, 0x2f, 0xc1, 0x9c, 0x90, 0x18, 0x86, 0x63, 0x53, 0x72, 0x34,
- 0xd9, 0xa8, 0x92, 0xce, 0x64, 0x3a, 0xeb, 0xba, 0xd8, 0x31, 0xf3, 0xfb,
- 0x2a, 0xac, 0xc6, 0xe7, 0xd1, 0x0b, 0x7c, 0xfc, 0xbb, 0x69, 0x57, 0xc8,
- 0x97, 0x3d, 0xdb, 0x81, 0x77, 0x2a, 0x9f, 0x07, 0x2c, 0x79, 0x69, 0xbc,
- 0x51, 0x0e, 0x68, 0x11, 0x00, 0x10, 0xed, 0x9f, 0xb8, 0x8d, 0xa0, 0x25,
- 0x20, 0xd3, 0x3d, 0x08, 0x20, 0x46, 0xfa, 0x89, 0xef, 0x69, 0x4c, 0x60,
- 0x33, 0x80, 0xb9, 0x53, 0xb4, 0x7b, 0xab, 0x38, 0xf1, 0xcd, 0xb8, 0x75,
- 0xc4, 0x85, 0x0a, 0xda, 0xab, 0x19, 0x40, 0xd3, 0x88, 0xd5, 0xf7, 0x5f,
- 0x8e, 0xcd, 0x8e, 0xa4, 0x1c, 0x9c, 0x22, 0x6d, 0xce, 0x66, 0x29, 0xfa,
- 0x62, 0x6f, 0x01, 0xdc, 0x46, 0x45, 0x38, 0x64, 0xf7, 0xc4, 0x94, 0xfd,
- 0x48, 0x44, 0x70, 0x4d, 0xef, 0xf0, 0x4b, 0x95, 0xf8, 0x68, 0x8d, 0xb7,
- 0x35, 0x7d, 0xc6, 0xf5, 0x97, 0xce, 0x5d, 0xad, 0xe8, 0x5c, 0xeb, 0x4f,
- 0x9b, 0x5b, 0x03, 0xce, 0x33, 0x60, 0xf5, 0xce, 0xcc, 0xfe, 0xfb, 0x77,
- 0x40, 0xc4, 0xf4, 0x9d, 0xf3, 0x2c, 0xdb, 0x83, 0xc2, 0x1a, 0xf2, 0xb6,
- 0xbe, 0xfc, 0x2c, 0x7f, 0x29, 0x20, 0x35, 0x50, 0x00, 0x60, 0x03, 0xd2,
- 0xb3, 0x03, 0x18, 0x64, 0xb9, 0x64, 0x98, 0x33, 0xdb, 0x47, 0x43, 0xe2,
- 0xa1, 0x85, 0x79, 0x9b, 0xb1, 0x0b, 0x0e, 0xbb, 0x14, 0x5f, 0xb9, 0x16,
- 0xb6, 0xc3, 0xf6, 0x5c, 0x01, 0xe3, 0xaa, 0x3f, 0x03, 0xad, 0x18, 0xeb,
- 0x0e, 0x3d, 0xa3, 0x1f, 0xcc, 0x4d, 0x48, 0x44, 0x7e, 0xda, 0xb9, 0x9d,
- 0x17, 0xe8, 0x92, 0x46, 0xea, 0xf5, 0x3e, 0x05, 0x4e, 0xa7, 0xb5, 0x94,
- 0x6d, 0x95, 0x42, 0xa7, 0x71, 0xfb, 0xc2, 0x45, 0xd6, 0xd2, 0x86, 0xd0,
- 0x79, 0x99, 0x1f, 0x96, 0x78, 0x22, 0xeb, 0x05, 0x26, 0xf2, 0xa1, 0x67,
- 0x67, 0x2b, 0xae, 0x1d, 0x28, 0x42, 0xd6, 0xbe, 0x08, 0xf6, 0xb7, 0x54,
- 0xc8, 0x82, 0xbf, 0x92, 0x0f, 0x2c, 0xba, 0x47, 0xe2, 0x01, 0x73, 0x2c,
- 0xd7, 0x34, 0x84, 0x2f, 0xb6, 0x41, 0x84, 0xeb, 0x7a, 0xb2, 0xf9, 0xdd,
- 0x31, 0xbe, 0x07, 0xb4, 0x88, 0x05, 0xd8, 0xe1, 0x79, 0x55, 0xe6, 0x4b,
- 0x8c, 0xdc, 0xd1, 0x76, 0x58, 0x72, 0x42, 0x28, 0xb3, 0x9f, 0xd0, 0x05,
- 0x37, 0x6b, 0x65, 0x74, 0xce, 0x0d, 0x01, 0xa9, 0x49, 0xc5, 0x90, 0xab,
- 0x90, 0x16, 0x2c, 0x9c, 0xba, 0xcb, 0x94, 0xc7, 0xfa, 0xe0, 0x39, 0x82,
- 0xa2, 0x88, 0xd6, 0x0c, 0xc4, 0x4d, 0xfe, 0xb4, 0xbc, 0x87, 0xe5, 0x63,
- 0x3b, 0x6b, 0xf0, 0xd1, 0x09, 0x39, 0x8f, 0x51, 0x4f, 0x32, 0xae, 0xed,
- 0x0c, 0xff, 0x79, 0x52, 0x19, 0xa9, 0x4e, 0x45, 0x11, 0xc3, 0x5f, 0xd6,
- 0x2b, 0x66, 0xe3, 0x9c, 0xbe, 0xbc, 0xda, 0x65, 0x25, 0xcd, 0xf5, 0x73,
- 0x45, 0x09, 0xf5, 0x5d, 0x6b, 0x83, 0x45, 0x28, 0x98, 0x2c, 0x58, 0x44,
- 0xca, 0x37, 0xeb, 0xc3, 0xc2, 0x10, 0x77, 0x14, 0x79, 0x9b, 0xd8, 0xb2,
- 0xbf, 0x45, 0xd5, 0x63, 0xe4, 0x37, 0x42, 0x7b, 0x2d, 0xe2, 0x49, 0xb3,
- 0x18, 0x8e, 0x86, 0x73, 0xf1, 0x59, 0x8a, 0xf2, 0x3c, 0x49, 0x12, 0x7b,
- 0xb1, 0x40, 0x8c, 0x8c, 0xac, 0x05, 0x50, 0xbd, 0x9b, 0x3b, 0x84, 0x81,
- 0x68, 0x26, 0x88, 0x1b, 0xbf, 0xa0, 0x28, 0xc2, 0x06, 0xa9, 0xe4, 0xd9,
- 0x1f, 0x5d, 0xca, 0x96, 0x4f, 0xfe, 0xd8, 0x64, 0xee, 0x73, 0x30, 0x82,
- 0x05, 0x76, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x01, 0xa0, 0x82, 0x05, 0x67, 0x04, 0x82, 0x05, 0x63, 0x30, 0x82, 0x05,
- 0x5f, 0x30, 0x82, 0x05, 0x5b, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x05, 0x23, 0x30, 0x82,
- 0x05, 0x1f, 0x30, 0x49, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x05, 0x0d, 0x30, 0x3c, 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, 0x30, 0x0e, 0x04, 0x08, 0xe3, 0x3e,
- 0xd3, 0x8d, 0xd6, 0xb5, 0x8a, 0x05, 0x02, 0x02, 0x08, 0x00, 0x30, 0x1d,
- 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02, 0x04,
- 0x10, 0x61, 0xa0, 0x2f, 0x8d, 0x0c, 0xa1, 0x03, 0xc9, 0xdf, 0x2e, 0x81,
- 0x65, 0xe0, 0x63, 0x70, 0x55, 0x04, 0x82, 0x04, 0xd0, 0x24, 0x1e, 0xf9,
- 0x1d, 0xc4, 0xe9, 0xbf, 0x49, 0x3c, 0x1e, 0x55, 0x4a, 0xd4, 0xb0, 0x0c,
- 0xdd, 0x5b, 0x92, 0xb2, 0xed, 0x18, 0xac, 0x66, 0x90, 0x1b, 0x29, 0x3d,
- 0x10, 0xad, 0x02, 0xe7, 0x17, 0x83, 0x44, 0x67, 0xba, 0x11, 0x6f, 0x05,
- 0xf5, 0xf7, 0x37, 0xcb, 0x5a, 0xe9, 0x0e, 0xc3, 0x4b, 0x1b, 0x62, 0xee,
- 0xb2, 0xb7, 0x14, 0x85, 0x07, 0x2d, 0x95, 0x83, 0xa9, 0xdc, 0x3d, 0x4b,
- 0x33, 0xad, 0x68, 0xbf, 0x54, 0xf8, 0xef, 0x25, 0x05, 0x40, 0xcd, 0x61,
- 0xbe, 0x12, 0xeb, 0x78, 0x75, 0x36, 0x08, 0x8c, 0x5a, 0x57, 0xa1, 0x98,
- 0xd5, 0x42, 0x01, 0x1b, 0x4c, 0x25, 0xc2, 0x18, 0x9f, 0x91, 0xfe, 0x78,
- 0x88, 0x99, 0x47, 0x5a, 0x20, 0x2c, 0x37, 0x31, 0x05, 0x98, 0xef, 0x91,
- 0x6e, 0xeb, 0x2e, 0x86, 0x90, 0x61, 0xb1, 0x57, 0x1a, 0x05, 0x82, 0x14,
- 0x0c, 0xa8, 0x94, 0xae, 0x56, 0x7b, 0xd6, 0x2f, 0x8b, 0x2e, 0x91, 0xa6,
- 0x12, 0x68, 0x1f, 0x06, 0x09, 0x2f, 0xa6, 0xed, 0x33, 0x99, 0x72, 0x56,
- 0xe5, 0xf7, 0xea, 0xcc, 0xcf, 0x27, 0xa5, 0xad, 0x49, 0x5a, 0xbc, 0x7b,
- 0xe3, 0x62, 0x63, 0x8f, 0x00, 0x2b, 0x96, 0xc5, 0x3f, 0xaf, 0x24, 0xba,
- 0xf6, 0x8d, 0xe2, 0xef, 0x18, 0x50, 0xd6, 0xd8, 0x4f, 0xb2, 0x5d, 0xb7,
- 0x96, 0x6f, 0x02, 0xf7, 0x7d, 0xf2, 0xa2, 0x7b, 0x9b, 0x13, 0x98, 0xde,
- 0xdd, 0x6e, 0xb5, 0x48, 0x52, 0x8e, 0x44, 0xad, 0xe0, 0xcf, 0x40, 0x9f,
- 0xfd, 0x88, 0x33, 0x66, 0xce, 0x6a, 0x49, 0x5f, 0xe7, 0x4b, 0x36, 0x93,
- 0x7f, 0x49, 0x62, 0xc9, 0x5a, 0xae, 0xa1, 0xca, 0xf7, 0x5a, 0xbe, 0x85,
- 0x77, 0x9a, 0x8f, 0xce, 0x4d, 0x84, 0x81, 0xd0, 0xa2, 0xee, 0x60, 0x92,
- 0x86, 0x16, 0x2a, 0xd5, 0x08, 0xb6, 0x58, 0x63, 0x07, 0x7c, 0x41, 0xac,
- 0x97, 0x4f, 0xf0, 0xcf, 0xd8, 0xd2, 0xb1, 0xd7, 0x1d, 0xe5, 0xb8, 0x7c,
- 0x04, 0x2b, 0xd9, 0xee, 0xf7, 0x22, 0x88, 0xa1, 0x53, 0xdb, 0x5e, 0x5b,
- 0x47, 0x49, 0xeb, 0xcf, 0x04, 0x78, 0x69, 0xd1, 0xfc, 0x8a, 0xa9, 0x61,
- 0x92, 0xbf, 0x5c, 0x7f, 0xde, 0x49, 0x42, 0xfc, 0x0d, 0xc2, 0xa2, 0x8f,
- 0xba, 0xdf, 0x12, 0xa4, 0x62, 0xfb, 0x8d, 0xd3, 0xc5, 0xf9, 0x85, 0x4c,
- 0x17, 0x70, 0xb7, 0xf7, 0x99, 0x29, 0x52, 0x92, 0x36, 0xc5, 0x4b, 0x31,
- 0x23, 0x5c, 0x09, 0x27, 0x3c, 0xa0, 0x76, 0x5d, 0x92, 0x99, 0x63, 0x88,
- 0xca, 0xad, 0xed, 0xd7, 0x85, 0x98, 0x2f, 0xbe, 0xaa, 0xa5, 0xf3, 0x0a,
- 0x76, 0x13, 0x01, 0x90, 0x8a, 0xe7, 0x5a, 0x2d, 0x2b, 0x1a, 0x80, 0x33,
- 0x86, 0xab, 0xd8, 0xa7, 0xae, 0x0b, 0x7d, 0xcd, 0x64, 0x8d, 0xa6, 0xb6,
- 0xfb, 0x83, 0x9f, 0x91, 0x23, 0xcb, 0xda, 0x63, 0xd0, 0xde, 0xf4, 0xdd,
- 0xaa, 0x23, 0x49, 0x6c, 0x44, 0xfa, 0x6f, 0x12, 0x13, 0x90, 0x37, 0xde,
- 0xa3, 0x72, 0x45, 0x1a, 0xa7, 0xab, 0x01, 0x6d, 0xd6, 0x34, 0xe7, 0x51,
- 0x0e, 0x33, 0xbc, 0x09, 0xbf, 0xb6, 0x16, 0xf8, 0xd3, 0x11, 0x11, 0xd1,
- 0x5f, 0xaa, 0x32, 0xb6, 0x5b, 0xe7, 0xbc, 0xdd, 0xaa, 0xe4, 0xed, 0x42,
- 0x3d, 0x2e, 0xf7, 0xa1, 0x06, 0x39, 0xd4, 0x00, 0xc6, 0xc8, 0xed, 0xb5,
- 0x96, 0xc1, 0xbf, 0x4c, 0xf1, 0xf6, 0xc6, 0x59, 0xf4, 0x99, 0x9c, 0x10,
- 0x22, 0xa1, 0x3a, 0xcd, 0x94, 0xac, 0x0b, 0xc8, 0x7e, 0x29, 0xbc, 0xf0,
- 0xae, 0x27, 0x7a, 0xb8, 0x5c, 0xa0, 0x13, 0x36, 0xb5, 0x19, 0x4b, 0x2c,
- 0xc1, 0xce, 0x49, 0x57, 0x1d, 0x36, 0xf0, 0xc2, 0x4c, 0xdf, 0x6d, 0xc9,
- 0x64, 0x68, 0xcb, 0xea, 0x22, 0x32, 0xd7, 0x11, 0x2c, 0x77, 0xbe, 0x01,
- 0xa3, 0x82, 0x2d, 0xa1, 0x4b, 0x13, 0x93, 0x87, 0x3d, 0x01, 0x74, 0xc6,
- 0xc6, 0xf9, 0xae, 0x2e, 0xa1, 0x44, 0x5d, 0x47, 0x6c, 0x6f, 0xc6, 0xce,
- 0xef, 0x32, 0xf8, 0x8d, 0x53, 0x4d, 0xa5, 0xf0, 0xa0, 0x51, 0x7e, 0xd8,
- 0x35, 0x55, 0x2a, 0x04, 0xb9, 0x42, 0xa7, 0x51, 0xba, 0xad, 0xce, 0x88,
- 0x7b, 0x93, 0x25, 0x9d, 0x03, 0x08, 0xfa, 0x75, 0x38, 0x63, 0x78, 0x13,
- 0x11, 0x9d, 0xf6, 0xcc, 0x18, 0xe3, 0x99, 0xa9, 0x5d, 0x90, 0x6b, 0xbf,
- 0x9c, 0x69, 0x99, 0x63, 0x27, 0x35, 0x8a, 0x26, 0x07, 0x67, 0xd1, 0xae,
- 0x57, 0xec, 0xc0, 0x45, 0x6e, 0x2a, 0x42, 0x46, 0x8f, 0xe4, 0x84, 0xc7,
- 0x67, 0x06, 0x0c, 0xa7, 0x7e, 0x5c, 0x20, 0x80, 0xdc, 0xc1, 0xe4, 0x7a,
- 0x74, 0x76, 0x8f, 0x41, 0x78, 0xce, 0x6a, 0xf9, 0xcb, 0x7f, 0xe9, 0x17,
- 0x70, 0x45, 0x01, 0x9a, 0xc3, 0x9c, 0xa2, 0x68, 0xa0, 0x79, 0xfd, 0x44,
- 0x4c, 0xc8, 0xa0, 0xaf, 0xa5, 0xba, 0x0f, 0x03, 0x30, 0x43, 0x4a, 0x1d,
- 0x3e, 0xd4, 0x8e, 0x1f, 0x6d, 0x09, 0xf9, 0x63, 0xde, 0xd2, 0x9e, 0x77,
- 0xe7, 0xde, 0x61, 0x52, 0x76, 0x0f, 0x6d, 0x37, 0xf7, 0xc2, 0x69, 0x96,
- 0x9d, 0xc5, 0xd9, 0x15, 0x10, 0xf2, 0x22, 0x1f, 0x3b, 0x83, 0xb3, 0xb4,
- 0x2c, 0x25, 0x36, 0xc3, 0x3a, 0x24, 0x17, 0xed, 0xad, 0x11, 0x1f, 0x46,
- 0x31, 0x0c, 0x6a, 0x3c, 0xd2, 0x1a, 0xe7, 0x41, 0xb3, 0x75, 0xd8, 0x80,
- 0xb3, 0xf8, 0x2b, 0xab, 0xb5, 0x81, 0xc6, 0x5e, 0x40, 0x9a, 0x77, 0xaa,
- 0x79, 0x31, 0x1f, 0x79, 0xfe, 0x0f, 0x0f, 0xb0, 0x36, 0xb7, 0xdc, 0xca,
- 0xf6, 0xbf, 0x80, 0xeb, 0x78, 0xc6, 0x73, 0x6a, 0xb3, 0x71, 0x69, 0x9c,
- 0x1d, 0xdd, 0x90, 0xd9, 0x73, 0x07, 0x43, 0x37, 0x19, 0x7f, 0x22, 0xa4,
- 0x9a, 0x4d, 0x98, 0x66, 0x10, 0x5b, 0x08, 0x62, 0xb3, 0xd8, 0x2f, 0x56,
- 0x68, 0x22, 0xdf, 0xd1, 0xa2, 0x5a, 0x45, 0xf9, 0xb4, 0xb9, 0xf2, 0x48,
- 0x4e, 0x38, 0x1a, 0x23, 0x36, 0x6d, 0x42, 0x56, 0xbb, 0x32, 0xe3, 0x00,
- 0x84, 0xa9, 0xe2, 0xba, 0xb6, 0x86, 0xc9, 0xa6, 0x64, 0x8a, 0xd6, 0xa6,
- 0xc4, 0xd7, 0x3e, 0x8b, 0x34, 0x1b, 0x6b, 0x65, 0xfe, 0xb1, 0xc9, 0x93,
- 0xe1, 0xeb, 0x8a, 0x3b, 0xf1, 0x0f, 0xdb, 0x84, 0xe2, 0x2d, 0xf8, 0x69,
- 0x04, 0xee, 0xaf, 0x58, 0x2f, 0xc7, 0x96, 0x70, 0x4d, 0xd9, 0x4c, 0x1d,
- 0x52, 0x38, 0xc6, 0x26, 0x27, 0x41, 0x38, 0x0b, 0xa5, 0x1c, 0x16, 0xd0,
- 0x1d, 0x32, 0x99, 0xb9, 0x1f, 0x35, 0xaf, 0x02, 0xb0, 0x13, 0x0f, 0x95,
- 0xd3, 0x9b, 0xd6, 0x09, 0xcc, 0x29, 0x46, 0xe8, 0xf1, 0x54, 0x4d, 0xb8,
- 0x96, 0xa6, 0x0d, 0x59, 0x61, 0x1f, 0xee, 0xaf, 0xbc, 0x23, 0x58, 0xff,
- 0xcf, 0x96, 0x91, 0x1f, 0x00, 0x80, 0x4e, 0x9a, 0xa2, 0xe0, 0x00, 0xf7,
- 0x3e, 0xb1, 0x91, 0x6c, 0x29, 0x58, 0x5e, 0xe7, 0xc7, 0x23, 0xfa, 0x88,
- 0xf7, 0xfb, 0x0b, 0x0e, 0x4a, 0x04, 0x46, 0xe0, 0x67, 0x10, 0x09, 0xea,
- 0xc0, 0xa9, 0xbe, 0x83, 0x11, 0x33, 0x8e, 0xfb, 0xd6, 0xd5, 0x67, 0xef,
- 0xb4, 0x13, 0x4d, 0x17, 0xa1, 0x44, 0xb7, 0x98, 0x77, 0xd0, 0x63, 0xe7,
- 0x9c, 0xa7, 0x96, 0x29, 0xe5, 0xfe, 0x72, 0x4c, 0xa9, 0x85, 0x9b, 0xc9,
- 0xf3, 0xf6, 0x05, 0x0a, 0x28, 0x68, 0x99, 0x31, 0xe8, 0x64, 0x30, 0x9c,
- 0x2a, 0x90, 0x48, 0x84, 0x00, 0x1a, 0x66, 0x0e, 0x3e, 0xf7, 0xaa, 0xc9,
- 0x6c, 0x5b, 0x57, 0x7b, 0xa9, 0x17, 0x91, 0x1e, 0x6b, 0xe8, 0x12, 0xa1,
- 0xd4, 0xde, 0x1e, 0x38, 0x14, 0x7b, 0xe0, 0x9a, 0x15, 0xae, 0x5a, 0x26,
- 0x93, 0x7a, 0xd6, 0x8d, 0x26, 0x61, 0x28, 0xf2, 0x40, 0x71, 0xc7, 0x8a,
- 0x2d, 0x69, 0x72, 0x04, 0x5b, 0xb9, 0xc1, 0x7b, 0x17, 0xde, 0x2c, 0xfc,
- 0xa9, 0xf2, 0xf8, 0x34, 0x33, 0x09, 0x87, 0x91, 0xdf, 0xeb, 0xf7, 0x57,
- 0x5b, 0x32, 0xe2, 0xd4, 0xe4, 0x47, 0x78, 0xe8, 0x9b, 0x1a, 0xab, 0x44,
- 0x55, 0x28, 0x98, 0x20, 0xa7, 0x16, 0x8b, 0x4e, 0x42, 0xf1, 0x91, 0xbe,
- 0x00, 0x87, 0x3a, 0x91, 0x63, 0x9a, 0xc2, 0x8d, 0x13, 0x34, 0x8b, 0x33,
- 0x02, 0x88, 0x1e, 0xb1, 0xa8, 0x07, 0x6d, 0xb1, 0xf5, 0xb3, 0x7a, 0x3d,
- 0x17, 0x3f, 0xbd, 0xa1, 0xdb, 0x04, 0x0f, 0x29, 0x7b, 0x0e, 0x98, 0x18,
- 0x63, 0x0b, 0x60, 0xcd, 0xa5, 0x0d, 0x5f, 0x1e, 0x53, 0xcd, 0xfa, 0xc0,
- 0xc7, 0x99, 0x53, 0x5f, 0xb7, 0xe5, 0x4a, 0x30, 0xde, 0x14, 0xc9, 0x49,
- 0x46, 0x31, 0xb6, 0x92, 0xf3, 0x4b, 0xc1, 0xb0, 0xdd, 0xec, 0x48, 0xff,
- 0x2d, 0x52, 0x53, 0x64, 0x27, 0x4c, 0x78, 0x96, 0x80, 0x90, 0xa3, 0xd7,
- 0xfd, 0x7a, 0x23, 0x36, 0xa0, 0x76, 0x9e, 0x96, 0xfc, 0xcd, 0xec, 0x58,
- 0xf8, 0x76, 0x4b, 0x2f, 0x8d, 0xb9, 0xd6, 0x89, 0xa1, 0x57, 0xe1, 0xc6,
- 0xed, 0x9a, 0x1e, 0xde, 0xc7, 0x68, 0x93, 0x2b, 0x2e, 0x84, 0x1a, 0xf9,
- 0x8c, 0x58, 0xb8, 0xf0, 0x29, 0xfe, 0x7b, 0x03, 0x84, 0xe8, 0x52, 0x1c,
- 0x01, 0xbb, 0xcc, 0x5d, 0x88, 0xcd, 0x37, 0x8b, 0xe2, 0x2d, 0x30, 0xd1,
- 0xbe, 0xf7, 0xc1, 0x95, 0xb7, 0x01, 0x43, 0xab, 0x30, 0x3f, 0x96, 0x47,
- 0x6d, 0x52, 0x29, 0x87, 0x10, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14,
- 0x14, 0x74, 0x2d, 0x52, 0x8e, 0x0d, 0x0c, 0x06, 0x6c, 0x32, 0x64, 0xd3,
- 0x7e, 0x33, 0x31, 0x68, 0x8b, 0x28, 0x1a, 0x75, 0x30, 0x31, 0x30, 0x21,
- 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04,
- 0x14, 0x2f, 0x5c, 0xc6, 0xaf, 0xa7, 0xcc, 0xb5, 0x77, 0x40, 0xca, 0x71,
- 0xc3, 0x8c, 0xc6, 0x69, 0xdc, 0xc6, 0x7f, 0x54, 0xef, 0x04, 0x08, 0xf8,
- 0x9c, 0x8b, 0x12, 0x27, 0xe8, 0xec, 0x65, 0x02, 0x02, 0x08, 0x00};
-
-// kPBES2WithSHA256 is a PKCS#12 file using PBES2 and HMAC-SHA-256. It was
-// generated in the same way as |kPBES2WithSHA1|, but using OpenSSL 1.1.1b,
-// which uses hmacWithSHA256 as the PRF.
-static const uint8_t kPBES2WithSHA256[] = {
- 0x30, 0x82, 0x0a, 0x7f, 0x02, 0x01, 0x03, 0x30, 0x82, 0x0a, 0x45, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
- 0x0a, 0x36, 0x04, 0x82, 0x0a, 0x32, 0x30, 0x82, 0x0a, 0x2e, 0x30, 0x82,
- 0x04, 0xa2, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x06, 0xa0, 0x82, 0x04, 0x93, 0x30, 0x82, 0x04, 0x8f, 0x02, 0x01, 0x00,
- 0x30, 0x82, 0x04, 0x88, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x01, 0x30, 0x57, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x05, 0x0d, 0x30, 0x4a, 0x30, 0x29, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, 0x30, 0x1c, 0x04, 0x08, 0xb2,
- 0x5e, 0x0d, 0x6d, 0xda, 0xaa, 0x2f, 0xbe, 0x02, 0x02, 0x08, 0x00, 0x30,
- 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x09, 0x05,
- 0x00, 0x30, 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
- 0x01, 0x02, 0x04, 0x10, 0x3c, 0x04, 0x78, 0x37, 0xb3, 0xb2, 0x24, 0xd3,
- 0xb5, 0x46, 0x20, 0xb7, 0xd2, 0xdd, 0x5d, 0x2e, 0x80, 0x82, 0x04, 0x20,
- 0x3a, 0x01, 0xe4, 0xf4, 0x57, 0xd3, 0xed, 0x14, 0xd0, 0x42, 0x3f, 0xd3,
- 0x61, 0xee, 0x84, 0xcd, 0x2b, 0x08, 0x60, 0x30, 0xbd, 0x72, 0xa7, 0xd5,
- 0xa4, 0xf2, 0x13, 0xe9, 0xf0, 0x44, 0x66, 0x26, 0x34, 0xe7, 0x2c, 0x5d,
- 0xc9, 0xb0, 0x4b, 0xab, 0x47, 0x16, 0xab, 0xe6, 0x06, 0xa6, 0x3b, 0x79,
- 0x41, 0x0c, 0x79, 0xd5, 0x9b, 0x02, 0x67, 0xd8, 0x7f, 0xc8, 0x36, 0x37,
- 0x27, 0xb4, 0x44, 0xa2, 0x5e, 0x0d, 0x38, 0xb8, 0x41, 0x8e, 0x3a, 0xf1,
- 0xe9, 0xab, 0xe0, 0x19, 0xd0, 0xe1, 0xc7, 0x92, 0xd4, 0x5b, 0x35, 0xf3,
- 0x79, 0x48, 0x3b, 0xfc, 0x25, 0xfc, 0xc6, 0x9f, 0xed, 0x35, 0x28, 0x5b,
- 0xfa, 0xee, 0x50, 0x42, 0xa3, 0xc3, 0x96, 0xee, 0xe0, 0x87, 0x33, 0x5e,
- 0xa7, 0xc7, 0x0a, 0xfe, 0xda, 0xe5, 0xd5, 0x29, 0x6a, 0x57, 0x08, 0x7f,
- 0x56, 0x37, 0x2a, 0x1a, 0xa0, 0x6d, 0xe9, 0x84, 0xac, 0xed, 0x0e, 0xd8,
- 0xc0, 0xd8, 0xc6, 0x77, 0xb1, 0xdd, 0x1b, 0xa1, 0xed, 0xa7, 0x79, 0x13,
- 0x2e, 0x5b, 0x9b, 0x80, 0x44, 0x9e, 0xff, 0x0a, 0x6e, 0x99, 0x33, 0xcf,
- 0xf1, 0x47, 0x24, 0xaa, 0x48, 0xe7, 0x2c, 0xb3, 0xe6, 0xdc, 0xd4, 0x1e,
- 0xe4, 0xb8, 0x5e, 0x72, 0xaf, 0x3f, 0xd3, 0x25, 0x4a, 0xac, 0x7b, 0x35,
- 0xb1, 0x82, 0xa5, 0xd9, 0xf8, 0x01, 0x12, 0x92, 0x49, 0x4c, 0x17, 0x07,
- 0xb2, 0xb1, 0x3e, 0xcb, 0xfd, 0xd1, 0x17, 0xb5, 0x65, 0x3d, 0x0c, 0x2b,
- 0x2b, 0xc0, 0x37, 0x9c, 0xe7, 0x04, 0x9b, 0x71, 0x5a, 0x10, 0xc0, 0xba,
- 0x3b, 0x31, 0xde, 0x0d, 0x66, 0x6c, 0x0d, 0x4c, 0x99, 0x22, 0x76, 0x2a,
- 0x75, 0x7f, 0x84, 0xd1, 0x07, 0x1f, 0x57, 0xf0, 0x0b, 0x71, 0x41, 0xea,
- 0x38, 0xe2, 0xe7, 0xbe, 0x11, 0x3c, 0x92, 0x8c, 0x7b, 0x0e, 0xb4, 0x7e,
- 0x76, 0xc4, 0x80, 0x41, 0xae, 0x4c, 0xe2, 0x38, 0x36, 0xcb, 0x82, 0x39,
- 0x38, 0x3a, 0x55, 0xb4, 0xe2, 0x35, 0x94, 0xc3, 0xae, 0x3d, 0xd1, 0x03,
- 0xf3, 0xdb, 0x00, 0xd9, 0xfa, 0x96, 0x62, 0x25, 0x97, 0x51, 0xc5, 0xcf,
- 0x84, 0xe8, 0xf7, 0x8b, 0x2f, 0x31, 0xeb, 0xa7, 0x0a, 0x22, 0x6f, 0xad,
- 0xf5, 0x28, 0x25, 0xaa, 0x99, 0x0e, 0xb1, 0x83, 0x9f, 0x70, 0x79, 0xaf,
- 0x10, 0x7c, 0x2c, 0x55, 0xfe, 0x24, 0x7d, 0xea, 0x85, 0x48, 0x8e, 0x7a,
- 0xf7, 0x47, 0xd8, 0x0c, 0x64, 0x97, 0xe0, 0x8f, 0x62, 0x5e, 0xd0, 0x4f,
- 0x21, 0xa4, 0x46, 0x8e, 0x28, 0xb0, 0xb1, 0x90, 0xec, 0x01, 0x7d, 0xc4,
- 0xc8, 0x6f, 0xf2, 0xe2, 0xb7, 0xc4, 0x35, 0x6c, 0xa9, 0xf6, 0xaf, 0xc2,
- 0xb6, 0xa9, 0x02, 0x6d, 0xb2, 0x8b, 0x43, 0x6b, 0x41, 0x80, 0x9d, 0x5e,
- 0x51, 0xa7, 0x31, 0x00, 0x1b, 0xb5, 0x24, 0xed, 0x40, 0x99, 0x33, 0xde,
- 0x87, 0xd1, 0x4b, 0x76, 0x78, 0x57, 0x4c, 0x33, 0x79, 0x89, 0xd3, 0xfa,
- 0x70, 0x0f, 0x2f, 0x31, 0x42, 0x8c, 0xce, 0xe9, 0xc0, 0x58, 0xe1, 0x30,
- 0x30, 0xf1, 0xe9, 0xab, 0xc8, 0x60, 0x7c, 0xe0, 0x6a, 0x99, 0xe7, 0xd3,
- 0x21, 0x1a, 0xcc, 0x98, 0x60, 0x44, 0xaa, 0xff, 0xee, 0xec, 0x34, 0x20,
- 0x19, 0xba, 0x03, 0x3b, 0x67, 0x6f, 0xee, 0xd5, 0xb3, 0xa7, 0x21, 0x57,
- 0xd6, 0x49, 0xaf, 0x91, 0x8f, 0xec, 0x70, 0xd0, 0x59, 0x1a, 0x79, 0xe2,
- 0xd2, 0x94, 0x82, 0x53, 0xfb, 0xea, 0xd6, 0x83, 0x49, 0x4a, 0x6f, 0xd6,
- 0xed, 0x15, 0xc3, 0x71, 0x08, 0x3a, 0xbf, 0xde, 0xa8, 0x2d, 0x54, 0xaf,
- 0x4a, 0x40, 0xbc, 0xe5, 0x53, 0xae, 0x4b, 0x3d, 0x70, 0xfe, 0x1c, 0x03,
- 0x1e, 0xb2, 0x9d, 0x1c, 0x35, 0xbd, 0x9a, 0xf8, 0xc5, 0xd1, 0xa5, 0x4a,
- 0x63, 0x18, 0x02, 0xd4, 0xff, 0xdd, 0xcd, 0xb3, 0x6c, 0x38, 0xd1, 0x9a,
- 0xad, 0x16, 0x71, 0xf1, 0xc6, 0x1d, 0x8f, 0x6c, 0x30, 0xfa, 0x2e, 0x13,
- 0x9d, 0x0b, 0x4e, 0xe6, 0xd3, 0x37, 0x80, 0x58, 0x26, 0x0d, 0x04, 0x97,
- 0xe6, 0x8d, 0xcc, 0x63, 0x3c, 0x39, 0x38, 0x2f, 0x7a, 0x73, 0x01, 0x0f,
- 0x22, 0x69, 0x47, 0x54, 0x9e, 0x42, 0xc8, 0x59, 0xb5, 0x35, 0x43, 0xb4,
- 0x37, 0x45, 0x59, 0x85, 0xf2, 0x47, 0xc3, 0xfb, 0x23, 0x13, 0x18, 0xef,
- 0xd8, 0x11, 0x70, 0x74, 0xce, 0x97, 0xcf, 0xbf, 0xd5, 0x2d, 0x99, 0x00,
- 0x86, 0x56, 0x9b, 0xdf, 0x05, 0x67, 0xf4, 0x49, 0x1e, 0xb5, 0x12, 0x23,
- 0x46, 0x04, 0x83, 0xf3, 0xc1, 0x59, 0xc7, 0x7b, 0xc3, 0x22, 0x0c, 0x2c,
- 0x1b, 0x7d, 0x18, 0xb6, 0xd2, 0xfa, 0x28, 0x36, 0x8b, 0x51, 0x6d, 0x58,
- 0xf4, 0xd6, 0xdf, 0x38, 0x94, 0xcf, 0x6c, 0x50, 0x4f, 0x0a, 0xf3, 0xc3,
- 0x91, 0x39, 0xa5, 0xc9, 0xbc, 0xa8, 0xeb, 0x24, 0x1a, 0xdd, 0x58, 0x9e,
- 0xdc, 0xb2, 0xee, 0xe1, 0xa5, 0x16, 0x68, 0xc2, 0x63, 0x8c, 0xc9, 0xa7,
- 0xbe, 0x1e, 0x30, 0x84, 0xa6, 0x28, 0xeb, 0x50, 0xd9, 0xdd, 0x15, 0xea,
- 0x64, 0x34, 0xf0, 0x7a, 0x56, 0x6a, 0xdd, 0xb2, 0x70, 0x2e, 0xea, 0x72,
- 0x66, 0x39, 0x54, 0xaa, 0x36, 0xfa, 0x68, 0xaa, 0x06, 0x5d, 0x48, 0xca,
- 0xad, 0x4e, 0xfe, 0x4b, 0x40, 0xdf, 0x43, 0x46, 0xd6, 0xdf, 0x3f, 0xa1,
- 0x9e, 0x4c, 0xdc, 0xfe, 0x4c, 0x01, 0x09, 0x7f, 0xd8, 0x00, 0x84, 0x94,
- 0x29, 0x17, 0x67, 0x00, 0xd3, 0x46, 0xd2, 0xba, 0xb9, 0x62, 0x66, 0x50,
- 0xcd, 0x7c, 0x7a, 0x70, 0x46, 0x4a, 0x32, 0x62, 0xc2, 0x6e, 0xe7, 0x5e,
- 0x04, 0x24, 0xc5, 0xfd, 0x9d, 0xf4, 0x9b, 0xc8, 0xe9, 0xeb, 0x73, 0xf9,
- 0xaa, 0xa4, 0xcc, 0x63, 0xa3, 0xdc, 0x63, 0xe0, 0x30, 0xec, 0x70, 0x40,
- 0x9e, 0x7c, 0x63, 0x79, 0xae, 0xba, 0xfd, 0x95, 0x4c, 0x46, 0xf1, 0xc4,
- 0xae, 0xb9, 0x03, 0xe8, 0xd4, 0xe4, 0x90, 0x29, 0x3a, 0xbb, 0xdb, 0xd8,
- 0x8f, 0x40, 0xc3, 0x39, 0x9a, 0x4c, 0x70, 0x54, 0x9f, 0xc9, 0x0a, 0x04,
- 0x23, 0x98, 0x6b, 0x9c, 0xc2, 0xe0, 0xad, 0xae, 0x30, 0xef, 0xff, 0x44,
- 0x5b, 0x73, 0x2e, 0x8f, 0xd7, 0x2b, 0x12, 0xf0, 0x31, 0x08, 0xfb, 0xb9,
- 0x55, 0xf0, 0xc3, 0x62, 0xbb, 0x5f, 0x6d, 0xa7, 0x1d, 0x61, 0xc2, 0x26,
- 0xce, 0xab, 0xb6, 0x88, 0x25, 0xce, 0x8b, 0x02, 0xb6, 0xc5, 0xa2, 0xcc,
- 0xd4, 0xa3, 0x74, 0x5b, 0x76, 0xf7, 0xb4, 0xd9, 0x9c, 0x93, 0x86, 0x7e,
- 0xac, 0x82, 0xe0, 0x0d, 0x83, 0xe1, 0xc9, 0x7f, 0x2a, 0x86, 0xbb, 0xaa,
- 0xfe, 0xdc, 0x17, 0x9c, 0x28, 0x77, 0xe1, 0x58, 0x18, 0x15, 0x09, 0xe3,
- 0xda, 0xdb, 0x8d, 0xee, 0x55, 0xf6, 0xda, 0xad, 0xe5, 0x52, 0x84, 0xb4,
- 0xf0, 0x24, 0xce, 0xa1, 0x54, 0x4b, 0x9f, 0xea, 0x5d, 0x4d, 0x7f, 0x53,
- 0x0b, 0x79, 0x1d, 0x87, 0xcb, 0x0b, 0xa8, 0xef, 0x03, 0xfa, 0x58, 0x57,
- 0xf6, 0x02, 0x70, 0xdb, 0x7a, 0x64, 0x89, 0x1f, 0xc7, 0xca, 0x87, 0x02,
- 0x27, 0x33, 0xc5, 0x5b, 0x2a, 0x50, 0xc5, 0xb5, 0x7b, 0x2d, 0x3d, 0xa9,
- 0xbc, 0x21, 0x7b, 0xf2, 0xbe, 0x9c, 0x56, 0x35, 0x83, 0xba, 0xce, 0x34,
- 0x8d, 0xec, 0x7b, 0xaa, 0xe4, 0xcb, 0xd1, 0x4f, 0x4a, 0x31, 0x00, 0xd1,
- 0xb8, 0x30, 0x38, 0xaf, 0xe8, 0xe3, 0xd7, 0xc2, 0x8c, 0xe3, 0xb4, 0x23,
- 0xb3, 0x27, 0x07, 0xc6, 0x88, 0xec, 0x58, 0xe9, 0x59, 0xfb, 0xa9, 0x11,
- 0xa2, 0xc8, 0x77, 0x22, 0x6a, 0x5b, 0x86, 0xde, 0xdc, 0xed, 0x76, 0x6e,
- 0x73, 0x79, 0x5c, 0xb4, 0xcf, 0x19, 0x76, 0x5c, 0x6b, 0x1c, 0x4b, 0x03,
- 0xcb, 0x35, 0x08, 0x94, 0x37, 0x01, 0x98, 0x52, 0xd8, 0x31, 0x42, 0x3d,
- 0x7f, 0xa1, 0x11, 0x06, 0x07, 0x88, 0xb8, 0x31, 0x35, 0xb2, 0x49, 0x28,
- 0xc6, 0x2c, 0x44, 0x43, 0xb6, 0xbc, 0x58, 0x76, 0x6c, 0x4f, 0xc8, 0xb6,
- 0x30, 0x82, 0x05, 0x84, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x01, 0xa0, 0x82, 0x05, 0x75, 0x04, 0x82, 0x05, 0x71, 0x30,
- 0x82, 0x05, 0x6d, 0x30, 0x82, 0x05, 0x69, 0x06, 0x0b, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x05, 0x31,
- 0x30, 0x82, 0x05, 0x2d, 0x30, 0x57, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x05, 0x0d, 0x30, 0x4a, 0x30, 0x29, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, 0x30, 0x1c, 0x04, 0x08,
- 0x79, 0x31, 0xf9, 0xe2, 0x42, 0x33, 0xf1, 0xaa, 0x02, 0x02, 0x08, 0x00,
- 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x09,
- 0x05, 0x00, 0x30, 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
- 0x04, 0x01, 0x02, 0x04, 0x10, 0xc9, 0xda, 0x5f, 0x96, 0xc8, 0x2c, 0x85,
- 0x5d, 0xa0, 0x30, 0x82, 0x16, 0x6b, 0xf4, 0xfd, 0x91, 0x04, 0x82, 0x04,
- 0xd0, 0xc3, 0x89, 0x6a, 0x56, 0x6a, 0x84, 0x58, 0x76, 0xd7, 0x23, 0xd5,
- 0xa8, 0xc1, 0x2f, 0x43, 0x38, 0x99, 0xf8, 0x64, 0x97, 0xe7, 0xe8, 0xd2,
- 0xcf, 0x36, 0x9b, 0x7e, 0x04, 0xe5, 0x87, 0x80, 0xff, 0xd5, 0x58, 0x50,
- 0x5a, 0xb3, 0xc0, 0x15, 0xc9, 0xd5, 0x61, 0xd6, 0x3b, 0x7f, 0x2f, 0x3b,
- 0x98, 0x50, 0x55, 0x09, 0xcf, 0xc3, 0xdd, 0xbd, 0x8b, 0xcd, 0xdf, 0x20,
- 0x90, 0xe1, 0xd2, 0xcd, 0x22, 0x9f, 0xa7, 0x3e, 0x10, 0xd3, 0xb7, 0x26,
- 0x54, 0x65, 0xfb, 0x18, 0x12, 0x58, 0x81, 0xd8, 0xe6, 0x97, 0xdf, 0x32,
- 0xd1, 0x04, 0x4a, 0xdb, 0x05, 0xb4, 0x13, 0xa9, 0x86, 0x62, 0x20, 0x94,
- 0xdc, 0xaf, 0x98, 0x53, 0x16, 0xc7, 0xb2, 0x9c, 0x44, 0x30, 0xc5, 0xaa,
- 0x14, 0x7a, 0x2d, 0x93, 0x20, 0xff, 0x6d, 0x8d, 0x47, 0x69, 0x6f, 0x39,
- 0xd4, 0x15, 0x81, 0x6b, 0x85, 0x36, 0xf9, 0x59, 0xa5, 0x8e, 0x5c, 0x40,
- 0x62, 0xf8, 0xfe, 0xf7, 0xe6, 0x75, 0xf7, 0x37, 0xfe, 0x5d, 0x53, 0xa6,
- 0x66, 0xe5, 0x0e, 0x4a, 0x23, 0xa9, 0x80, 0x4b, 0x04, 0x11, 0x0e, 0x50,
- 0xef, 0x9e, 0x88, 0xed, 0x39, 0xd1, 0x5f, 0xfa, 0x90, 0x22, 0xa3, 0x70,
- 0x0c, 0x8b, 0x20, 0x9c, 0x80, 0x2c, 0x90, 0x2e, 0x2c, 0xe0, 0xe6, 0x26,
- 0x84, 0xd8, 0x6a, 0xe4, 0x20, 0x1e, 0xbc, 0x96, 0xba, 0x07, 0x9d, 0x1d,
- 0x3d, 0x6c, 0xd1, 0x04, 0xc8, 0xd1, 0x79, 0x2c, 0x96, 0x0f, 0xe8, 0xa5,
- 0x6b, 0x03, 0x06, 0x51, 0xfd, 0x7b, 0x44, 0xab, 0x66, 0x4a, 0x41, 0x04,
- 0x02, 0x64, 0x5a, 0x40, 0x7d, 0x6b, 0x1a, 0xbc, 0x6e, 0xee, 0x68, 0x70,
- 0x3c, 0x10, 0x32, 0x73, 0x76, 0x28, 0x48, 0xd9, 0xa4, 0xe1, 0x21, 0xf6,
- 0xe4, 0x03, 0x94, 0x10, 0xef, 0x82, 0xe0, 0x76, 0x7c, 0x99, 0x30, 0x26,
- 0x9a, 0x95, 0xa2, 0xc5, 0xb9, 0xa7, 0xae, 0x9f, 0x85, 0xcb, 0xf1, 0x82,
- 0xcd, 0x3d, 0x06, 0xec, 0xaf, 0x72, 0xc1, 0x33, 0x09, 0xf9, 0x51, 0x94,
- 0x42, 0xf0, 0x69, 0xb9, 0xc6, 0x04, 0xe6, 0x7a, 0xfb, 0x1c, 0xee, 0xac,
- 0x95, 0x9b, 0x88, 0x67, 0x19, 0xa8, 0x79, 0x67, 0xc7, 0x1b, 0xcc, 0x72,
- 0xe9, 0x18, 0xd2, 0x96, 0xcf, 0x3d, 0xf8, 0x98, 0x20, 0x53, 0xc9, 0x37,
- 0x0f, 0x92, 0xb1, 0xbc, 0xaf, 0xc6, 0xec, 0x4f, 0x25, 0xda, 0x95, 0x14,
- 0xed, 0xb8, 0x3e, 0xaf, 0xd1, 0x52, 0x4c, 0x28, 0x3b, 0x84, 0x8c, 0x49,
- 0x34, 0x63, 0x2b, 0xd4, 0xf4, 0x78, 0xb1, 0x8f, 0xb0, 0x35, 0x7b, 0xd5,
- 0x44, 0xc3, 0x98, 0x9e, 0x85, 0x86, 0xae, 0xee, 0x05, 0xdd, 0xa1, 0x6f,
- 0x53, 0xe4, 0xdc, 0x6f, 0xf5, 0x7c, 0x7e, 0xd8, 0x7a, 0x9b, 0x18, 0x43,
- 0x3f, 0x7b, 0x2a, 0xf3, 0xb5, 0x39, 0x5a, 0x1c, 0x72, 0x3b, 0xdd, 0x01,
- 0x79, 0x97, 0xff, 0xdb, 0x58, 0xe5, 0x4d, 0x61, 0xde, 0xcf, 0x2f, 0x13,
- 0x7b, 0xaf, 0x6b, 0xa4, 0xf2, 0x59, 0x0a, 0x13, 0x56, 0x1c, 0x05, 0x00,
- 0x0f, 0x18, 0x66, 0x33, 0x72, 0xbd, 0x62, 0x8d, 0x11, 0xf7, 0x20, 0x52,
- 0x29, 0x42, 0x83, 0x33, 0xc1, 0x0f, 0x07, 0x80, 0xd4, 0x58, 0xe2, 0x22,
- 0x94, 0xad, 0xec, 0xbf, 0x01, 0xb6, 0x71, 0x7d, 0x92, 0xb1, 0x75, 0x14,
- 0xf2, 0xfb, 0x77, 0x39, 0x0d, 0x82, 0xb5, 0x51, 0xba, 0x1f, 0x65, 0x57,
- 0xaa, 0x68, 0x6a, 0x17, 0x41, 0x13, 0x38, 0xc0, 0xe5, 0xeb, 0xcc, 0x8c,
- 0xdd, 0xb7, 0x00, 0x4e, 0x01, 0x06, 0x25, 0xab, 0x87, 0x1c, 0x30, 0x69,
- 0xc4, 0x15, 0x0e, 0xf8, 0xf0, 0x72, 0xb6, 0x1d, 0x92, 0x7e, 0xe2, 0xe6,
- 0x77, 0xed, 0xb8, 0x3f, 0xcf, 0x57, 0x8d, 0x90, 0xe4, 0xa3, 0x79, 0x49,
- 0x9a, 0xe0, 0x1f, 0x4a, 0xde, 0xe9, 0x44, 0x8d, 0xd5, 0x23, 0x3b, 0x07,
- 0x63, 0x92, 0x9f, 0xde, 0xba, 0x7e, 0x67, 0xb0, 0x82, 0x41, 0x2a, 0xcd,
- 0xe1, 0xbb, 0x40, 0xf1, 0x8a, 0x66, 0x70, 0x74, 0xf1, 0x99, 0x7d, 0xb0,
- 0x0b, 0x6a, 0xa2, 0x5e, 0x7e, 0xc0, 0x8c, 0xb2, 0x71, 0xda, 0xcf, 0xbc,
- 0xfb, 0x9c, 0x03, 0x0e, 0x33, 0x5e, 0x13, 0xb2, 0x34, 0x38, 0xc1, 0x83,
- 0x95, 0xdf, 0x46, 0xfc, 0xe0, 0xe0, 0xaf, 0x93, 0xe0, 0x70, 0xd5, 0x15,
- 0x8c, 0x2f, 0xae, 0x4b, 0xa6, 0xeb, 0x13, 0x8f, 0xaf, 0x1b, 0xf5, 0x71,
- 0xc4, 0x62, 0x71, 0x08, 0x97, 0x10, 0x52, 0xfe, 0xbd, 0x60, 0xd7, 0x9f,
- 0xdf, 0x3d, 0xc5, 0xdd, 0xcd, 0xe7, 0x8e, 0x85, 0x60, 0xdf, 0x61, 0x79,
- 0x5b, 0x90, 0xd9, 0xaa, 0x56, 0x30, 0x6d, 0x0f, 0xfb, 0x27, 0x84, 0xdd,
- 0x3d, 0x04, 0x6a, 0xe0, 0x70, 0x7e, 0xbb, 0x59, 0xf4, 0xeb, 0xe8, 0xc0,
- 0x62, 0xaa, 0xf6, 0xed, 0xca, 0xae, 0xb2, 0x2b, 0x0f, 0xc1, 0x56, 0x45,
- 0xe7, 0x24, 0x6b, 0xaf, 0xeb, 0x15, 0x26, 0xb2, 0xcd, 0xae, 0x1f, 0xe7,
- 0x11, 0xc0, 0x1c, 0x19, 0x4a, 0xc7, 0x51, 0x2a, 0x29, 0xdf, 0x14, 0x82,
- 0x43, 0xfe, 0x52, 0x39, 0xba, 0xe6, 0x6c, 0xa5, 0x76, 0x8b, 0xb1, 0x21,
- 0x9c, 0x20, 0xb0, 0x10, 0x0c, 0x44, 0xf2, 0xd4, 0x6e, 0x41, 0x1b, 0x8f,
- 0x90, 0x23, 0xe3, 0x87, 0xfc, 0xf1, 0x46, 0xc6, 0x5b, 0xae, 0xd0, 0x2a,
- 0x2b, 0x78, 0xf5, 0x2b, 0xb9, 0x9f, 0x46, 0x4b, 0x30, 0xf8, 0x49, 0x57,
- 0x7e, 0xb4, 0xff, 0xca, 0xad, 0x4d, 0xf3, 0xc1, 0x7b, 0x42, 0xe0, 0xa4,
- 0x37, 0x2f, 0xe2, 0xb2, 0x60, 0xe8, 0xaf, 0xd7, 0x39, 0x23, 0x4c, 0x67,
- 0x44, 0xe5, 0x6d, 0xb3, 0x25, 0x11, 0x9f, 0x2b, 0xea, 0x23, 0xfb, 0x1e,
- 0xce, 0xbf, 0xa4, 0x2f, 0x88, 0xec, 0x18, 0x40, 0x16, 0x43, 0x9f, 0x71,
- 0x9c, 0x8d, 0xbd, 0x5d, 0x55, 0x3b, 0x92, 0x4e, 0x23, 0x3c, 0x87, 0xed,
- 0x5f, 0x2e, 0x8f, 0xde, 0x83, 0xad, 0x30, 0x42, 0x7e, 0x1a, 0x5e, 0xf5,
- 0xc5, 0x75, 0xbb, 0x99, 0x6e, 0xf1, 0x87, 0xe0, 0xf3, 0x51, 0x1e, 0x7d,
- 0xe8, 0xfc, 0xc6, 0x88, 0xf2, 0x39, 0x6d, 0xae, 0x73, 0x9f, 0xad, 0x9b,
- 0x7b, 0x67, 0x99, 0xdb, 0x90, 0x0e, 0xa0, 0xfc, 0xaf, 0xcc, 0xdb, 0x8b,
- 0xaa, 0xc2, 0x54, 0xd5, 0x2d, 0xb3, 0x5f, 0xa3, 0x0a, 0x3e, 0xd6, 0x8d,
- 0x40, 0x4d, 0x3b, 0xe5, 0x2d, 0x31, 0xd8, 0xb2, 0x12, 0x07, 0xca, 0x36,
- 0x56, 0xd9, 0x2f, 0x55, 0x82, 0xdc, 0x8e, 0x92, 0xa9, 0x6c, 0x91, 0x9e,
- 0x22, 0xe4, 0xc6, 0x27, 0x8b, 0x1a, 0xa2, 0x78, 0x56, 0x2c, 0x5a, 0x19,
- 0xdf, 0x40, 0xf9, 0xfb, 0x44, 0x21, 0x5b, 0xdf, 0x2f, 0x99, 0x84, 0x49,
- 0xcf, 0x1a, 0x15, 0xa5, 0x59, 0x3a, 0x66, 0x09, 0x4d, 0xc1, 0xf2, 0xb1,
- 0x24, 0x33, 0xbd, 0x86, 0x41, 0xdc, 0x33, 0x9b, 0x03, 0xc0, 0xa8, 0xf8,
- 0x94, 0x78, 0x2e, 0x16, 0x97, 0xef, 0x23, 0xee, 0xa4, 0xac, 0x3a, 0x90,
- 0xb6, 0xd9, 0xc0, 0xda, 0x5e, 0x26, 0x34, 0x26, 0xce, 0xc9, 0xf8, 0x45,
- 0x37, 0x83, 0x7c, 0xbd, 0x9c, 0x60, 0x40, 0x61, 0x28, 0xcd, 0x9c, 0xb4,
- 0xe4, 0xe6, 0x5c, 0x4f, 0xd1, 0x79, 0x42, 0x13, 0xa9, 0x6f, 0x26, 0x23,
- 0xc2, 0x6c, 0x8e, 0x8d, 0x7e, 0x3f, 0xee, 0x2b, 0x4d, 0xd2, 0x5b, 0x80,
- 0xdc, 0x74, 0xda, 0x1f, 0xbc, 0x26, 0x54, 0xc5, 0xfe, 0xee, 0xa9, 0x4f,
- 0xce, 0x46, 0xaf, 0x90, 0xb0, 0x12, 0x9a, 0x18, 0x0e, 0x06, 0x05, 0xc7,
- 0x98, 0xef, 0xcc, 0x6d, 0xa3, 0x46, 0x91, 0xa5, 0x0e, 0xe7, 0x35, 0x1a,
- 0x7f, 0x9d, 0xae, 0xa0, 0xb4, 0x0a, 0x32, 0x3b, 0xe4, 0xcd, 0x4b, 0x3e,
- 0x89, 0x73, 0xc9, 0x97, 0x38, 0xe5, 0x86, 0x4f, 0x24, 0xed, 0x4a, 0x43,
- 0x04, 0x02, 0xc1, 0x29, 0x8d, 0x85, 0xa2, 0xdd, 0xb2, 0x61, 0x3c, 0xce,
- 0x8b, 0x47, 0x2e, 0xed, 0x4b, 0x24, 0x94, 0xb7, 0xbf, 0x9d, 0x55, 0x42,
- 0x95, 0xc2, 0x27, 0xe5, 0x09, 0xd4, 0x20, 0x03, 0x20, 0x21, 0x3a, 0xd8,
- 0xd2, 0xa2, 0xb3, 0x47, 0x93, 0x4f, 0x5a, 0x39, 0xca, 0xd8, 0x74, 0xa9,
- 0x19, 0xa6, 0x9a, 0x23, 0xb1, 0x21, 0xa3, 0xb3, 0x14, 0xcc, 0xe2, 0x12,
- 0x91, 0x30, 0xdb, 0x50, 0xf8, 0x44, 0x74, 0xd6, 0x70, 0xdd, 0x7d, 0x26,
- 0x7f, 0xbf, 0x32, 0x93, 0x1f, 0x3d, 0x40, 0xbf, 0x2e, 0xec, 0x28, 0xf5,
- 0xb1, 0xaf, 0x11, 0xc7, 0x4e, 0x64, 0x13, 0x3c, 0xbf, 0x2e, 0x19, 0x81,
- 0xfe, 0x35, 0xba, 0xec, 0x6e, 0xb6, 0xa9, 0xfe, 0xc6, 0x85, 0x33, 0x41,
- 0x58, 0xab, 0x06, 0xae, 0x2b, 0x96, 0x62, 0x1f, 0x2c, 0x6c, 0xad, 0xec,
- 0x1a, 0x59, 0x55, 0x5a, 0x6f, 0xe0, 0xeb, 0x71, 0x8d, 0xb5, 0x0c, 0x81,
- 0x2a, 0x39, 0xbd, 0x67, 0x39, 0x48, 0xfb, 0x91, 0x64, 0xad, 0x01, 0x4c,
- 0x4a, 0x0f, 0x30, 0x29, 0xa0, 0xcf, 0x30, 0x96, 0x43, 0xe9, 0xfc, 0x22,
- 0x4b, 0xf3, 0x4f, 0xab, 0xec, 0xbc, 0x5a, 0xfb, 0x7f, 0x20, 0xd9, 0xd5,
- 0xc7, 0xce, 0x93, 0xa3, 0x2e, 0x82, 0xd1, 0xa0, 0xc6, 0x16, 0xd5, 0x64,
- 0x2d, 0x3f, 0x69, 0x15, 0xfd, 0xf3, 0x28, 0x3d, 0x4e, 0x61, 0x01, 0x2c,
- 0xd4, 0x2b, 0x40, 0x51, 0x6e, 0x95, 0x00, 0xa4, 0x34, 0x31, 0x25, 0x30,
- 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15,
- 0x31, 0x16, 0x04, 0x14, 0x47, 0xf4, 0x18, 0xa5, 0x4b, 0x85, 0xb7, 0x02,
- 0xc1, 0x97, 0xff, 0x57, 0xb6, 0x6f, 0x21, 0x45, 0x34, 0x3d, 0x92, 0x22,
- 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
- 0x1a, 0x05, 0x00, 0x04, 0x14, 0x17, 0x45, 0x0c, 0xdf, 0x53, 0x76, 0x9b,
- 0xce, 0x3b, 0x12, 0xdd, 0x47, 0x05, 0x6d, 0x16, 0x90, 0x9d, 0x29, 0x9b,
- 0xe1, 0x04, 0x08, 0xa1, 0xf2, 0x82, 0x1c, 0xd1, 0xd1, 0x7b, 0x5c, 0x02,
- 0x02, 0x08, 0x00,
-};
-
-// kNoEncryption is a PKCS#12 file with neither the key or certificate is
-// encrypted. It was generated with:
-//
-// openssl pkcs12 -export -inkey ecdsa_p256_key.pem -in ecdsa_p256_cert.pem -keypbe NONE -certpbe NONE -password pass:foo
-static const uint8_t kNoEncryption[] = {
- 0x30, 0x82, 0x03, 0x6e, 0x02, 0x01, 0x03, 0x30, 0x82, 0x03, 0x34, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
- 0x03, 0x25, 0x04, 0x82, 0x03, 0x21, 0x30, 0x82, 0x03, 0x1d, 0x30, 0x82,
- 0x02, 0x3e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x01, 0xa0, 0x82, 0x02, 0x2f, 0x04, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x02,
- 0x27, 0x30, 0x82, 0x02, 0x23, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x03, 0xa0, 0x82, 0x01, 0xeb, 0x30, 0x82,
- 0x01, 0xe7, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
- 0x16, 0x01, 0xa0, 0x82, 0x01, 0xd7, 0x04, 0x82, 0x01, 0xd3, 0x30, 0x82,
- 0x01, 0xcf, 0x30, 0x82, 0x01, 0x76, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
- 0x09, 0x00, 0xd9, 0x4c, 0x04, 0xda, 0x49, 0x7d, 0xbf, 0xeb, 0x30, 0x09,
- 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01, 0x30, 0x45, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55,
- 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53,
- 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30,
- 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73,
- 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
- 0x31, 0x34, 0x30, 0x34, 0x32, 0x33, 0x32, 0x33, 0x32, 0x31, 0x35, 0x37,
- 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, 0x32, 0x33, 0x32, 0x33, 0x32,
- 0x31, 0x35, 0x37, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53,
- 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20,
- 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
- 0x4c, 0x74, 0x64, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48,
- 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
- 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65,
- 0x9f, 0x97, 0xbe, 0x2f, 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b,
- 0xb7, 0xa9, 0x1e, 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc,
- 0xba, 0x5a, 0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4,
- 0xa3, 0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5,
- 0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, 0xa3, 0x50,
- 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
- 0x14, 0xab, 0x84, 0xd2, 0xac, 0xab, 0x95, 0xf0, 0x82, 0x4e, 0x16, 0x78,
- 0x07, 0x55, 0x57, 0x5f, 0xe4, 0x26, 0x8d, 0x82, 0xd1, 0x30, 0x1f, 0x06,
- 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xab, 0x84,
- 0xd2, 0xac, 0xab, 0x95, 0xf0, 0x82, 0x4e, 0x16, 0x78, 0x07, 0x55, 0x57,
- 0x5f, 0xe4, 0x26, 0x8d, 0x82, 0xd1, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
- 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x09, 0x06, 0x07,
- 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01, 0x03, 0x48, 0x00, 0x30, 0x45,
- 0x02, 0x21, 0x00, 0xf2, 0xa0, 0x35, 0x5e, 0x51, 0x3a, 0x36, 0xc3, 0x82,
- 0x79, 0x9b, 0xee, 0x27, 0x50, 0x85, 0x8e, 0x70, 0x06, 0x74, 0x95, 0x57,
- 0xd2, 0x29, 0x74, 0x00, 0xf4, 0xbe, 0x15, 0x87, 0x5d, 0xc4, 0x07, 0x02,
- 0x20, 0x7c, 0x1e, 0x79, 0x14, 0x6a, 0x21, 0x83, 0xf0, 0x7a, 0x74, 0x68,
- 0x79, 0x5f, 0x14, 0x99, 0x9a, 0x68, 0xb4, 0xf1, 0xcb, 0x9e, 0x15, 0x5e,
- 0xe6, 0x1f, 0x32, 0x52, 0x61, 0x5e, 0x75, 0xc9, 0x14, 0x31, 0x25, 0x30,
- 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15,
- 0x31, 0x16, 0x04, 0x14, 0x3f, 0x31, 0x38, 0xec, 0xb9, 0xf1, 0x45, 0xe1,
- 0x3e, 0x90, 0x71, 0x0d, 0xc1, 0x28, 0xba, 0x4e, 0x6f, 0xa0, 0x9c, 0xed,
- 0x30, 0x81, 0xd8, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x07, 0x01, 0xa0, 0x81, 0xca, 0x04, 0x81, 0xc7, 0x30, 0x81, 0xc4, 0x30,
- 0x81, 0xc1, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c,
- 0x0a, 0x01, 0x01, 0xa0, 0x81, 0x8a, 0x30, 0x81, 0x87, 0x02, 0x01, 0x00,
- 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
- 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30,
- 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, 0x07, 0x0f, 0x08, 0x72, 0x7a, 0xd4,
- 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9, 0x4d, 0x89, 0x68, 0x77, 0x08, 0xb5,
- 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e, 0xe8, 0xd1, 0xc9, 0xce, 0x0a, 0x8b,
- 0xb4, 0x6a, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2,
- 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5,
- 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e,
- 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9,
- 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a,
- 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1,
- 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x3f, 0x31, 0x38, 0xec, 0xb9,
- 0xf1, 0x45, 0xe1, 0x3e, 0x90, 0x71, 0x0d, 0xc1, 0x28, 0xba, 0x4e, 0x6f,
- 0xa0, 0x9c, 0xed, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b,
- 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0xd0, 0xb4, 0x17, 0x1a,
- 0xdb, 0xa3, 0x27, 0xd8, 0x9e, 0xd3, 0xf2, 0xb3, 0x3e, 0x96, 0x07, 0x3a,
- 0xf2, 0x6a, 0xc2, 0x1c, 0x04, 0x08, 0xb5, 0xa8, 0xb9, 0xdb, 0x2f, 0xf1,
- 0xa4, 0xcd, 0x02, 0x02, 0x08, 0x00,
-};
+std::string GetTestData(const char *path);
+// kPassword is the password shared by most of the sample PKCS#12 files.
static const char kPassword[] = "foo";
-// Generated with
-// openssl pkcs12 -export -inkey ecdsa_p256_key.pem -in ecdsa_p256_cert.pem -password pass:
-static const uint8_t kEmptyPassword[] = {
- 0x30, 0x82, 0x03, 0xd2, 0x02, 0x01, 0x03, 0x30, 0x82, 0x03, 0x98, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
- 0x03, 0x89, 0x04, 0x82, 0x03, 0x85, 0x30, 0x82, 0x03, 0x81, 0x30, 0x82,
- 0x02, 0x77, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x06, 0xa0, 0x82, 0x02, 0x68, 0x30, 0x82, 0x02, 0x64, 0x02, 0x01, 0x00,
- 0x30, 0x82, 0x02, 0x5d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0xe2, 0xb3, 0x39,
- 0xd2, 0xbd, 0x5a, 0x8c, 0x0e, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x02,
- 0x30, 0x78, 0x22, 0x01, 0x8c, 0x16, 0xcd, 0x11, 0x86, 0xa1, 0xc7, 0x6e,
- 0xc4, 0x77, 0xa1, 0x8d, 0xb4, 0x85, 0xc3, 0xb2, 0x02, 0x63, 0x70, 0x8b,
- 0xfb, 0xb0, 0x5c, 0x8f, 0x1c, 0xec, 0x0f, 0xc7, 0x7d, 0xb6, 0x0a, 0x03,
- 0x5f, 0x20, 0x00, 0x32, 0x2d, 0x2e, 0x12, 0x4e, 0x5a, 0x60, 0x48, 0x6f,
- 0xd0, 0xe9, 0x8c, 0x15, 0x59, 0x5c, 0x62, 0xe6, 0x24, 0x4c, 0xfd, 0x1f,
- 0x30, 0xa1, 0x22, 0x8b, 0x0f, 0xe5, 0x37, 0x82, 0x6b, 0x19, 0x0d, 0xcc,
- 0x85, 0x4d, 0xce, 0x64, 0x9b, 0x82, 0x29, 0xfe, 0x4a, 0xe4, 0x11, 0xd2,
- 0xe6, 0x01, 0xce, 0xdb, 0x54, 0x64, 0x6b, 0x07, 0x69, 0xb5, 0x19, 0xfb,
- 0xf1, 0x72, 0x84, 0x3c, 0x4e, 0x8d, 0x64, 0xfd, 0xa9, 0x33, 0xaa, 0x1d,
- 0x59, 0x1a, 0x3c, 0xcd, 0x1e, 0xee, 0x3a, 0x3e, 0x8a, 0x9c, 0xf1, 0x21,
- 0x24, 0xeb, 0x52, 0xd1, 0x7f, 0x32, 0x57, 0x68, 0xa0, 0xac, 0x2d, 0x94,
- 0xe8, 0x4c, 0x59, 0xa3, 0x43, 0xfb, 0x18, 0x79, 0x4c, 0xbe, 0xc2, 0x84,
- 0x3d, 0x6e, 0xb3, 0x2f, 0xc8, 0x72, 0xbc, 0x29, 0xec, 0x06, 0x87, 0xc3,
- 0x9a, 0x48, 0x40, 0x0e, 0xe6, 0x34, 0xc1, 0x4a, 0xf7, 0x2a, 0x6e, 0xe0,
- 0x0c, 0x9c, 0xa2, 0x32, 0x55, 0xd6, 0x43, 0x2c, 0x9d, 0x74, 0x4b, 0xf0,
- 0x5c, 0xaa, 0x2f, 0x6b, 0xb4, 0xa3, 0xb6, 0x10, 0xe1, 0x20, 0xad, 0xa2,
- 0xb7, 0x31, 0x54, 0x1c, 0x92, 0x55, 0xb1, 0x47, 0x9b, 0x56, 0xe7, 0x89,
- 0x90, 0x40, 0xa4, 0x87, 0x71, 0x38, 0x95, 0xec, 0x43, 0x26, 0x4b, 0x59,
- 0xad, 0x6d, 0xf0, 0xc2, 0xf7, 0x6f, 0xa0, 0x9a, 0xbb, 0x23, 0x50, 0x44,
- 0xbf, 0x8f, 0x49, 0x37, 0xc9, 0x4f, 0xd5, 0x23, 0x7e, 0xf6, 0x5d, 0xfb,
- 0xd8, 0x07, 0x64, 0xe0, 0xa8, 0xa3, 0x3a, 0x3e, 0xc7, 0x8f, 0x57, 0x8a,
- 0xb2, 0x5b, 0xc9, 0xfc, 0x27, 0x25, 0x2d, 0xcd, 0xcc, 0x9b, 0x5c, 0x44,
- 0x07, 0x7d, 0xf4, 0xad, 0x42, 0x12, 0x25, 0x48, 0x14, 0x56, 0x22, 0x66,
- 0xe5, 0xec, 0xe8, 0x76, 0x32, 0xe3, 0x18, 0xb1, 0xac, 0x2b, 0x0f, 0xd2,
- 0x92, 0x82, 0xe2, 0xd4, 0x42, 0x0d, 0x0d, 0x31, 0xb3, 0x8e, 0x53, 0x17,
- 0xc4, 0x8a, 0x0a, 0xf9, 0x6f, 0x39, 0xd1, 0x09, 0x55, 0x04, 0xe5, 0x09,
- 0x15, 0xe7, 0x3f, 0x2a, 0xf0, 0x89, 0xff, 0xb1, 0xa8, 0xe3, 0x8a, 0xf8,
- 0x9b, 0xa4, 0x34, 0x93, 0xea, 0x46, 0x26, 0xcf, 0x23, 0x73, 0x82, 0x87,
- 0x7c, 0xe3, 0xd2, 0x9b, 0x49, 0x53, 0x5b, 0x99, 0xa9, 0xd4, 0x87, 0xa4,
- 0xf0, 0xd0, 0x82, 0x40, 0xb0, 0x0b, 0x8c, 0xb2, 0x72, 0xca, 0x2c, 0xb1,
- 0x57, 0x54, 0x65, 0xf6, 0x88, 0xbb, 0x0d, 0x93, 0xac, 0xcb, 0x73, 0x90,
- 0xa8, 0x7b, 0x16, 0x55, 0x73, 0x7e, 0x7e, 0xe3, 0xe1, 0xc5, 0xc4, 0x0c,
- 0x36, 0x5e, 0x33, 0x91, 0x49, 0x9c, 0x71, 0x11, 0xf5, 0xd3, 0x5b, 0x38,
- 0xbd, 0xe6, 0xb5, 0x0f, 0x72, 0x8c, 0x34, 0xc6, 0x18, 0x6c, 0xc9, 0xe5,
- 0x40, 0x9c, 0xbe, 0xd8, 0x3e, 0x4d, 0x42, 0xd3, 0x96, 0x98, 0x14, 0x51,
- 0x29, 0xba, 0xed, 0x4c, 0x4f, 0x09, 0x50, 0x47, 0xf1, 0x84, 0x14, 0x65,
- 0x07, 0x85, 0x82, 0xad, 0x72, 0x34, 0x54, 0x5b, 0x0e, 0x44, 0x5d, 0xb8,
- 0x2c, 0x71, 0x67, 0x55, 0x20, 0x73, 0x20, 0xb9, 0x56, 0x7a, 0x69, 0x46,
- 0xca, 0x24, 0x47, 0x43, 0xd9, 0x47, 0xe7, 0x78, 0x7e, 0xc6, 0xfc, 0x59,
- 0xe5, 0xd9, 0x75, 0xe7, 0x65, 0x2e, 0xd8, 0xa3, 0x6e, 0x58, 0xdd, 0x96,
- 0x6b, 0xf4, 0x30, 0xd2, 0x3c, 0x42, 0xce, 0x2a, 0x9c, 0x7f, 0xa7, 0x69,
- 0xdf, 0xf5, 0x78, 0xc1, 0x83, 0x1e, 0x21, 0x5a, 0xad, 0x2a, 0x6a, 0x0a,
- 0x8b, 0x93, 0xa0, 0x0b, 0x96, 0x6d, 0xd9, 0xaa, 0x57, 0xa9, 0xd2, 0x31,
- 0x21, 0x52, 0x11, 0x51, 0x4b, 0x85, 0xe5, 0x07, 0x2f, 0x9b, 0x50, 0xff,
- 0xa7, 0x93, 0x93, 0xa7, 0xf6, 0x9e, 0x39, 0xc8, 0xfd, 0x53, 0x4d, 0x6d,
- 0x64, 0x2b, 0xdd, 0xc6, 0x7e, 0xe8, 0xfe, 0x04, 0xa8, 0x20, 0xf8, 0xb3,
- 0xa2, 0x5b, 0xa0, 0x0b, 0x27, 0x8a, 0x25, 0x70, 0x95, 0x30, 0x82, 0x01,
- 0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
- 0xa0, 0x81, 0xf4, 0x04, 0x81, 0xf1, 0x30, 0x81, 0xee, 0x30, 0x81, 0xeb,
- 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01,
- 0x02, 0xa0, 0x81, 0xb4, 0x30, 0x81, 0xb1, 0x30, 0x1c, 0x06, 0x0a, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04,
- 0x08, 0x3b, 0xa5, 0xb3, 0x6e, 0x74, 0x4b, 0xef, 0x0c, 0x02, 0x02, 0x08,
- 0x00, 0x04, 0x81, 0x90, 0x36, 0x54, 0x47, 0x07, 0xf6, 0xa4, 0x5f, 0xb1,
- 0x28, 0xd7, 0xcb, 0x92, 0xe1, 0xbd, 0x43, 0xa9, 0xf0, 0xa2, 0x07, 0x97,
- 0x29, 0x0d, 0xec, 0x4a, 0xea, 0xd1, 0x14, 0xe9, 0xa5, 0x10, 0xcb, 0x52,
- 0x26, 0x2e, 0x18, 0xf8, 0xc8, 0x73, 0xf4, 0xee, 0x91, 0x8e, 0x78, 0xc1,
- 0x38, 0xd7, 0x7c, 0x9b, 0x5d, 0xb9, 0x64, 0x49, 0x5f, 0x23, 0x6b, 0xe4,
- 0xf1, 0xe1, 0x72, 0x71, 0xb9, 0xad, 0xdf, 0x31, 0x9a, 0xab, 0xd0, 0xad,
- 0x17, 0xb9, 0x2d, 0x4b, 0x8e, 0xbe, 0xe0, 0xb1, 0x94, 0xd6, 0xc0, 0x37,
- 0xee, 0x38, 0x65, 0xc0, 0xc5, 0x4e, 0x09, 0x7a, 0x02, 0x17, 0xd8, 0x4f,
- 0x83, 0x4f, 0xa2, 0x2e, 0x62, 0xb6, 0x97, 0x3e, 0x36, 0xbd, 0x15, 0x08,
- 0x40, 0x50, 0xc1, 0x8b, 0x7e, 0x9b, 0xc6, 0x79, 0xe1, 0x1e, 0xaf, 0xd9,
- 0x53, 0x82, 0x61, 0xb2, 0x52, 0x8a, 0xf2, 0x56, 0x70, 0xc3, 0x72, 0xcd,
- 0xa9, 0xb5, 0xf0, 0x6a, 0xc0, 0x4b, 0x89, 0xe5, 0x7c, 0x93, 0xb9, 0x1e,
- 0x68, 0xb4, 0x3a, 0xc3, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x3f,
- 0x31, 0x38, 0xec, 0xb9, 0xf1, 0x45, 0xe1, 0x3e, 0x90, 0x71, 0x0d, 0xc1,
- 0x28, 0xba, 0x4e, 0x6f, 0xa0, 0x9c, 0xed, 0x30, 0x31, 0x30, 0x21, 0x30,
- 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
- 0x7f, 0xd4, 0x5b, 0x84, 0x34, 0xb7, 0xf9, 0x87, 0x88, 0x7c, 0x52, 0x7a,
- 0x79, 0x02, 0x96, 0x58, 0xcc, 0xdb, 0x9d, 0xf2, 0x04, 0x08, 0x62, 0xf5,
- 0x7d, 0x8f, 0x84, 0xe5, 0x64, 0x25, 0x02, 0x02, 0x08, 0x00};
-
-// Generated with
-// openssl pkcs12 -export -inkey ecdsa_p256_key.pem -in ecdsa_p256_cert.pem -password pass:
-// But with OpenSSL patched to pass NULL into PKCS12_create and PKCS12_set_mac.
-static const uint8_t kNullPassword[] = {
- 0x30, 0x82, 0x03, 0xd2, 0x02, 0x01, 0x03, 0x30, 0x82, 0x03, 0x98, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
- 0x03, 0x89, 0x04, 0x82, 0x03, 0x85, 0x30, 0x82, 0x03, 0x81, 0x30, 0x82,
- 0x02, 0x77, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x06, 0xa0, 0x82, 0x02, 0x68, 0x30, 0x82, 0x02, 0x64, 0x02, 0x01, 0x00,
- 0x30, 0x82, 0x02, 0x5d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x72, 0xdc, 0x9c,
- 0xcd, 0xe8, 0x69, 0xd5, 0xcc, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x02,
- 0x30, 0x35, 0xfd, 0xee, 0x78, 0x47, 0x71, 0x12, 0x87, 0xc2, 0xcf, 0x1c,
- 0x12, 0xc4, 0x7a, 0x68, 0x6a, 0xb5, 0x21, 0xd6, 0xa4, 0x1a, 0x0d, 0xd3,
- 0x47, 0x6b, 0xad, 0xf0, 0xe0, 0xfc, 0x58, 0x6b, 0xd1, 0xf1, 0x1a, 0xce,
- 0xf5, 0x55, 0xca, 0x3b, 0x85, 0x18, 0x7e, 0x0d, 0x1e, 0x33, 0xcd, 0xf0,
- 0xd1, 0x0c, 0x26, 0x67, 0x67, 0x44, 0xba, 0x71, 0x93, 0xf8, 0xa4, 0xe0,
- 0x18, 0xe2, 0x1a, 0x23, 0x8e, 0xb5, 0xc7, 0xdc, 0xe1, 0x73, 0xa9, 0xa6,
- 0x03, 0xb1, 0x3a, 0x3a, 0xbd, 0x21, 0x51, 0x04, 0x30, 0xf0, 0x9e, 0xb5,
- 0xc9, 0xee, 0x5d, 0x7c, 0xf4, 0xae, 0x55, 0xd7, 0x15, 0x0c, 0xb3, 0x50,
- 0xa4, 0x52, 0x49, 0x74, 0x1a, 0xb3, 0xe9, 0xe8, 0x95, 0x4d, 0x57, 0x11,
- 0x5a, 0x8b, 0xf2, 0xdb, 0x2c, 0x2b, 0x79, 0xb0, 0xee, 0x1f, 0xd2, 0x02,
- 0xa4, 0x4c, 0x44, 0x1c, 0x7b, 0xea, 0x81, 0x8d, 0x5c, 0x1d, 0x52, 0xbe,
- 0x68, 0xf1, 0x56, 0x96, 0xf1, 0x14, 0x62, 0x2c, 0x34, 0x12, 0xbc, 0x7e,
- 0xa4, 0x59, 0x46, 0x6d, 0x9e, 0x97, 0xd5, 0x2a, 0x33, 0x43, 0x85, 0x93,
- 0x06, 0xf7, 0x8a, 0xc9, 0xd1, 0xb5, 0x91, 0x4a, 0x52, 0xba, 0xde, 0xca,
- 0x34, 0x65, 0x4b, 0x0a, 0xc8, 0x8a, 0xb1, 0xf1, 0x72, 0x21, 0x40, 0xc6,
- 0x6f, 0x23, 0xf7, 0x42, 0xb9, 0xec, 0xbb, 0xf1, 0x43, 0x1b, 0x98, 0x6e,
- 0xba, 0xe4, 0xee, 0x33, 0xc3, 0x51, 0xcb, 0x0c, 0x67, 0x7e, 0x19, 0xb3,
- 0x4e, 0x20, 0xab, 0x5a, 0x27, 0x81, 0xbb, 0x74, 0xd0, 0x2c, 0xa6, 0x16,
- 0x18, 0x57, 0xdd, 0xcf, 0xf9, 0xdc, 0x3d, 0x6d, 0x53, 0x2c, 0x91, 0xb6,
- 0xf1, 0xe6, 0xe2, 0xee, 0xc3, 0xc4, 0x06, 0x62, 0x98, 0x83, 0x2a, 0xe8,
- 0xc7, 0xdd, 0x22, 0xbc, 0xd1, 0xeb, 0x1f, 0xd5, 0x33, 0x49, 0x52, 0x72,
- 0x01, 0x84, 0x3a, 0x9e, 0xbd, 0x98, 0x9b, 0x44, 0xff, 0x58, 0x66, 0x6e,
- 0x03, 0x9a, 0x96, 0x52, 0x9e, 0x1d, 0xa2, 0x59, 0xc5, 0x5b, 0x32, 0xe1,
- 0x9e, 0xb0, 0xe0, 0x8c, 0xfb, 0x4c, 0x41, 0x04, 0x3a, 0x4e, 0x41, 0x3d,
- 0x7c, 0x01, 0x50, 0x8f, 0xe9, 0x21, 0xaa, 0xfc, 0x8b, 0x56, 0x64, 0xe2,
- 0x6b, 0x48, 0x74, 0x9f, 0x57, 0x21, 0x3e, 0x7f, 0x79, 0x12, 0x09, 0x84,
- 0x48, 0xa2, 0xcd, 0xdb, 0xb0, 0x27, 0x34, 0xf1, 0xef, 0x3c, 0xe5, 0xef,
- 0xe4, 0xe2, 0x1f, 0x04, 0x85, 0xc6, 0x00, 0x50, 0x19, 0x65, 0x1b, 0x7d,
- 0x0b, 0x60, 0x09, 0xe5, 0xe1, 0xd1, 0x71, 0xdc, 0x2f, 0x5e, 0xfa, 0x86,
- 0xf0, 0x8c, 0xf0, 0xf0, 0xf0, 0x46, 0xc5, 0xff, 0xc7, 0xcb, 0x6f, 0x37,
- 0x94, 0xc5, 0xb7, 0x62, 0xcb, 0xbc, 0x44, 0x2c, 0x0b, 0x96, 0xb7, 0x1d,
- 0x4f, 0xd6, 0xb0, 0x58, 0x50, 0x2f, 0xd6, 0xef, 0xe6, 0xfb, 0x75, 0x4c,
- 0xcf, 0xa6, 0x23, 0x79, 0xd1, 0x94, 0x7c, 0xaf, 0xff, 0x4e, 0x20, 0x61,
- 0x5f, 0x1d, 0x79, 0x59, 0x5c, 0x78, 0xd2, 0xad, 0xda, 0x87, 0xb9, 0x20,
- 0x5b, 0x67, 0x50, 0x82, 0x8b, 0x5f, 0xb0, 0x58, 0x99, 0x62, 0xa6, 0xd2,
- 0x03, 0x82, 0xbc, 0x8e, 0x89, 0xba, 0x9c, 0xe5, 0x20, 0x9a, 0x42, 0x37,
- 0x5f, 0x5b, 0x7b, 0xf0, 0x64, 0xf2, 0xc5, 0x54, 0x22, 0x9e, 0x15, 0xec,
- 0xca, 0xf7, 0x27, 0xad, 0x3a, 0xfb, 0x3c, 0xc0, 0x11, 0x9e, 0x4b, 0x5f,
- 0x41, 0xf1, 0xcd, 0x0e, 0xca, 0x9b, 0xb5, 0x0d, 0xab, 0x29, 0x76, 0x67,
- 0x04, 0x1b, 0xff, 0x52, 0xc7, 0x2c, 0x14, 0xd6, 0x04, 0x23, 0xc9, 0xcf,
- 0xf4, 0x3b, 0x71, 0x93, 0xb7, 0xe2, 0x2f, 0xe6, 0x1a, 0x32, 0x19, 0xba,
- 0x1c, 0x93, 0x87, 0x73, 0x7d, 0x51, 0x1d, 0x6b, 0x75, 0xbd, 0x17, 0xff,
- 0xef, 0xd0, 0x8f, 0x65, 0x37, 0xa0, 0x48, 0x67, 0x94, 0xfd, 0x6a, 0x71,
- 0xb3, 0x3f, 0x4e, 0x69, 0xa9, 0xc4, 0xae, 0xd1, 0x9b, 0x78, 0xdd, 0xeb,
- 0x06, 0x09, 0xca, 0x38, 0x13, 0x3b, 0x2a, 0xed, 0xea, 0x0c, 0xdf, 0xfe,
- 0x1f, 0x15, 0x86, 0x6b, 0xec, 0x20, 0x0d, 0x19, 0xd1, 0x32, 0xd6, 0x68,
- 0xc8, 0x26, 0x04, 0x91, 0x46, 0x6a, 0x67, 0x52, 0xba, 0x30, 0x82, 0x01,
- 0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
- 0xa0, 0x81, 0xf4, 0x04, 0x81, 0xf1, 0x30, 0x81, 0xee, 0x30, 0x81, 0xeb,
- 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01,
- 0x02, 0xa0, 0x81, 0xb4, 0x30, 0x81, 0xb1, 0x30, 0x1c, 0x06, 0x0a, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04,
- 0x08, 0x32, 0xe5, 0x74, 0x9b, 0x0d, 0xcf, 0xa3, 0x05, 0x02, 0x02, 0x08,
- 0x00, 0x04, 0x81, 0x90, 0x7f, 0xa7, 0x6e, 0x5b, 0x73, 0x39, 0x15, 0x93,
- 0x42, 0x7c, 0xda, 0xc0, 0x16, 0xa0, 0x75, 0x96, 0x3d, 0x95, 0xc8, 0x52,
- 0x6b, 0x65, 0x32, 0xe5, 0xce, 0x62, 0x9b, 0xd5, 0xac, 0x38, 0xd7, 0xaa,
- 0x69, 0x22, 0xcc, 0xa9, 0x8d, 0x74, 0x15, 0x87, 0x06, 0xbd, 0x25, 0xd4,
- 0xd5, 0xa5, 0xda, 0x12, 0xd9, 0xd9, 0x47, 0x42, 0x05, 0xf3, 0xb7, 0x17,
- 0x4c, 0x54, 0xdb, 0x5e, 0x1c, 0xb9, 0x1d, 0x6b, 0xe2, 0xa8, 0x95, 0x08,
- 0x20, 0x09, 0x71, 0x35, 0x68, 0xb7, 0x1c, 0x6a, 0x6c, 0xfd, 0x99, 0xf9,
- 0x2b, 0x6f, 0xb3, 0x53, 0x55, 0xd9, 0xbe, 0x8c, 0xb1, 0x26, 0x12, 0xab,
- 0x8a, 0x58, 0x68, 0x84, 0x9f, 0xa1, 0xa6, 0xeb, 0x70, 0x33, 0x14, 0x0e,
- 0xf6, 0xb7, 0x31, 0x81, 0x79, 0x35, 0xb2, 0xab, 0x10, 0x4d, 0xe3, 0x16,
- 0xbd, 0x7f, 0x7e, 0x72, 0x12, 0xd5, 0x04, 0xd8, 0x23, 0x97, 0xca, 0x26,
- 0x38, 0x62, 0x2c, 0xb7, 0x09, 0x00, 0x3f, 0x01, 0xe0, 0xf7, 0xff, 0x12,
- 0x25, 0x26, 0x99, 0xdc, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x3f,
- 0x31, 0x38, 0xec, 0xb9, 0xf1, 0x45, 0xe1, 0x3e, 0x90, 0x71, 0x0d, 0xc1,
- 0x28, 0xba, 0x4e, 0x6f, 0xa0, 0x9c, 0xed, 0x30, 0x31, 0x30, 0x21, 0x30,
- 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
- 0xd1, 0x96, 0xa3, 0x29, 0xa9, 0x45, 0x1d, 0xad, 0xa1, 0x78, 0xa7, 0x1e,
- 0x30, 0xb8, 0x76, 0xd0, 0x87, 0x23, 0x4b, 0x02, 0x04, 0x08, 0x9c, 0xff,
- 0x9a, 0xa3, 0xf5, 0x70, 0xa8, 0xd9, 0x02, 0x02, 0x08, 0x00};
-
-// Generated with
-// openssl pkcs12 -export -inkey ecdsa_p256_key.pem -in ecdsa_p256_cert.pem -password pass:"Hello, 世界"
-static const uint8_t kUnicode[] = {
- 0x30, 0x82, 0x03, 0xd2, 0x02, 0x01, 0x03, 0x30, 0x82, 0x03, 0x98, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
- 0x03, 0x89, 0x04, 0x82, 0x03, 0x85, 0x30, 0x82, 0x03, 0x81, 0x30, 0x82,
- 0x02, 0x77, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
- 0x06, 0xa0, 0x82, 0x02, 0x68, 0x30, 0x82, 0x02, 0x64, 0x02, 0x01, 0x00,
- 0x30, 0x82, 0x02, 0x5d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x41, 0x46, 0x22,
- 0xac, 0xe7, 0xd6, 0x7e, 0x61, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x02,
- 0x30, 0x9a, 0x05, 0x55, 0x5a, 0xa0, 0xf6, 0xd4, 0x8c, 0x5e, 0x1c, 0x27,
- 0x91, 0x11, 0xfd, 0x1d, 0xe8, 0xfd, 0xae, 0xf2, 0xe6, 0x9f, 0x28, 0xb8,
- 0x1e, 0xfa, 0xce, 0x88, 0xb4, 0x23, 0xd6, 0xfa, 0x6e, 0x07, 0xe9, 0x33,
- 0x81, 0x70, 0x1d, 0xd0, 0x5e, 0x94, 0x04, 0xf1, 0x60, 0x8e, 0xbf, 0xe1,
- 0xef, 0xf4, 0xd7, 0xb2, 0x2f, 0x0d, 0xe9, 0x70, 0x2b, 0xe8, 0x62, 0xfc,
- 0xd3, 0x2a, 0x49, 0xf3, 0xf1, 0x06, 0x6f, 0x2a, 0x94, 0x8c, 0x42, 0xff,
- 0xc6, 0x80, 0xa8, 0x6a, 0xbf, 0xa3, 0x0a, 0xd3, 0x8e, 0x59, 0x52, 0xea,
- 0x60, 0xe8, 0x5a, 0x64, 0x23, 0xac, 0x8d, 0x40, 0x2d, 0xc9, 0xfe, 0x0b,
- 0xf3, 0x93, 0x52, 0xc3, 0x3e, 0xea, 0x34, 0x9a, 0xea, 0x42, 0x6a, 0xe4,
- 0x09, 0x25, 0x44, 0x5d, 0x5e, 0xb4, 0x3b, 0xfb, 0xe0, 0xc2, 0xdf, 0xd8,
- 0xaf, 0xae, 0x20, 0x59, 0xb0, 0x8c, 0xdd, 0xb3, 0x4a, 0x5f, 0xca, 0x6c,
- 0x2f, 0xe3, 0xb4, 0x99, 0xc6, 0x8f, 0x75, 0xc5, 0x72, 0x31, 0x0e, 0x4c,
- 0x46, 0xe6, 0xe1, 0xbf, 0x3f, 0xdf, 0x02, 0x7d, 0xde, 0x35, 0xad, 0xd9,
- 0x9d, 0xcb, 0x74, 0xa7, 0x5c, 0x52, 0x3b, 0xc2, 0x9c, 0x76, 0xbd, 0xf7,
- 0x96, 0xfc, 0xc5, 0x9d, 0xc7, 0xa7, 0x79, 0x30, 0xa0, 0x89, 0xd6, 0xd3,
- 0xa8, 0xe8, 0x63, 0xd2, 0x3a, 0x3f, 0x88, 0xc1, 0x22, 0x8c, 0x20, 0x9c,
- 0xa0, 0x23, 0x07, 0xc3, 0xe4, 0x0c, 0x36, 0x19, 0xa8, 0xa3, 0xc4, 0xbc,
- 0xbc, 0xd6, 0x3d, 0x80, 0xcb, 0x54, 0x91, 0xc4, 0xab, 0x02, 0xd2, 0x43,
- 0x30, 0xe5, 0x01, 0xbd, 0x25, 0xcd, 0xe4, 0x29, 0x55, 0x0f, 0x6e, 0x83,
- 0xb8, 0xfb, 0x70, 0xf2, 0x34, 0x9a, 0x15, 0xc6, 0x16, 0xdf, 0x89, 0xe4,
- 0xd4, 0x83, 0x26, 0x08, 0x62, 0x05, 0xa6, 0xea, 0xf3, 0x63, 0xc3, 0xb5,
- 0x69, 0x62, 0xf8, 0x60, 0x5c, 0x28, 0x21, 0x51, 0xa4, 0x43, 0x76, 0xdd,
- 0x41, 0x6d, 0xbd, 0x6d, 0x8e, 0x3c, 0x63, 0x44, 0xb6, 0xea, 0x3a, 0x2a,
- 0x1c, 0x9d, 0x4b, 0x84, 0xed, 0xbd, 0x2e, 0x3b, 0x97, 0x89, 0xc3, 0x88,
- 0xca, 0x5f, 0x84, 0x0f, 0xbd, 0x50, 0xeb, 0x94, 0x67, 0x83, 0xa7, 0x83,
- 0xdf, 0xd7, 0x9d, 0x81, 0x40, 0x3a, 0x7b, 0xcf, 0x8b, 0x1d, 0x19, 0x9b,
- 0xe1, 0x4e, 0xb4, 0x4b, 0x1d, 0x5b, 0x98, 0xa8, 0xe3, 0x89, 0xed, 0xf3,
- 0x48, 0xfc, 0x0d, 0x38, 0xd5, 0x42, 0x31, 0xe3, 0x79, 0x3a, 0xea, 0xa3,
- 0x4b, 0x58, 0xa3, 0x75, 0x7c, 0xd4, 0xc4, 0x38, 0x27, 0x9e, 0x97, 0x4e,
- 0xc1, 0x70, 0xa8, 0xee, 0x85, 0xe2, 0xb8, 0x53, 0x57, 0x15, 0x05, 0xbb,
- 0xf1, 0xb4, 0xfd, 0xe8, 0x24, 0x99, 0x64, 0xa7, 0xf3, 0x6a, 0xcc, 0x4b,
- 0xe9, 0x8d, 0x66, 0x38, 0x9a, 0x45, 0xe2, 0x73, 0x5e, 0x66, 0x18, 0xd9,
- 0x64, 0x46, 0xd7, 0xd1, 0x23, 0x30, 0xbe, 0xa2, 0x4b, 0x5c, 0x0e, 0x4c,
- 0x8a, 0x47, 0x88, 0xb4, 0x7a, 0x2e, 0x0f, 0xb6, 0xab, 0x2d, 0x56, 0x20,
- 0x76, 0xf4, 0xa1, 0x37, 0xb6, 0x6b, 0x98, 0x2a, 0xb4, 0xda, 0x67, 0xcb,
- 0x67, 0x5c, 0xc7, 0x2d, 0x41, 0xf6, 0x14, 0x0d, 0x6b, 0x16, 0x05, 0xe6,
- 0x0a, 0xa2, 0xf7, 0x03, 0x5e, 0xf8, 0x9c, 0x85, 0x58, 0xa5, 0x82, 0xa4,
- 0xaf, 0xd1, 0xf0, 0x3a, 0x48, 0xa1, 0x68, 0x10, 0xa4, 0xa5, 0xc5, 0x87,
- 0xf5, 0xc3, 0xf8, 0x94, 0x9d, 0x13, 0xcb, 0x08, 0x42, 0x14, 0xb3, 0x68,
- 0x68, 0x18, 0xec, 0xa9, 0x57, 0x9c, 0xeb, 0xc9, 0xe9, 0xaf, 0x7d, 0xcc,
- 0xb9, 0x4d, 0x58, 0x8d, 0xbf, 0x04, 0xb7, 0x1c, 0x3f, 0xfa, 0xd3, 0xb9,
- 0xb9, 0xad, 0x0e, 0xd2, 0x5f, 0x8b, 0x41, 0xfa, 0xdc, 0x85, 0x3e, 0x0a,
- 0xba, 0x49, 0x1b, 0xe2, 0x0c, 0xb6, 0x85, 0x9b, 0x24, 0x3c, 0xdf, 0x26,
- 0x9d, 0x05, 0x50, 0x64, 0x12, 0x96, 0x24, 0xdb, 0x4d, 0x79, 0x07, 0xa7,
- 0xb2, 0x3c, 0xf9, 0x42, 0xca, 0xda, 0x67, 0xc0, 0x6d, 0xf2, 0x7e, 0xbc,
- 0x1e, 0x5c, 0x2b, 0x4b, 0xf6, 0xf4, 0x35, 0x82, 0x70, 0x6b, 0x81, 0x16,
- 0xfc, 0xf1, 0xa9, 0x5f, 0x07, 0x2c, 0xe9, 0x1e, 0x3f, 0x30, 0x82, 0x01,
- 0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
- 0xa0, 0x81, 0xf4, 0x04, 0x81, 0xf1, 0x30, 0x81, 0xee, 0x30, 0x81, 0xeb,
- 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01,
- 0x02, 0xa0, 0x81, 0xb4, 0x30, 0x81, 0xb1, 0x30, 0x1c, 0x06, 0x0a, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04,
- 0x08, 0x6f, 0xb9, 0x01, 0x93, 0x6c, 0x0d, 0x4d, 0xe1, 0x02, 0x02, 0x08,
- 0x00, 0x04, 0x81, 0x90, 0x07, 0x42, 0x6a, 0x5a, 0x4c, 0x41, 0x41, 0x38,
- 0xe4, 0x15, 0xc2, 0x85, 0x4e, 0x88, 0xc6, 0xd3, 0x6f, 0x9f, 0x25, 0xd8,
- 0x66, 0x86, 0xf3, 0x65, 0x5d, 0x51, 0x43, 0xd6, 0x03, 0x91, 0x4c, 0xeb,
- 0xbb, 0x75, 0xce, 0x8b, 0xf4, 0x47, 0x43, 0x4c, 0x1a, 0x4b, 0x48, 0x92,
- 0xf4, 0xaf, 0x0a, 0x5f, 0x49, 0x96, 0xea, 0xaf, 0x31, 0x29, 0x7b, 0xa3,
- 0xb5, 0xd3, 0xe4, 0x67, 0x0c, 0x20, 0x0e, 0x52, 0x9e, 0xcf, 0xcf, 0x6a,
- 0x2d, 0x45, 0x38, 0x52, 0x61, 0xbf, 0x10, 0x2b, 0xc1, 0xc5, 0xde, 0x04,
- 0x1d, 0x0a, 0x52, 0x88, 0x07, 0x39, 0xc2, 0xc1, 0xd0, 0x44, 0x39, 0x9f,
- 0x46, 0xf2, 0x69, 0xa4, 0x30, 0x5b, 0xe4, 0x60, 0x68, 0x69, 0xb0, 0x95,
- 0x78, 0x05, 0xef, 0xe1, 0x81, 0xc2, 0xd2, 0x4e, 0x29, 0x52, 0x39, 0x51,
- 0xfc, 0x3d, 0x28, 0xe1, 0x7b, 0x58, 0x76, 0xcf, 0x35, 0x33, 0x2f, 0xef,
- 0x95, 0x76, 0x0c, 0x52, 0x11, 0x69, 0x17, 0x3c, 0x56, 0x36, 0xc6, 0xe1,
- 0x9c, 0x1c, 0xd4, 0x23, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x3f,
- 0x31, 0x38, 0xec, 0xb9, 0xf1, 0x45, 0xe1, 0x3e, 0x90, 0x71, 0x0d, 0xc1,
- 0x28, 0xba, 0x4e, 0x6f, 0xa0, 0x9c, 0xed, 0x30, 0x31, 0x30, 0x21, 0x30,
- 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
- 0x52, 0x8c, 0x3f, 0x72, 0x8c, 0xcf, 0x3a, 0xeb, 0xc8, 0xff, 0xc2, 0x8c,
- 0x48, 0x42, 0xa6, 0x1c, 0x42, 0x6e, 0x18, 0x43, 0x04, 0x08, 0xea, 0xec,
- 0xdc, 0xf6, 0xc4, 0xdf, 0xda, 0xd6, 0x02, 0x02, 0x08, 0x00};
-
+// kUnicodePassword is the password for unicode_password.p12
static const char kUnicodePassword[] = u8"Hello, 世界";
+static bssl::Span<const uint8_t> StringToBytes(const std::string &str) {
+ return bssl::MakeConstSpan(reinterpret_cast<const uint8_t *>(str.data()),
+ str.size());
+}
+
static void TestImpl(const char *name, bssl::Span<const uint8_t> der,
const char *password,
const char *friendly_name) {
@@ -1531,50 +93,91 @@ static void TestCompat(bssl::Span<const uint8_t> der) {
}
TEST(PKCS12Test, TestOpenSSL) {
- TestImpl("OpenSSL", kOpenSSL, kPassword, nullptr);
+ // openssl.p12 was generated by OpenSSL with:
+ // openssl pkcs12 -export -inkey key.pem -in cacert.pem
+ std::string data = GetTestData("crypto/pkcs8/test/openssl.p12");
+ TestImpl("OpenSSL", StringToBytes(data), kPassword, nullptr);
}
TEST(PKCS12Test, TestNSS) {
- TestImpl("NSS", kNSS, kPassword, "Internet Widgits Pty Ltd");
+ // nss.p12 is the result of importing the OpenSSL example PKCS#12 into Chrome
+ // on Linux and then exporting it again.
+ std::string data = GetTestData("crypto/pkcs8/test/nss.p12");
+ TestImpl("NSS", StringToBytes(data), kPassword, "Internet Widgits Pty Ltd");
}
TEST(PKCS12Test, TestWindows) {
- // kWindows has a friendlyName, but only on the key, where we ignore it, and
- // not the certificate.
- TestImpl("Windows", kWindows, kPassword, nullptr);
+ // windows.p12 is a dummy key and certificate exported from the certificate
+ // manager on Windows 7. It has a friendlyName, but only on the key, where we
+ // ignore it, and not the certificate.
+ std::string data = GetTestData("crypto/pkcs8/test/windows.p12");
+ TestImpl("Windows", StringToBytes(data), kPassword, nullptr);
}
TEST(PKCS12Test, TestPBES2) {
- TestImpl("kPBES2WithSHA1", kPBES2WithSHA1, kPassword, nullptr);
- TestImpl("kPBES2WithSHA256", kPBES2WithSHA256, kPassword, nullptr);
+ // pbes2_sha1.p12 is a PKCS#12 file using PBES2 and HMAC-SHA-1 created with:
+ // openssl pkcs12 -export -inkey key.pem -in cert.pem -keypbe AES-128-CBC
+ // -certpbe AES-128-CBC
+ //
+ // This was generated with an older OpenSSL, which used hmacWithSHA1 as the
+ // PRF. (There is currently no way to specify the PRF in the pkcs12 command.)
+ std::string data = GetTestData("crypto/pkcs8/test/pbes2_sha1.p12");
+ TestImpl("kPBES2WithSHA1", StringToBytes(data), kPassword, nullptr);
+
+ // pbes2_sha256.p12 is a PKCS#12 file using PBES2 and HMAC-SHA-256. It was
+ // generated in the same way as pbes2_sha1.p12, but using OpenSSL 1.1.1b,
+ // which uses hmacWithSHA256 as the PRF.
+ data = GetTestData("crypto/pkcs8/test/pbes2_sha256.p12");
+ TestImpl("kPBES2WithSHA256", StringToBytes(data), kPassword, nullptr);
}
TEST(PKCS12Test, TestNoEncryption) {
- TestImpl("kNoEncryption", kNoEncryption, kPassword, nullptr);
+ // no_encryption.p12 is a PKCS#12 file with neither the key or certificate is
+ // encrypted. It was generated with:
+ //
+ // openssl pkcs12 -export -inkey ecdsa_p256_key.pem -in ecdsa_p256_cert.pem -keypbe NONE -certpbe NONE -password pass:foo
+ std::string data = GetTestData("crypto/pkcs8/test/no_encryption.p12");
+ TestImpl("kNoEncryption", StringToBytes(data), kPassword, nullptr);
}
TEST(PKCS12Test, TestEmptyPassword) {
#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
return; // The MAC check always passes in fuzzer mode.
#endif
- TestImpl("EmptyPassword (empty password)", kEmptyPassword, "", nullptr);
- TestImpl("EmptyPassword (null password)", kEmptyPassword, nullptr, nullptr);
+
+ // Generated with
+ // openssl pkcs12 -export -inkey ecdsa_p256_key.pem -in ecdsa_p256_cert.pem -password pass:
+ std::string data = GetTestData("crypto/pkcs8/test/empty_password.p12");
+ TestImpl("EmptyPassword (empty password)", StringToBytes(data), "", nullptr);
+ TestImpl("EmptyPassword (null password)", StringToBytes(data), nullptr,
+ nullptr);
}
TEST(PKCS12Test, TestNullPassword) {
#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
return; // The MAC check always passes in fuzzer mode.
#endif
- TestImpl("NullPassword (empty password)", kNullPassword, "", nullptr);
- TestImpl("NullPassword (null password)", kNullPassword, nullptr, nullptr);
+
+ // Generated with
+ // openssl pkcs12 -export -inkey ecdsa_p256_key.pem -in ecdsa_p256_cert.pem -password pass:
+ // But with OpenSSL patched to pass NULL into PKCS12_create and
+ // PKCS12_set_mac.
+ std::string data = GetTestData("crypto/pkcs8/test/null_password.p12");
+ TestImpl("NullPassword (empty password)", StringToBytes(data), "", nullptr);
+ TestImpl("NullPassword (null password)", StringToBytes(data), nullptr,
+ nullptr);
}
TEST(PKCS12Test, TestUnicode) {
- TestImpl("Unicode", kUnicode, kUnicodePassword, nullptr);
+ // Generated with
+ // openssl pkcs12 -export -inkey ecdsa_p256_key.pem -in ecdsa_p256_cert.pem -password pass:"Hello, 世界"
+ std::string data = GetTestData("crypto/pkcs8/test/unicode_password.p12");
+ TestImpl("Unicode", StringToBytes(data), kUnicodePassword, nullptr);
}
TEST(PKCS12Test, TestWindowsCompat) {
- TestCompat(kWindows);
+ std::string data = GetTestData("crypto/pkcs8/test/windows.p12");
+ TestCompat(StringToBytes(data));
}
// kTestKey is a test P-256 key.
@@ -1825,6 +428,27 @@ TEST(PKCS12Test, RoundTrip) {
{bssl::Span<const uint8_t>(kTestCert2)},
NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
NID_pbe_WithSHA1And3_Key_TripleDES_CBC, 100, 100);
+
+ // Test unencrypted and partially unencrypted PKCS#12 files.
+ TestRoundTrip(kPassword, /*name=*/nullptr,
+ bssl::Span<const uint8_t>(kTestKey),
+ bssl::Span<const uint8_t>(kTestCert),
+ {bssl::Span<const uint8_t>(kTestCert2)},
+ /*key_nid=*/-1,
+ /*cert_nid=*/-1, /*iterations=*/100, /*mac_iterations=*/100);
+ TestRoundTrip(kPassword, /*name=*/nullptr,
+ bssl::Span<const uint8_t>(kTestKey),
+ bssl::Span<const uint8_t>(kTestCert),
+ {bssl::Span<const uint8_t>(kTestCert2)},
+ /*key_nid=*/NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
+ /*cert_nid=*/-1, /*iterations=*/100, /*mac_iterations=*/100);
+ TestRoundTrip(kPassword, /*name=*/nullptr,
+ bssl::Span<const uint8_t>(kTestKey),
+ bssl::Span<const uint8_t>(kTestCert),
+ {bssl::Span<const uint8_t>(kTestCert2)},
+ /*key_nid=*/-1,
+ /*cert_nid=*/NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
+ /*iterations=*/100, /*mac_iterations=*/100);
}
static bssl::UniquePtr<EVP_PKEY> MakeTestKey() {
diff --git a/deps/boringssl/src/crypto/pkcs8/pkcs8_x509.c b/deps/boringssl/src/crypto/pkcs8/pkcs8_x509.c
index a2f9075..e24fb42 100644
--- a/deps/boringssl/src/crypto/pkcs8/pkcs8_x509.c
+++ b/deps/boringssl/src/crypto/pkcs8/pkcs8_x509.c
@@ -943,11 +943,6 @@ int PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey,
// OpenSSL selects the last certificate which matches the private key as
// |out_cert|.
- //
- // TODO(davidben): OpenSSL additionally reverses the order of the
- // certificates, which was likely originally a bug, but may be a feature by
- // now. See https://crbug.com/boringssl/250 and
- // https://github.com/openssl/openssl/issues/6698.
*out_cert = NULL;
size_t num_certs = sk_X509_num(ca_certs);
if (*out_pkey != NULL && num_certs > 0) {
@@ -1074,31 +1069,24 @@ static int add_cert_bag(CBB *cbb, X509 *cert, const char *name,
return 1;
}
-static int make_cert_safe_contents(uint8_t **out_data, size_t *out_len,
- X509 *cert, const STACK_OF(X509) *chain,
- const char *name, const uint8_t *key_id,
- size_t key_id_len) {
- int ret = 0;
- CBB cbb, safe_contents;
- if (!CBB_init(&cbb, 0) ||
- !CBB_add_asn1(&cbb, &safe_contents, CBS_ASN1_SEQUENCE) ||
+static int add_cert_safe_contents(CBB *cbb, X509 *cert,
+ const STACK_OF(X509) *chain, const char *name,
+ const uint8_t *key_id, size_t key_id_len) {
+ CBB safe_contents;
+ if (!CBB_add_asn1(cbb, &safe_contents, CBS_ASN1_SEQUENCE) ||
(cert != NULL &&
!add_cert_bag(&safe_contents, cert, name, key_id, key_id_len))) {
- goto err;
+ return 0;
}
for (size_t i = 0; i < sk_X509_num(chain); i++) {
// Only the leaf certificate gets attributes.
if (!add_cert_bag(&safe_contents, sk_X509_value(chain, i), NULL, NULL, 0)) {
- goto err;
+ return 0;
}
}
- ret = CBB_finish(&cbb, out_data, out_len);
-
-err:
- CBB_cleanup(&cbb);
- return ret;
+ return CBB_flush(cbb);
}
static int add_encrypted_data(CBB *out, int pbe_nid, const char *password,
@@ -1181,9 +1169,6 @@ PKCS12 *PKCS12_create(const char *password, const char *name,
if (// In OpenSSL, this specifies a non-standard Microsoft key usage extension
// which we do not currently support.
key_type != 0 ||
- // In OpenSSL, -1 here means to use no encryption, which we do not
- // currently support.
- key_nid < 0 || cert_nid < 0 ||
// In OpenSSL, -1 here means to omit the MAC, which we do not
// currently support. Omitting it is also invalid for a password-based
// PKCS#12 file.
@@ -1194,6 +1179,36 @@ PKCS12 *PKCS12_create(const char *password, const char *name,
return 0;
}
+ // PKCS#12 is a very confusing recursive data format, built out of another
+ // recursive data format. Section 5.1 of RFC 7292 describes the encoding
+ // algorithm, but there is no clear overview. A quick summary:
+ //
+ // PKCS#7 defines a ContentInfo structure, which is a overgeneralized typed
+ // combinator structure for applying cryptography. We care about two types. A
+ // data ContentInfo contains an OCTET STRING and is a leaf node of the
+ // combinator tree. An encrypted-data ContentInfo contains encryption
+ // parameters (key derivation and encryption) and wraps another ContentInfo,
+ // usually data.
+ //
+ // A PKCS#12 file is a PFX structure (section 4), which contains a single data
+ // ContentInfo and a MAC over it. This root ContentInfo is the
+ // AuthenticatedSafe and its payload is a SEQUENCE of other ContentInfos, so
+ // that different parts of the PKCS#12 file can by differently protected.
+ //
+ // Each ContentInfo in the AuthenticatedSafe, after undoing all the PKCS#7
+ // combinators, has SafeContents payload. A SafeContents is a SEQUENCE of
+ // SafeBag. SafeBag is PKCS#12's typed structure, with subtypes such as KeyBag
+ // and CertBag. Confusingly, there is a SafeContents bag type which itself
+ // recursively contains more SafeBags, but we do not implement this. Bags also
+ // can have attributes.
+ //
+ // The grouping of SafeBags into intermediate ContentInfos does not appear to
+ // be significant, except that all SafeBags sharing a ContentInfo have the
+ // same level of protection. Additionally, while keys may be encrypted by
+ // placing a KeyBag in an encrypted-data ContentInfo, PKCS#12 also defines a
+ // key-specific encryption container, PKCS8ShroudedKeyBag, which is used
+ // instead.
+
// Note that |password| may be NULL to specify no password, rather than the
// empty string. They are encoded differently in PKCS#12. (One is the empty
// byte array and the other is NUL-terminated UCS-2.)
@@ -1236,24 +1251,43 @@ PKCS12 *PKCS12_create(const char *password, const char *name,
// If there are any certificates, place them in CertBags wrapped in a single
// encrypted ContentInfo.
if (cert != NULL || sk_X509_num(chain) > 0) {
- uint8_t *data;
- size_t len;
- if (!make_cert_safe_contents(&data, &len, cert, chain, name, key_id,
- key_id_len)) {
- goto err;
- }
- int ok = add_encrypted_data(&content_infos, cert_nid, password,
- password_len, iterations, data, len);
- OPENSSL_free(data);
- if (!ok) {
- goto err;
+ if (cert_nid < 0) {
+ // Place the certificates in an unencrypted ContentInfo. This could be
+ // more compactly-encoded by reusing the same ContentInfo as the key, but
+ // OpenSSL does not do this. We keep them separate for consistency. (Keys,
+ // even when encrypted, are always placed in unencrypted ContentInfos.
+ // PKCS#12 defines bag-level encryption for keys.)
+ CBB content_info, oid, wrapper, data;
+ if (!CBB_add_asn1(&content_infos, &content_info, CBS_ASN1_SEQUENCE) ||
+ !CBB_add_asn1(&content_info, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, kPKCS7Data, sizeof(kPKCS7Data)) ||
+ !CBB_add_asn1(&content_info, &wrapper,
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0) ||
+ !CBB_add_asn1(&wrapper, &data, CBS_ASN1_OCTETSTRING) ||
+ !add_cert_safe_contents(&data, cert, chain, name, key_id,
+ key_id_len) ||
+ !CBB_flush(&content_infos)) {
+ goto err;
+ }
+ } else {
+ CBB plaintext_cbb;
+ int ok = CBB_init(&plaintext_cbb, 0) &&
+ add_cert_safe_contents(&plaintext_cbb, cert, chain, name, key_id,
+ key_id_len) &&
+ add_encrypted_data(
+ &content_infos, cert_nid, password, password_len, iterations,
+ CBB_data(&plaintext_cbb), CBB_len(&plaintext_cbb));
+ CBB_cleanup(&plaintext_cbb);
+ if (!ok) {
+ goto err;
+ }
}
}
- // If there is a key, place it in a single PKCS8ShroudedKeyBag wrapped in an
- // unencrypted ContentInfo. (One could also place it in a KeyBag inside an
- // encrypted ContentInfo, but OpenSSL does not do this and some PKCS#12
- // consumers do not support KeyBags.)
+ // If there is a key, place it in a single KeyBag or PKCS8ShroudedKeyBag
+ // wrapped in an unencrypted ContentInfo. (One could also place it in a KeyBag
+ // inside an encrypted ContentInfo, but OpenSSL does not do this and some
+ // PKCS#12 consumers do not support KeyBags.)
if (pkey != NULL) {
CBB content_info, oid, wrapper, data, safe_contents, bag, bag_oid,
bag_contents;
@@ -1267,16 +1301,29 @@ PKCS12 *PKCS12_create(const char *password, const char *name,
!CBB_add_asn1(&data, &safe_contents, CBS_ASN1_SEQUENCE) ||
// Add a SafeBag containing a PKCS8ShroudedKeyBag.
!CBB_add_asn1(&safe_contents, &bag, CBS_ASN1_SEQUENCE) ||
- !CBB_add_asn1(&bag, &bag_oid, CBS_ASN1_OBJECT) ||
- !CBB_add_bytes(&bag_oid, kPKCS8ShroudedKeyBag,
- sizeof(kPKCS8ShroudedKeyBag)) ||
- !CBB_add_asn1(&bag, &bag_contents,
- CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0) ||
- !PKCS8_marshal_encrypted_private_key(
- &bag_contents, key_nid, NULL, password, password_len,
- NULL /* generate a random salt */, 0 /* use default salt length */,
- iterations, pkey) ||
- !add_bag_attributes(&bag, name, key_id, key_id_len) ||
+ !CBB_add_asn1(&bag, &bag_oid, CBS_ASN1_OBJECT)) {
+ goto err;
+ }
+ if (key_nid < 0) {
+ if (!CBB_add_bytes(&bag_oid, kKeyBag, sizeof(kKeyBag)) ||
+ !CBB_add_asn1(&bag, &bag_contents,
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0) ||
+ !EVP_marshal_private_key(&bag_contents, pkey)) {
+ goto err;
+ }
+ } else {
+ if (!CBB_add_bytes(&bag_oid, kPKCS8ShroudedKeyBag,
+ sizeof(kPKCS8ShroudedKeyBag)) ||
+ !CBB_add_asn1(&bag, &bag_contents,
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0) ||
+ !PKCS8_marshal_encrypted_private_key(
+ &bag_contents, key_nid, NULL, password, password_len,
+ NULL /* generate a random salt */,
+ 0 /* use default salt length */, iterations, pkey)) {
+ goto err;
+ }
+ }
+ if (!add_bag_attributes(&bag, name, key_id, key_id_len) ||
!CBB_flush(&content_infos)) {
goto err;
}
diff --git a/deps/boringssl/src/crypto/poly1305/poly1305.c b/deps/boringssl/src/crypto/poly1305/poly1305.c
index 31a567d..c07b1e9 100644
--- a/deps/boringssl/src/crypto/poly1305/poly1305.c
+++ b/deps/boringssl/src/crypto/poly1305/poly1305.c
@@ -56,7 +56,7 @@ OPENSSL_STATIC_ASSERT(
static inline struct poly1305_state_st *poly1305_aligned_state(
poly1305_state *state) {
- return (struct poly1305_state_st *)(((uintptr_t)state + 63) & ~63);
+ return align_pointer(state, 64);
}
// poly1305_blocks updates |state| given some amount of input data. This
diff --git a/deps/boringssl/src/crypto/pool/pool.c b/deps/boringssl/src/crypto/pool/pool.c
index 917e43c..88bf8af 100644
--- a/deps/boringssl/src/crypto/pool/pool.c
+++ b/deps/boringssl/src/crypto/pool/pool.c
@@ -22,6 +22,7 @@
#include <openssl/thread.h>
#include "../internal.h"
+#include "../lhash/internal.h"
#include "internal.h"
diff --git a/deps/boringssl/src/crypto/rand_extra/deterministic.c b/deps/boringssl/src/crypto/rand_extra/deterministic.c
index 38cfd11..435f063 100644
--- a/deps/boringssl/src/crypto/rand_extra/deterministic.c
+++ b/deps/boringssl/src/crypto/rand_extra/deterministic.c
@@ -49,4 +49,8 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
CRYPTO_chacha_20(out, out, requested, kZeroKey, nonce, 0);
}
+void CRYPTO_sysrand_for_seed(uint8_t *out, size_t requested) {
+ CRYPTO_sysrand(out, requested);
+}
+
#endif // BORINGSSL_UNSAFE_DETERMINISTIC_MODE
diff --git a/deps/boringssl/src/crypto/rand_extra/fuchsia.c b/deps/boringssl/src/crypto/rand_extra/fuchsia.c
index 0514d80..ee6cfdb 100644
--- a/deps/boringssl/src/crypto/rand_extra/fuchsia.c
+++ b/deps/boringssl/src/crypto/rand_extra/fuchsia.c
@@ -27,4 +27,8 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
zx_cprng_draw(out, requested);
}
+void CRYPTO_sysrand_for_seed(uint8_t *out, size_t requested) {
+ CRYPTO_sysrand(out, requested);
+}
+
#endif // OPENSSL_FUCHSIA && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE
diff --git a/deps/boringssl/src/crypto/rand_extra/passive.c b/deps/boringssl/src/crypto/rand_extra/passive.c
index a8c2487..a2b388f 100644
--- a/deps/boringssl/src/crypto/rand_extra/passive.c
+++ b/deps/boringssl/src/crypto/rand_extra/passive.c
@@ -15,7 +15,7 @@
#include <openssl/base.h>
#include "../fipsmodule/rand/internal.h"
-#if defined(BORINGSSL_FIPS_PASSIVE_ENTROPY)
+#if defined(BORINGSSL_FIPS)
// RAND_need_entropy is called by the FIPS module when it has blocked because of
// a lack of entropy. This signal is used as an indication to feed it more.
@@ -31,4 +31,4 @@ void RAND_need_entropy(size_t bytes_needed) {
RAND_load_entropy(buf, todo, used_cpu);
}
-#endif // BORINGSSL_FIPS_PASSIVE_ENTROPY
+#endif // FIPS
diff --git a/deps/boringssl/src/crypto/rand_extra/rand_extra.c b/deps/boringssl/src/crypto/rand_extra/rand_extra.c
index 596605a..e73b99e 100644
--- a/deps/boringssl/src/crypto/rand_extra/rand_extra.c
+++ b/deps/boringssl/src/crypto/rand_extra/rand_extra.c
@@ -69,6 +69,6 @@ RAND_METHOD *RAND_OpenSSL(void) {
const RAND_METHOD *RAND_get_rand_method(void) { return RAND_SSLeay(); }
-void RAND_set_rand_method(const RAND_METHOD *method) {}
+int RAND_set_rand_method(const RAND_METHOD *method) { return 1; }
void RAND_cleanup(void) {}
diff --git a/deps/boringssl/src/crypto/rand_extra/windows.c b/deps/boringssl/src/crypto/rand_extra/windows.c
index 82d5542..8ade689 100644
--- a/deps/boringssl/src/crypto/rand_extra/windows.c
+++ b/deps/boringssl/src/crypto/rand_extra/windows.c
@@ -66,4 +66,8 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
return;
}
+void CRYPTO_sysrand_for_seed(uint8_t *out, size_t requested) {
+ CRYPTO_sysrand(out, requested);
+}
+
#endif // OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE
diff --git a/deps/boringssl/src/crypto/rsa_extra/rsa_asn1.c b/deps/boringssl/src/crypto/rsa_extra/rsa_asn1.c
index 3cc6a9c..58fd69a 100644
--- a/deps/boringssl/src/crypto/rsa_extra/rsa_asn1.c
+++ b/deps/boringssl/src/crypto/rsa_extra/rsa_asn1.c
@@ -102,8 +102,7 @@ RSA *RSA_parse_public_key(CBS *cbs) {
return NULL;
}
- if (!BN_is_odd(ret->e) ||
- BN_num_bits(ret->e) < 2) {
+ if (!RSA_check_key(ret)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_RSA_PARAMETERS);
RSA_free(ret);
return NULL;
diff --git a/deps/boringssl/src/crypto/thread_pthread.c b/deps/boringssl/src/crypto/thread_pthread.c
index 2cb1000..e873d04 100644
--- a/deps/boringssl/src/crypto/thread_pthread.c
+++ b/deps/boringssl/src/crypto/thread_pthread.c
@@ -127,34 +127,6 @@ static pthread_once_t g_thread_local_init_once = PTHREAD_ONCE_INIT;
static pthread_key_t g_thread_local_key;
static int g_thread_local_key_created = 0;
-// OPENSSL_DANGEROUS_RELEASE_PTHREAD_KEY can be defined to cause
-// |pthread_key_delete| to be called in a destructor function. This can be
-// useful for programs that dlclose BoringSSL.
-//
-// Note that dlclose()ing BoringSSL is not supported and will leak memory:
-// thread-local values will be leaked as well as anything initialised via a
-// once. The |pthread_key_t| is destroyed because they run out very quickly,
-// while the other leaks are slow, and this allows code that happens to use
-// dlclose() despite all the problems to continue functioning.
-//
-// This is marked "dangerous" because it can cause multi-threaded processes to
-// crash (even if they don't use dlclose): if the destructor runs while other
-// threads are still executing then they may end up using an invalid key to
-// access thread-local variables.
-//
-// This may be removed after February 2020.
-#if defined(OPENSSL_DANGEROUS_RELEASE_PTHREAD_KEY) && \
- (defined(__GNUC__) || defined(__clang__))
-// thread_key_destructor is called when the library is unloaded with dlclose.
-static void thread_key_destructor(void) __attribute__((destructor, unused));
-static void thread_key_destructor(void) {
- if (g_thread_local_key_created) {
- g_thread_local_key_created = 0;
- pthread_key_delete(g_thread_local_key);
- }
-}
-#endif
-
static void thread_local_init(void) {
g_thread_local_key_created =
pthread_key_create(&g_thread_local_key, thread_local_destructor) == 0;
diff --git a/deps/boringssl/src/crypto/x509/a_verify.c b/deps/boringssl/src/crypto/x509/a_verify.c
index 8587b59..ec671c0 100644
--- a/deps/boringssl/src/crypto/x509/a_verify.c
+++ b/deps/boringssl/src/crypto/x509/a_verify.c
@@ -69,23 +69,27 @@
#include "internal.h"
-int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
- ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey)
-{
- EVP_MD_CTX ctx;
- uint8_t *buf_in = NULL;
- int ret = 0, inl = 0;
-
+int ASN1_item_verify(const ASN1_ITEM *it, const X509_ALGOR *a,
+ const ASN1_BIT_STRING *signature, void *asn,
+ EVP_PKEY *pkey) {
if (!pkey) {
OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
- if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) {
- OPENSSL_PUT_ERROR(X509, X509_R_INVALID_BIT_STRING_BITS_LEFT);
- return 0;
+ size_t sig_len;
+ if (signature->type == V_ASN1_BIT_STRING) {
+ if (!ASN1_BIT_STRING_num_bytes(signature, &sig_len)) {
+ OPENSSL_PUT_ERROR(X509, X509_R_INVALID_BIT_STRING_BITS_LEFT);
+ return 0;
+ }
+ } else {
+ sig_len = (size_t)ASN1_STRING_length(signature);
}
+ EVP_MD_CTX ctx;
+ uint8_t *buf_in = NULL;
+ int ret = 0, inl = 0;
EVP_MD_CTX_init(&ctx);
if (!x509_digest_verify_init(&ctx, a, pkey)) {
@@ -99,7 +103,7 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
goto err;
}
- if (!EVP_DigestVerify(&ctx, signature->data, (size_t)signature->length,
+ if (!EVP_DigestVerify(&ctx, ASN1_STRING_get0_data(signature), sig_len,
buf_in, inl)) {
OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB);
goto err;
diff --git a/deps/boringssl/src/crypto/x509/algorithm.c b/deps/boringssl/src/crypto/x509/algorithm.c
index c021dc4..7f90480 100644
--- a/deps/boringssl/src/crypto/x509/algorithm.c
+++ b/deps/boringssl/src/crypto/x509/algorithm.c
@@ -110,7 +110,7 @@ int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
return 1;
}
-int x509_digest_verify_init(EVP_MD_CTX *ctx, X509_ALGOR *sigalg,
+int x509_digest_verify_init(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg,
EVP_PKEY *pkey) {
/* Convert the signature OID into digest and public key OIDs. */
int sigalg_nid = OBJ_obj2nid(sigalg->algorithm);
diff --git a/deps/boringssl/src/crypto/x509/by_dir.c b/deps/boringssl/src/crypto/x509/by_dir.c
index 7b91cbd..a630cdf 100644
--- a/deps/boringssl/src/crypto/x509/by_dir.c
+++ b/deps/boringssl/src/crypto/x509/by_dir.c
@@ -68,6 +68,7 @@
#if !defined(OPENSSL_TRUSTY)
#include "../internal.h"
+#include "internal.h"
typedef struct lookup_dir_hashes_st {
unsigned long hash;
diff --git a/deps/boringssl/src/crypto/x509/by_file.c b/deps/boringssl/src/crypto/x509/by_file.c
index 994beb9..1614c8c 100644
--- a/deps/boringssl/src/crypto/x509/by_file.c
+++ b/deps/boringssl/src/crypto/x509/by_file.c
@@ -61,6 +61,8 @@
#include <openssl/pem.h>
#include <openssl/thread.h>
+#include "internal.h"
+
#ifndef OPENSSL_NO_STDIO
static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc,
diff --git a/deps/boringssl/src/crypto/x509/internal.h b/deps/boringssl/src/crypto/x509/internal.h
index 4957c1e..ac68755 100644
--- a/deps/boringssl/src/crypto/x509/internal.h
+++ b/deps/boringssl/src/crypto/x509/internal.h
@@ -1,16 +1,60 @@
-/* Copyright (c) 2016, Google Inc.
+/*
+ * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
+ * 2013.
+ */
+/* ====================================================================
+ * Copyright (c) 2013 The OpenSSL Project. All rights reserved.
*
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
*
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
#ifndef OPENSSL_HEADER_X509_INTERNAL_H
#define OPENSSL_HEADER_X509_INTERNAL_H
@@ -24,13 +68,302 @@ extern "C" {
#endif
+/* Internal structures. */
+
+struct X509_val_st {
+ ASN1_TIME *notBefore;
+ ASN1_TIME *notAfter;
+} /* X509_VAL */;
+
+struct X509_pubkey_st {
+ X509_ALGOR *algor;
+ ASN1_BIT_STRING *public_key;
+ EVP_PKEY *pkey;
+} /* X509_PUBKEY */;
+
+struct X509_name_entry_st {
+ ASN1_OBJECT *object;
+ ASN1_STRING *value;
+ int set;
+} /* X509_NAME_ENTRY */;
+
+// we always keep X509_NAMEs in 2 forms.
+struct X509_name_st {
+ STACK_OF(X509_NAME_ENTRY) *entries;
+ int modified; // true if 'bytes' needs to be built
+ BUF_MEM *bytes;
+ // unsigned long hash; Keep the hash around for lookups
+ unsigned char *canon_enc;
+ int canon_enclen;
+} /* X509_NAME */;
+
+struct x509_attributes_st {
+ ASN1_OBJECT *object;
+ STACK_OF(ASN1_TYPE) *set;
+} /* X509_ATTRIBUTE */;
+
+struct x509_cert_aux_st {
+ STACK_OF(ASN1_OBJECT) *trust; // trusted uses
+ STACK_OF(ASN1_OBJECT) *reject; // rejected uses
+ ASN1_UTF8STRING *alias; // "friendly name"
+ ASN1_OCTET_STRING *keyid; // key id of private key
+ STACK_OF(X509_ALGOR) *other; // other unspecified info
+} /* X509_CERT_AUX */;
+
+struct X509_extension_st {
+ ASN1_OBJECT *object;
+ ASN1_BOOLEAN critical;
+ ASN1_OCTET_STRING *value;
+} /* X509_EXTENSION */;
+
+typedef struct {
+ ASN1_INTEGER *version; // [ 0 ] default of v1
+ ASN1_INTEGER *serialNumber;
+ X509_ALGOR *signature;
+ X509_NAME *issuer;
+ X509_VAL *validity;
+ X509_NAME *subject;
+ X509_PUBKEY *key;
+ ASN1_BIT_STRING *issuerUID; // [ 1 ] optional in v2
+ ASN1_BIT_STRING *subjectUID; // [ 2 ] optional in v2
+ STACK_OF(X509_EXTENSION) *extensions; // [ 3 ] optional in v3
+ ASN1_ENCODING enc;
+} X509_CINF;
+
+DECLARE_ASN1_FUNCTIONS(X509_CINF)
+
+struct x509_st {
+ X509_CINF *cert_info;
+ X509_ALGOR *sig_alg;
+ ASN1_BIT_STRING *signature;
+ CRYPTO_refcount_t references;
+ CRYPTO_EX_DATA ex_data;
+ // These contain copies of various extension values
+ long ex_pathlen;
+ long ex_pcpathlen;
+ unsigned long ex_flags;
+ unsigned long ex_kusage;
+ unsigned long ex_xkusage;
+ unsigned long ex_nscert;
+ ASN1_OCTET_STRING *skid;
+ AUTHORITY_KEYID *akid;
+ X509_POLICY_CACHE *policy_cache;
+ STACK_OF(DIST_POINT) *crldp;
+ STACK_OF(GENERAL_NAME) *altname;
+ NAME_CONSTRAINTS *nc;
+ unsigned char sha1_hash[SHA_DIGEST_LENGTH];
+ X509_CERT_AUX *aux;
+ CRYPTO_BUFFER *buf;
+ CRYPTO_MUTEX lock;
+} /* X509 */;
+
+typedef struct {
+ ASN1_ENCODING enc;
+ ASN1_INTEGER *version;
+ X509_NAME *subject;
+ X509_PUBKEY *pubkey;
+ // d=2 hl=2 l= 0 cons: cont: 00
+ STACK_OF(X509_ATTRIBUTE) *attributes; // [ 0 ]
+} X509_REQ_INFO;
+
+DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO)
+
+struct X509_req_st {
+ X509_REQ_INFO *req_info;
+ X509_ALGOR *sig_alg;
+ ASN1_BIT_STRING *signature;
+ CRYPTO_refcount_t references;
+} /* X509_REQ */;
+
+typedef struct {
+ ASN1_INTEGER *version;
+ X509_ALGOR *sig_alg;
+ X509_NAME *issuer;
+ ASN1_TIME *lastUpdate;
+ ASN1_TIME *nextUpdate;
+ STACK_OF(X509_REVOKED) *revoked;
+ STACK_OF(X509_EXTENSION) /* [0] */ *extensions;
+ ASN1_ENCODING enc;
+} X509_CRL_INFO;
+
+DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO)
+
+struct X509_crl_st {
+ // actual signature
+ X509_CRL_INFO *crl;
+ X509_ALGOR *sig_alg;
+ ASN1_BIT_STRING *signature;
+ CRYPTO_refcount_t references;
+ int flags;
+ // Copies of various extensions
+ AUTHORITY_KEYID *akid;
+ ISSUING_DIST_POINT *idp;
+ // Convenient breakdown of IDP
+ int idp_flags;
+ int idp_reasons;
+ // CRL and base CRL numbers for delta processing
+ ASN1_INTEGER *crl_number;
+ ASN1_INTEGER *base_crl_number;
+ unsigned char sha1_hash[SHA_DIGEST_LENGTH];
+ STACK_OF(GENERAL_NAMES) *issuers;
+ const X509_CRL_METHOD *meth;
+ void *meth_data;
+} /* X509_CRL */;
+
+struct X509_VERIFY_PARAM_st {
+ char *name;
+ time_t check_time; // Time to use
+ unsigned long inh_flags; // Inheritance flags
+ unsigned long flags; // Various verify flags
+ int purpose; // purpose to check untrusted certificates
+ int trust; // trust setting to check
+ int depth; // Verify depth
+ STACK_OF(ASN1_OBJECT) *policies; // Permissible policies
+ // The following fields specify acceptable peer identities.
+ STACK_OF(OPENSSL_STRING) *hosts; // Set of acceptable names
+ unsigned int hostflags; // Flags to control matching features
+ char *peername; // Matching hostname in peer certificate
+ char *email; // If not NULL email address to match
+ size_t emaillen;
+ unsigned char *ip; // If not NULL IP address to match
+ size_t iplen; // Length of IP address
+ unsigned char poison; // Fail all verifications at name checking
+} /* X509_VERIFY_PARAM */;
+
+struct x509_object_st {
+ // one of the above types
+ int type;
+ union {
+ char *ptr;
+ X509 *x509;
+ X509_CRL *crl;
+ EVP_PKEY *pkey;
+ } data;
+} /* X509_OBJECT */;
+
+// This is a static that defines the function interface
+struct x509_lookup_method_st {
+ const char *name;
+ int (*new_item)(X509_LOOKUP *ctx);
+ void (*free)(X509_LOOKUP *ctx);
+ int (*init)(X509_LOOKUP *ctx);
+ int (*shutdown)(X509_LOOKUP *ctx);
+ int (*ctrl)(X509_LOOKUP *ctx, int cmd, const char *argc, long argl,
+ char **ret);
+ int (*get_by_subject)(X509_LOOKUP *ctx, int type, X509_NAME *name,
+ X509_OBJECT *ret);
+ int (*get_by_issuer_serial)(X509_LOOKUP *ctx, int type, X509_NAME *name,
+ ASN1_INTEGER *serial, X509_OBJECT *ret);
+ int (*get_by_fingerprint)(X509_LOOKUP *ctx, int type, unsigned char *bytes,
+ int len, X509_OBJECT *ret);
+ int (*get_by_alias)(X509_LOOKUP *ctx, int type, char *str, int len,
+ X509_OBJECT *ret);
+} /* X509_LOOKUP_METHOD */;
+
+// This is used to hold everything. It is used for all certificate
+// validation. Once we have a certificate chain, the 'verify'
+// function is then called to actually check the cert chain.
+struct x509_store_st {
+ // The following is a cache of trusted certs
+ int cache; // if true, stash any hits
+ STACK_OF(X509_OBJECT) *objs; // Cache of all objects
+ CRYPTO_MUTEX objs_lock;
+ STACK_OF(X509) *additional_untrusted;
+
+ // These are external lookup methods
+ STACK_OF(X509_LOOKUP) *get_cert_methods;
+
+ X509_VERIFY_PARAM *param;
+
+ // Callbacks for various operations
+ X509_STORE_CTX_verify_fn verify; // called to verify a certificate
+ X509_STORE_CTX_verify_cb verify_cb; // error callback
+ X509_STORE_CTX_get_issuer_fn get_issuer; // get issuers cert from ctx
+ X509_STORE_CTX_check_issued_fn check_issued; // check issued
+ X509_STORE_CTX_check_revocation_fn
+ check_revocation; // Check revocation status of chain
+ X509_STORE_CTX_get_crl_fn get_crl; // retrieve CRL
+ X509_STORE_CTX_check_crl_fn check_crl; // Check CRL validity
+ X509_STORE_CTX_cert_crl_fn cert_crl; // Check certificate against CRL
+ X509_STORE_CTX_lookup_certs_fn lookup_certs;
+ X509_STORE_CTX_lookup_crls_fn lookup_crls;
+ X509_STORE_CTX_cleanup_fn cleanup;
+
+ CRYPTO_refcount_t references;
+} /* X509_STORE */;
+
+
+// This is the functions plus an instance of the local variables.
+struct x509_lookup_st {
+ int init; // have we been started
+ int skip; // don't use us.
+ X509_LOOKUP_METHOD *method; // the functions
+ char *method_data; // method data
+
+ X509_STORE *store_ctx; // who owns us
+} /* X509_LOOKUP */;
+
+// This is a used when verifying cert chains. Since the
+// gathering of the cert chain can take some time (and have to be
+// 'retried', this needs to be kept and passed around.
+struct x509_store_ctx_st {
+ X509_STORE *ctx;
+
+ // The following are set by the caller
+ X509 *cert; // The cert to check
+ STACK_OF(X509) *untrusted; // chain of X509s - untrusted - passed in
+ STACK_OF(X509_CRL) *crls; // set of CRLs passed in
+
+ X509_VERIFY_PARAM *param;
+ void *other_ctx; // Other info for use with get_issuer()
+
+ // Callbacks for various operations
+ X509_STORE_CTX_verify_fn verify; // called to verify a certificate
+ X509_STORE_CTX_verify_cb verify_cb; // error callback
+ X509_STORE_CTX_get_issuer_fn get_issuer; // get issuers cert from ctx
+ X509_STORE_CTX_check_issued_fn check_issued; // check issued
+ X509_STORE_CTX_check_revocation_fn
+ check_revocation; // Check revocation status of chain
+ X509_STORE_CTX_get_crl_fn get_crl; // retrieve CRL
+ X509_STORE_CTX_check_crl_fn check_crl; // Check CRL validity
+ X509_STORE_CTX_cert_crl_fn cert_crl; // Check certificate against CRL
+ X509_STORE_CTX_check_policy_fn check_policy;
+ X509_STORE_CTX_lookup_certs_fn lookup_certs;
+ X509_STORE_CTX_lookup_crls_fn lookup_crls;
+ X509_STORE_CTX_cleanup_fn cleanup;
+
+ // The following is built up
+ int valid; // if 0, rebuild chain
+ int last_untrusted; // index of last untrusted cert
+ STACK_OF(X509) *chain; // chain of X509s - built up and trusted
+ X509_POLICY_TREE *tree; // Valid policy tree
+
+ int explicit_policy; // Require explicit policy value
+
+ // When something goes wrong, this is why
+ int error_depth;
+ int error;
+ X509 *current_cert;
+ X509 *current_issuer; // cert currently being tested as valid issuer
+ X509_CRL *current_crl; // current CRL
+
+ int current_crl_score; // score of current CRL
+ unsigned int current_reasons; // Reason mask
+
+ X509_STORE_CTX *parent; // For CRL path validation: parent context
+
+ CRYPTO_EX_DATA ex_data;
+} /* X509_STORE_CTX */;
+
+
/* RSA-PSS functions. */
/* x509_rsa_pss_to_ctx configures |ctx| for an RSA-PSS operation based on
* signature algorithm parameters in |sigalg| (which must have type
* |NID_rsassaPss|) and key |pkey|. It returns one on success and zero on
* error. */
-int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey);
+int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg,
+ EVP_PKEY *pkey);
/* x509_rsa_pss_to_ctx sets |algor| to the signature algorithm parameters for
* |ctx|, which must have been configured for an RSA-PSS signing operation. It
@@ -55,7 +388,7 @@ int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor);
* with public key |pkey| and parameters from |algor|. The |ctx| argument must
* have been initialised with |EVP_MD_CTX_init|. It returns one on success, or
* zero on error. */
-int x509_digest_verify_init(EVP_MD_CTX *ctx, X509_ALGOR *sigalg,
+int x509_digest_verify_init(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg,
EVP_PKEY *pkey);
diff --git a/deps/boringssl/src/crypto/x509/name_print.c b/deps/boringssl/src/crypto/x509/name_print.c
new file mode 100644
index 0000000..b5523c0
--- /dev/null
+++ b/deps/boringssl/src/crypto/x509/name_print.c
@@ -0,0 +1,246 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/x509.h>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/obj.h>
+
+
+static int maybe_write(BIO *out, const void *buf, int len)
+{
+ /* If |out| is NULL, ignore the output but report the length. */
+ return out == NULL || BIO_write(out, buf, len) == len;
+}
+
+/* do_indent prints |indent| spaces to |out|. */
+static int do_indent(BIO *out, int indent)
+{
+ for (int i = 0; i < indent; i++) {
+ if (!maybe_write(out, " ", 1)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#define FN_WIDTH_LN 25
+#define FN_WIDTH_SN 10
+
+static int do_name_ex(BIO *out, const X509_NAME *n, int indent,
+ unsigned long flags)
+{
+ int i, prev = -1, orflags, cnt;
+ int fn_opt, fn_nid;
+ ASN1_OBJECT *fn;
+ ASN1_STRING *val;
+ X509_NAME_ENTRY *ent;
+ char objtmp[80];
+ const char *objbuf;
+ int outlen, len;
+ const char *sep_dn, *sep_mv, *sep_eq;
+ int sep_dn_len, sep_mv_len, sep_eq_len;
+ if (indent < 0)
+ indent = 0;
+ outlen = indent;
+ if (!do_indent(out, indent))
+ return -1;
+ switch (flags & XN_FLAG_SEP_MASK) {
+ case XN_FLAG_SEP_MULTILINE:
+ sep_dn = "\n";
+ sep_dn_len = 1;
+ sep_mv = " + ";
+ sep_mv_len = 3;
+ break;
+
+ case XN_FLAG_SEP_COMMA_PLUS:
+ sep_dn = ",";
+ sep_dn_len = 1;
+ sep_mv = "+";
+ sep_mv_len = 1;
+ indent = 0;
+ break;
+
+ case XN_FLAG_SEP_CPLUS_SPC:
+ sep_dn = ", ";
+ sep_dn_len = 2;
+ sep_mv = " + ";
+ sep_mv_len = 3;
+ indent = 0;
+ break;
+
+ case XN_FLAG_SEP_SPLUS_SPC:
+ sep_dn = "; ";
+ sep_dn_len = 2;
+ sep_mv = " + ";
+ sep_mv_len = 3;
+ indent = 0;
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (flags & XN_FLAG_SPC_EQ) {
+ sep_eq = " = ";
+ sep_eq_len = 3;
+ } else {
+ sep_eq = "=";
+ sep_eq_len = 1;
+ }
+
+ fn_opt = flags & XN_FLAG_FN_MASK;
+
+ cnt = X509_NAME_entry_count(n);
+ for (i = 0; i < cnt; i++) {
+ if (flags & XN_FLAG_DN_REV)
+ ent = X509_NAME_get_entry(n, cnt - i - 1);
+ else
+ ent = X509_NAME_get_entry(n, i);
+ if (prev != -1) {
+ if (prev == X509_NAME_ENTRY_set(ent)) {
+ if (!maybe_write(out, sep_mv, sep_mv_len))
+ return -1;
+ outlen += sep_mv_len;
+ } else {
+ if (!maybe_write(out, sep_dn, sep_dn_len))
+ return -1;
+ outlen += sep_dn_len;
+ if (!do_indent(out, indent))
+ return -1;
+ outlen += indent;
+ }
+ }
+ prev = X509_NAME_ENTRY_set(ent);
+ fn = X509_NAME_ENTRY_get_object(ent);
+ val = X509_NAME_ENTRY_get_data(ent);
+ fn_nid = OBJ_obj2nid(fn);
+ if (fn_opt != XN_FLAG_FN_NONE) {
+ int objlen, fld_len;
+ if ((fn_opt == XN_FLAG_FN_OID) || (fn_nid == NID_undef)) {
+ OBJ_obj2txt(objtmp, sizeof objtmp, fn, 1);
+ fld_len = 0; /* XXX: what should this be? */
+ objbuf = objtmp;
+ } else {
+ if (fn_opt == XN_FLAG_FN_SN) {
+ fld_len = FN_WIDTH_SN;
+ objbuf = OBJ_nid2sn(fn_nid);
+ } else if (fn_opt == XN_FLAG_FN_LN) {
+ fld_len = FN_WIDTH_LN;
+ objbuf = OBJ_nid2ln(fn_nid);
+ } else {
+ fld_len = 0; /* XXX: what should this be? */
+ objbuf = "";
+ }
+ }
+ objlen = strlen(objbuf);
+ if (!maybe_write(out, objbuf, objlen))
+ return -1;
+ if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
+ if (!do_indent(out, fld_len - objlen))
+ return -1;
+ outlen += fld_len - objlen;
+ }
+ if (!maybe_write(out, sep_eq, sep_eq_len))
+ return -1;
+ outlen += objlen + sep_eq_len;
+ }
+ /*
+ * If the field name is unknown then fix up the DER dump flag. We
+ * might want to limit this further so it will DER dump on anything
+ * other than a few 'standard' fields.
+ */
+ if ((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS))
+ orflags = ASN1_STRFLGS_DUMP_ALL;
+ else
+ orflags = 0;
+
+ len = ASN1_STRING_print_ex(out, val, flags | orflags);
+ if (len < 0)
+ return -1;
+ outlen += len;
+ }
+ return outlen;
+}
+
+int X509_NAME_print_ex(BIO *out, const X509_NAME *nm, int indent,
+ unsigned long flags)
+{
+ if (flags == XN_FLAG_COMPAT)
+ return X509_NAME_print(out, nm, indent);
+ return do_name_ex(out, nm, indent, flags);
+}
+
+int X509_NAME_print_ex_fp(FILE *fp, const X509_NAME *nm, int indent,
+ unsigned long flags)
+{
+ BIO *bio = NULL;
+ if (fp != NULL) {
+ /* If |fp| is NULL, this function returns the number of bytes without
+ * writing. */
+ bio = BIO_new_fp(fp, BIO_NOCLOSE);
+ if (bio == NULL) {
+ return -1;
+ }
+ }
+ int ret = X509_NAME_print_ex(bio, nm, indent, flags);
+ BIO_free(bio);
+ return ret;
+}
diff --git a/deps/boringssl/src/crypto/x509/rsa_pss.c b/deps/boringssl/src/crypto/x509/rsa_pss.c
index 39637b9..1520c08 100644
--- a/deps/boringssl/src/crypto/x509/rsa_pss.c
+++ b/deps/boringssl/src/crypto/x509/rsa_pss.c
@@ -167,7 +167,8 @@ static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) {
}
/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */
-static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash) {
+static const EVP_MD *rsa_mgf1_to_md(const X509_ALGOR *alg,
+ X509_ALGOR *maskHash) {
const EVP_MD *md;
if (!alg) {
return EVP_sha1();
@@ -246,7 +247,8 @@ err:
return ret;
}
-int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey) {
+int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg,
+ EVP_PKEY *pkey) {
assert(OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss);
/* Decode PSS parameters */
diff --git a/deps/boringssl/src/crypto/x509/t_crl.c b/deps/boringssl/src/crypto/x509/t_crl.c
index 14f98c5..d924f85 100644
--- a/deps/boringssl/src/crypto/x509/t_crl.c
+++ b/deps/boringssl/src/crypto/x509/t_crl.c
@@ -61,7 +61,6 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
-#ifndef OPENSSL_NO_FP_API
int X509_CRL_print_fp(FILE *fp, X509_CRL *x)
{
BIO *b = BIO_new_fp(fp, BIO_NOCLOSE);
@@ -73,7 +72,6 @@ int X509_CRL_print_fp(FILE *fp, X509_CRL *x)
BIO_free(b);
return ret;
}
-#endif
int X509_CRL_print(BIO *out, X509_CRL *x)
{
@@ -86,7 +84,13 @@ int X509_CRL_print(BIO *out, X509_CRL *x)
BIO_printf(out, "Certificate Revocation List (CRL):\n");
l = X509_CRL_get_version(x);
BIO_printf(out, "%8sVersion %lu (0x%lx)\n", "", l + 1, l);
- X509_signature_print(out, x->sig_alg, NULL);
+ const X509_ALGOR *sig_alg;
+ const ASN1_BIT_STRING *signature;
+ X509_CRL_get0_signature(x, &signature, &sig_alg);
+ // Note this and the other |X509_signature_print| call print the outer
+ // signature algorithm twice, rather than both the inner and outer ones.
+ // This matches OpenSSL, though it was probably a bug.
+ X509_signature_print(out, sig_alg, NULL);
p = X509_NAME_oneline(X509_CRL_get_issuer(x), NULL, 0);
BIO_printf(out, "%8sIssuer: %s\n", "", p);
OPENSSL_free(p);
@@ -99,7 +103,8 @@ int X509_CRL_print(BIO *out, X509_CRL *x)
BIO_printf(out, "NONE");
BIO_printf(out, "\n");
- X509V3_extensions_print(out, "CRL extensions", x->crl->extensions, 0, 8);
+ X509V3_extensions_print(out, "CRL extensions", X509_CRL_get0_extensions(x),
+ 0, 8);
rev = X509_CRL_get_REVOKED(x);
@@ -118,7 +123,7 @@ int X509_CRL_print(BIO *out, X509_CRL *x)
X509V3_extensions_print(out, "CRL entry extensions",
r->extensions, 0, 8);
}
- X509_signature_print(out, x->sig_alg, x->signature);
+ X509_signature_print(out, sig_alg, signature);
return 1;
diff --git a/deps/boringssl/src/crypto/x509/t_req.c b/deps/boringssl/src/crypto/x509/t_req.c
index 2fd36f8..8202664 100644
--- a/deps/boringssl/src/crypto/x509/t_req.c
+++ b/deps/boringssl/src/crypto/x509/t_req.c
@@ -63,6 +63,8 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include "internal.h"
+
int X509_REQ_print_fp(FILE *fp, X509_REQ *x) {
BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE);
diff --git a/deps/boringssl/src/crypto/x509/t_x509.c b/deps/boringssl/src/crypto/x509/t_x509.c
index 5db8746..7c32a87 100644
--- a/deps/boringssl/src/crypto/x509/t_x509.c
+++ b/deps/boringssl/src/crypto/x509/t_x509.c
@@ -54,7 +54,6 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
-#include <ctype.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/digest.h>
@@ -68,7 +67,6 @@
#include "internal.h"
-#ifndef OPENSSL_NO_FP_API
int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag,
unsigned long cflag)
{
@@ -86,7 +84,6 @@ int X509_print_fp(FILE *fp, X509 *x)
{
return X509_print_ex_fp(fp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
}
-#endif
int X509_print(BIO *bp, X509 *x)
{
@@ -318,182 +315,6 @@ int X509_signature_print(BIO *bp, const X509_ALGOR *sigalg,
return 1;
}
-int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v)
-{
- int i, n;
- char buf[80];
- const char *p;
-
- if (v == NULL)
- return (0);
- n = 0;
- p = (const char *)v->data;
- for (i = 0; i < v->length; i++) {
- if ((p[i] > '~') || ((p[i] < ' ') &&
- (p[i] != '\n') && (p[i] != '\r')))
- buf[n] = '.';
- else
- buf[n] = p[i];
- n++;
- if (n >= 80) {
- if (BIO_write(bp, buf, n) <= 0)
- return (0);
- n = 0;
- }
- }
- if (n > 0)
- if (BIO_write(bp, buf, n) <= 0)
- return (0);
- return (1);
-}
-
-int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
-{
- if (tm->type == V_ASN1_UTCTIME)
- return ASN1_UTCTIME_print(bp, tm);
- if (tm->type == V_ASN1_GENERALIZEDTIME)
- return ASN1_GENERALIZEDTIME_print(bp, tm);
- BIO_write(bp, "Bad time value", 14);
- return (0);
-}
-
-static const char *const mon[12] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
-int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm)
-{
- char *v;
- int gmt = 0;
- int i;
- int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0;
- char *f = NULL;
- int f_len = 0;
-
- i = tm->length;
- v = (char *)tm->data;
-
- if (i < 12)
- goto err;
- if (v[i - 1] == 'Z')
- gmt = 1;
- for (i = 0; i < 12; i++)
- if ((v[i] > '9') || (v[i] < '0'))
- goto err;
- y = (v[0] - '0') * 1000 + (v[1] - '0') * 100 + (v[2] - '0') * 10 + (v[3] -
- '0');
- M = (v[4] - '0') * 10 + (v[5] - '0');
- if ((M > 12) || (M < 1))
- goto err;
- d = (v[6] - '0') * 10 + (v[7] - '0');
- h = (v[8] - '0') * 10 + (v[9] - '0');
- m = (v[10] - '0') * 10 + (v[11] - '0');
- if (tm->length >= 14 &&
- (v[12] >= '0') && (v[12] <= '9') &&
- (v[13] >= '0') && (v[13] <= '9')) {
- s = (v[12] - '0') * 10 + (v[13] - '0');
- /* Check for fractions of seconds. */
- if (tm->length >= 15 && v[14] == '.') {
- int l = tm->length;
- f = &v[14]; /* The decimal point. */
- f_len = 1;
- while (14 + f_len < l && f[f_len] >= '0' && f[f_len] <= '9')
- ++f_len;
- }
- }
-
- if (BIO_printf(bp, "%s %2d %02d:%02d:%02d%.*s %d%s",
- mon[M - 1], d, h, m, s, f_len, f, y,
- (gmt) ? " GMT" : "") <= 0)
- return (0);
- else
- return (1);
- err:
- BIO_write(bp, "Bad time value", 14);
- return (0);
-}
-
-// consume_two_digits is a helper function for ASN1_UTCTIME_print. If |*v|,
-// assumed to be |*len| bytes long, has two leading digits, updates |*out| with
-// their value, updates |v| and |len|, and returns one. Otherwise, returns
-// zero.
-static int consume_two_digits(int* out, const char **v, int *len) {
- if (*len < 2|| !isdigit((*v)[0]) || !isdigit((*v)[1])) {
- return 0;
- }
- *out = ((*v)[0] - '0') * 10 + ((*v)[1] - '0');
- *len -= 2;
- *v += 2;
- return 1;
-}
-
-// consume_zulu_timezone is a helper function for ASN1_UTCTIME_print. If |*v|,
-// assumed to be |*len| bytes long, starts with "Z" then it updates |*v| and
-// |*len| and returns one. Otherwise returns zero.
-static int consume_zulu_timezone(const char **v, int *len) {
- if (*len == 0 || (*v)[0] != 'Z') {
- return 0;
- }
-
- *len -= 1;
- *v += 1;
- return 1;
-}
-
-int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) {
- const char *v = (const char *)tm->data;
- int len = tm->length;
- int Y = 0, M = 0, D = 0, h = 0, m = 0, s = 0;
-
- // YYMMDDhhmm are required to be present.
- if (!consume_two_digits(&Y, &v, &len) ||
- !consume_two_digits(&M, &v, &len) ||
- !consume_two_digits(&D, &v, &len) ||
- !consume_two_digits(&h, &v, &len) ||
- !consume_two_digits(&m, &v, &len)) {
- goto err;
- }
- // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires seconds
- // to be present, but historically this code has forgiven its absence.
- consume_two_digits(&s, &v, &len);
-
- // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, specifies this
- // interpretation of the year.
- if (Y < 50) {
- Y += 2000;
- } else {
- Y += 1900;
- }
- if (M > 12 || M == 0) {
- goto err;
- }
- if (D > 31 || D == 0) {
- goto err;
- }
- if (h > 23 || m > 59 || s > 60) {
- goto err;
- }
-
- // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires the "Z"
- // to be present, but historically this code has forgiven its absence.
- const int is_gmt = consume_zulu_timezone(&v, &len);
-
- // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, does not permit
- // the specification of timezones using the +hhmm / -hhmm syntax, which is
- // the only other thing that might legitimately be found at the end.
- if (len) {
- goto err;
- }
-
- return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s", mon[M - 1], D, h, m, s, Y,
- is_gmt ? " GMT" : "") > 0;
-
-err:
- BIO_write(bp, "Bad time value", 14);
- return 0;
-}
-
int X509_NAME_print(BIO *bp, const X509_NAME *name, int obase)
{
char *s, *c, *b;
diff --git a/deps/boringssl/src/crypto/x509/t_x509a.c b/deps/boringssl/src/crypto/x509/t_x509a.c
index 5436828..4c7b212 100644
--- a/deps/boringssl/src/crypto/x509/t_x509a.c
+++ b/deps/boringssl/src/crypto/x509/t_x509a.c
@@ -60,6 +60,9 @@
#include <openssl/obj.h>
#include <openssl/x509.h>
+#include "internal.h"
+
+
/* X509_CERT_AUX and string set routines */
int X509_CERT_AUX_print(BIO *out, X509_CERT_AUX *aux, int indent)
@@ -99,8 +102,10 @@ int X509_CERT_AUX_print(BIO *out, X509_CERT_AUX *aux, int indent)
BIO_puts(out, "\n");
} else
BIO_printf(out, "%*sNo Rejected Uses.\n", indent, "");
- if (aux->alias)
- BIO_printf(out, "%*sAlias: %s\n", indent, "", aux->alias->data);
+ if (aux->alias) {
+ BIO_printf(out, "%*sAlias: %.*s\n", indent, "", aux->alias->length,
+ aux->alias->data);
+ }
if (aux->keyid) {
BIO_printf(out, "%*sKey Id: ", indent, "");
for (j = 0; j < aux->keyid->length; j++)
diff --git a/deps/boringssl/src/crypto/x509/vpm_int.h b/deps/boringssl/src/crypto/x509/vpm_int.h
deleted file mode 100644
index 53b4a0d..0000000
--- a/deps/boringssl/src/crypto/x509/vpm_int.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* vpm_int.h */
-/*
- * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
- * 2013.
- */
-/* ====================================================================
- * Copyright (c) 2013 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-/* internal only structure to hold additional X509_VERIFY_PARAM data */
-
-struct X509_VERIFY_PARAM_ID_st {
- STACK_OF(OPENSSL_STRING) *hosts; /* Set of acceptable names */
- unsigned int hostflags; /* Flags to control matching features */
- char *peername; /* Matching hostname in peer certificate */
- char *email; /* If not NULL email address to match */
- size_t emaillen;
- unsigned char *ip; /* If not NULL IP address to match */
- size_t iplen; /* Length of IP address */
- unsigned char poison; /* Fail all verifications */
-};
diff --git a/deps/boringssl/src/crypto/x509/x509_att.c b/deps/boringssl/src/crypto/x509/x509_att.c
index 85d65e7..e2a5121 100644
--- a/deps/boringssl/src/crypto/x509/x509_att.c
+++ b/deps/boringssl/src/crypto/x509/x509_att.c
@@ -62,6 +62,10 @@
#include <openssl/stack.h>
#include <openssl/x509.h>
+#include "../asn1/internal.h"
+#include "internal.h"
+
+
int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x)
{
return sk_X509_ATTRIBUTE_num(x);
@@ -70,12 +74,11 @@ int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x)
int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid,
int lastpos)
{
- const ASN1_OBJECT *obj;
-
- obj = OBJ_nid2obj(nid);
- if (obj == NULL)
- return (-2);
- return (X509at_get_attr_by_OBJ(x, obj, lastpos));
+ const ASN1_OBJECT *obj = OBJ_nid2obj(nid);
+ if (obj == NULL) {
+ return -1;
+ }
+ return X509at_get_attr_by_OBJ(x, obj, lastpos);
}
int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk,
@@ -197,24 +200,8 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE)
return ret;
}
-void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x,
- ASN1_OBJECT *obj, int lastpos, int type)
-{
- int i;
- X509_ATTRIBUTE *at;
- i = X509at_get_attr_by_OBJ(x, obj, lastpos);
- if (i == -1)
- return NULL;
- if ((lastpos <= -2) && (X509at_get_attr_by_OBJ(x, obj, i) != -1))
- return NULL;
- at = X509at_get_attr(x, i);
- if (lastpos <= -3 && (X509_ATTRIBUTE_count(at) != 1))
- return NULL;
- return X509_ATTRIBUTE_get0_data(at, 0, type, NULL);
-}
-
X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
- int atrtype, const void *data,
+ int attrtype, const void *data,
int len)
{
const ASN1_OBJECT *obj;
@@ -224,12 +211,12 @@ X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID);
return (NULL);
}
- return X509_ATTRIBUTE_create_by_OBJ(attr, obj, atrtype, data, len);
+ return X509_ATTRIBUTE_create_by_OBJ(attr, obj, attrtype, data, len);
}
X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
const ASN1_OBJECT *obj,
- int atrtype, const void *data,
+ int attrtype, const void *data,
int len)
{
X509_ATTRIBUTE *ret;
@@ -244,7 +231,7 @@ X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
if (!X509_ATTRIBUTE_set1_object(ret, obj))
goto err;
- if (!X509_ATTRIBUTE_set1_data(ret, atrtype, data, len))
+ if (!X509_ATTRIBUTE_set1_data(ret, attrtype, data, len))
goto err;
if ((attr != NULL) && (*attr == NULL))
@@ -257,17 +244,17 @@ X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
}
X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr,
- const char *atrname, int type,
+ const char *attrname, int type,
const unsigned char *bytes,
int len)
{
ASN1_OBJECT *obj;
X509_ATTRIBUTE *nattr;
- obj = OBJ_txt2obj(atrname, 0);
+ obj = OBJ_txt2obj(attrname, 0);
if (obj == NULL) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_NAME);
- ERR_add_error_data(2, "name=", atrname);
+ ERR_add_error_data(2, "name=", attrname);
return (NULL);
}
nattr = X509_ATTRIBUTE_create_by_OBJ(attr, obj, type, bytes, len);
@@ -307,9 +294,6 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
goto err;
atype = attrtype;
}
- if (!(attr->value.set = sk_ASN1_TYPE_new_null()))
- goto err;
- attr->single = 0;
/*
* This is a bit naughty because the attribute should really have at
* least one value but some types use and zero length SET and require
@@ -328,7 +312,7 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
ASN1_TYPE_set(ttmp, atype, stmp);
stmp = NULL;
}
- if (!sk_ASN1_TYPE_push(attr->value.set, ttmp))
+ if (!sk_ASN1_TYPE_push(attr->set, ttmp))
goto err;
return 1;
err:
@@ -338,13 +322,9 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
return 0;
}
-int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr)
+int X509_ATTRIBUTE_count(const X509_ATTRIBUTE *attr)
{
- if (!attr->single)
- return sk_ASN1_TYPE_num(attr->value.set);
- if (attr->value.single)
- return 1;
- return 0;
+ return sk_ASN1_TYPE_num(attr->set);
}
ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr)
@@ -355,27 +335,24 @@ ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr)
}
void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx,
- int atrtype, void *data)
+ int attrtype, void *unused)
{
ASN1_TYPE *ttmp;
ttmp = X509_ATTRIBUTE_get0_type(attr, idx);
if (!ttmp)
return NULL;
- if (atrtype != ASN1_TYPE_get(ttmp)) {
+ if (attrtype != ASN1_TYPE_get(ttmp)) {
OPENSSL_PUT_ERROR(X509, X509_R_WRONG_TYPE);
return NULL;
}
- return ttmp->value.ptr;
+ return (void *)asn1_type_value_as_pointer(ttmp);
}
ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx)
{
if (attr == NULL)
- return (NULL);
+ return NULL;
if (idx >= X509_ATTRIBUTE_count(attr))
return NULL;
- if (!attr->single)
- return sk_ASN1_TYPE_value(attr->value.set, idx);
- else
- return attr->value.single;
+ return sk_ASN1_TYPE_value(attr->set, idx);
}
diff --git a/deps/boringssl/src/crypto/x509/x509_cmp.c b/deps/boringssl/src/crypto/x509/x509_cmp.c
index cf0a941..5811f44 100644
--- a/deps/boringssl/src/crypto/x509/x509_cmp.c
+++ b/deps/boringssl/src/crypto/x509/x509_cmp.c
@@ -68,6 +68,7 @@
#include "../internal.h"
#include "../x509v3/internal.h"
+#include "internal.h"
int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b)
@@ -83,34 +84,6 @@ int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b)
return (X509_NAME_cmp(ai->issuer, bi->issuer));
}
-unsigned long X509_issuer_and_serial_hash(X509 *a)
-{
- unsigned long ret = 0;
- EVP_MD_CTX ctx;
- unsigned char md[16];
- char *f;
-
- EVP_MD_CTX_init(&ctx);
- f = X509_NAME_oneline(a->cert_info->issuer, NULL, 0);
- if (!EVP_DigestInit_ex(&ctx, EVP_md5(), NULL))
- goto err;
- if (!EVP_DigestUpdate(&ctx, (unsigned char *)f, strlen(f)))
- goto err;
- OPENSSL_free(f);
- if (!EVP_DigestUpdate
- (&ctx, (unsigned char *)a->cert_info->serialNumber->data,
- (unsigned long)a->cert_info->serialNumber->length))
- goto err;
- if (!EVP_DigestFinal_ex(&ctx, &(md[0]), NULL))
- goto err;
- ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) |
- ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L)
- ) & 0xffffffffL;
- err:
- EVP_MD_CTX_cleanup(&ctx);
- return (ret);
-}
-
int X509_issuer_name_cmp(const X509 *a, const X509 *b)
{
return (X509_NAME_cmp(a->cert_info->issuer, b->cert_info->issuer));
@@ -411,7 +384,7 @@ int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
} else
i = 0;
- if (X509_get_version(x) != 2) {
+ if (X509_get_version(x) != X509_VERSION_3) {
rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
/* Correct error depth */
i = 0;
@@ -429,7 +402,7 @@ int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
for (; i < sk_X509_num(chain); i++) {
sign_nid = X509_get_signature_nid(x);
x = sk_X509_value(chain, i);
- if (X509_get_version(x) != 2) {
+ if (X509_get_version(x) != X509_VERSION_3) {
rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
goto end;
}
diff --git a/deps/boringssl/src/crypto/x509/x509_ext.c b/deps/boringssl/src/crypto/x509/x509_ext.c
index f6da54a..a08e2a8 100644
--- a/deps/boringssl/src/crypto/x509/x509_ext.c
+++ b/deps/boringssl/src/crypto/x509/x509_ext.c
@@ -62,6 +62,8 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include "internal.h"
+
int X509_CRL_get_ext_count(const X509_CRL *x)
{
return (X509v3_get_ext_count(x->crl->extensions));
@@ -208,5 +210,3 @@ int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit,
{
return X509V3_add1_i2d(&x->extensions, nid, value, crit, flags);
}
-
-IMPLEMENT_ASN1_SET_OF(X509_EXTENSION)
diff --git a/deps/boringssl/src/crypto/x509/x509_lu.c b/deps/boringssl/src/crypto/x509/x509_lu.c
index 4046c3e..6d51ffd 100644
--- a/deps/boringssl/src/crypto/x509/x509_lu.c
+++ b/deps/boringssl/src/crypto/x509/x509_lu.c
@@ -64,6 +64,7 @@
#include <openssl/x509v3.h>
#include "../internal.h"
+#include "internal.h"
X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method)
{
diff --git a/deps/boringssl/src/crypto/x509/x509_obj.c b/deps/boringssl/src/crypto/x509/x509_obj.c
index 80d16c1..df54f77 100644
--- a/deps/boringssl/src/crypto/x509/x509_obj.c
+++ b/deps/boringssl/src/crypto/x509/x509_obj.c
@@ -64,6 +64,7 @@
#include <openssl/x509.h>
#include "../internal.h"
+#include "internal.h"
/*
diff --git a/deps/boringssl/src/crypto/x509/x509_req.c b/deps/boringssl/src/crypto/x509/x509_req.c
index 9ab6e9d..99eabfe 100644
--- a/deps/boringssl/src/crypto/x509/x509_req.c
+++ b/deps/boringssl/src/crypto/x509/x509_req.c
@@ -65,6 +65,9 @@
#include <openssl/pem.h>
#include <openssl/x509.h>
+#include "internal.h"
+
+
X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
{
X509_REQ *ret;
@@ -157,62 +160,31 @@ int X509_REQ_check_private_key(X509_REQ *x, EVP_PKEY *k)
return (ok);
}
-/*
- * It seems several organisations had the same idea of including a list of
- * extensions in a certificate request. There are at least two OIDs that are
- * used and there may be more: so the list is configurable.
- */
-
-static const int ext_nid_list[] = { NID_ext_req, NID_ms_ext_req, NID_undef };
-
-static const int *ext_nids = ext_nid_list;
-
int X509_REQ_extension_nid(int req_nid)
{
- int i, nid;
- for (i = 0;; i++) {
- nid = ext_nids[i];
- if (nid == NID_undef)
- return 0;
- else if (req_nid == nid)
- return 1;
- }
-}
-
-const int *X509_REQ_get_extension_nids(void)
-{
- return ext_nids;
-}
-
-void X509_REQ_set_extension_nids(const int *nids)
-{
- ext_nids = nids;
+ return req_nid == NID_ext_req || req_nid == NID_ms_ext_req;
}
STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req)
{
- X509_ATTRIBUTE *attr;
- ASN1_TYPE *ext = NULL;
- int idx;
- const int *pnid;
- const unsigned char *p;
+ if (req == NULL || req->req_info == NULL) {
+ return NULL;
+ }
- if ((req == NULL) || (req->req_info == NULL) || !ext_nids)
- return (NULL);
- for (pnid = ext_nids; *pnid != NID_undef; pnid++) {
- idx = X509_REQ_get_attr_by_NID(req, *pnid, -1);
- if (idx == -1)
- continue;
- attr = X509_REQ_get_attr(req, idx);
- if (attr->single)
- ext = attr->value.single;
- else if (sk_ASN1_TYPE_num(attr->value.set))
- ext = sk_ASN1_TYPE_value(attr->value.set, 0);
- break;
+ int idx = X509_REQ_get_attr_by_NID(req, NID_ext_req, -1);
+ if (idx == -1) {
+ idx = X509_REQ_get_attr_by_NID(req, NID_ms_ext_req, -1);
+ }
+ if (idx == -1) {
+ return NULL;
}
- if (!ext || (ext->type != V_ASN1_SEQUENCE))
+
+ X509_ATTRIBUTE *attr = X509_REQ_get_attr(req, idx);
+ ASN1_TYPE *ext = X509_ATTRIBUTE_get0_type(attr, 0);
+ if (!ext || ext->type != V_ASN1_SEQUENCE) {
return NULL;
- p = ext->value.sequence->data;
+ }
+ const unsigned char *p = ext->value.sequence->data;
return (STACK_OF(X509_EXTENSION) *)
ASN1_item_d2i(NULL, &p, ext->value.sequence->length,
ASN1_ITEM_rptr(X509_EXTENSIONS));
@@ -223,44 +195,25 @@ STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req)
* in case we want to create a non standard one.
*/
-int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts,
- int nid)
+int X509_REQ_add_extensions_nid(X509_REQ *req,
+ const STACK_OF(X509_EXTENSION) *exts, int nid)
{
- ASN1_TYPE *at = NULL;
- X509_ATTRIBUTE *attr = NULL;
- if (!(at = ASN1_TYPE_new()) || !(at->value.sequence = ASN1_STRING_new()))
- goto err;
-
- at->type = V_ASN1_SEQUENCE;
/* Generate encoding of extensions */
- at->value.sequence->length =
- ASN1_item_i2d((ASN1_VALUE *)exts,
- &at->value.sequence->data,
- ASN1_ITEM_rptr(X509_EXTENSIONS));
- if (!(attr = X509_ATTRIBUTE_new()))
- goto err;
- if (!(attr->value.set = sk_ASN1_TYPE_new_null()))
- goto err;
- if (!sk_ASN1_TYPE_push(attr->value.set, at))
- goto err;
- at = NULL;
- attr->single = 0;
- attr->object = (ASN1_OBJECT *)OBJ_nid2obj(nid);
- if (!req->req_info->attributes) {
- if (!(req->req_info->attributes = sk_X509_ATTRIBUTE_new_null()))
- goto err;
+ unsigned char *ext = NULL;
+ int ext_len = ASN1_item_i2d((ASN1_VALUE *)exts, &ext,
+ ASN1_ITEM_rptr(X509_EXTENSIONS));
+ if (ext_len <= 0) {
+ return 0;
}
- if (!sk_X509_ATTRIBUTE_push(req->req_info->attributes, attr))
- goto err;
- return 1;
- err:
- X509_ATTRIBUTE_free(attr);
- ASN1_TYPE_free(at);
- return 0;
+ int ret = X509_REQ_add1_attr_by_NID(req, nid, V_ASN1_SEQUENCE, ext,
+ ext_len);
+ OPENSSL_free(ext);
+ return ret;
}
/* This is the normal usage: use the "official" OID */
-int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts)
+int X509_REQ_add_extensions(X509_REQ *req,
+ const STACK_OF(X509_EXTENSION) *exts)
{
return X509_REQ_add_extensions_nid(req, exts, NID_ext_req);
}
@@ -277,7 +230,7 @@ int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, int lastpos)
return X509at_get_attr_by_NID(req->req_info->attributes, nid, lastpos);
}
-int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj,
+int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, const ASN1_OBJECT *obj,
int lastpos)
{
return X509at_get_attr_by_OBJ(req->req_info->attributes, obj, lastpos);
@@ -301,31 +254,31 @@ int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr)
}
int X509_REQ_add1_attr_by_OBJ(X509_REQ *req,
- const ASN1_OBJECT *obj, int type,
- const unsigned char *bytes, int len)
+ const ASN1_OBJECT *obj, int attrtype,
+ const unsigned char *data, int len)
{
if (X509at_add1_attr_by_OBJ(&req->req_info->attributes, obj,
- type, bytes, len))
+ attrtype, data, len))
return 1;
return 0;
}
int X509_REQ_add1_attr_by_NID(X509_REQ *req,
- int nid, int type,
- const unsigned char *bytes, int len)
+ int nid, int attrtype,
+ const unsigned char *data, int len)
{
if (X509at_add1_attr_by_NID(&req->req_info->attributes, nid,
- type, bytes, len))
+ attrtype, data, len))
return 1;
return 0;
}
int X509_REQ_add1_attr_by_txt(X509_REQ *req,
- const char *attrname, int type,
- const unsigned char *bytes, int len)
+ const char *attrname, int attrtype,
+ const unsigned char *data, int len)
{
if (X509at_add1_attr_by_txt(&req->req_info->attributes, attrname,
- type, bytes, len))
+ attrtype, data, len))
return 1;
return 0;
}
diff --git a/deps/boringssl/src/crypto/x509/x509_set.c b/deps/boringssl/src/crypto/x509/x509_set.c
index 5f17851..93bb6a3 100644
--- a/deps/boringssl/src/crypto/x509/x509_set.c
+++ b/deps/boringssl/src/crypto/x509/x509_set.c
@@ -60,18 +60,21 @@
#include <openssl/obj.h>
#include <openssl/x509.h>
+#include "internal.h"
+
+
long X509_get_version(const X509 *x509)
{
+ // The default version is v1(0).
+ if (x509->cert_info->version == NULL) {
+ return X509_VERSION_1;
+ }
return ASN1_INTEGER_get(x509->cert_info->version);
}
-X509_CINF *X509_get_cert_info(const X509 *x509)
-{
- return x509->cert_info;
-}
-
int X509_set_version(X509 *x, long version)
{
+ // TODO(davidben): Reject invalid version numbers.
if (x == NULL)
return (0);
if (version == 0) {
@@ -86,7 +89,7 @@ int X509_set_version(X509 *x, long version)
return (ASN1_INTEGER_set(x->cert_info->version, version));
}
-int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial)
+int X509_set_serialNumber(X509 *x, const ASN1_INTEGER *serial)
{
ASN1_INTEGER *in;
@@ -231,16 +234,6 @@ const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x)
return x->cert_info->signature;
}
-void X509_CINF_set_modified(X509_CINF *cinf)
-{
- cinf->enc.modified = 1;
-}
-
-const X509_ALGOR *X509_CINF_get_signature(const X509_CINF *cinf)
-{
- return cinf->signature;
-}
-
X509_PUBKEY *X509_get_X509_PUBKEY(const X509 *x509)
{
return x509->cert_info->key;
diff --git a/deps/boringssl/src/crypto/x509/x509_test.cc b/deps/boringssl/src/crypto/x509/x509_test.cc
index 0debb8a..848bd07 100644
--- a/deps/boringssl/src/crypto/x509/x509_test.cc
+++ b/deps/boringssl/src/crypto/x509/x509_test.cc
@@ -19,17 +19,20 @@
#include <gtest/gtest.h>
+#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/curve25519.h>
#include <openssl/digest.h>
#include <openssl/err.h>
+#include <openssl/nid.h>
#include <openssl/pem.h>
#include <openssl/pool.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include "internal.h"
#include "../internal.h"
#include "../test/test_util.h"
#include "../x509v3/internal.h"
@@ -441,6 +444,40 @@ o/1TpfOMSGhMyMoyPrk=
-----END X509 CRL-----
)";
+// kAlgorithmMismatchCRL is kBasicCRL but with mismatched AlgorithmIdentifiers
+// in the outer structure and signed portion. The signature reflects the signed
+// portion.
+static const char kAlgorithmMismatchCRL[] = R"(
+-----BEGIN X509 CRL-----
+MIIBpzCBkAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ
+Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoA4wDDAKBgNV
+HRQEAwIBATANBgkqhkiG9w0BAQwFAAOCAQEAnrBKKgvd9x9zwK9rtUvVeFeJ7+LN
+ZEAc+a5oxpPNEsJx6hXoApYEbzXMxuWBQoCs5iEBycSGudct21L+MVf27M38KrWo
+eOkq0a2siqViQZO2Fb/SUFR0k9zb8xl86Zf65lgPplALun0bV/HT7MJcl04Tc4os
+dsAReBs5nqTGNEd5AlC1iKHvQZkM//MD51DspKnDpsDiUVi54h9C1SpfZmX8H2Vv
+diyu0fZ/bPAM3VAGawatf/SyWfBMyKpoPXEG39oAzmjjOj8en82psn7m474IGaho
+/vBbhl1ms5qQiLYPjm4YELtnXQoFyC72tBjbdFd/ZE9k4CNKDbxFUXFbkw==
+-----END X509 CRL-----
+)";
+
+// kAlgorithmMismatchCRL2 is kBasicCRL but with mismatched AlgorithmIdentifiers
+// in the outer structure and signed portion. The signature reflects the outer
+// structure.
+static const char kAlgorithmMismatchCRL2[] = R"(
+-----BEGIN X509 CRL-----
+MIIBpzCBkAIBATANBgkqhkiG9w0BAQwFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ
+Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoA4wDDAKBgNV
+HRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAjCWtU7AK8nQ5TCFfzvbU04MWNuLp
+iZfqapRSRyMta4pyRomK773rEmJmYOc/ZNeIphVOlupMgGC2wyv5Z/SD1mxccJbv
+SlUWciwjskjgvyyU9KnJ5xPgf3e3Fl3G0u9yJEFd4mg6fRavs5pEDX56b0f+SkG+
+Vl1FZU94Uylm2kCqk9fRpTxualPGP6dksj3Aitt4x2Vdni4sUfg9vIEEOx2jnisq
+iLqpT94IdETCWAciE0dgbogdOOsNzMqSASfHM/XPigYLXpYgfaR8fca6OKDwFsVH
+SrkFz8Se3F6mCHnbDzYElbmA46iKU2J12LTrso3Ewq/qHq0mebfp2z0y6g==
+-----END X509 CRL-----
+)";
+
// kEd25519Cert is a self-signed Ed25519 certificate.
static const char kEd25519Cert[] = R"(
-----BEGIN CERTIFICATE-----
@@ -1069,6 +1106,8 @@ static bssl::UniquePtr<STACK_OF(X509_CRL)> CRLsToStack(
return stack;
}
+static const time_t kReferenceTime = 1474934400 /* Sep 27th, 2016 */;
+
static int Verify(X509 *leaf, const std::vector<X509 *> &roots,
const std::vector<X509 *> &intermediates,
const std::vector<X509_CRL *> &crls, unsigned long flags,
@@ -1111,7 +1150,7 @@ static int Verify(X509 *leaf, const std::vector<X509 *> &roots,
if (param == nullptr) {
return X509_V_ERR_UNSPECIFIED;
}
- X509_VERIFY_PARAM_set_time(param, 1474934400 /* Sep 27th, 2016 */);
+ X509_VERIFY_PARAM_set_time(param, kReferenceTime);
X509_VERIFY_PARAM_set_depth(param, 16);
if (configure_callback) {
configure_callback(param);
@@ -1363,6 +1402,10 @@ TEST(X509Test, TestCRL) {
CRLFromPEM(kUnknownCriticalCRL));
bssl::UniquePtr<X509_CRL> unknown_critical_crl2(
CRLFromPEM(kUnknownCriticalCRL2));
+ bssl::UniquePtr<X509_CRL> algorithm_mismatch_crl(
+ CRLFromPEM(kAlgorithmMismatchCRL));
+ bssl::UniquePtr<X509_CRL> algorithm_mismatch_crl2(
+ CRLFromPEM(kAlgorithmMismatchCRL2));
ASSERT_TRUE(root);
ASSERT_TRUE(leaf);
@@ -1372,30 +1415,38 @@ TEST(X509Test, TestCRL) {
ASSERT_TRUE(known_critical_crl);
ASSERT_TRUE(unknown_critical_crl);
ASSERT_TRUE(unknown_critical_crl2);
+ ASSERT_TRUE(algorithm_mismatch_crl);
+ ASSERT_TRUE(algorithm_mismatch_crl2);
- ASSERT_EQ(X509_V_OK, Verify(leaf.get(), {root.get()}, {root.get()},
+ EXPECT_EQ(X509_V_OK, Verify(leaf.get(), {root.get()}, {root.get()},
{basic_crl.get()}, X509_V_FLAG_CRL_CHECK));
- ASSERT_EQ(
+ EXPECT_EQ(
X509_V_ERR_CERT_REVOKED,
Verify(leaf.get(), {root.get()}, {root.get()},
{basic_crl.get(), revoked_crl.get()}, X509_V_FLAG_CRL_CHECK));
std::vector<X509_CRL *> empty_crls;
- ASSERT_EQ(X509_V_ERR_UNABLE_TO_GET_CRL,
+ EXPECT_EQ(X509_V_ERR_UNABLE_TO_GET_CRL,
Verify(leaf.get(), {root.get()}, {root.get()}, empty_crls,
X509_V_FLAG_CRL_CHECK));
- ASSERT_EQ(X509_V_ERR_UNABLE_TO_GET_CRL,
+ EXPECT_EQ(X509_V_ERR_UNABLE_TO_GET_CRL,
Verify(leaf.get(), {root.get()}, {root.get()},
{bad_issuer_crl.get()}, X509_V_FLAG_CRL_CHECK));
- ASSERT_EQ(X509_V_OK,
+ EXPECT_EQ(X509_V_OK,
Verify(leaf.get(), {root.get()}, {root.get()},
{known_critical_crl.get()}, X509_V_FLAG_CRL_CHECK));
- ASSERT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION,
+ EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION,
Verify(leaf.get(), {root.get()}, {root.get()},
{unknown_critical_crl.get()}, X509_V_FLAG_CRL_CHECK));
- ASSERT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION,
+ EXPECT_EQ(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION,
Verify(leaf.get(), {root.get()}, {root.get()},
{unknown_critical_crl2.get()}, X509_V_FLAG_CRL_CHECK));
+ EXPECT_EQ(X509_V_ERR_CRL_SIGNATURE_FAILURE,
+ Verify(leaf.get(), {root.get()}, {root.get()},
+ {algorithm_mismatch_crl.get()}, X509_V_FLAG_CRL_CHECK));
+ EXPECT_EQ(X509_V_ERR_CRL_SIGNATURE_FAILURE,
+ Verify(leaf.get(), {root.get()}, {root.get()},
+ {algorithm_mismatch_crl2.get()}, X509_V_FLAG_CRL_CHECK));
// Parsing kBadExtensionCRL should fail.
EXPECT_FALSE(CRLFromPEM(kBadExtensionCRL));
@@ -1442,6 +1493,211 @@ TEST(X509Test, ManyNamesAndConstraints) {
{many_constraints.get()}, {}));
}
+static bssl::UniquePtr<GENERAL_NAME> MakeGeneralName(int type,
+ const std::string &value) {
+ if (type != GEN_EMAIL && type != GEN_DNS && type != GEN_URI) {
+ // This function only supports the IA5String types.
+ return nullptr;
+ }
+ bssl::UniquePtr<ASN1_IA5STRING> str(ASN1_IA5STRING_new());
+ bssl::UniquePtr<GENERAL_NAME> name(GENERAL_NAME_new());
+ if (!str || !name ||
+ !ASN1_STRING_set(str.get(), value.data(), value.size())) {
+ return nullptr;
+ }
+
+ name->type = type;
+ name->d.ia5 = str.release();
+ return name;
+}
+
+static bssl::UniquePtr<X509> MakeTestCert(const char *issuer,
+ const char *subject, EVP_PKEY *key) {
+ bssl::UniquePtr<X509> cert(X509_new());
+ if (!cert || //
+ !X509_set_version(cert.get(), X509_VERSION_3) ||
+ !X509_NAME_add_entry_by_txt(
+ X509_get_issuer_name(cert.get()), "CN", MBSTRING_UTF8,
+ reinterpret_cast<const uint8_t *>(issuer), -1, -1, 0) ||
+ !X509_NAME_add_entry_by_txt(
+ X509_get_subject_name(cert.get()), "CN", MBSTRING_UTF8,
+ reinterpret_cast<const uint8_t *>(subject), -1, -1, 0) ||
+ !X509_set_pubkey(cert.get(), key) ||
+ !ASN1_TIME_adj(X509_getm_notBefore(cert.get()), kReferenceTime, -1, 0) ||
+ !ASN1_TIME_adj(X509_getm_notAfter(cert.get()), kReferenceTime, 1, 0)) {
+ return nullptr;
+ }
+ return cert;
+}
+
+TEST(X509Test, NameConstraints) {
+ bssl::UniquePtr<EVP_PKEY> key = PrivateKeyFromPEM(kP256Key);
+ ASSERT_TRUE(key);
+
+ const struct {
+ int type;
+ std::string name;
+ std::string constraint;
+ int result;
+ } kTests[] = {
+ // Empty string matches everything.
+ {GEN_DNS, "foo.example.com", "", X509_V_OK},
+ // Name constraints match the entire subtree.
+ {GEN_DNS, "foo.example.com", "example.com", X509_V_OK},
+ {GEN_DNS, "foo.example.com", "EXAMPLE.COM", X509_V_OK},
+ {GEN_DNS, "foo.example.com", "xample.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_DNS, "foo.example.com", "unrelated.much.longer.name.example",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ // A leading dot means at least one component must be added.
+ {GEN_DNS, "foo.example.com", ".example.com", X509_V_OK},
+ {GEN_DNS, "foo.example.com", "foo.example.com", X509_V_OK},
+ {GEN_DNS, "foo.example.com", ".foo.example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_DNS, "foo.example.com", ".xample.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_DNS, "foo.example.com", ".unrelated.much.longer.name.example",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ // NUL bytes, if not rejected, should not confuse the matching logic.
+ {GEN_DNS, std::string({'a', '\0', 'a'}), std::string({'a', '\0', 'b'}),
+ X509_V_ERR_PERMITTED_VIOLATION},
+
+ // Names must be emails.
+ {GEN_EMAIL, "not-an-email.example", "not-an-email.example",
+ X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
+ // A leading dot matches all local names and all subdomains
+ {GEN_EMAIL, "foo@bar.example.com", ".example.com", X509_V_OK},
+ {GEN_EMAIL, "foo@bar.example.com", ".EXAMPLE.COM", X509_V_OK},
+ {GEN_EMAIL, "foo@bar.example.com", ".bar.example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ // Without a leading dot, the host must match exactly.
+ {GEN_EMAIL, "foo@example.com", "example.com", X509_V_OK},
+ {GEN_EMAIL, "foo@example.com", "EXAMPLE.COM", X509_V_OK},
+ {GEN_EMAIL, "foo@bar.example.com", "example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ // If the constraint specifies a mailbox, it specifies the whole thing.
+ // The halves are compared insensitively.
+ {GEN_EMAIL, "foo@example.com", "foo@example.com", X509_V_OK},
+ {GEN_EMAIL, "foo@example.com", "foo@EXAMPLE.COM", X509_V_OK},
+ {GEN_EMAIL, "foo@example.com", "FOO@example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_EMAIL, "foo@example.com", "bar@example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ // OpenSSL ignores a stray leading @.
+ {GEN_EMAIL, "foo@example.com", "@example.com", X509_V_OK},
+ {GEN_EMAIL, "foo@example.com", "@EXAMPLE.COM", X509_V_OK},
+ {GEN_EMAIL, "foo@bar.example.com", "@example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+
+ // Basic syntax check.
+ {GEN_URI, "not-a-url", "not-a-url", X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
+ {GEN_URI, "foo:not-a-url", "not-a-url",
+ X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
+ {GEN_URI, "foo:/not-a-url", "not-a-url",
+ X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
+ {GEN_URI, "foo:///not-a-url", "not-a-url",
+ X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
+ {GEN_URI, "foo://:not-a-url", "not-a-url",
+ X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
+ {GEN_URI, "foo://", "not-a-url", X509_V_ERR_UNSUPPORTED_NAME_SYNTAX},
+ // Hosts are an exact match.
+ {GEN_URI, "foo://example.com", "example.com", X509_V_OK},
+ {GEN_URI, "foo://example.com:443", "example.com", X509_V_OK},
+ {GEN_URI, "foo://example.com/whatever", "example.com", X509_V_OK},
+ {GEN_URI, "foo://bar.example.com", "example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://bar.example.com:443", "example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://bar.example.com/whatever", "example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://bar.example.com", "xample.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://bar.example.com:443", "xample.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://bar.example.com/whatever", "xample.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com", "some-other-name.example",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com:443", "some-other-name.example",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com/whatever", "some-other-name.example",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ // A leading dot allows components to be added.
+ {GEN_URI, "foo://example.com", ".example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com:443", ".example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com/whatever", ".example.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://bar.example.com", ".example.com", X509_V_OK},
+ {GEN_URI, "foo://bar.example.com:443", ".example.com", X509_V_OK},
+ {GEN_URI, "foo://bar.example.com/whatever", ".example.com", X509_V_OK},
+ {GEN_URI, "foo://example.com", ".some-other-name.example",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com:443", ".some-other-name.example",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com/whatever", ".some-other-name.example",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com", ".xample.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com:443", ".xample.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ {GEN_URI, "foo://example.com/whatever", ".xample.com",
+ X509_V_ERR_PERMITTED_VIOLATION},
+ };
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(t.type);
+ SCOPED_TRACE(t.name);
+ SCOPED_TRACE(t.constraint);
+
+ bssl::UniquePtr<GENERAL_NAME> name = MakeGeneralName(t.type, t.name);
+ ASSERT_TRUE(name);
+ bssl::UniquePtr<GENERAL_NAMES> names(GENERAL_NAMES_new());
+ ASSERT_TRUE(names);
+ ASSERT_TRUE(bssl::PushToStack(names.get(), std::move(name)));
+
+ bssl::UniquePtr<NAME_CONSTRAINTS> nc(NAME_CONSTRAINTS_new());
+ ASSERT_TRUE(nc);
+ nc->permittedSubtrees = sk_GENERAL_SUBTREE_new_null();
+ ASSERT_TRUE(nc->permittedSubtrees);
+ bssl::UniquePtr<GENERAL_SUBTREE> subtree(GENERAL_SUBTREE_new());
+ ASSERT_TRUE(subtree);
+ GENERAL_NAME_free(subtree->base);
+ subtree->base = MakeGeneralName(t.type, t.constraint).release();
+ ASSERT_TRUE(subtree->base);
+ ASSERT_TRUE(bssl::PushToStack(nc->permittedSubtrees, std::move(subtree)));
+
+ bssl::UniquePtr<X509> root = MakeTestCert("Root", "Root", key.get());
+ ASSERT_TRUE(root);
+ ASSERT_TRUE(X509_add1_ext_i2d(root.get(), NID_name_constraints, nc.get(),
+ /*crit=*/1, /*flags=*/0));
+ ASSERT_TRUE(X509_sign(root.get(), key.get(), EVP_sha256()));
+
+ bssl::UniquePtr<X509> leaf = MakeTestCert("Root", "Leaf", key.get());
+ ASSERT_TRUE(leaf);
+ ASSERT_TRUE(X509_add1_ext_i2d(leaf.get(), NID_subject_alt_name, names.get(),
+ /*crit=*/0, /*flags=*/0));
+ ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
+
+ int ret = Verify(leaf.get(), {root.get()}, {}, {}, 0);
+ EXPECT_EQ(t.result, ret) << X509_verify_cert_error_string(ret);
+ }
+}
+
+TEST(X509Test, PrintGeneralName) {
+ // TODO(https://crbug.com/boringssl/430): Add more tests. Also fix the
+ // external projects that use this to extract the SAN list and unexport.
+ bssl::UniquePtr<GENERAL_NAME> gen = MakeGeneralName(GEN_DNS, "example.com");
+ ASSERT_TRUE(gen);
+ bssl::UniquePtr<STACK_OF(CONF_VALUE)> values(
+ i2v_GENERAL_NAME(nullptr, gen.get(), nullptr));
+ ASSERT_TRUE(values);
+ ASSERT_EQ(1u, sk_CONF_VALUE_num(values.get()));
+ const CONF_VALUE *value = sk_CONF_VALUE_value(values.get(), 0);
+ EXPECT_STREQ(value->name, "DNS");
+ EXPECT_STREQ(value->value, "example.com");
+}
+
TEST(X509Test, TestPSS) {
bssl::UniquePtr<X509> cert(CertFromPEM(kExamplePSSCert));
ASSERT_TRUE(cert);
@@ -1599,7 +1855,7 @@ TEST(X509Test, RSASignManual) {
if (new_cert) {
cert.reset(X509_new());
// Fill in some fields for the certificate arbitrarily.
- EXPECT_TRUE(X509_set_version(cert.get(), 2 /* X.509v3 */));
+ EXPECT_TRUE(X509_set_version(cert.get(), X509_VERSION_3));
EXPECT_TRUE(ASN1_INTEGER_set(X509_get_serialNumber(cert.get()), 1));
EXPECT_TRUE(X509_gmtime_adj(X509_getm_notBefore(cert.get()), 0));
EXPECT_TRUE(
@@ -1750,7 +2006,8 @@ TEST(X509Test, TestFromBufferModified) {
ASSERT_EQ(static_cast<long>(data_len), i2d_X509(root.get(), nullptr));
- X509_CINF_set_modified(root->cert_info);
+ // Re-encode the TBSCertificate.
+ i2d_re_X509_tbs(root.get(), nullptr);
ASSERT_NE(static_cast<long>(data_len), i2d_X509(root.get(), nullptr));
}
@@ -1937,65 +2194,6 @@ TEST(X509Test, X509NameSet) {
EXPECT_EQ(X509_NAME_ENTRY_set(X509_NAME_get_entry(name.get(), 2)), 2);
}
-TEST(X509Test, StringDecoding) {
- static const struct {
- std::vector<uint8_t> in;
- int type;
- const char *expected;
- } kTests[] = {
- // Non-minimal, two-byte UTF-8.
- {{0xc0, 0x81}, V_ASN1_UTF8STRING, nullptr},
- // Non-minimal, three-byte UTF-8.
- {{0xe0, 0x80, 0x81}, V_ASN1_UTF8STRING, nullptr},
- // Non-minimal, four-byte UTF-8.
- {{0xf0, 0x80, 0x80, 0x81}, V_ASN1_UTF8STRING, nullptr},
- // Truncated, four-byte UTF-8.
- {{0xf0, 0x80, 0x80}, V_ASN1_UTF8STRING, nullptr},
- // Low-surrogate value.
- {{0xed, 0xa0, 0x80}, V_ASN1_UTF8STRING, nullptr},
- // High-surrogate value.
- {{0xed, 0xb0, 0x81}, V_ASN1_UTF8STRING, nullptr},
- // Initial BOMs should be rejected from UCS-2 and UCS-4.
- {{0xfe, 0xff, 0, 88}, V_ASN1_BMPSTRING, nullptr},
- {{0, 0, 0xfe, 0xff, 0, 0, 0, 88}, V_ASN1_UNIVERSALSTRING, nullptr},
- // Otherwise, BOMs should pass through.
- {{0, 88, 0xfe, 0xff}, V_ASN1_BMPSTRING, "X\xef\xbb\xbf"},
- {{0, 0, 0, 88, 0, 0, 0xfe, 0xff}, V_ASN1_UNIVERSALSTRING,
- "X\xef\xbb\xbf"},
- // The maximum code-point should pass though.
- {{0, 16, 0xff, 0xfd}, V_ASN1_UNIVERSALSTRING, "\xf4\x8f\xbf\xbd"},
- // Values outside the Unicode space should not.
- {{0, 17, 0, 0}, V_ASN1_UNIVERSALSTRING, nullptr},
- // Non-characters should be rejected.
- {{0, 1, 0xff, 0xff}, V_ASN1_UNIVERSALSTRING, nullptr},
- {{0, 1, 0xff, 0xfe}, V_ASN1_UNIVERSALSTRING, nullptr},
- {{0, 0, 0xfd, 0xd5}, V_ASN1_UNIVERSALSTRING, nullptr},
- // BMPString is UCS-2, not UTF-16, so surrogate pairs are invalid.
- {{0xd8, 0, 0xdc, 1}, V_ASN1_BMPSTRING, nullptr},
- };
-
- for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTests); i++) {
- SCOPED_TRACE(i);
- const auto& test = kTests[i];
- ASN1_STRING s;
- s.type = test.type;
- s.data = const_cast<uint8_t*>(test.in.data());
- s.length = test.in.size();
-
- uint8_t *utf8;
- const int utf8_len = ASN1_STRING_to_UTF8(&utf8, &s);
- EXPECT_EQ(utf8_len < 0, test.expected == nullptr);
- if (utf8_len >= 0) {
- if (test.expected != nullptr) {
- EXPECT_EQ(Bytes(test.expected), Bytes(utf8, utf8_len));
- }
- OPENSSL_free(utf8);
- } else {
- ERR_clear_error();
- }
- }
-}
-
TEST(X509Test, NoBasicConstraintsCertSign) {
bssl::UniquePtr<X509> root(CertFromPEM(kSANTypesRoot));
bssl::UniquePtr<X509> intermediate(
@@ -2986,3 +3184,165 @@ TEST(X509Test, GeneralName) {
}
}
}
+
+// Test that extracting fields of an |X509_ALGOR| works correctly.
+TEST(X509Test, X509AlgorExtract) {
+ static const char kTestOID[] = "1.2.840.113554.4.1.72585.2";
+ const struct {
+ int param_type;
+ std::vector<uint8_t> param_der;
+ } kTests[] = {
+ // No parameter.
+ {V_ASN1_UNDEF, {}},
+ // BOOLEAN { TRUE }
+ {V_ASN1_BOOLEAN, {0x01, 0x01, 0xff}},
+ // BOOLEAN { FALSE }
+ {V_ASN1_BOOLEAN, {0x01, 0x01, 0x00}},
+ // OCTET_STRING { "a" }
+ {V_ASN1_OCTET_STRING, {0x04, 0x01, 0x61}},
+ // BIT_STRING { `01` `00` }
+ {V_ASN1_BIT_STRING, {0x03, 0x02, 0x01, 0x00}},
+ // INTEGER { -1 }
+ {V_ASN1_INTEGER, {0x02, 0x01, 0xff}},
+ // OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2 }
+ {V_ASN1_OBJECT,
+ {0x06, 0x0c, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7,
+ 0x09, 0x02}},
+ // NULL {}
+ {V_ASN1_NULL, {0x05, 0x00}},
+ // SEQUENCE {}
+ {V_ASN1_SEQUENCE, {0x30, 0x00}},
+ // SET {}
+ {V_ASN1_SET, {0x31, 0x00}},
+ // [0] { UTF8String { "a" } }
+ {V_ASN1_OTHER, {0xa0, 0x03, 0x0c, 0x01, 0x61}},
+ };
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(Bytes(t.param_der));
+
+ // Assemble an AlgorithmIdentifier with the parameter.
+ bssl::ScopedCBB cbb;
+ CBB seq, oid;
+ ASSERT_TRUE(CBB_init(cbb.get(), 64));
+ ASSERT_TRUE(CBB_add_asn1(cbb.get(), &seq, CBS_ASN1_SEQUENCE));
+ ASSERT_TRUE(CBB_add_asn1(&seq, &oid, CBS_ASN1_OBJECT));
+ ASSERT_TRUE(CBB_add_asn1_oid_from_text(&oid, kTestOID, strlen(kTestOID)));
+ ASSERT_TRUE(CBB_add_bytes(&seq, t.param_der.data(), t.param_der.size()));
+ ASSERT_TRUE(CBB_flush(cbb.get()));
+
+ const uint8_t *ptr = CBB_data(cbb.get());
+ bssl::UniquePtr<X509_ALGOR> alg(
+ d2i_X509_ALGOR(nullptr, &ptr, CBB_len(cbb.get())));
+ ASSERT_TRUE(alg);
+
+ const ASN1_OBJECT *obj;
+ int param_type;
+ const void *param_value;
+ X509_ALGOR_get0(&obj, &param_type, &param_value, alg.get());
+
+ EXPECT_EQ(param_type, t.param_type);
+ char oid_buf[sizeof(kTestOID)];
+ ASSERT_EQ(int(sizeof(oid_buf) - 1),
+ OBJ_obj2txt(oid_buf, sizeof(oid_buf), obj,
+ /*always_return_oid=*/1));
+ EXPECT_STREQ(oid_buf, kTestOID);
+
+ // |param_type| and |param_value| must be consistent with |ASN1_TYPE|.
+ if (param_type == V_ASN1_UNDEF) {
+ EXPECT_EQ(nullptr, param_value);
+ } else {
+ bssl::UniquePtr<ASN1_TYPE> param(ASN1_TYPE_new());
+ ASSERT_TRUE(param);
+ ASSERT_TRUE(ASN1_TYPE_set1(param.get(), param_type, param_value));
+
+ uint8_t *param_der = nullptr;
+ int param_len = i2d_ASN1_TYPE(param.get(), &param_der);
+ ASSERT_GE(param_len, 0);
+ bssl::UniquePtr<uint8_t> free_param_der(param_der);
+
+ EXPECT_EQ(Bytes(param_der, param_len), Bytes(t.param_der));
+ }
+ }
+}
+
+// Test the various |X509_ATTRIBUTE| creation functions.
+TEST(X509Test, Attribute) {
+ // The friendlyName attribute has a BMPString value. See RFC 2985,
+ // section 5.5.1.
+ static const uint8_t kTest1[] = {0x26, 0x03}; // U+2603 SNOWMAN
+ static const uint8_t kTest1UTF8[] = {0xe2, 0x98, 0x83};
+ static const uint8_t kTest2[] = {0, 't', 0, 'e', 0, 's', 0, 't'};
+
+ auto check_attribute = [&](X509_ATTRIBUTE *attr, bool has_test2) {
+ EXPECT_EQ(NID_friendlyName, OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)));
+
+ EXPECT_EQ(has_test2 ? 2 : 1, X509_ATTRIBUTE_count(attr));
+
+ // The first attribute should contain |kTest1|.
+ const ASN1_TYPE *value = X509_ATTRIBUTE_get0_type(attr, 0);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(V_ASN1_BMPSTRING, value->type);
+ EXPECT_EQ(Bytes(kTest1),
+ Bytes(ASN1_STRING_get0_data(value->value.bmpstring),
+ ASN1_STRING_length(value->value.bmpstring)));
+
+ // |X509_ATTRIBUTE_get0_data| requires the type match.
+ EXPECT_FALSE(
+ X509_ATTRIBUTE_get0_data(attr, 0, V_ASN1_OCTET_STRING, nullptr));
+ const ASN1_BMPSTRING *bmpstring = static_cast<const ASN1_BMPSTRING *>(
+ X509_ATTRIBUTE_get0_data(attr, 0, V_ASN1_BMPSTRING, nullptr));
+ ASSERT_TRUE(bmpstring);
+ EXPECT_EQ(Bytes(kTest1), Bytes(ASN1_STRING_get0_data(bmpstring),
+ ASN1_STRING_length(bmpstring)));
+
+ if (has_test2) {
+ value = X509_ATTRIBUTE_get0_type(attr, 1);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(V_ASN1_BMPSTRING, value->type);
+ EXPECT_EQ(Bytes(kTest2),
+ Bytes(ASN1_STRING_get0_data(value->value.bmpstring),
+ ASN1_STRING_length(value->value.bmpstring)));
+ } else {
+ EXPECT_FALSE(X509_ATTRIBUTE_get0_type(attr, 1));
+ }
+
+ EXPECT_FALSE(X509_ATTRIBUTE_get0_type(attr, 2));
+ };
+
+ bssl::UniquePtr<ASN1_STRING> str(ASN1_STRING_type_new(V_ASN1_BMPSTRING));
+ ASSERT_TRUE(str);
+ ASSERT_TRUE(ASN1_STRING_set(str.get(), kTest1, sizeof(kTest1)));
+
+ // Test |X509_ATTRIBUTE_create|.
+ bssl::UniquePtr<X509_ATTRIBUTE> attr(
+ X509_ATTRIBUTE_create(NID_friendlyName, V_ASN1_BMPSTRING, str.get()));
+ ASSERT_TRUE(attr);
+ str.release(); // |X509_ATTRIBUTE_create| takes ownership on success.
+ check_attribute(attr.get(), /*has_test2=*/false);
+
+ // Test the |MBSTRING_*| form of |X509_ATTRIBUTE_set1_data|.
+ attr.reset(X509_ATTRIBUTE_new());
+ ASSERT_TRUE(attr);
+ ASSERT_TRUE(
+ X509_ATTRIBUTE_set1_object(attr.get(), OBJ_nid2obj(NID_friendlyName)));
+ ASSERT_TRUE(X509_ATTRIBUTE_set1_data(attr.get(), MBSTRING_UTF8, kTest1UTF8,
+ sizeof(kTest1UTF8)));
+ check_attribute(attr.get(), /*has_test2=*/false);
+
+ // Test the |ASN1_STRING| form of |X509_ATTRIBUTE_set1_data|.
+ ASSERT_TRUE(X509_ATTRIBUTE_set1_data(attr.get(), V_ASN1_BMPSTRING, kTest2,
+ sizeof(kTest2)));
+ check_attribute(attr.get(), /*has_test2=*/true);
+
+ // Test the |ASN1_TYPE| form of |X509_ATTRIBUTE_set1_data|.
+ attr.reset(X509_ATTRIBUTE_new());
+ ASSERT_TRUE(attr);
+ ASSERT_TRUE(
+ X509_ATTRIBUTE_set1_object(attr.get(), OBJ_nid2obj(NID_friendlyName)));
+ str.reset(ASN1_STRING_type_new(V_ASN1_BMPSTRING));
+ ASSERT_TRUE(str);
+ ASSERT_TRUE(ASN1_STRING_set(str.get(), kTest1, sizeof(kTest1)));
+ ASSERT_TRUE(
+ X509_ATTRIBUTE_set1_data(attr.get(), V_ASN1_BMPSTRING, str.get(), -1));
+ check_attribute(attr.get(), /*has_test2=*/false);
+}
diff --git a/deps/boringssl/src/crypto/x509/x509_trs.c b/deps/boringssl/src/crypto/x509/x509_trs.c
index d3002e8..c95d6fc 100644
--- a/deps/boringssl/src/crypto/x509/x509_trs.c
+++ b/deps/boringssl/src/crypto/x509/x509_trs.c
@@ -60,6 +60,8 @@
#include <openssl/x509v3.h>
#include "../x509v3/internal.h"
+#include "internal.h"
+
static int tr_cmp(const X509_TRUST **a, const X509_TRUST **b);
static void trtable_free(X509_TRUST *p);
diff --git a/deps/boringssl/src/crypto/x509/x509_v3.c b/deps/boringssl/src/crypto/x509/x509_v3.c
index 91bf024..985161d 100644
--- a/deps/boringssl/src/crypto/x509/x509_v3.c
+++ b/deps/boringssl/src/crypto/x509/x509_v3.c
@@ -62,6 +62,9 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include "internal.h"
+
+
int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x)
{
if (x == NULL)
@@ -72,12 +75,11 @@ int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x)
int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, int nid,
int lastpos)
{
- const ASN1_OBJECT *obj;
-
- obj = OBJ_nid2obj(nid);
- if (obj == NULL)
- return (-2);
- return (X509v3_get_ext_by_OBJ(x, obj, lastpos));
+ const ASN1_OBJECT *obj = OBJ_nid2obj(nid);
+ if (obj == NULL) {
+ return -1;
+ }
+ return X509v3_get_ext_by_OBJ(x, obj, lastpos);
}
int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *sk,
@@ -103,21 +105,24 @@ int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *sk,
int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *sk, int crit,
int lastpos)
{
- int n;
- X509_EXTENSION *ex;
+ if (sk == NULL) {
+ return -1;
+ }
- if (sk == NULL)
- return (-1);
lastpos++;
- if (lastpos < 0)
+ if (lastpos < 0) {
lastpos = 0;
- n = sk_X509_EXTENSION_num(sk);
+ }
+
+ crit = !!crit;
+ int n = sk_X509_EXTENSION_num(sk);
for (; lastpos < n; lastpos++) {
- ex = sk_X509_EXTENSION_value(sk, lastpos);
- if (((ex->critical > 0) && crit) || ((ex->critical <= 0) && !crit))
- return (lastpos);
+ const X509_EXTENSION *ex = sk_X509_EXTENSION_value(sk, lastpos);
+ if (X509_EXTENSION_get_critical(ex) == crit) {
+ return lastpos;
+ }
}
- return (-1);
+ return -1;
}
X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc)
@@ -172,11 +177,9 @@ STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x,
err:
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
err2:
- if (new_ex != NULL)
- X509_EXTENSION_free(new_ex);
- if (sk != NULL)
- sk_X509_EXTENSION_free(sk);
- return (NULL);
+ X509_EXTENSION_free(new_ex);
+ sk_X509_EXTENSION_free(sk);
+ return NULL;
}
X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, int nid,
@@ -268,7 +271,7 @@ ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ex)
return (ex->value);
}
-int X509_EXTENSION_get_critical(X509_EXTENSION *ex)
+int X509_EXTENSION_get_critical(const X509_EXTENSION *ex)
{
if (ex == NULL)
return (0);
diff --git a/deps/boringssl/src/crypto/x509/x509_vfy.c b/deps/boringssl/src/crypto/x509/x509_vfy.c
index a997202..818459c 100644
--- a/deps/boringssl/src/crypto/x509/x509_vfy.c
+++ b/deps/boringssl/src/crypto/x509/x509_vfy.c
@@ -67,7 +67,7 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
-#include "vpm_int.h"
+#include "internal.h"
#include "../internal.h"
#include "../x509v3/internal.h"
@@ -835,20 +835,20 @@ static int check_id_error(X509_STORE_CTX *ctx, int errcode)
return ctx->verify_cb(0, ctx);
}
-static int check_hosts(X509 *x, X509_VERIFY_PARAM_ID *id)
+static int check_hosts(X509 *x, X509_VERIFY_PARAM *param)
{
size_t i;
- size_t n = sk_OPENSSL_STRING_num(id->hosts);
+ size_t n = sk_OPENSSL_STRING_num(param->hosts);
char *name;
- if (id->peername != NULL) {
- OPENSSL_free(id->peername);
- id->peername = NULL;
+ if (param->peername != NULL) {
+ OPENSSL_free(param->peername);
+ param->peername = NULL;
}
for (i = 0; i < n; ++i) {
- name = sk_OPENSSL_STRING_value(id->hosts, i);
- if (X509_check_host(x, name, strlen(name), id->hostflags,
- &id->peername) > 0)
+ name = sk_OPENSSL_STRING_value(param->hosts, i);
+ if (X509_check_host(x, name, strlen(name), param->hostflags,
+ &param->peername) > 0)
return 1;
}
return n == 0;
@@ -857,21 +857,20 @@ static int check_hosts(X509 *x, X509_VERIFY_PARAM_ID *id)
static int check_id(X509_STORE_CTX *ctx)
{
X509_VERIFY_PARAM *vpm = ctx->param;
- X509_VERIFY_PARAM_ID *id = vpm->id;
X509 *x = ctx->cert;
- if (id->poison) {
+ if (vpm->poison) {
if (!check_id_error(ctx, X509_V_ERR_INVALID_CALL))
return 0;
}
- if (id->hosts && check_hosts(x, id) <= 0) {
+ if (vpm->hosts && check_hosts(x, vpm) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH))
return 0;
}
- if (id->email && X509_check_email(x, id->email, id->emaillen, 0) <= 0) {
+ if (vpm->email && X509_check_email(x, vpm->email, vpm->emaillen, 0) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH))
return 0;
}
- if (id->ip && X509_check_ip(x, id->ip, id->iplen, 0) <= 0) {
+ if (vpm->ip && X509_check_ip(x, vpm->ip, vpm->iplen, 0) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH))
return 0;
}
@@ -1404,12 +1403,12 @@ static int check_crl_path(X509_STORE_CTX *ctx, X509 *x)
}
/*
- * RFC3280 says nothing about the relationship between CRL path and
+ * RFC 3280 says nothing about the relationship between CRL path and
* certificate path, which could lead to situations where a certificate could
- * be revoked or validated by a CA not authorised to do so. RFC5280 is more
+ * be revoked or validated by a CA not authorised to do so. RFC 5280 is more
* strict and states that the two paths must end in the same trust anchor,
* though some discussions remain... until this is resolved we use the
- * RFC5280 version
+ * RFC 5280 version
*/
static int check_crl_chain(X509_STORE_CTX *ctx,
@@ -1920,8 +1919,8 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
int i, day, sec, ret = 0;
/*
- * Note that ASN.1 allows much more slack in the time format than RFC5280.
- * In RFC5280, the representation is fixed:
+ * Note that ASN.1 allows much more slack in the time format than RFC 5280.
+ * In RFC 5280, the representation is fixed:
* UTCTime: YYMMDDHHMMSSZ
* GeneralizedTime: YYYYMMDDHHMMSSZ
*
@@ -1977,9 +1976,9 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
return ret;
}
-ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj)
+ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long offset_sec)
{
- return X509_time_adj(s, adj, NULL);
+ return X509_time_adj(s, offset_sec, NULL);
}
ASN1_TIME *X509_time_adj(ASN1_TIME *s, long offset_sec, time_t *in_tm)
@@ -1992,17 +1991,12 @@ ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s,
{
time_t t = 0;
- if (in_tm)
+ if (in_tm) {
t = *in_tm;
- else
+ } else {
time(&t);
-
- if (s && !(s->flags & ASN1_STRING_FLAG_MSTRING)) {
- if (s->type == V_ASN1_UTCTIME)
- return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec);
- if (s->type == V_ASN1_GENERALIZEDTIME)
- return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, offset_sec);
}
+
return ASN1_TIME_adj(s, t, offset_day, offset_sec);
}
@@ -2052,7 +2046,7 @@ X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer,
}
/* Create new CRL */
crl = X509_CRL_new();
- if (!crl || !X509_CRL_set_version(crl, 1))
+ if (!crl || !X509_CRL_set_version(crl, X509_CRL_VERSION_2))
goto memerr;
/* Set issuer name */
if (!X509_CRL_set_issuer_name(crl, X509_CRL_get_issuer(newer)))
@@ -2494,7 +2488,3 @@ void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param)
X509_VERIFY_PARAM_free(ctx->param);
ctx->param = param;
}
-
-IMPLEMENT_ASN1_SET_OF(X509)
-
-IMPLEMENT_ASN1_SET_OF(X509_ATTRIBUTE)
diff --git a/deps/boringssl/src/crypto/x509/x509_vpm.c b/deps/boringssl/src/crypto/x509/x509_vpm.c
index d8d1efe..5a881d6 100644
--- a/deps/boringssl/src/crypto/x509/x509_vpm.c
+++ b/deps/boringssl/src/crypto/x509/x509_vpm.c
@@ -62,8 +62,9 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
-#include "vpm_int.h"
+#include "internal.h"
#include "../internal.h"
+#include "../x509v3/internal.h"
/* X509_VERIFY_PARAM functions */
@@ -83,7 +84,7 @@ static void str_free(char *s)
#define string_stack_free(sk) sk_OPENSSL_STRING_pop_free(sk, str_free)
-static int int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode,
+static int int_x509_param_set_hosts(X509_VERIFY_PARAM *param, int mode,
const char *name, size_t namelen)
{
char *copy;
@@ -100,26 +101,26 @@ static int int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode,
if (name && OPENSSL_memchr(name, '\0', namelen))
return 0;
- if (mode == SET_HOST && id->hosts) {
- string_stack_free(id->hosts);
- id->hosts = NULL;
+ if (mode == SET_HOST && param->hosts) {
+ string_stack_free(param->hosts);
+ param->hosts = NULL;
}
copy = OPENSSL_strndup(name, namelen);
if (copy == NULL)
return 0;
- if (id->hosts == NULL &&
- (id->hosts = sk_OPENSSL_STRING_new_null()) == NULL) {
+ if (param->hosts == NULL &&
+ (param->hosts = sk_OPENSSL_STRING_new_null()) == NULL) {
OPENSSL_free(copy);
return 0;
}
- if (!sk_OPENSSL_STRING_push(id->hosts, copy)) {
+ if (!sk_OPENSSL_STRING_push(param->hosts, copy)) {
OPENSSL_free(copy);
- if (sk_OPENSSL_STRING_num(id->hosts) == 0) {
- sk_OPENSSL_STRING_free(id->hosts);
- id->hosts = NULL;
+ if (sk_OPENSSL_STRING_num(param->hosts) == 0) {
+ sk_OPENSSL_STRING_free(param->hosts);
+ param->hosts = NULL;
}
return 0;
}
@@ -129,7 +130,6 @@ static int int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode,
static void x509_verify_param_zero(X509_VERIFY_PARAM *param)
{
- X509_VERIFY_PARAM_ID *paramid;
if (!param)
return;
param->name = NULL;
@@ -145,43 +145,34 @@ static void x509_verify_param_zero(X509_VERIFY_PARAM *param)
sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
param->policies = NULL;
}
- paramid = param->id;
- if (paramid->hosts) {
- string_stack_free(paramid->hosts);
- paramid->hosts = NULL;
+ if (param->hosts) {
+ string_stack_free(param->hosts);
+ param->hosts = NULL;
}
- if (paramid->peername) {
- OPENSSL_free(paramid->peername);
- paramid->peername = NULL;
+ if (param->peername) {
+ OPENSSL_free(param->peername);
+ param->peername = NULL;
}
- if (paramid->email) {
- OPENSSL_free(paramid->email);
- paramid->email = NULL;
- paramid->emaillen = 0;
+ if (param->email) {
+ OPENSSL_free(param->email);
+ param->email = NULL;
+ param->emaillen = 0;
}
- if (paramid->ip) {
- OPENSSL_free(paramid->ip);
- paramid->ip = NULL;
- paramid->iplen = 0;
+ if (param->ip) {
+ OPENSSL_free(param->ip);
+ param->ip = NULL;
+ param->iplen = 0;
}
- paramid->poison = 0;
+ param->poison = 0;
}
X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void)
{
X509_VERIFY_PARAM *param;
- X509_VERIFY_PARAM_ID *paramid;
param = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM));
if (!param)
return NULL;
- paramid = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM_ID));
- if (!paramid) {
- OPENSSL_free(param);
- return NULL;
- }
OPENSSL_memset(param, 0, sizeof(X509_VERIFY_PARAM));
- OPENSSL_memset(paramid, 0, sizeof(X509_VERIFY_PARAM_ID));
- param->id = paramid;
x509_verify_param_zero(param);
return param;
}
@@ -191,7 +182,6 @@ void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param)
if (param == NULL)
return;
x509_verify_param_zero(param);
- OPENSSL_free(param->id);
OPENSSL_free(param);
}
@@ -233,11 +223,6 @@ void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param)
(to_overwrite || \
((src->field != (def)) && (to_default || (dest->field == (def)))))
-/* As above but for ID fields */
-
-#define test_x509_verify_param_copy_id(idf, def) \
- test_x509_verify_param_copy(id->idf, def)
-
/* Macro to test and copy a field if necessary */
#define x509_verify_param_copy(field, def) \
@@ -249,10 +234,8 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
{
unsigned long inh_flags;
int to_default, to_overwrite;
- X509_VERIFY_PARAM_ID *id;
if (!src)
return 1;
- id = src->id;
inh_flags = dest->inh_flags | src->inh_flags;
if (inh_flags & X509_VP_FLAG_ONCE)
@@ -294,31 +277,31 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
}
/* Copy the host flags if and only if we're copying the host list */
- if (test_x509_verify_param_copy_id(hosts, NULL)) {
- if (dest->id->hosts) {
- string_stack_free(dest->id->hosts);
- dest->id->hosts = NULL;
+ if (test_x509_verify_param_copy(hosts, NULL)) {
+ if (dest->hosts) {
+ string_stack_free(dest->hosts);
+ dest->hosts = NULL;
}
- if (id->hosts) {
- dest->id->hosts =
- sk_OPENSSL_STRING_deep_copy(id->hosts, str_copy, str_free);
- if (dest->id->hosts == NULL)
+ if (src->hosts) {
+ dest->hosts =
+ sk_OPENSSL_STRING_deep_copy(src->hosts, str_copy, str_free);
+ if (dest->hosts == NULL)
return 0;
- dest->id->hostflags = id->hostflags;
+ dest->hostflags = src->hostflags;
}
}
- if (test_x509_verify_param_copy_id(email, NULL)) {
- if (!X509_VERIFY_PARAM_set1_email(dest, id->email, id->emaillen))
+ if (test_x509_verify_param_copy(email, NULL)) {
+ if (!X509_VERIFY_PARAM_set1_email(dest, src->email, src->emaillen))
return 0;
}
- if (test_x509_verify_param_copy_id(ip, NULL)) {
- if (!X509_VERIFY_PARAM_set1_ip(dest, id->ip, id->iplen))
+ if (test_x509_verify_param_copy(ip, NULL)) {
+ if (!X509_VERIFY_PARAM_set1_ip(dest, src->ip, src->iplen))
return 0;
}
- dest->id->poison = src->id->poison;
+ dest->poison = src->poison;
return 1;
}
@@ -457,8 +440,8 @@ int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen)
{
- if (!int_x509_param_set_hosts(param->id, SET_HOST, name, namelen)) {
- param->id->poison = 1;
+ if (!int_x509_param_set_hosts(param, SET_HOST, name, namelen)) {
+ param->poison = 1;
return 0;
}
return 1;
@@ -467,8 +450,8 @@ int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen)
{
- if (!int_x509_param_set_hosts(param->id, ADD_HOST, name, namelen)) {
- param->id->poison = 1;
+ if (!int_x509_param_set_hosts(param, ADD_HOST, name, namelen)) {
+ param->poison = 1;
return 0;
}
return 1;
@@ -477,21 +460,21 @@ int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param,
void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
unsigned int flags)
{
- param->id->hostflags = flags;
+ param->hostflags = flags;
}
char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param)
{
- return param->id->peername;
+ return param->peername;
}
int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen)
{
if (OPENSSL_memchr(email, '\0', emaillen) != NULL ||
- !int_x509_param_set1(&param->id->email, &param->id->emaillen,
+ !int_x509_param_set1(&param->email, &param->emaillen,
email, emaillen)) {
- param->id->poison = 1;
+ param->poison = 1;
return 0;
}
@@ -502,9 +485,9 @@ int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
const unsigned char *ip, size_t iplen)
{
if ((iplen != 4 && iplen != 16) ||
- !int_x509_param_set1((char **)&param->id->ip, &param->id->iplen,
+ !int_x509_param_set1((char **)&param->ip, &param->iplen,
(char *)ip, iplen)) {
- param->id->poison = 1;
+ param->poison = 1;
return 0;
}
@@ -516,7 +499,7 @@ int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc)
unsigned char ipout[16];
size_t iplen;
- iplen = (size_t)a2i_ipadd(ipout, ipasc);
+ iplen = (size_t)x509v3_a2i_ipadd(ipout, ipasc);
if (iplen == 0)
return 0;
return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen);
@@ -532,10 +515,7 @@ const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param)
return param->name;
}
-static const X509_VERIFY_PARAM_ID _empty_id =
- { NULL, 0U, NULL, NULL, 0, NULL, 0, 0 };
-
-#define vpm_empty_id ((X509_VERIFY_PARAM_ID *)&_empty_id)
+#define vpm_empty_id NULL, 0U, NULL, NULL, 0, NULL, 0, 0
/*
* Default verify parameters: these are used for various applications and can
diff --git a/deps/boringssl/src/crypto/x509/x509cset.c b/deps/boringssl/src/crypto/x509/x509cset.c
index cc27acb..7816d73 100644
--- a/deps/boringssl/src/crypto/x509/x509cset.c
+++ b/deps/boringssl/src/crypto/x509/x509cset.c
@@ -60,6 +60,7 @@
#include <openssl/x509.h>
#include "../internal.h"
+#include "internal.h"
int X509_CRL_set_version(X509_CRL *x, long version)
{
@@ -250,3 +251,34 @@ int i2d_X509_CRL_tbs(X509_CRL *crl, unsigned char **outp)
{
return i2d_X509_CRL_INFO(crl->crl, outp);
}
+
+int X509_CRL_set1_signature_algo(X509_CRL *crl, const X509_ALGOR *algo)
+{
+ /* TODO(davidben): Const-correct generated ASN.1 dup functions.
+ * Alternatively, when the types are hidden and we can embed required fields
+ * directly in structs, import |X509_ALGOR_copy| from upstream. */
+ X509_ALGOR *copy1 = X509_ALGOR_dup((X509_ALGOR *)algo);
+ X509_ALGOR *copy2 = X509_ALGOR_dup((X509_ALGOR *)algo);
+ if (copy1 == NULL || copy2 == NULL) {
+ X509_ALGOR_free(copy1);
+ X509_ALGOR_free(copy2);
+ return 0;
+ }
+
+ X509_ALGOR_free(crl->sig_alg);
+ crl->sig_alg = copy1;
+ X509_ALGOR_free(crl->crl->sig_alg);
+ crl->crl->sig_alg = copy2;
+ return 1;
+}
+
+int X509_CRL_set1_signature_value(X509_CRL *crl, const uint8_t *sig,
+ size_t sig_len)
+{
+ if (!ASN1_STRING_set(crl->signature, sig, sig_len)) {
+ return 0;
+ }
+ crl->signature->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ crl->signature->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+ return 1;
+}
diff --git a/deps/boringssl/src/crypto/x509/x509name.c b/deps/boringssl/src/crypto/x509/x509name.c
index 0bf3459..6bc0952 100644
--- a/deps/boringssl/src/crypto/x509/x509name.c
+++ b/deps/boringssl/src/crypto/x509/x509name.c
@@ -64,6 +64,7 @@
#include <openssl/x509.h>
#include "../internal.h"
+#include "internal.h"
int X509_NAME_get_text_by_NID(const X509_NAME *name, int nid, char *buf,
@@ -367,10 +368,7 @@ int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type,
if (!i)
return (0);
if (type != V_ASN1_UNDEF) {
- if (type == V_ASN1_APP_CHOOSE)
- ne->value->type = ASN1_PRINTABLE_type(bytes, len);
- else
- ne->value->type = type;
+ ne->value->type = type;
}
return (1);
}
diff --git a/deps/boringssl/src/crypto/x509/x509rset.c b/deps/boringssl/src/crypto/x509/x509rset.c
index c4e6683..72b4148 100644
--- a/deps/boringssl/src/crypto/x509/x509rset.c
+++ b/deps/boringssl/src/crypto/x509/x509rset.c
@@ -59,6 +59,9 @@
#include <openssl/obj.h>
#include <openssl/x509.h>
+#include "internal.h"
+
+
int X509_REQ_set_version(X509_REQ *x, long version)
{
if (x == NULL)
diff --git a/deps/boringssl/src/crypto/x509/x_algor.c b/deps/boringssl/src/crypto/x509/x_algor.c
index 13c9a8c..a454c0c 100644
--- a/deps/boringssl/src/crypto/x509/x_algor.c
+++ b/deps/boringssl/src/crypto/x509/x_algor.c
@@ -61,6 +61,8 @@
#include <openssl/digest.h>
#include <openssl/obj.h>
+#include "../asn1/internal.h"
+
ASN1_SEQUENCE(X509_ALGOR) = {
ASN1_SIMPLE(X509_ALGOR, algorithm, ASN1_OBJECT),
@@ -75,10 +77,7 @@ IMPLEMENT_ASN1_FUNCTIONS(X509_ALGOR)
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_ALGORS, X509_ALGORS, X509_ALGORS)
IMPLEMENT_ASN1_DUP_FUNCTION(X509_ALGOR)
-IMPLEMENT_ASN1_SET_OF(X509_ALGOR)
-
-int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype,
- void *pval)
+int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *aobj, int ptype, void *pval)
{
if (!alg)
return 0;
@@ -89,9 +88,8 @@ int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype,
return 0;
}
if (alg) {
- if (alg->algorithm)
- ASN1_OBJECT_free(alg->algorithm);
- alg->algorithm = (ASN1_OBJECT *)aobj;
+ ASN1_OBJECT_free(alg->algorithm);
+ alg->algorithm = aobj;
}
if (ptype == 0)
return 1;
@@ -105,19 +103,23 @@ int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype,
return 1;
}
-void X509_ALGOR_get0(const ASN1_OBJECT **paobj, int *pptype, const void **ppval,
- const X509_ALGOR *algor)
+void X509_ALGOR_get0(const ASN1_OBJECT **out_obj, int *out_param_type,
+ const void **out_param_value, const X509_ALGOR *alg)
{
- if (paobj)
- *paobj = algor->algorithm;
- if (pptype) {
- if (algor->parameter == NULL) {
- *pptype = V_ASN1_UNDEF;
- return;
- } else
- *pptype = algor->parameter->type;
- if (ppval)
- *ppval = algor->parameter->value.ptr;
+ if (out_obj != NULL) {
+ *out_obj = alg->algorithm;
+ }
+ if (out_param_type != NULL) {
+ int type = V_ASN1_UNDEF;
+ const void *value = NULL;
+ if (alg->parameter != NULL) {
+ type = alg->parameter->type;
+ value = asn1_type_value_as_pointer(alg->parameter);
+ }
+ *out_param_type = type;
+ if (out_param_value != NULL) {
+ *out_param_value = value;
+ }
}
}
diff --git a/deps/boringssl/src/crypto/x509/x_all.c b/deps/boringssl/src/crypto/x509/x_all.c
index a29e038..7ceff50 100644
--- a/deps/boringssl/src/crypto/x509/x_all.c
+++ b/deps/boringssl/src/crypto/x509/x_all.c
@@ -66,6 +66,9 @@
#include <openssl/rsa.h>
#include <openssl/stack.h>
+#include "internal.h"
+
+
int X509_verify(X509 *x509, EVP_PKEY *pkey)
{
if (X509_ALGOR_cmp(x509->sig_alg, x509->cert_info->signature)) {
@@ -137,7 +140,6 @@ int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *spki, EVP_PKEY *pkey)
spki->signature, spki->spkac, pkey));
}
-#ifndef OPENSSL_NO_FP_API
X509 *d2i_X509_fp(FILE *fp, X509 **x509)
{
return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509), fp, x509);
@@ -147,7 +149,6 @@ int i2d_X509_fp(FILE *fp, X509 *x509)
{
return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509), fp, x509);
}
-#endif
X509 *d2i_X509_bio(BIO *bp, X509 **x509)
{
@@ -159,7 +160,6 @@ int i2d_X509_bio(BIO *bp, X509 *x509)
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bp, x509);
}
-#ifndef OPENSSL_NO_FP_API
X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl)
{
return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl);
@@ -169,7 +169,6 @@ int i2d_X509_CRL_fp(FILE *fp, X509_CRL *crl)
{
return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl);
}
-#endif
X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl)
{
@@ -181,7 +180,6 @@ int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl)
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl);
}
-#ifndef OPENSSL_NO_FP_API
X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **req)
{
return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_REQ), fp, req);
@@ -191,7 +189,6 @@ int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req)
{
return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_REQ), fp, req);
}
-#endif
X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req)
{
@@ -203,7 +200,6 @@ int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req)
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_REQ), bp, req);
}
-#ifndef OPENSSL_NO_FP_API
#define IMPLEMENT_D2I_FP(type, name, bio_func) \
type *name(FILE *fp, type **obj) { \
@@ -235,7 +231,6 @@ IMPLEMENT_I2D_FP(RSA, i2d_RSAPublicKey_fp, i2d_RSAPublicKey_bio)
IMPLEMENT_D2I_FP(RSA, d2i_RSA_PUBKEY_fp, d2i_RSA_PUBKEY_bio)
IMPLEMENT_I2D_FP(RSA, i2d_RSA_PUBKEY_fp, i2d_RSA_PUBKEY_bio)
-#endif
#define IMPLEMENT_D2I_BIO(type, name, d2i_func) \
type *name(BIO *bio, type **obj) { \
@@ -272,13 +267,11 @@ IMPLEMENT_D2I_BIO(RSA, d2i_RSA_PUBKEY_bio, d2i_RSA_PUBKEY)
IMPLEMENT_I2D_BIO(RSA, i2d_RSA_PUBKEY_bio, i2d_RSA_PUBKEY)
#ifndef OPENSSL_NO_DSA
-# ifndef OPENSSL_NO_FP_API
IMPLEMENT_D2I_FP(DSA, d2i_DSAPrivateKey_fp, d2i_DSAPrivateKey_bio)
IMPLEMENT_I2D_FP(DSA, i2d_DSAPrivateKey_fp, i2d_DSAPrivateKey_bio)
IMPLEMENT_D2I_FP(DSA, d2i_DSA_PUBKEY_fp, d2i_DSA_PUBKEY_bio)
IMPLEMENT_I2D_FP(DSA, i2d_DSA_PUBKEY_fp, i2d_DSA_PUBKEY_bio)
-# endif
IMPLEMENT_D2I_BIO(DSA, d2i_DSAPrivateKey_bio, d2i_DSAPrivateKey)
IMPLEMENT_I2D_BIO(DSA, i2d_DSAPrivateKey_bio, i2d_DSAPrivateKey)
@@ -287,13 +280,11 @@ IMPLEMENT_D2I_BIO(DSA, d2i_DSA_PUBKEY_bio, d2i_DSA_PUBKEY)
IMPLEMENT_I2D_BIO(DSA, i2d_DSA_PUBKEY_bio, i2d_DSA_PUBKEY)
#endif
-#ifndef OPENSSL_NO_FP_API
IMPLEMENT_D2I_FP(EC_KEY, d2i_ECPrivateKey_fp, d2i_ECPrivateKey_bio)
IMPLEMENT_I2D_FP(EC_KEY, i2d_ECPrivateKey_fp, i2d_ECPrivateKey_bio)
IMPLEMENT_D2I_FP(EC_KEY, d2i_EC_PUBKEY_fp, d2i_EC_PUBKEY_bio)
IMPLEMENT_I2D_FP(EC_KEY, i2d_EC_PUBKEY_fp, i2d_EC_PUBKEY_bio)
-#endif
IMPLEMENT_D2I_BIO(EC_KEY, d2i_ECPrivateKey_bio, d2i_ECPrivateKey)
IMPLEMENT_I2D_BIO(EC_KEY, i2d_ECPrivateKey_bio, i2d_ECPrivateKey)
@@ -339,15 +330,12 @@ int X509_NAME_digest(const X509_NAME *data, const EVP_MD *type,
(ASN1_ITEM_rptr(X509_NAME), type, (char *)data, md, len));
}
-#ifndef OPENSSL_NO_FP_API
IMPLEMENT_D2I_FP(X509_SIG, d2i_PKCS8_fp, d2i_PKCS8_bio)
IMPLEMENT_I2D_FP(X509_SIG, i2d_PKCS8_fp, i2d_PKCS8_bio)
-#endif
IMPLEMENT_D2I_BIO(X509_SIG, d2i_PKCS8_bio, d2i_X509_SIG)
IMPLEMENT_I2D_BIO(X509_SIG, i2d_PKCS8_bio, i2d_X509_SIG)
-#ifndef OPENSSL_NO_FP_API
IMPLEMENT_D2I_FP(PKCS8_PRIV_KEY_INFO, d2i_PKCS8_PRIV_KEY_INFO_fp,
d2i_PKCS8_PRIV_KEY_INFO_bio)
IMPLEMENT_I2D_FP(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO_fp,
@@ -387,7 +375,6 @@ int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key)
PKCS8_PRIV_KEY_INFO_free(p8inf);
return ret;
}
-#endif
IMPLEMENT_D2I_BIO(EVP_PKEY, d2i_PrivateKey_bio, d2i_AutoPrivateKey)
IMPLEMENT_I2D_BIO(EVP_PKEY, i2d_PrivateKey_bio, i2d_PrivateKey)
diff --git a/deps/boringssl/src/crypto/x509/x_attrib.c b/deps/boringssl/src/crypto/x509/x_attrib.c
index de8c95c..91b3ee8 100644
--- a/deps/boringssl/src/crypto/x509/x_attrib.c
+++ b/deps/boringssl/src/crypto/x509/x_attrib.c
@@ -59,53 +59,40 @@
#include <openssl/x509.h>
#include <openssl/obj.h>
-/*
- * X509_ATTRIBUTE: this has the following form: typedef struct
- * x509_attributes_st { ASN1_OBJECT *object; int single; union { char *ptr;
- * STACK_OF(ASN1_TYPE) *set; ASN1_TYPE *single; } value; } X509_ATTRIBUTE;
- * this needs some extra thought because the CHOICE type is merged with the
- * main structure and because the value can be anything at all we *must* try
- * the SET OF first because the ASN1_ANY type will swallow anything including
- * the whole SET OF structure.
- */
+#include "internal.h"
-ASN1_CHOICE(X509_ATTRIBUTE_SET) = {
- ASN1_SET_OF(X509_ATTRIBUTE, value.set, ASN1_ANY),
- ASN1_SIMPLE(X509_ATTRIBUTE, value.single, ASN1_ANY)
-} ASN1_CHOICE_END_selector(X509_ATTRIBUTE, X509_ATTRIBUTE_SET, single)
ASN1_SEQUENCE(X509_ATTRIBUTE) = {
ASN1_SIMPLE(X509_ATTRIBUTE, object, ASN1_OBJECT),
- /* CHOICE type merged with parent */
- ASN1_EX_COMBINE(0, 0, X509_ATTRIBUTE_SET)
+ ASN1_SET_OF(X509_ATTRIBUTE, set, ASN1_ANY),
} ASN1_SEQUENCE_END(X509_ATTRIBUTE)
IMPLEMENT_ASN1_FUNCTIONS(X509_ATTRIBUTE)
IMPLEMENT_ASN1_DUP_FUNCTION(X509_ATTRIBUTE)
-X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value)
+X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int attrtype, void *value)
{
- X509_ATTRIBUTE *ret = NULL;
- ASN1_TYPE *val = NULL;
+ ASN1_OBJECT *obj = OBJ_nid2obj(nid);
+ if (obj == NULL) {
+ return NULL;
+ }
- if ((ret = X509_ATTRIBUTE_new()) == NULL)
- return (NULL);
- /* TODO(fork): const correctness. */
- ret->object = (ASN1_OBJECT *)OBJ_nid2obj(nid);
- ret->single = 0;
- if ((ret->value.set = sk_ASN1_TYPE_new_null()) == NULL)
+ X509_ATTRIBUTE *ret = X509_ATTRIBUTE_new();
+ ASN1_TYPE *val = ASN1_TYPE_new();
+ if (ret == NULL || val == NULL) {
goto err;
- if ((val = ASN1_TYPE_new()) == NULL)
- goto err;
- if (!sk_ASN1_TYPE_push(ret->value.set, val))
+ }
+
+ ret->object = obj;
+ if (!sk_ASN1_TYPE_push(ret->set, val)) {
goto err;
+ }
+
+ ASN1_TYPE_set(val, attrtype, value);
+ return ret;
- ASN1_TYPE_set(val, atrtype, value);
- return (ret);
err:
- if (ret != NULL)
- X509_ATTRIBUTE_free(ret);
- if (val != NULL)
- ASN1_TYPE_free(val);
- return (NULL);
+ X509_ATTRIBUTE_free(ret);
+ ASN1_TYPE_free(val);
+ return NULL;
}
diff --git a/deps/boringssl/src/crypto/x509/x_crl.c b/deps/boringssl/src/crypto/x509/x_crl.c
index 3b9f137..0d419ac 100644
--- a/deps/boringssl/src/crypto/x509/x_crl.c
+++ b/deps/boringssl/src/crypto/x509/x_crl.c
@@ -66,6 +66,7 @@
#include <openssl/x509v3.h>
#include "../internal.h"
+#include "internal.h"
/*
* Method to handle CRL access. In general a CRL could be very large (several
@@ -204,11 +205,12 @@ static int crl_set_issuers(X509_CRL *crl)
for (k = 0; k < sk_X509_EXTENSION_num(exts); k++) {
ext = sk_X509_EXTENSION_value(exts, k);
- if (ext->critical > 0) {
- if (OBJ_obj2nid(ext->object) == NID_certificate_issuer)
- continue;
- crl->flags |= EXFLAG_CRITICAL;
- break;
+ if (X509_EXTENSION_get_critical(ext)) {
+ if (OBJ_obj2nid(X509_EXTENSION_get_object(ext)) ==
+ NID_certificate_issuer)
+ continue;
+ crl->flags |= EXFLAG_CRITICAL;
+ break;
}
}
@@ -297,10 +299,10 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
for (idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++) {
int nid;
ext = sk_X509_EXTENSION_value(exts, idx);
- nid = OBJ_obj2nid(ext->object);
+ nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
if (nid == NID_freshest_crl)
crl->flags |= EXFLAG_FRESHEST;
- if (ext->critical > 0) {
+ if (X509_EXTENSION_get_critical(ext)) {
/* We handle IDP and deltas */
if ((nid == NID_issuing_distribution_point)
|| (nid == NID_authority_key_identifier)
@@ -436,6 +438,11 @@ int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x)
static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r)
{
+ if (X509_ALGOR_cmp(crl->sig_alg, crl->crl->sig_alg) != 0) {
+ OPENSSL_PUT_ERROR(X509, X509_R_SIGNATURE_ALGORITHM_MISMATCH);
+ return 0;
+ }
+
return (ASN1_item_verify(ASN1_ITEM_rptr(X509_CRL_INFO),
crl->sig_alg, crl->signature, crl->crl, r));
}
@@ -556,7 +563,3 @@ void *X509_CRL_get_meth_data(X509_CRL *crl)
{
return crl->meth_data;
}
-
-IMPLEMENT_ASN1_SET_OF(X509_REVOKED)
-
-IMPLEMENT_ASN1_SET_OF(X509_CRL)
diff --git a/deps/boringssl/src/crypto/x509/x_exten.c b/deps/boringssl/src/crypto/x509/x_exten.c
index 36403e4..89998ca 100644
--- a/deps/boringssl/src/crypto/x509/x_exten.c
+++ b/deps/boringssl/src/crypto/x509/x_exten.c
@@ -59,6 +59,8 @@
#include <openssl/cipher.h>
#include <openssl/x509.h>
+#include "internal.h"
+
ASN1_SEQUENCE(X509_EXTENSION) = {
ASN1_SIMPLE(X509_EXTENSION, object, ASN1_OBJECT),
diff --git a/deps/boringssl/src/crypto/x509/x_name.c b/deps/boringssl/src/crypto/x509/x_name.c
index bef9ec4..e4b5835 100644
--- a/deps/boringssl/src/crypto/x509/x_name.c
+++ b/deps/boringssl/src/crypto/x509/x_name.c
@@ -66,8 +66,9 @@
#include <openssl/stack.h>
#include <openssl/x509.h>
-#include "../asn1/asn1_locl.h"
+#include "../asn1/internal.h"
#include "../internal.h"
+#include "internal.h"
typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY;
@@ -521,8 +522,6 @@ int X509_NAME_set(X509_NAME **xn, X509_NAME *name)
return 1;
}
-IMPLEMENT_ASN1_SET_OF(X509_NAME_ENTRY)
-
int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne)
{
return ne->set;
diff --git a/deps/boringssl/src/crypto/x509/x_pubkey.c b/deps/boringssl/src/crypto/x509/x_pubkey.c
index 37dee49..c283e0d 100644
--- a/deps/boringssl/src/crypto/x509/x_pubkey.c
+++ b/deps/boringssl/src/crypto/x509/x_pubkey.c
@@ -68,6 +68,7 @@
#include <openssl/thread.h>
#include "../internal.h"
+#include "internal.h"
/* Minor tweak to operation: free up EVP_PKEY */
static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
@@ -180,35 +181,37 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
return NULL;
}
-int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj,
- int ptype, void *pval,
- unsigned char *penc, int penclen)
+int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *obj, int param_type,
+ void *param_value, uint8_t *key, int key_len)
{
- if (!X509_ALGOR_set0(pub->algor, aobj, ptype, pval))
+ if (!X509_ALGOR_set0(pub->algor, obj, param_type, param_value)) {
return 0;
- if (penc) {
- if (pub->public_key->data)
- OPENSSL_free(pub->public_key->data);
- pub->public_key->data = penc;
- pub->public_key->length = penclen;
- /* Set number of unused bits to zero */
- pub->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
- pub->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
}
+
+ ASN1_STRING_set0(pub->public_key, key, key_len);
+ /* Set the number of unused bits to zero. */
+ pub->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ pub->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
return 1;
}
-int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg,
- const unsigned char **pk, int *ppklen,
- X509_ALGOR **pa, X509_PUBKEY *pub)
+int X509_PUBKEY_get0_param(ASN1_OBJECT **out_obj, const uint8_t **out_key,
+ int *out_key_len, X509_ALGOR **out_alg,
+ X509_PUBKEY *pub)
{
- if (ppkalg)
- *ppkalg = pub->algor->algorithm;
- if (pk) {
- *pk = pub->public_key->data;
- *ppklen = pub->public_key->length;
+ if (out_obj != NULL) {
+ *out_obj = pub->algor->algorithm;
+ }
+ if (out_key != NULL) {
+ *out_key = pub->public_key->data;
+ *out_key_len = pub->public_key->length;
+ }
+ if (out_alg != NULL) {
+ *out_alg = pub->algor;
}
- if (pa)
- *pa = pub->algor;
return 1;
}
+
+const ASN1_BIT_STRING *X509_PUBKEY_get0_public_key(const X509_PUBKEY *pub) {
+ return pub->public_key;
+}
diff --git a/deps/boringssl/src/crypto/x509/x_req.c b/deps/boringssl/src/crypto/x509/x_req.c
index 5dfe19e..0e9dce1 100644
--- a/deps/boringssl/src/crypto/x509/x_req.c
+++ b/deps/boringssl/src/crypto/x509/x_req.c
@@ -60,17 +60,16 @@
#include <openssl/thread.h>
#include <openssl/x509.h>
+#include "internal.h"
+
+
/*
* X509_REQ_INFO is handled in an unusual way to get round invalid encodings.
* Some broken certificate requests don't encode the attributes field if it
* is empty. This is in violation of PKCS#10 but we need to tolerate it. We
* do this by making the attributes field OPTIONAL then using the callback to
* initialise it to an empty STACK. This means that the field will be
- * correctly encoded unless we NULL out the field. As a result we no longer
- * need the req_kludge field because the information is now contained in the
- * attributes field: 1. If it is NULL then it's the invalid omission. 2. If
- * it is empty it is the correct encoding. 3. If it is not empty then some
- * attributes are present.
+ * correctly encoded unless we NULL out the field.
*/
static int rinf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
@@ -90,9 +89,7 @@ ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = {
ASN1_SIMPLE(X509_REQ_INFO, version, ASN1_INTEGER),
ASN1_SIMPLE(X509_REQ_INFO, subject, X509_NAME),
ASN1_SIMPLE(X509_REQ_INFO, pubkey, X509_PUBKEY),
- /* This isn't really OPTIONAL but it gets round invalid
- * encodings
- */
+ /* This isn't really OPTIONAL but it gets around invalid encodings. */
ASN1_IMP_SET_OF_OPT(X509_REQ_INFO, attributes, X509_ATTRIBUTE, 0)
} ASN1_SEQUENCE_END_enc(X509_REQ_INFO, X509_REQ_INFO)
diff --git a/deps/boringssl/src/crypto/x509/x_sig.c b/deps/boringssl/src/crypto/x509/x_sig.c
index ca08c64..8f9a5b7 100644
--- a/deps/boringssl/src/crypto/x509/x_sig.c
+++ b/deps/boringssl/src/crypto/x509/x_sig.c
@@ -61,6 +61,11 @@
#include <openssl/x509.h>
+struct X509_sig_st {
+ X509_ALGOR *algor;
+ ASN1_OCTET_STRING *digest;
+} /* X509_SIG */;
+
ASN1_SEQUENCE(X509_SIG) = {
ASN1_SIMPLE(X509_SIG, algor, X509_ALGOR),
ASN1_SIMPLE(X509_SIG, digest, ASN1_OCTET_STRING)
diff --git a/deps/boringssl/src/crypto/x509/x_val.c b/deps/boringssl/src/crypto/x509/x_val.c
index ad4f7e1..006c53b 100644
--- a/deps/boringssl/src/crypto/x509/x_val.c
+++ b/deps/boringssl/src/crypto/x509/x_val.c
@@ -60,6 +60,8 @@
#include <openssl/asn1t.h>
#include <openssl/x509.h>
+#include "internal.h"
+
ASN1_SEQUENCE(X509_VAL) = {
ASN1_SIMPLE(X509_VAL, notBefore, ASN1_TIME),
diff --git a/deps/boringssl/src/crypto/x509/x_x509.c b/deps/boringssl/src/crypto/x509/x_x509.c
index ff0bff8..38cceb1 100644
--- a/deps/boringssl/src/crypto/x509/x_x509.c
+++ b/deps/boringssl/src/crypto/x509/x_x509.c
@@ -69,6 +69,7 @@
#include <openssl/x509v3.h>
#include "../internal.h"
+#include "internal.h"
static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT;
@@ -128,14 +129,14 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
}
}
- /* Per RFC5280, section 4.1.2.8, these fields require v2 or v3. */
+ /* Per RFC 5280, section 4.1.2.8, these fields require v2 or v3. */
if (version == 0 && (ret->cert_info->issuerUID != NULL ||
ret->cert_info->subjectUID != NULL)) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_FOR_VERSION);
return 0;
}
- /* Per RFC5280, section 4.1.2.9, extensions require v3. */
+ /* Per RFC 5280, section 4.1.2.9, extensions require v3. */
if (version != 2 && ret->cert_info->extensions != NULL) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_FOR_VERSION);
return 0;
diff --git a/deps/boringssl/src/crypto/x509/x_x509a.c b/deps/boringssl/src/crypto/x509/x_x509a.c
index 823fa5c..fca02a6 100644
--- a/deps/boringssl/src/crypto/x509/x_x509a.c
+++ b/deps/boringssl/src/crypto/x509/x_x509a.c
@@ -61,6 +61,9 @@
#include <openssl/obj.h>
#include <openssl/x509.h>
+#include "internal.h"
+
+
/*
* X509_CERT_AUX routines. These are used to encode additional user
* modifiable data about a certificate. This data is appended to the X509
diff --git a/deps/boringssl/src/crypto/x509v3/internal.h b/deps/boringssl/src/crypto/x509v3/internal.h
index 245a5d1..df7d813 100644
--- a/deps/boringssl/src/crypto/x509v3/internal.h
+++ b/deps/boringssl/src/crypto/x509v3/internal.h
@@ -17,6 +17,8 @@
#include <openssl/base.h>
+#include <openssl/conf.h>
+
#if defined(__cplusplus)
extern "C" {
#endif
@@ -53,6 +55,27 @@ OPENSSL_EXPORT int x509v3_looks_like_dns_name(const unsigned char *in,
// invalid.
int x509v3_cache_extensions(X509 *x);
+// x509v3_a2i_ipadd decodes |ipasc| as an IPv4 or IPv6 address. IPv6 addresses
+// use colon-separated syntax while IPv4 addresses use dotted decimal syntax. If
+// it decodes an IPv4 address, it writes the result to the first four bytes of
+// |ipout| and returns four. If it decodes an IPv6 address, it writes the result
+// to all 16 bytes of |ipout| and returns 16. Otherwise, it returns zero.
+int x509v3_a2i_ipadd(unsigned char ipout[16], const char *ipasc);
+
+// A |BIT_STRING_BITNAME| is used to contain a list of bit names.
+typedef struct {
+ int bitnum;
+ const char *lname;
+ const char *sname;
+} BIT_STRING_BITNAME;
+
+// x509V3_add_value_asn1_string appends a |CONF_VALUE| with the specified name
+// and value to |*extlist|. if |*extlist| is NULL, it sets |*extlist| to a
+// newly-allocated |STACK_OF(CONF_VALUE)| first. It returns one on success and
+// zero on error.
+int x509V3_add_value_asn1_string(const char *name, const ASN1_STRING *value,
+ STACK_OF(CONF_VALUE) **extlist);
+
#if defined(__cplusplus)
} /* extern C */
diff --git a/deps/boringssl/src/crypto/x509v3/pcy_cache.c b/deps/boringssl/src/crypto/x509v3/pcy_cache.c
index 755c079..1caea76 100644
--- a/deps/boringssl/src/crypto/x509v3/pcy_cache.c
+++ b/deps/boringssl/src/crypto/x509v3/pcy_cache.c
@@ -62,6 +62,7 @@
#include "pcy_int.h"
#include "../internal.h"
+#include "../x509/internal.h"
static int policy_data_cmp(const X509_POLICY_DATA **a,
const X509_POLICY_DATA **b);
diff --git a/deps/boringssl/src/crypto/x509v3/pcy_data.c b/deps/boringssl/src/crypto/x509v3/pcy_data.c
index 58584c2..c4a56ca 100644
--- a/deps/boringssl/src/crypto/x509v3/pcy_data.c
+++ b/deps/boringssl/src/crypto/x509v3/pcy_data.c
@@ -79,7 +79,7 @@ void policy_data_free(X509_POLICY_DATA *data)
/*
* Create a data based on an existing policy. If 'id' is NULL use the oid in
* the policy, otherwise use 'id'. This behaviour covers the two types of
- * data in RFC3280: data with from a CertificatePolcies extension and
+ * data in RFC 3280: data with from a CertificatePolcies extension and
* additional data with just the qualifiers of anyPolicy and ID from another
* source.
*/
diff --git a/deps/boringssl/src/crypto/x509v3/pcy_int.h b/deps/boringssl/src/crypto/x509v3/pcy_int.h
index fc6e20a..aee71d6 100644
--- a/deps/boringssl/src/crypto/x509v3/pcy_int.h
+++ b/deps/boringssl/src/crypto/x509v3/pcy_int.h
@@ -65,7 +65,7 @@ DEFINE_STACK_OF(X509_POLICY_DATA)
/*
* This structure and the field names correspond to the Policy 'node' of
- * RFC3280. NB this structure contains no pointers to parent or child data:
+ * RFC 3280. NB this structure contains no pointers to parent or child data:
* X509_POLICY_NODE contains that. This means that the main policy data can
* be kept static and cached with the certificate.
*/
diff --git a/deps/boringssl/src/crypto/x509v3/pcy_map.c b/deps/boringssl/src/crypto/x509v3/pcy_map.c
index 7263c69..a4a3601 100644
--- a/deps/boringssl/src/crypto/x509v3/pcy_map.c
+++ b/deps/boringssl/src/crypto/x509v3/pcy_map.c
@@ -62,6 +62,7 @@
#include <openssl/x509v3.h>
#include "pcy_int.h"
+#include "../x509/internal.h"
/*
* Set policy mapping entries in cache. Note: this modifies the passed
diff --git a/deps/boringssl/src/crypto/x509v3/pcy_tree.c b/deps/boringssl/src/crypto/x509v3/pcy_tree.c
index 136b45f..596266b 100644
--- a/deps/boringssl/src/crypto/x509v3/pcy_tree.c
+++ b/deps/boringssl/src/crypto/x509v3/pcy_tree.c
@@ -67,6 +67,7 @@
#include "pcy_int.h"
#include "../internal.h"
+#include "../x509/internal.h"
/*
* Enable this to print out the complete policy tree at various point during
@@ -332,7 +333,7 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
}
/*
- * This corresponds to RFC3280 6.1.3(d)(1): link any data from
+ * This corresponds to RFC 3280 6.1.3(d)(1): link any data from
* CertificatePolicies onto matching parent or anyPolicy if no match.
*/
@@ -365,7 +366,7 @@ static int tree_link_nodes(X509_POLICY_LEVEL *curr,
}
/*
- * This corresponds to RFC3280 6.1.3(d)(2): Create new data for any unmatched
+ * This corresponds to RFC 3280 6.1.3(d)(2): Create new data for any unmatched
* policies in the parent and link to anyPolicy.
*/
@@ -500,7 +501,7 @@ static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr)
if (curr->flags & X509_V_FLAG_INHIBIT_MAP) {
for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) {
node = sk_X509_POLICY_NODE_value(nodes, i);
- /* Delete any mapped data: see RFC3280 XXXX */
+ /* Delete any mapped data: see RFC 3280 XXXX */
if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) {
node->parent->nchild--;
OPENSSL_free(node);
diff --git a/deps/boringssl/src/crypto/x509v3/v3_akey.c b/deps/boringssl/src/crypto/x509v3/v3_akey.c
index 1037673..0aba20e 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_akey.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_akey.c
@@ -93,20 +93,39 @@ static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
STACK_OF(CONF_VALUE)
*extlist)
{
- char *tmp;
+ char *tmp = NULL;
+ int extlist_was_null = extlist == NULL;
if (akeyid->keyid) {
tmp = x509v3_bytes_to_hex(akeyid->keyid->data, akeyid->keyid->length);
- X509V3_add_value("keyid", tmp, &extlist);
+ int ok = tmp != NULL && X509V3_add_value("keyid", tmp, &extlist);
OPENSSL_free(tmp);
+ if (!ok) {
+ goto err;
+ }
+ }
+ if (akeyid->issuer) {
+ STACK_OF(CONF_VALUE) *tmpextlist =
+ i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist);
+ if (tmpextlist == NULL) {
+ goto err;
+ }
+ extlist = tmpextlist;
}
- if (akeyid->issuer)
- extlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist);
if (akeyid->serial) {
tmp = x509v3_bytes_to_hex(akeyid->serial->data, akeyid->serial->length);
- X509V3_add_value("serial", tmp, &extlist);
+ int ok = tmp != NULL && X509V3_add_value("serial", tmp, &extlist);
OPENSSL_free(tmp);
+ if (!ok) {
+ goto err;
+ }
}
return extlist;
+
+err:
+ if (extlist_was_null) {
+ sk_CONF_VALUE_pop_free(extlist, X509V3_conf_free);
+ }
+ return NULL;
}
/*
diff --git a/deps/boringssl/src/crypto/x509v3/v3_alt.c b/deps/boringssl/src/crypto/x509v3/v3_alt.c
index 4d54075..0c55816 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_alt.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_alt.c
@@ -104,11 +104,17 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
GENERAL_NAMES *gens,
STACK_OF(CONF_VALUE) *ret)
{
- size_t i;
- GENERAL_NAME *gen;
- for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
- gen = sk_GENERAL_NAME_value(gens, i);
- ret = i2v_GENERAL_NAME(method, gen, ret);
+ int ret_was_null = ret == NULL;
+ for (size_t i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+ GENERAL_NAME *gen = sk_GENERAL_NAME_value(gens, i);
+ STACK_OF(CONF_VALUE) *tmp = i2v_GENERAL_NAME(method, gen, ret);
+ if (tmp == NULL) {
+ if (ret_was_null) {
+ sk_CONF_VALUE_pop_free(ret, X509V3_conf_free);
+ }
+ return NULL;
+ }
+ ret = tmp;
}
if (!ret)
return sk_CONF_VALUE_new_null();
@@ -119,6 +125,9 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
GENERAL_NAME *gen,
STACK_OF(CONF_VALUE) *ret)
{
+ /* Note the error-handling for this function relies on there being at most
+ * one |X509V3_add_value| call. If there were two and the second failed, we
+ * would need to sometimes free the first call's result. */
unsigned char *p;
char oline[256], htmp[5];
int i;
@@ -139,17 +148,17 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
break;
case GEN_EMAIL:
- if (!X509V3_add_value_uchar("email", gen->d.ia5->data, &ret))
+ if (!x509V3_add_value_asn1_string("email", gen->d.ia5, &ret))
return NULL;
break;
case GEN_DNS:
- if (!X509V3_add_value_uchar("DNS", gen->d.ia5->data, &ret))
+ if (!x509V3_add_value_asn1_string("DNS", gen->d.ia5, &ret))
return NULL;
break;
case GEN_URI:
- if (!X509V3_add_value_uchar("URI", gen->d.ia5->data, &ret))
+ if (!x509V3_add_value_asn1_string("URI", gen->d.ia5, &ret))
return NULL;
break;
diff --git a/deps/boringssl/src/crypto/x509v3/v3_bitst.c b/deps/boringssl/src/crypto/x509v3/v3_bitst.c
index 402f830..871b776 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_bitst.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_bitst.c
@@ -63,6 +63,9 @@
#include <openssl/obj.h>
#include <openssl/x509v3.h>
+#include "internal.h"
+
+
static const BIT_STRING_BITNAME ns_cert_type_table[] = {
{0, "SSL Client", "client"},
{1, "SSL Server", "server"},
diff --git a/deps/boringssl/src/crypto/x509v3/v3_conf.c b/deps/boringssl/src/crypto/x509v3/v3_conf.c
index 158f8df..3192752 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_conf.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_conf.c
@@ -69,6 +69,7 @@
#include <openssl/x509v3.h>
#include "../internal.h"
+#include "../x509/internal.h"
#include "internal.h"
static int v3_check_critical(const char **value);
diff --git a/deps/boringssl/src/crypto/x509v3/v3_cpols.c b/deps/boringssl/src/crypto/x509v3/v3_cpols.c
index 216e7ae..9f66f47 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_cpols.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_cpols.c
@@ -239,8 +239,7 @@ static POLICYINFO *policy_section(X509V3_CTX *ctx,
goto merr;
if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
goto merr;
- /* TODO(fork): const correctness */
- qual->pqualid = (ASN1_OBJECT *)OBJ_nid2obj(NID_id_qt_cps);
+ qual->pqualid = OBJ_nid2obj(NID_id_qt_cps);
if (qual->pqualid == NULL) {
OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR);
goto err;
@@ -307,8 +306,7 @@ static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
POLICYQUALINFO *qual;
if (!(qual = POLICYQUALINFO_new()))
goto merr;
- /* TODO(fork): const correctness */
- qual->pqualid = (ASN1_OBJECT *)OBJ_nid2obj(NID_id_qt_unotice);
+ qual->pqualid = OBJ_nid2obj(NID_id_qt_unotice);
if (qual->pqualid == NULL) {
OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR);
goto err;
@@ -434,8 +432,8 @@ static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals,
qualinfo = sk_POLICYQUALINFO_value(quals, i);
switch (OBJ_obj2nid(qualinfo->pqualid)) {
case NID_id_qt_cps:
- BIO_printf(out, "%*sCPS: %s\n", indent, "",
- qualinfo->d.cpsuri->data);
+ BIO_printf(out, "%*sCPS: %.*s\n", indent, "",
+ qualinfo->d.cpsuri->length, qualinfo->d.cpsuri->data);
break;
case NID_id_qt_unotice:
@@ -459,8 +457,8 @@ static void print_notice(BIO *out, USERNOTICE *notice, int indent)
if (notice->noticeref) {
NOTICEREF *ref;
ref = notice->noticeref;
- BIO_printf(out, "%*sOrganization: %s\n", indent, "",
- ref->organization->data);
+ BIO_printf(out, "%*sOrganization: %.*s\n", indent, "",
+ ref->organization->length, ref->organization->data);
BIO_printf(out, "%*sNumber%s: ", indent, "",
sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : "");
for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) {
@@ -482,8 +480,8 @@ static void print_notice(BIO *out, USERNOTICE *notice, int indent)
BIO_puts(out, "\n");
}
if (notice->exptext)
- BIO_printf(out, "%*sExplicit Text: %s\n", indent, "",
- notice->exptext->data);
+ BIO_printf(out, "%*sExplicit Text: %.*s\n", indent, "",
+ notice->exptext->length, notice->exptext->data);
}
void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent)
diff --git a/deps/boringssl/src/crypto/x509v3/v3_crld.c b/deps/boringssl/src/crypto/x509v3/v3_crld.c
index c93c449..93e5b6d 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_crld.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_crld.c
@@ -66,6 +66,10 @@
#include <openssl/obj.h>
#include <openssl/x509v3.h>
+#include "internal.h"
+#include "../x509/internal.h"
+
+
static void *v2i_crld(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
@@ -341,8 +345,6 @@ static void *v2i_crld(const X509V3_EXT_METHOD *method,
return NULL;
}
-IMPLEMENT_ASN1_SET_OF(DIST_POINT)
-
static int dpn_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
{
diff --git a/deps/boringssl/src/crypto/x509v3/v3_enum.c b/deps/boringssl/src/crypto/x509v3/v3_enum.c
index 3a9d4d6..9b222bb 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_enum.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_enum.c
@@ -61,6 +61,11 @@
#include <openssl/mem.h>
#include <openssl/x509v3.h>
+#include "internal.h"
+
+
+typedef BIT_STRING_BITNAME ENUMERATED_NAMES;
+
static const ENUMERATED_NAMES crl_reasons[] = {
{CRL_REASON_UNSPECIFIED, "Unspecified", "unspecified"},
{CRL_REASON_KEY_COMPROMISE, "Key Compromise", "keyCompromise"},
diff --git a/deps/boringssl/src/crypto/x509v3/v3_lib.c b/deps/boringssl/src/crypto/x509v3/v3_lib.c
index d89733f..3fb0285 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_lib.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_lib.c
@@ -66,6 +66,8 @@
#include <openssl/obj.h>
#include <openssl/x509v3.h>
+#include "../x509/internal.h"
+
#include "ext_dat.h"
static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL;
diff --git a/deps/boringssl/src/crypto/x509v3/v3_ncons.c b/deps/boringssl/src/crypto/x509v3/v3_ncons.c
index 593a520..739a59e 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_ncons.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_ncons.c
@@ -66,6 +66,7 @@
#include <openssl/x509v3.h>
#include "../internal.h"
+#include "../x509/internal.h"
static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
@@ -389,25 +390,73 @@ static int nc_dn(X509_NAME *nm, X509_NAME *base)
return X509_V_OK;
}
+static int starts_with(const CBS *cbs, uint8_t c)
+{
+ return CBS_len(cbs) > 0 && CBS_data(cbs)[0] == c;
+}
+
+static int equal_case(const CBS *a, const CBS *b)
+{
+ if (CBS_len(a) != CBS_len(b)) {
+ return 0;
+ }
+ /* Note we cannot use |OPENSSL_strncasecmp| because that would stop
+ * iterating at NUL. */
+ const uint8_t *a_data = CBS_data(a), *b_data = CBS_data(b);
+ for (size_t i = 0; i < CBS_len(a); i++) {
+ if (OPENSSL_tolower(a_data[i]) != OPENSSL_tolower(b_data[i])) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int has_suffix_case(const CBS *a, const CBS *b)
+{
+ if (CBS_len(a) < CBS_len(b)) {
+ return 0;
+ }
+ CBS copy = *a;
+ CBS_skip(&copy, CBS_len(a) - CBS_len(b));
+ return equal_case(&copy, b);
+}
+
static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base)
{
- char *baseptr = (char *)base->data;
- char *dnsptr = (char *)dns->data;
+ CBS dns_cbs, base_cbs;
+ CBS_init(&dns_cbs, dns->data, dns->length);
+ CBS_init(&base_cbs, base->data, base->length);
+
/* Empty matches everything */
- if (!*baseptr)
+ if (CBS_len(&base_cbs) == 0) {
return X509_V_OK;
+ }
+
+ /* If |base_cbs| begins with a '.', do a simple suffix comparison. This is
+ * not part of RFC5280, but is part of OpenSSL's original behavior. */
+ if (starts_with(&base_cbs, '.')) {
+ if (has_suffix_case(&dns_cbs, &base_cbs)) {
+ return X509_V_OK;
+ }
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ }
+
/*
* Otherwise can add zero or more components on the left so compare RHS
* and if dns is longer and expect '.' as preceding character.
*/
- if (dns->length > base->length) {
- dnsptr += dns->length - base->length;
- if (*baseptr != '.' && dnsptr[-1] != '.')
+ if (CBS_len(&dns_cbs) > CBS_len(&base_cbs)) {
+ uint8_t dot;
+ if (!CBS_skip(&dns_cbs, CBS_len(&dns_cbs) - CBS_len(&base_cbs) - 1) ||
+ !CBS_get_u8(&dns_cbs, &dot) ||
+ dot != '.') {
return X509_V_ERR_PERMITTED_VIOLATION;
+ }
}
- if (OPENSSL_strcasecmp(baseptr, dnsptr))
+ if (!equal_case(&dns_cbs, &base_cbs)) {
return X509_V_ERR_PERMITTED_VIOLATION;
+ }
return X509_V_OK;
@@ -415,86 +464,94 @@ static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base)
static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base)
{
- const char *baseptr = (char *)base->data;
- const char *emlptr = (char *)eml->data;
-
- const char *baseat = strchr(baseptr, '@');
- const char *emlat = strchr(emlptr, '@');
- if (!emlat)
+ CBS eml_cbs, base_cbs;
+ CBS_init(&eml_cbs, eml->data, eml->length);
+ CBS_init(&base_cbs, base->data, base->length);
+
+ /* TODO(davidben): In OpenSSL 1.1.1, this switched from the first '@' to the
+ * last one. Match them here, or perhaps do an actual parse. Looks like
+ * multiple '@'s may be allowed in quoted strings. */
+ CBS eml_local, base_local;
+ if (!CBS_get_until_first(&eml_cbs, &eml_local, '@')) {
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ }
+ int base_has_at = CBS_get_until_first(&base_cbs, &base_local, '@');
+
/* Special case: inital '.' is RHS match */
- if (!baseat && (*baseptr == '.')) {
- if (eml->length > base->length) {
- emlptr += eml->length - base->length;
- if (!OPENSSL_strcasecmp(baseptr, emlptr))
- return X509_V_OK;
+ if (!base_has_at && starts_with(&base_cbs, '.')) {
+ if (has_suffix_case(&eml_cbs, &base_cbs)) {
+ return X509_V_OK;
}
return X509_V_ERR_PERMITTED_VIOLATION;
}
/* If we have anything before '@' match local part */
-
- if (baseat) {
- if (baseat != baseptr) {
- if ((baseat - baseptr) != (emlat - emlptr))
- return X509_V_ERR_PERMITTED_VIOLATION;
+ if (base_has_at) {
+ /* TODO(davidben): This interprets a constraint of "@example.com" as
+ * "example.com", which is not part of RFC5280. */
+ if (CBS_len(&base_local) > 0) {
/* Case sensitive match of local part */
- if (strncmp(baseptr, emlptr, emlat - emlptr))
+ if (!CBS_mem_equal(&base_local, CBS_data(&eml_local),
+ CBS_len(&eml_local))) {
return X509_V_ERR_PERMITTED_VIOLATION;
+ }
}
/* Position base after '@' */
- baseptr = baseat + 1;
+ assert(starts_with(&base_cbs, '@'));
+ CBS_skip(&base_cbs, 1);
}
- emlptr = emlat + 1;
+
/* Just have hostname left to match: case insensitive */
- if (OPENSSL_strcasecmp(baseptr, emlptr))
+ assert(starts_with(&eml_cbs, '@'));
+ CBS_skip(&eml_cbs, 1);
+ if (!equal_case(&base_cbs, &eml_cbs)) {
return X509_V_ERR_PERMITTED_VIOLATION;
+ }
return X509_V_OK;
-
}
static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base)
{
- const char *baseptr = (char *)base->data;
- const char *hostptr = (char *)uri->data;
- const char *p = strchr(hostptr, ':');
- int hostlen;
+ CBS uri_cbs, base_cbs;
+ CBS_init(&uri_cbs, uri->data, uri->length);
+ CBS_init(&base_cbs, base->data, base->length);
+
/* Check for foo:// and skip past it */
- if (!p || (p[1] != '/') || (p[2] != '/'))
+ CBS scheme;
+ uint8_t byte;
+ if (!CBS_get_until_first(&uri_cbs, &scheme, ':') ||
+ !CBS_skip(&uri_cbs, 1) || // Skip the colon
+ !CBS_get_u8(&uri_cbs, &byte) || byte != '/' ||
+ !CBS_get_u8(&uri_cbs, &byte) || byte != '/') {
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
- hostptr = p + 3;
-
- /* Determine length of hostname part of URI */
-
- /* Look for a port indicator as end of hostname first */
-
- p = strchr(hostptr, ':');
- /* Otherwise look for trailing slash */
- if (!p)
- p = strchr(hostptr, '/');
+ }
- if (!p)
- hostlen = strlen(hostptr);
- else
- hostlen = p - hostptr;
+ /* Look for a port indicator as end of hostname first. Otherwise look for
+ * trailing slash, or the end of the string.
+ * TODO(davidben): This is not a correct URI parser and mishandles IPv6
+ * literals. */
+ CBS host;
+ if (!CBS_get_until_first(&uri_cbs, &host, ':') &&
+ !CBS_get_until_first(&uri_cbs, &host, '/')) {
+ host = uri_cbs;
+ }
- if (hostlen == 0)
+ if (CBS_len(&host) == 0) {
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ }
/* Special case: inital '.' is RHS match */
- if (*baseptr == '.') {
- if (hostlen > base->length) {
- p = hostptr + hostlen - base->length;
- if (!OPENSSL_strncasecmp(p, baseptr, base->length))
- return X509_V_OK;
+ if (starts_with(&base_cbs, '.')) {
+ if (has_suffix_case(&host, &base_cbs)) {
+ return X509_V_OK;
}
return X509_V_ERR_PERMITTED_VIOLATION;
}
- if ((base->length != (int)hostlen)
- || OPENSSL_strncasecmp(hostptr, baseptr, hostlen))
+ if (!equal_case(&base_cbs, &host)) {
return X509_V_ERR_PERMITTED_VIOLATION;
+ }
return X509_V_OK;
diff --git a/deps/boringssl/src/crypto/x509v3/v3_pci.c b/deps/boringssl/src/crypto/x509v3/v3_pci.c
index f9031c0..57b64ef 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_pci.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_pci.c
@@ -75,7 +75,8 @@ static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci,
i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage);
BIO_puts(out, "\n");
if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data)
- BIO_printf(out, "%*sPolicy Text: %s\n", indent, "",
+ BIO_printf(out, "%*sPolicy Text: %.*s\n", indent, "",
+ pci->proxyPolicy->policy->length,
pci->proxyPolicy->policy->data);
return 1;
}
diff --git a/deps/boringssl/src/crypto/x509v3/v3_prn.c b/deps/boringssl/src/crypto/x509v3/v3_prn.c
index f6f341a..ee4c482 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_prn.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_prn.c
@@ -107,20 +107,20 @@ int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag,
{
void *ext_str = NULL;
char *value = NULL;
- const unsigned char *p;
const X509V3_EXT_METHOD *method;
STACK_OF(CONF_VALUE) *nval = NULL;
int ok = 1;
if (!(method = X509V3_EXT_get(ext)))
return unknown_ext_print(out, ext, flag, indent, 0);
- p = ext->value->data;
- if (method->it)
- ext_str =
- ASN1_item_d2i(NULL, &p, ext->value->length,
- ASN1_ITEM_ptr(method->it));
- else
- ext_str = method->d2i(NULL, &p, ext->value->length);
+ const ASN1_STRING *ext_data = X509_EXTENSION_get_data(ext);
+ const unsigned char *p = ASN1_STRING_get0_data(ext_data);
+ if (method->it) {
+ ext_str = ASN1_item_d2i(NULL, &p, ASN1_STRING_length(ext_data),
+ ASN1_ITEM_ptr(method->it));
+ } else {
+ ext_str = method->d2i(NULL, &p, ASN1_STRING_length(ext_data));
+ }
if (!ext_str)
return unknown_ext_print(out, ext, flag, indent, 1);
@@ -183,7 +183,7 @@ int X509V3_extensions_print(BIO *bp, const char *title,
return 0;
if (!X509V3_EXT_print(bp, ex, flag, indent + 4)) {
BIO_printf(bp, "%*s", indent + 4, "");
- ASN1_STRING_print(bp, ex->value);
+ ASN1_STRING_print(bp, X509_EXTENSION_get_data(ex));
}
if (BIO_write(bp, "\n", 1) <= 0)
return 0;
@@ -207,15 +207,17 @@ static int unknown_ext_print(BIO *out, X509_EXTENSION *ext,
return 1;
case X509V3_EXT_PARSE_UNKNOWN:
- case X509V3_EXT_DUMP_UNKNOWN:
- return BIO_hexdump(out, ext->value->data, ext->value->length, indent);
+ case X509V3_EXT_DUMP_UNKNOWN: {
+ const ASN1_STRING *data = X509_EXTENSION_get_data(ext);
+ return BIO_hexdump(out, ASN1_STRING_get0_data(data),
+ ASN1_STRING_length(data), indent);
+ }
default:
return 1;
}
}
-#ifndef OPENSSL_NO_FP_API
int X509V3_EXT_print_fp(FILE *fp, X509_EXTENSION *ext, int flag, int indent)
{
BIO *bio_tmp;
@@ -226,4 +228,3 @@ int X509V3_EXT_print_fp(FILE *fp, X509_EXTENSION *ext, int flag, int indent)
BIO_free(bio_tmp);
return ret;
}
-#endif
diff --git a/deps/boringssl/src/crypto/x509v3/v3_purp.c b/deps/boringssl/src/crypto/x509v3/v3_purp.c
index acb7602..d1f56f0 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_purp.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_purp.c
@@ -68,6 +68,7 @@
#include <openssl/x509v3.h>
#include "../internal.h"
+#include "../x509/internal.h"
#include "internal.h"
#define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
@@ -440,7 +441,7 @@ int x509v3_cache_extensions(X509 *x)
if (!X509_digest(x, EVP_sha1(), x->sha1_hash, NULL))
x->ex_flags |= EXFLAG_INVALID;
/* V1 should mean no extensions ... */
- if (!X509_get_version(x))
+ if (X509_get_version(x) == X509_VERSION_1)
x->ex_flags |= EXFLAG_V1;
/* Handle basic constraints */
if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &j, NULL))) {
diff --git a/deps/boringssl/src/crypto/x509v3/v3_skey.c b/deps/boringssl/src/crypto/x509v3/v3_skey.c
index 140356d..1cae7e1 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_skey.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_skey.c
@@ -63,6 +63,7 @@
#include <openssl/obj.h>
#include <openssl/x509v3.h>
+#include "../x509/internal.h"
#include "internal.h"
diff --git a/deps/boringssl/src/crypto/x509v3/v3_utl.c b/deps/boringssl/src/crypto/x509v3/v3_utl.c
index c0952c0..5d91aed 100644
--- a/deps/boringssl/src/crypto/x509v3/v3_utl.c
+++ b/deps/boringssl/src/crypto/x509v3/v3_utl.c
@@ -81,49 +81,76 @@ static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name,
static void str_free(OPENSSL_STRING str);
static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email);
-static int ipv4_from_asc(unsigned char *v4, const char *in);
-static int ipv6_from_asc(unsigned char *v6, const char *in);
+static int ipv4_from_asc(unsigned char v4[4], const char *in);
+static int ipv6_from_asc(unsigned char v6[16], const char *in);
static int ipv6_cb(const char *elem, int len, void *usr);
static int ipv6_hex(unsigned char *out, const char *in, int inlen);
/* Add a CONF_VALUE name value pair to stack */
-int X509V3_add_value(const char *name, const char *value,
- STACK_OF(CONF_VALUE) **extlist)
+static int x509V3_add_len_value(const char *name, const char *value,
+ size_t value_len, int omit_value,
+ STACK_OF(CONF_VALUE) **extlist)
{
CONF_VALUE *vtmp = NULL;
char *tname = NULL, *tvalue = NULL;
+ int extlist_was_null = *extlist == NULL;
if (name && !(tname = OPENSSL_strdup(name)))
- goto err;
- if (value && !(tvalue = OPENSSL_strdup(value)))
- goto err;
+ goto malloc_err;
+ if (!omit_value) {
+ /* |CONF_VALUE| cannot represent strings with NULs. */
+ if (OPENSSL_memchr(value, 0, value_len)) {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_VALUE);
+ goto err;
+ }
+ tvalue = OPENSSL_strndup(value, value_len);
+ if (tvalue == NULL) {
+ goto malloc_err;
+ }
+ }
if (!(vtmp = CONF_VALUE_new()))
- goto err;
+ goto malloc_err;
if (!*extlist && !(*extlist = sk_CONF_VALUE_new_null()))
- goto err;
+ goto malloc_err;
vtmp->section = NULL;
vtmp->name = tname;
vtmp->value = tvalue;
if (!sk_CONF_VALUE_push(*extlist, vtmp))
- goto err;
+ goto malloc_err;
return 1;
- err:
+ malloc_err:
OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
- if (vtmp)
- OPENSSL_free(vtmp);
- if (tname)
- OPENSSL_free(tname);
- if (tvalue)
- OPENSSL_free(tvalue);
+ err:
+ if (extlist_was_null) {
+ sk_CONF_VALUE_free(*extlist);
+ *extlist = NULL;
+ }
+ OPENSSL_free(vtmp);
+ OPENSSL_free(tname);
+ OPENSSL_free(tvalue);
return 0;
}
+int X509V3_add_value(const char *name, const char *value,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ return x509V3_add_len_value(name, value, value != NULL ? strlen(value) : 0,
+ /*omit_value=*/value == NULL, extlist);
+}
+
int X509V3_add_value_uchar(const char *name, const unsigned char *value,
STACK_OF(CONF_VALUE) **extlist)
{
return X509V3_add_value(name, (const char *)value, extlist);
}
+int x509V3_add_value_asn1_string(const char *name, const ASN1_STRING *value,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ return x509V3_add_len_value(name, (const char *)value->data, value->length,
+ /*omit_value=*/0, extlist);
+}
+
/* Free function for STACK_OF(CONF_VALUE) */
void X509V3_conf_free(CONF_VALUE *conf)
@@ -268,7 +295,7 @@ ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, const char *value)
return aint;
}
-int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
+int X509V3_add_value_int(const char *name, const ASN1_INTEGER *aint,
STACK_OF(CONF_VALUE) **extlist)
{
char *strtmp;
@@ -631,27 +658,45 @@ static void str_free(OPENSSL_STRING str)
static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email)
{
- char *emtmp;
/* First some sanity checks */
if (email->type != V_ASN1_IA5STRING)
return 1;
- if (!email->data || !email->length)
+ if (email->data == NULL || email->length == 0)
return 1;
+ /* |OPENSSL_STRING| cannot represent strings with embedded NULs. Do not
+ * report them as outputs. */
+ if (OPENSSL_memchr(email->data, 0, email->length) != NULL)
+ return 1;
+
+ char *emtmp = NULL;
if (!*sk)
*sk = sk_OPENSSL_STRING_new(sk_strcmp);
if (!*sk)
- return 0;
+ goto err;
+
+ emtmp = OPENSSL_strndup((char *)email->data, email->length);
+ if (emtmp == NULL) {
+ goto err;
+ }
+
/* Don't add duplicates */
sk_OPENSSL_STRING_sort(*sk);
- if (sk_OPENSSL_STRING_find(*sk, NULL, (char *)email->data))
+ if (sk_OPENSSL_STRING_find(*sk, NULL, emtmp)) {
+ OPENSSL_free(emtmp);
return 1;
- emtmp = OPENSSL_strdup((char *)email->data);
- if (!emtmp || !sk_OPENSSL_STRING_push(*sk, emtmp)) {
- X509_email_free(*sk);
- *sk = NULL;
- return 0;
+ }
+ if (!sk_OPENSSL_STRING_push(*sk, emtmp)) {
+ goto err;
}
return 1;
+
+err:
+ /* TODO(davidben): Fix the error-handling in this file. It currently relies
+ * on |append_ia5| leaving |*sk| at NULL on error. */
+ OPENSSL_free(emtmp);
+ X509_email_free(*sk);
+ *sk = NULL;
+ return 0;
}
void X509_email_free(STACK_OF(OPENSSL_STRING) *sk)
@@ -1112,7 +1157,7 @@ int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags)
if (ipasc == NULL)
return -2;
- iplen = (size_t)a2i_ipadd(ipout, ipasc);
+ iplen = (size_t)x509v3_a2i_ipadd(ipout, ipasc);
if (iplen == 0)
return -2;
return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, NULL);
@@ -1120,7 +1165,7 @@ int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags)
/*
* Convert IP addresses both IPv4 and IPv6 into an OCTET STRING compatible
- * with RFC3280.
+ * with RFC 3280.
*/
ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc)
@@ -1129,10 +1174,7 @@ ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc)
ASN1_OCTET_STRING *ret;
int iplen;
- /* If string contains a ':' assume IPv6 */
-
- iplen = a2i_ipadd(ipout, ipasc);
-
+ iplen = x509v3_a2i_ipadd(ipout, ipasc);
if (!iplen)
return NULL;
@@ -1161,12 +1203,12 @@ ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc)
p = iptmp + (p - ipasc);
*p++ = 0;
- iplen1 = a2i_ipadd(ipout, iptmp);
+ iplen1 = x509v3_a2i_ipadd(ipout, iptmp);
if (!iplen1)
goto err;
- iplen2 = a2i_ipadd(ipout + iplen1, p);
+ iplen2 = x509v3_a2i_ipadd(ipout + iplen1, p);
OPENSSL_free(iptmp);
iptmp = NULL;
@@ -1190,7 +1232,7 @@ ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc)
return NULL;
}
-int a2i_ipadd(unsigned char *ipout, const char *ipasc)
+int x509v3_a2i_ipadd(unsigned char ipout[16], const char *ipasc)
{
/* If string contains a ':' assume IPv6 */
@@ -1205,7 +1247,7 @@ int a2i_ipadd(unsigned char *ipout, const char *ipasc)
}
}
-static int ipv4_from_asc(unsigned char *v4, const char *in)
+static int ipv4_from_asc(unsigned char v4[4], const char *in)
{
int a0, a1, a2, a3;
if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4)
@@ -1231,7 +1273,7 @@ typedef struct {
int zero_cnt;
} IPV6_STAT;
-static int ipv6_from_asc(unsigned char *v6, const char *in)
+static int ipv6_from_asc(unsigned char v6[16], const char *in)
{
IPV6_STAT v6stat;
v6stat.total = 0;
diff --git a/deps/boringssl/src/crypto/x509v3/v3name_test.cc b/deps/boringssl/src/crypto/x509v3/v3name_test.cc
index 2dcdd87..a501115 100644
--- a/deps/boringssl/src/crypto/x509v3/v3name_test.cc
+++ b/deps/boringssl/src/crypto/x509v3/v3name_test.cc
@@ -305,7 +305,7 @@ static X509 *make_cert(void)
crt = X509_new();
if (crt == NULL)
goto out;
- if (!X509_set_version(crt, 3))
+ if (!X509_set_version(crt, X509_VERSION_3))
goto out;
ret = crt;
crt = NULL;
diff --git a/deps/boringssl/src/decrepit/evp/evp_do_all.c b/deps/boringssl/src/decrepit/evp/evp_do_all.c
index d540144..a3fb077 100644
--- a/deps/boringssl/src/decrepit/evp/evp_do_all.c
+++ b/deps/boringssl/src/decrepit/evp/evp_do_all.c
@@ -78,6 +78,7 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
callback(EVP_sha256(), "SHA256", NULL, arg);
callback(EVP_sha384(), "SHA384", NULL, arg);
callback(EVP_sha512(), "SHA512", NULL, arg);
+ callback(EVP_sha512_256(), "SHA512-256", NULL, arg);
callback(EVP_md4(), "md4", NULL, arg);
callback(EVP_md5(), "md5", NULL, arg);
@@ -86,4 +87,11 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
callback(EVP_sha256(), "sha256", NULL, arg);
callback(EVP_sha384(), "sha384", NULL, arg);
callback(EVP_sha512(), "sha512", NULL, arg);
+ callback(EVP_sha512_256(), "sha512-256", NULL, arg);
+}
+
+void EVP_MD_do_all(void (*callback)(const EVP_MD *cipher, const char *name,
+ const char *unused, void *arg),
+ void *arg) {
+ EVP_MD_do_all_sorted(callback, arg);
}
diff --git a/deps/boringssl/src/decrepit/ripemd/internal.h b/deps/boringssl/src/decrepit/ripemd/internal.h
deleted file mode 100644
index 089be15..0000000
--- a/deps/boringssl/src/decrepit/ripemd/internal.h
+++ /dev/null
@@ -1,494 +0,0 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.] */
-
-#ifndef OPENSSL_HEADER_RIPEMD_INTERNAL_H
-#define OPENSSL_HEADER_RIPEMD_INTERNAL_H
-
-#include <openssl/base.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-
-static void ripemd160_block_data_order(uint32_t h[5], const uint8_t *data,
- size_t num);
-
-#define DATA_ORDER_IS_LITTLE_ENDIAN
-
-#define HASH_LONG uint32_t
-#define HASH_CTX RIPEMD160_CTX
-#define HASH_CBLOCK RIPEMD160_CBLOCK
-#define HASH_DIGEST_LENGTH RIPEMD160_DIGEST_LENGTH
-#define HASH_UPDATE RIPEMD160_Update
-#define HASH_TRANSFORM RIPEMD160_Transform
-#define HASH_FINAL RIPEMD160_Final
-#define HASH_MAKE_STRING(c, s) \
- do { \
- unsigned long ll; \
- ll = (c)->h[0]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[1]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[2]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[3]; \
- HOST_l2c(ll, (s)); \
- ll = (c)->h[4]; \
- HOST_l2c(ll, (s)); \
- } while (0)
-#define HASH_BLOCK_DATA_ORDER ripemd160_block_data_order
-
-#include "../../crypto/fipsmodule/digest/md32_common.h"
-
-// Transformed F2 and F4 are courtesy of Wei Dai <weidai@eskimo.com>
-#define F1(x, y, z) ((x) ^ (y) ^ (z))
-#define F2(x, y, z) ((((y) ^ (z)) & (x)) ^ (z))
-#define F3(x, y, z) (((~(y)) | (x)) ^ (z))
-#define F4(x, y, z) ((((x) ^ (y)) & (z)) ^ (y))
-#define F5(x, y, z) (((~(z)) | (y)) ^ (x))
-
-#define RIPEMD160_A 0x67452301L
-#define RIPEMD160_B 0xEFCDAB89L
-#define RIPEMD160_C 0x98BADCFEL
-#define RIPEMD160_D 0x10325476L
-#define RIPEMD160_E 0xC3D2E1F0L
-
-#define ROTATE(a, n) (((a) << (n)) | (((a)&0xffffffff) >> (32 - (n))))
-
-#define RIP1(a, b, c, d, e, w, s) \
- { \
- a += F1(b, c, d) + X(w); \
- a = ROTATE(a, s) + e; \
- c = ROTATE(c, 10); \
- }
-
-#define RIP2(a, b, c, d, e, w, s, K) \
- { \
- a += F2(b, c, d) + X(w) + K; \
- a = ROTATE(a, s) + e; \
- c = ROTATE(c, 10); \
- }
-
-#define RIP3(a, b, c, d, e, w, s, K) \
- { \
- a += F3(b, c, d) + X(w) + K; \
- a = ROTATE(a, s) + e; \
- c = ROTATE(c, 10); \
- }
-
-#define RIP4(a, b, c, d, e, w, s, K) \
- { \
- a += F4(b, c, d) + X(w) + K; \
- a = ROTATE(a, s) + e; \
- c = ROTATE(c, 10); \
- }
-
-#define RIP5(a, b, c, d, e, w, s, K) \
- { \
- a += F5(b, c, d) + X(w) + K; \
- a = ROTATE(a, s) + e; \
- c = ROTATE(c, 10); \
- }
-
-#define KL0 0x00000000L
-#define KL1 0x5A827999L
-#define KL2 0x6ED9EBA1L
-#define KL3 0x8F1BBCDCL
-#define KL4 0xA953FD4EL
-
-#define KR0 0x50A28BE6L
-#define KR1 0x5C4DD124L
-#define KR2 0x6D703EF3L
-#define KR3 0x7A6D76E9L
-#define KR4 0x00000000L
-
-#define WL00 0
-#define SL00 11
-#define WL01 1
-#define SL01 14
-#define WL02 2
-#define SL02 15
-#define WL03 3
-#define SL03 12
-#define WL04 4
-#define SL04 5
-#define WL05 5
-#define SL05 8
-#define WL06 6
-#define SL06 7
-#define WL07 7
-#define SL07 9
-#define WL08 8
-#define SL08 11
-#define WL09 9
-#define SL09 13
-#define WL10 10
-#define SL10 14
-#define WL11 11
-#define SL11 15
-#define WL12 12
-#define SL12 6
-#define WL13 13
-#define SL13 7
-#define WL14 14
-#define SL14 9
-#define WL15 15
-#define SL15 8
-
-#define WL16 7
-#define SL16 7
-#define WL17 4
-#define SL17 6
-#define WL18 13
-#define SL18 8
-#define WL19 1
-#define SL19 13
-#define WL20 10
-#define SL20 11
-#define WL21 6
-#define SL21 9
-#define WL22 15
-#define SL22 7
-#define WL23 3
-#define SL23 15
-#define WL24 12
-#define SL24 7
-#define WL25 0
-#define SL25 12
-#define WL26 9
-#define SL26 15
-#define WL27 5
-#define SL27 9
-#define WL28 2
-#define SL28 11
-#define WL29 14
-#define SL29 7
-#define WL30 11
-#define SL30 13
-#define WL31 8
-#define SL31 12
-
-#define WL32 3
-#define SL32 11
-#define WL33 10
-#define SL33 13
-#define WL34 14
-#define SL34 6
-#define WL35 4
-#define SL35 7
-#define WL36 9
-#define SL36 14
-#define WL37 15
-#define SL37 9
-#define WL38 8
-#define SL38 13
-#define WL39 1
-#define SL39 15
-#define WL40 2
-#define SL40 14
-#define WL41 7
-#define SL41 8
-#define WL42 0
-#define SL42 13
-#define WL43 6
-#define SL43 6
-#define WL44 13
-#define SL44 5
-#define WL45 11
-#define SL45 12
-#define WL46 5
-#define SL46 7
-#define WL47 12
-#define SL47 5
-
-#define WL48 1
-#define SL48 11
-#define WL49 9
-#define SL49 12
-#define WL50 11
-#define SL50 14
-#define WL51 10
-#define SL51 15
-#define WL52 0
-#define SL52 14
-#define WL53 8
-#define SL53 15
-#define WL54 12
-#define SL54 9
-#define WL55 4
-#define SL55 8
-#define WL56 13
-#define SL56 9
-#define WL57 3
-#define SL57 14
-#define WL58 7
-#define SL58 5
-#define WL59 15
-#define SL59 6
-#define WL60 14
-#define SL60 8
-#define WL61 5
-#define SL61 6
-#define WL62 6
-#define SL62 5
-#define WL63 2
-#define SL63 12
-
-#define WL64 4
-#define SL64 9
-#define WL65 0
-#define SL65 15
-#define WL66 5
-#define SL66 5
-#define WL67 9
-#define SL67 11
-#define WL68 7
-#define SL68 6
-#define WL69 12
-#define SL69 8
-#define WL70 2
-#define SL70 13
-#define WL71 10
-#define SL71 12
-#define WL72 14
-#define SL72 5
-#define WL73 1
-#define SL73 12
-#define WL74 3
-#define SL74 13
-#define WL75 8
-#define SL75 14
-#define WL76 11
-#define SL76 11
-#define WL77 6
-#define SL77 8
-#define WL78 15
-#define SL78 5
-#define WL79 13
-#define SL79 6
-
-#define WR00 5
-#define SR00 8
-#define WR01 14
-#define SR01 9
-#define WR02 7
-#define SR02 9
-#define WR03 0
-#define SR03 11
-#define WR04 9
-#define SR04 13
-#define WR05 2
-#define SR05 15
-#define WR06 11
-#define SR06 15
-#define WR07 4
-#define SR07 5
-#define WR08 13
-#define SR08 7
-#define WR09 6
-#define SR09 7
-#define WR10 15
-#define SR10 8
-#define WR11 8
-#define SR11 11
-#define WR12 1
-#define SR12 14
-#define WR13 10
-#define SR13 14
-#define WR14 3
-#define SR14 12
-#define WR15 12
-#define SR15 6
-
-#define WR16 6
-#define SR16 9
-#define WR17 11
-#define SR17 13
-#define WR18 3
-#define SR18 15
-#define WR19 7
-#define SR19 7
-#define WR20 0
-#define SR20 12
-#define WR21 13
-#define SR21 8
-#define WR22 5
-#define SR22 9
-#define WR23 10
-#define SR23 11
-#define WR24 14
-#define SR24 7
-#define WR25 15
-#define SR25 7
-#define WR26 8
-#define SR26 12
-#define WR27 12
-#define SR27 7
-#define WR28 4
-#define SR28 6
-#define WR29 9
-#define SR29 15
-#define WR30 1
-#define SR30 13
-#define WR31 2
-#define SR31 11
-
-#define WR32 15
-#define SR32 9
-#define WR33 5
-#define SR33 7
-#define WR34 1
-#define SR34 15
-#define WR35 3
-#define SR35 11
-#define WR36 7
-#define SR36 8
-#define WR37 14
-#define SR37 6
-#define WR38 6
-#define SR38 6
-#define WR39 9
-#define SR39 14
-#define WR40 11
-#define SR40 12
-#define WR41 8
-#define SR41 13
-#define WR42 12
-#define SR42 5
-#define WR43 2
-#define SR43 14
-#define WR44 10
-#define SR44 13
-#define WR45 0
-#define SR45 13
-#define WR46 4
-#define SR46 7
-#define WR47 13
-#define SR47 5
-
-#define WR48 8
-#define SR48 15
-#define WR49 6
-#define SR49 5
-#define WR50 4
-#define SR50 8
-#define WR51 1
-#define SR51 11
-#define WR52 3
-#define SR52 14
-#define WR53 11
-#define SR53 14
-#define WR54 15
-#define SR54 6
-#define WR55 0
-#define SR55 14
-#define WR56 5
-#define SR56 6
-#define WR57 12
-#define SR57 9
-#define WR58 2
-#define SR58 12
-#define WR59 13
-#define SR59 9
-#define WR60 9
-#define SR60 12
-#define WR61 7
-#define SR61 5
-#define WR62 10
-#define SR62 15
-#define WR63 14
-#define SR63 8
-
-#define WR64 12
-#define SR64 8
-#define WR65 15
-#define SR65 5
-#define WR66 10
-#define SR66 12
-#define WR67 4
-#define SR67 9
-#define WR68 1
-#define SR68 12
-#define WR69 5
-#define SR69 5
-#define WR70 8
-#define SR70 14
-#define WR71 7
-#define SR71 6
-#define WR72 6
-#define SR72 8
-#define WR73 2
-#define SR73 13
-#define WR74 13
-#define SR74 6
-#define WR75 14
-#define SR75 5
-#define WR76 0
-#define SR76 15
-#define WR77 3
-#define SR77 13
-#define WR78 9
-#define SR78 11
-#define WR79 11
-#define SR79 11
-
-
-#if defined(__cplusplus)
-} // extern C
-#endif
-
-#endif // OPENSSL_HEADER_RIPEMD_INTERNAL_H
diff --git a/deps/boringssl/src/decrepit/ripemd/ripemd.c b/deps/boringssl/src/decrepit/ripemd/ripemd.c
index 17b3fdf..9120cdd 100644
--- a/deps/boringssl/src/decrepit/ripemd/ripemd.c
+++ b/deps/boringssl/src/decrepit/ripemd/ripemd.c
@@ -58,9 +58,16 @@
#include <string.h>
-#include "internal.h"
+#include "../../crypto/internal.h"
+#include "../../crypto/fipsmodule/digest/md32_common.h"
+#define RIPEMD160_A 0x67452301L
+#define RIPEMD160_B 0xEFCDAB89L
+#define RIPEMD160_C 0x98BADCFEL
+#define RIPEMD160_D 0x10325476L
+#define RIPEMD160_E 0xC3D2E1F0L
+
int RIPEMD160_Init(RIPEMD160_CTX *ctx) {
OPENSSL_memset(ctx, 0, sizeof(*ctx));
ctx->h[0] = RIPEMD160_A;
@@ -72,9 +79,422 @@ int RIPEMD160_Init(RIPEMD160_CTX *ctx) {
}
static void ripemd160_block_data_order(uint32_t h[5], const uint8_t *data,
+ size_t num);
+
+void RIPEMD160_Transform(RIPEMD160_CTX *c,
+ const uint8_t data[RIPEMD160_CBLOCK]) {
+ ripemd160_block_data_order(c->h, data, 1);
+}
+
+int RIPEMD160_Update(RIPEMD160_CTX *c, const void *data, size_t len) {
+ crypto_md32_update(&ripemd160_block_data_order, c->h, c->data,
+ RIPEMD160_CBLOCK, &c->num, &c->Nh, &c->Nl, data, len);
+ return 1;
+}
+
+int RIPEMD160_Final(uint8_t out[RIPEMD160_DIGEST_LENGTH], RIPEMD160_CTX *c) {
+ crypto_md32_final(&ripemd160_block_data_order, c->h, c->data,
+ RIPEMD160_CBLOCK, &c->num, c->Nh, c->Nl,
+ /*is_big_endian=*/0);
+
+ CRYPTO_store_u32_le(out, c->h[0]);
+ CRYPTO_store_u32_le(out + 4, c->h[1]);
+ CRYPTO_store_u32_le(out + 8, c->h[2]);
+ CRYPTO_store_u32_le(out + 12, c->h[3]);
+ CRYPTO_store_u32_le(out + 16, c->h[4]);
+ return 1;
+}
+
+// Transformed F2 and F4 are courtesy of Wei Dai <weidai@eskimo.com>
+#define F1(x, y, z) ((x) ^ (y) ^ (z))
+#define F2(x, y, z) ((((y) ^ (z)) & (x)) ^ (z))
+#define F3(x, y, z) (((~(y)) | (x)) ^ (z))
+#define F4(x, y, z) ((((x) ^ (y)) & (z)) ^ (y))
+#define F5(x, y, z) (((~(z)) | (y)) ^ (x))
+
+#define ROTATE(a, n) (((a) << (n)) | (((a)&0xffffffff) >> (32 - (n))))
+
+#define RIP1(a, b, c, d, e, w, s) \
+ { \
+ a += F1(b, c, d) + X(w); \
+ a = ROTATE(a, s) + e; \
+ c = ROTATE(c, 10); \
+ }
+
+#define RIP2(a, b, c, d, e, w, s, K) \
+ { \
+ a += F2(b, c, d) + X(w) + K; \
+ a = ROTATE(a, s) + e; \
+ c = ROTATE(c, 10); \
+ }
+
+#define RIP3(a, b, c, d, e, w, s, K) \
+ { \
+ a += F3(b, c, d) + X(w) + K; \
+ a = ROTATE(a, s) + e; \
+ c = ROTATE(c, 10); \
+ }
+
+#define RIP4(a, b, c, d, e, w, s, K) \
+ { \
+ a += F4(b, c, d) + X(w) + K; \
+ a = ROTATE(a, s) + e; \
+ c = ROTATE(c, 10); \
+ }
+
+#define RIP5(a, b, c, d, e, w, s, K) \
+ { \
+ a += F5(b, c, d) + X(w) + K; \
+ a = ROTATE(a, s) + e; \
+ c = ROTATE(c, 10); \
+ }
+
+#define KL0 0x00000000L
+#define KL1 0x5A827999L
+#define KL2 0x6ED9EBA1L
+#define KL3 0x8F1BBCDCL
+#define KL4 0xA953FD4EL
+
+#define KR0 0x50A28BE6L
+#define KR1 0x5C4DD124L
+#define KR2 0x6D703EF3L
+#define KR3 0x7A6D76E9L
+#define KR4 0x00000000L
+
+#define WL00 0
+#define SL00 11
+#define WL01 1
+#define SL01 14
+#define WL02 2
+#define SL02 15
+#define WL03 3
+#define SL03 12
+#define WL04 4
+#define SL04 5
+#define WL05 5
+#define SL05 8
+#define WL06 6
+#define SL06 7
+#define WL07 7
+#define SL07 9
+#define WL08 8
+#define SL08 11
+#define WL09 9
+#define SL09 13
+#define WL10 10
+#define SL10 14
+#define WL11 11
+#define SL11 15
+#define WL12 12
+#define SL12 6
+#define WL13 13
+#define SL13 7
+#define WL14 14
+#define SL14 9
+#define WL15 15
+#define SL15 8
+
+#define WL16 7
+#define SL16 7
+#define WL17 4
+#define SL17 6
+#define WL18 13
+#define SL18 8
+#define WL19 1
+#define SL19 13
+#define WL20 10
+#define SL20 11
+#define WL21 6
+#define SL21 9
+#define WL22 15
+#define SL22 7
+#define WL23 3
+#define SL23 15
+#define WL24 12
+#define SL24 7
+#define WL25 0
+#define SL25 12
+#define WL26 9
+#define SL26 15
+#define WL27 5
+#define SL27 9
+#define WL28 2
+#define SL28 11
+#define WL29 14
+#define SL29 7
+#define WL30 11
+#define SL30 13
+#define WL31 8
+#define SL31 12
+
+#define WL32 3
+#define SL32 11
+#define WL33 10
+#define SL33 13
+#define WL34 14
+#define SL34 6
+#define WL35 4
+#define SL35 7
+#define WL36 9
+#define SL36 14
+#define WL37 15
+#define SL37 9
+#define WL38 8
+#define SL38 13
+#define WL39 1
+#define SL39 15
+#define WL40 2
+#define SL40 14
+#define WL41 7
+#define SL41 8
+#define WL42 0
+#define SL42 13
+#define WL43 6
+#define SL43 6
+#define WL44 13
+#define SL44 5
+#define WL45 11
+#define SL45 12
+#define WL46 5
+#define SL46 7
+#define WL47 12
+#define SL47 5
+
+#define WL48 1
+#define SL48 11
+#define WL49 9
+#define SL49 12
+#define WL50 11
+#define SL50 14
+#define WL51 10
+#define SL51 15
+#define WL52 0
+#define SL52 14
+#define WL53 8
+#define SL53 15
+#define WL54 12
+#define SL54 9
+#define WL55 4
+#define SL55 8
+#define WL56 13
+#define SL56 9
+#define WL57 3
+#define SL57 14
+#define WL58 7
+#define SL58 5
+#define WL59 15
+#define SL59 6
+#define WL60 14
+#define SL60 8
+#define WL61 5
+#define SL61 6
+#define WL62 6
+#define SL62 5
+#define WL63 2
+#define SL63 12
+
+#define WL64 4
+#define SL64 9
+#define WL65 0
+#define SL65 15
+#define WL66 5
+#define SL66 5
+#define WL67 9
+#define SL67 11
+#define WL68 7
+#define SL68 6
+#define WL69 12
+#define SL69 8
+#define WL70 2
+#define SL70 13
+#define WL71 10
+#define SL71 12
+#define WL72 14
+#define SL72 5
+#define WL73 1
+#define SL73 12
+#define WL74 3
+#define SL74 13
+#define WL75 8
+#define SL75 14
+#define WL76 11
+#define SL76 11
+#define WL77 6
+#define SL77 8
+#define WL78 15
+#define SL78 5
+#define WL79 13
+#define SL79 6
+
+#define WR00 5
+#define SR00 8
+#define WR01 14
+#define SR01 9
+#define WR02 7
+#define SR02 9
+#define WR03 0
+#define SR03 11
+#define WR04 9
+#define SR04 13
+#define WR05 2
+#define SR05 15
+#define WR06 11
+#define SR06 15
+#define WR07 4
+#define SR07 5
+#define WR08 13
+#define SR08 7
+#define WR09 6
+#define SR09 7
+#define WR10 15
+#define SR10 8
+#define WR11 8
+#define SR11 11
+#define WR12 1
+#define SR12 14
+#define WR13 10
+#define SR13 14
+#define WR14 3
+#define SR14 12
+#define WR15 12
+#define SR15 6
+
+#define WR16 6
+#define SR16 9
+#define WR17 11
+#define SR17 13
+#define WR18 3
+#define SR18 15
+#define WR19 7
+#define SR19 7
+#define WR20 0
+#define SR20 12
+#define WR21 13
+#define SR21 8
+#define WR22 5
+#define SR22 9
+#define WR23 10
+#define SR23 11
+#define WR24 14
+#define SR24 7
+#define WR25 15
+#define SR25 7
+#define WR26 8
+#define SR26 12
+#define WR27 12
+#define SR27 7
+#define WR28 4
+#define SR28 6
+#define WR29 9
+#define SR29 15
+#define WR30 1
+#define SR30 13
+#define WR31 2
+#define SR31 11
+
+#define WR32 15
+#define SR32 9
+#define WR33 5
+#define SR33 7
+#define WR34 1
+#define SR34 15
+#define WR35 3
+#define SR35 11
+#define WR36 7
+#define SR36 8
+#define WR37 14
+#define SR37 6
+#define WR38 6
+#define SR38 6
+#define WR39 9
+#define SR39 14
+#define WR40 11
+#define SR40 12
+#define WR41 8
+#define SR41 13
+#define WR42 12
+#define SR42 5
+#define WR43 2
+#define SR43 14
+#define WR44 10
+#define SR44 13
+#define WR45 0
+#define SR45 13
+#define WR46 4
+#define SR46 7
+#define WR47 13
+#define SR47 5
+
+#define WR48 8
+#define SR48 15
+#define WR49 6
+#define SR49 5
+#define WR50 4
+#define SR50 8
+#define WR51 1
+#define SR51 11
+#define WR52 3
+#define SR52 14
+#define WR53 11
+#define SR53 14
+#define WR54 15
+#define SR54 6
+#define WR55 0
+#define SR55 14
+#define WR56 5
+#define SR56 6
+#define WR57 12
+#define SR57 9
+#define WR58 2
+#define SR58 12
+#define WR59 13
+#define SR59 9
+#define WR60 9
+#define SR60 12
+#define WR61 7
+#define SR61 5
+#define WR62 10
+#define SR62 15
+#define WR63 14
+#define SR63 8
+
+#define WR64 12
+#define SR64 8
+#define WR65 15
+#define SR65 5
+#define WR66 10
+#define SR66 12
+#define WR67 4
+#define SR67 9
+#define WR68 1
+#define SR68 12
+#define WR69 5
+#define SR69 5
+#define WR70 8
+#define SR70 14
+#define WR71 7
+#define SR71 6
+#define WR72 6
+#define SR72 8
+#define WR73 2
+#define SR73 13
+#define WR74 13
+#define SR74 6
+#define WR75 14
+#define SR75 5
+#define WR76 0
+#define SR76 15
+#define WR77 3
+#define SR77 13
+#define WR78 9
+#define SR78 11
+#define WR79 11
+#define SR79 11
+
+static void ripemd160_block_data_order(uint32_t h[5], const uint8_t *data,
size_t num) {
uint32_t A, B, C, D, E;
- uint32_t a, b, c, d, e, l;
+ uint32_t a, b, c, d, e;
uint32_t XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9, XX10, XX11, XX12,
XX13, XX14, XX15;
#define X(i) XX##i
@@ -86,52 +506,52 @@ static void ripemd160_block_data_order(uint32_t h[5], const uint8_t *data,
D = h[3];
E = h[4];
- HOST_c2l(data, l);
- X(0) = l;
- HOST_c2l(data, l);
- X(1) = l;
+ X(0) = CRYPTO_load_u32_le(data);
+ data += 4;
+ X(1) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(A, B, C, D, E, WL00, SL00);
- HOST_c2l(data, l);
- X(2) = l;
+ X(2) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(E, A, B, C, D, WL01, SL01);
- HOST_c2l(data, l);
- X(3) = l;
+ X(3) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(D, E, A, B, C, WL02, SL02);
- HOST_c2l(data, l);
- X(4) = l;
+ X(4) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(C, D, E, A, B, WL03, SL03);
- HOST_c2l(data, l);
- X(5) = l;
+ X(5) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(B, C, D, E, A, WL04, SL04);
- HOST_c2l(data, l);
- X(6) = l;
+ X(6) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(A, B, C, D, E, WL05, SL05);
- HOST_c2l(data, l);
- X(7) = l;
+ X(7) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(E, A, B, C, D, WL06, SL06);
- HOST_c2l(data, l);
- X(8) = l;
+ X(8) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(D, E, A, B, C, WL07, SL07);
- HOST_c2l(data, l);
- X(9) = l;
+ X(9) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(C, D, E, A, B, WL08, SL08);
- HOST_c2l(data, l);
- X(10) = l;
+ X(10) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(B, C, D, E, A, WL09, SL09);
- HOST_c2l(data, l);
- X(11) = l;
+ X(11) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(A, B, C, D, E, WL10, SL10);
- HOST_c2l(data, l);
- X(12) = l;
+ X(12) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(E, A, B, C, D, WL11, SL11);
- HOST_c2l(data, l);
- X(13) = l;
+ X(13) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(D, E, A, B, C, WL12, SL12);
- HOST_c2l(data, l);
- X(14) = l;
+ X(14) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(C, D, E, A, B, WL13, SL13);
- HOST_c2l(data, l);
- X(15) = l;
+ X(15) = CRYPTO_load_u32_le(data);
+ data += 4;
RIP1(B, C, D, E, A, WL14, SL14);
RIP1(A, B, C, D, E, WL15, SL15);
diff --git a/deps/boringssl/src/fuzz/CMakeLists.txt b/deps/boringssl/src/fuzz/CMakeLists.txt
index 98a959a..62652cb 100644
--- a/deps/boringssl/src/fuzz/CMakeLists.txt
+++ b/deps/boringssl/src/fuzz/CMakeLists.txt
@@ -29,3 +29,4 @@ fuzzer(dtls_server ssl)
fuzzer(dtls_client ssl)
fuzzer(ssl_ctx_api ssl)
fuzzer(session ssl)
+fuzzer(decode_client_hello_inner ssl)
diff --git a/deps/boringssl/src/fuzz/cert.cc b/deps/boringssl/src/fuzz/cert.cc
index 0bfcac4..79e1456 100644
--- a/deps/boringssl/src/fuzz/cert.cc
+++ b/deps/boringssl/src/fuzz/cert.cc
@@ -26,6 +26,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
uint8_t *der = NULL;
i2d_X509(x509, &der);
OPENSSL_free(der);
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ X509_print(bio, x509);
+ BIO_free(bio);
}
X509_free(x509);
ERR_clear_error();
diff --git a/deps/boringssl/src/fuzz/decode_client_hello_inner.cc b/deps/boringssl/src/fuzz/decode_client_hello_inner.cc
new file mode 100644
index 0000000..db090c5
--- /dev/null
+++ b/deps/boringssl/src/fuzz/decode_client_hello_inner.cc
@@ -0,0 +1,52 @@
+/* Copyright (c) 2021, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/bytestring.h>
+#include <openssl/ssl.h>
+#include <openssl/span.h>
+
+#include "../ssl/internal.h"
+
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
+ static bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ static bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
+
+ CBS reader(bssl::MakeConstSpan(buf, len));
+ CBS encoded_client_hello_inner_cbs;
+
+ if (!CBS_get_u24_length_prefixed(&reader, &encoded_client_hello_inner_cbs)) {
+ return 0;
+ }
+
+ bssl::Array<uint8_t> encoded_client_hello_inner;
+ if (!encoded_client_hello_inner.CopyFrom(encoded_client_hello_inner_cbs)) {
+ return 0;
+ }
+
+ // Use the remaining bytes in |reader| as the ClientHelloOuter.
+ SSL_CLIENT_HELLO client_hello_outer;
+ if (!bssl::ssl_client_hello_init(ssl.get(), &client_hello_outer, reader)) {
+ return 0;
+ }
+
+ // Recover the ClientHelloInner from the EncodedClientHelloInner and
+ // ClientHelloOuter.
+ uint8_t alert_unused;
+ bssl::Array<uint8_t> client_hello_inner;
+ bssl::ssl_decode_client_hello_inner(
+ ssl.get(), &alert_unused, &client_hello_inner, encoded_client_hello_inner,
+ &client_hello_outer);
+ return 0;
+}
diff --git a/deps/boringssl/src/fuzz/ssl_ctx_api.cc b/deps/boringssl/src/fuzz/ssl_ctx_api.cc
index abf2f16..da0a2d3 100644
--- a/deps/boringssl/src/fuzz/ssl_ctx_api.cc
+++ b/deps/boringssl/src/fuzz/ssl_ctx_api.cc
@@ -22,6 +22,7 @@
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#include <openssl/hpke.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
#include <openssl/stack.h>
@@ -491,6 +492,28 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
}
SSL_CTX_set1_sigalgs_list(ctx, sigalgs.c_str());
},
+ [](SSL_CTX *ctx, CBS *cbs) {
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ if (keys == nullptr) {
+ return;
+ }
+ uint8_t is_retry_config;
+ CBS ech_config, private_key;
+ if (!CBS_get_u8(cbs, &is_retry_config) ||
+ !CBS_get_u16_length_prefixed(cbs, &ech_config) ||
+ !CBS_get_u16_length_prefixed(cbs, &private_key)) {
+ return;
+ }
+ bssl::ScopedEVP_HPKE_KEY key;
+ if (!EVP_HPKE_KEY_init(key.get(), EVP_hpke_x25519_hkdf_sha256(),
+ CBS_data(&private_key), CBS_len(&private_key)) ||
+ !SSL_ECH_KEYS_add(keys.get(), is_retry_config,
+ CBS_data(&ech_config), CBS_len(&ech_config),
+ key.get()) ||
+ !SSL_CTX_set1_ech_keys(ctx, keys.get())) {
+ return;
+ }
+ },
};
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
diff --git a/deps/boringssl/src/include/openssl/aead.h b/deps/boringssl/src/include/openssl/aead.h
index 3bc74e7..38eb076 100644
--- a/deps/boringssl/src/include/openssl/aead.h
+++ b/deps/boringssl/src/include/openssl/aead.h
@@ -122,7 +122,7 @@ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_192_gcm(void);
OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm(void);
// EVP_aead_chacha20_poly1305 is the AEAD built from ChaCha20 and
-// Poly1305 as described in RFC 7539.
+// Poly1305 as described in RFC 8439.
OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305(void);
// EVP_aead_xchacha20_poly1305 is ChaCha20-Poly1305 with an extended nonce that
@@ -397,12 +397,9 @@ OPENSSL_EXPORT const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx);
OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void);
OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(void);
-OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha256_tls(void);
OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls(void);
OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(void);
-OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha256_tls(void);
-OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha384_tls(void);
OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls(void);
OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(void);
diff --git a/deps/boringssl/src/include/openssl/arm_arch.h b/deps/boringssl/src/include/openssl/arm_arch.h
index 31ff8a6..81dc796 100644
--- a/deps/boringssl/src/include/openssl/arm_arch.h
+++ b/deps/boringssl/src/include/openssl/arm_arch.h
@@ -124,7 +124,72 @@
// - Armv8.5-A Branch Target Identification
// features which require emitting a .note.gnu.property section with the
// appropriate architecture-dependent feature bits set.
-// Read more: "ELF for the Arm® 64-bit Architecture"
+//
+// |AARCH64_SIGN_LINK_REGISTER| and |AARCH64_VALIDATE_LINK_REGISTER| expand to
+// PACIxSP and AUTIxSP, respectively. |AARCH64_SIGN_LINK_REGISTER| should be
+// used immediately before saving the LR register (x30) to the stack.
+// |AARCH64_VALIDATE_LINK_REGISTER| should be used immediately after restoring
+// it. Note |AARCH64_SIGN_LINK_REGISTER|'s modifications to LR must be undone
+// with |AARCH64_VALIDATE_LINK_REGISTER| before RET. The SP register must also
+// have the same value at the two points. For example:
+//
+// .global f
+// f:
+// AARCH64_SIGN_LINK_REGISTER
+// stp x29, x30, [sp, #-96]!
+// mov x29, sp
+// ...
+// ldp x29, x30, [sp], #96
+// AARCH64_VALIDATE_LINK_REGISTER
+// ret
+//
+// |AARCH64_VALID_CALL_TARGET| expands to BTI 'c'. Either it, or
+// |AARCH64_SIGN_LINK_REGISTER|, must be used at every point that may be an
+// indirect call target. In particular, all symbols exported from a file must
+// begin with one of these macros. For example, a leaf function that does not
+// save LR can instead use |AARCH64_VALID_CALL_TARGET|:
+//
+// .globl return_zero
+// return_zero:
+// AARCH64_VALID_CALL_TARGET
+// mov x0, #0
+// ret
+//
+// A non-leaf function which does not immediately save LR may need both macros
+// because |AARCH64_SIGN_LINK_REGISTER| appears late. For example, the function
+// may jump to an alternate implementation before setting up the stack:
+//
+// .globl with_early_jump
+// with_early_jump:
+// AARCH64_VALID_CALL_TARGET
+// cmp x0, #128
+// b.lt .Lwith_early_jump_128
+// AARCH64_SIGN_LINK_REGISTER
+// stp x29, x30, [sp, #-96]!
+// mov x29, sp
+// ...
+// ldp x29, x30, [sp], #96
+// AARCH64_VALIDATE_LINK_REGISTER
+// ret
+//
+// .Lwith_early_jump_128:
+// ...
+// ret
+//
+// These annotations are only required with indirect calls. Private symbols that
+// are only the target of direct calls do not require annotations. Also note
+// that |AARCH64_VALID_CALL_TARGET| is only valid for indirect calls (BLR), not
+// indirect jumps (BR). Indirect jumps in assembly are currently not supported
+// and would require a macro for BTI 'j'.
+//
+// Although not necessary, it is safe to use these macros in 32-bit ARM
+// assembly. This may be used to simplify dual 32-bit and 64-bit files.
+//
+// References:
+// - "ELF for the Arm® 64-bit Architecture"
+// https://github.com/ARM-software/abi-aa/blob/master/aaelf64/aaelf64.rst
+// - "Providing protection for complex software"
+// https://developer.arm.com/architectures/learn-the-architecture/providing-protection-for-complex-software
#if defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1
#define GNU_PROPERTY_AARCH64_BTI (1 << 0) // Has Branch Target Identification
diff --git a/deps/boringssl/src/include/openssl/asn1.h b/deps/boringssl/src/include/openssl/asn1.h
index 9269553..4f6fb3b 100644
--- a/deps/boringssl/src/include/openssl/asn1.h
+++ b/deps/boringssl/src/include/openssl/asn1.h
@@ -103,7 +103,7 @@ extern "C" {
#define V_ASN1_PRIMITIVE_TAG 0x1f
// V_ASN1_MAX_UNIVERSAL is the highest supported universal tag number. It is
-// necessary to avoid ambiguity with |V_ASN1_NEG|.
+// necessary to avoid ambiguity with |V_ASN1_NEG| and |MBSTRING_FLAG|.
//
// TODO(davidben): Make this private.
#define V_ASN1_MAX_UNIVERSAL 0xff
@@ -111,10 +111,6 @@ extern "C" {
// V_ASN1_UNDEF is used in some APIs to indicate an ASN.1 element is omitted.
#define V_ASN1_UNDEF (-1)
-// V_ASN1_APP_CHOOSE is used in some APIs to specify a default ASN.1 type based
-// on the context.
-#define V_ASN1_APP_CHOOSE (-2)
-
// V_ASN1_OTHER is used in |ASN1_TYPE| to indicate a non-universal ASN.1 type.
#define V_ASN1_OTHER (-3)
@@ -157,6 +153,31 @@ extern "C" {
#define V_ASN1_NEG_INTEGER (V_ASN1_INTEGER | V_ASN1_NEG)
#define V_ASN1_NEG_ENUMERATED (V_ASN1_ENUMERATED | V_ASN1_NEG)
+// The following constants are bitmask representations of ASN.1 types.
+#define B_ASN1_NUMERICSTRING 0x0001
+#define B_ASN1_PRINTABLESTRING 0x0002
+#define B_ASN1_T61STRING 0x0004
+#define B_ASN1_TELETEXSTRING 0x0004
+#define B_ASN1_VIDEOTEXSTRING 0x0008
+#define B_ASN1_IA5STRING 0x0010
+#define B_ASN1_GRAPHICSTRING 0x0020
+#define B_ASN1_ISO64STRING 0x0040
+#define B_ASN1_VISIBLESTRING 0x0040
+#define B_ASN1_GENERALSTRING 0x0080
+#define B_ASN1_UNIVERSALSTRING 0x0100
+#define B_ASN1_OCTET_STRING 0x0200
+#define B_ASN1_BIT_STRING 0x0400
+#define B_ASN1_BMPSTRING 0x0800
+#define B_ASN1_UNKNOWN 0x1000
+#define B_ASN1_UTF8STRING 0x2000
+#define B_ASN1_UTCTIME 0x4000
+#define B_ASN1_GENERALIZEDTIME 0x8000
+#define B_ASN1_SEQUENCE 0x10000
+
+// ASN1_tag2str returns a string representation of |tag|, interpret as a tag
+// number for a universal type, or |V_ASN1_NEG_*|.
+OPENSSL_EXPORT const char *ASN1_tag2str(int tag);
+
// Strings.
//
@@ -177,29 +198,19 @@ extern "C" {
// string.
//
// When representing a BIT STRING value, the type field is |V_ASN1_BIT_STRING|.
-// The data contains the encoded form of the BIT STRING, including any padding
-// bits added to round to a whole number of bytes, but excluding the leading
-// byte containing the number of padding bits. The number of padding bits is
-// encoded in the flags field. See |ASN1_STRING_FLAG_BITS_LEFT| for details. For
-// example, DER encodes the BIT STRING {1, 0} as {0x06, 0x80 = 0b10_000000}. The
-// |ASN1_STRING| representation has data of {0x80} and flags of
-// ASN1_STRING_FLAG_BITS_LEFT | 6.
-//
-// When representing an INTEGER or ENUMERATED value, the data contains the
-// big-endian encoding of the absolute value of the integer. The sign bit is
-// encoded in the type: non-negative values have a type of |V_ASN1_INTEGER| or
-// |V_ASN1_ENUMERATED|, while negative values have a type of
-// |V_ASN1_NEG_INTEGER| or |V_ASN1_NEG_ENUMERATED|. Note this differs from DER's
-// two's complement representation.
+// See bit string documentation below for how the data and flags are used.
+//
+// When representing an INTEGER or ENUMERATED value, the type field is one of
+// |V_ASN1_INTEGER|, |V_ASN1_NEG_INTEGER|, |V_ASN1_ENUMERATED|, or
+// |V_ASN1_NEG_ENUMERATED|. See integer documentation below for details.
//
// When representing a GeneralizedTime or UTCTime value, the type field is
// |V_ASN1_GENERALIZEDTIME| or |V_ASN1_UTCTIME|, respectively. The data contains
// the DER encoding of the value. For example, the UNIX epoch would be
// "19700101000000Z" for a GeneralizedTime and "700101000000Z" for a UTCTime.
//
-// TODO(davidben): |ASN1_TYPE| additionally uses |ASN1_STRING| to represent
-// various other odd cases. It also likes to assume unknown universal tags are
-// string types. Make a note here when documenting |ASN1_TYPE|.
+// |ASN1_STRING|, when stored in an |ASN1_TYPE|, may also represent an element
+// with tag not directly supported by this library. See |ASN1_TYPE| for details.
//
// |ASN1_STRING| additionally has the following typedefs: |ASN1_BIT_STRING|,
// |ASN1_BMPSTRING|, |ASN1_ENUMERATED|, |ASN1_GENERALIZEDTIME|,
@@ -242,14 +253,6 @@ struct asn1_string_st {
// treated as padding. This behavior is deprecated and should not be used.
#define ASN1_STRING_FLAG_BITS_LEFT 0x08
-// ASN1_STRING_FLAG_MSTRING indicates that the |ASN1_STRING| is an MSTRING type,
-// which is how this library refers to a CHOICE type of several string types.
-// For example, DirectoryString as defined in RFC5280.
-//
-// TODO(davidben): This is only used in one place within the library and is easy
-// to accidentally drop. Can it be removed?
-#define ASN1_STRING_FLAG_MSTRING 0x040
-
// ASN1_STRING_type_new returns a newly-allocated empty |ASN1_STRING| object of
// type |type|, or NULL on error.
OPENSSL_EXPORT ASN1_STRING *ASN1_STRING_type_new(int type);
@@ -291,11 +294,16 @@ OPENSSL_EXPORT int ASN1_STRING_length(const ASN1_STRING *str);
// ASN1_STRING_cmp compares |a| and |b|'s type and contents. It returns an
// integer equal to, less than, or greater than zero if |a| is equal to, less
-// than, or greater than |b|, respectively. The comparison is suitable for
-// sorting, but callers should not rely on the particular comparison.
+// than, or greater than |b|, respectively. This function compares by length,
+// then data, then type. Note the data compared is the |ASN1_STRING| internal
+// representation and the type order is arbitrary. While this comparison is
+// suitable for sorting, callers should not rely on the exact order when |a|
+// and |b| are different types.
//
-// Note if |a| or |b| are BIT STRINGs, this function does not compare the
-// |ASN1_STRING_FLAG_BITS_LEFT| flags.
+// If |a| or |b| are BIT STRINGs, this function does not compare the
+// |ASN1_STRING_FLAG_BITS_LEFT| flags. Additionally, if |a| and |b| are
+// INTEGERs, this comparison does not order the values numerically. For a
+// numerical comparison, use |ASN1_INTEGER_cmp|.
//
// TODO(davidben): The BIT STRING comparison seems like a bug. Fix it?
OPENSSL_EXPORT int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b);
@@ -309,61 +317,532 @@ OPENSSL_EXPORT int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len);
// |OPENSSL_malloc|.
OPENSSL_EXPORT void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len);
-// TODO(davidben): Pull up and document functions specific to individual string
-// types.
-
-
-// Underdocumented functions.
-//
-// The following functions are not yet documented and organized.
-
-// For use with d2i_ASN1_type_bytes()
-#define B_ASN1_NUMERICSTRING 0x0001
-#define B_ASN1_PRINTABLESTRING 0x0002
-#define B_ASN1_T61STRING 0x0004
-#define B_ASN1_TELETEXSTRING 0x0004
-#define B_ASN1_VIDEOTEXSTRING 0x0008
-#define B_ASN1_IA5STRING 0x0010
-#define B_ASN1_GRAPHICSTRING 0x0020
-#define B_ASN1_ISO64STRING 0x0040
-#define B_ASN1_VISIBLESTRING 0x0040
-#define B_ASN1_GENERALSTRING 0x0080
-#define B_ASN1_UNIVERSALSTRING 0x0100
-#define B_ASN1_OCTET_STRING 0x0200
-#define B_ASN1_BIT_STRING 0x0400
-#define B_ASN1_BMPSTRING 0x0800
-#define B_ASN1_UNKNOWN 0x1000
-#define B_ASN1_UTF8STRING 0x2000
-#define B_ASN1_UTCTIME 0x4000
-#define B_ASN1_GENERALIZEDTIME 0x8000
-#define B_ASN1_SEQUENCE 0x10000
+// ASN1_STRING_to_UTF8 converts |in| to UTF-8. On success, sets |*out| to a
+// newly-allocated buffer containing the resulting string and returns the length
+// of the string. The caller must call |OPENSSL_free| to release |*out| when
+// done. On error, it returns a negative number.
+OPENSSL_EXPORT int ASN1_STRING_to_UTF8(unsigned char **out,
+ const ASN1_STRING *in);
-// For use with ASN1_mbstring_copy()
+// The following formats define encodings for use with functions like
+// |ASN1_mbstring_copy|.
#define MBSTRING_FLAG 0x1000
#define MBSTRING_UTF8 (MBSTRING_FLAG)
-// |MBSTRING_ASC| refers to Latin-1, not ASCII. It is used with TeletexString
-// which, in turn, is treated as Latin-1 rather than T.61 by OpenSSL and most
-// other software.
+// |MBSTRING_ASC| refers to Latin-1, not ASCII.
#define MBSTRING_ASC (MBSTRING_FLAG | 1)
#define MBSTRING_BMP (MBSTRING_FLAG | 2)
#define MBSTRING_UNIV (MBSTRING_FLAG | 4)
-#define DECLARE_ASN1_SET_OF(type) // filled in by mkstack.pl
-#define IMPLEMENT_ASN1_SET_OF(type) // nothing, no longer needed
+// DIRSTRING_TYPE contains the valid string types in an X.509 DirectoryString.
+#define DIRSTRING_TYPE \
+ (B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_BMPSTRING | \
+ B_ASN1_UTF8STRING)
+
+// PKCS9STRING_TYPE contains the valid string types in a PKCS9String.
+#define PKCS9STRING_TYPE (DIRSTRING_TYPE | B_ASN1_IA5STRING)
-// These are used internally in the ASN1_OBJECT to keep track of
-// whether the names and data need to be free()ed
-#define ASN1_OBJECT_FLAG_DYNAMIC 0x01 // internal use
-#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 // internal use
-#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08 // internal use
-struct asn1_object_st {
- const char *sn, *ln;
- int nid;
- int length;
- const unsigned char *data; // data remains const after init
- int flags; // Should we free this one
+// ASN1_mbstring_copy converts |len| bytes from |in| to an ASN.1 string. If
+// |len| is -1, |in| must be NUL-terminated and the length is determined by
+// |strlen|. |in| is decoded according to |inform|, which must be one of
+// |MBSTRING_*|. |mask| determines the set of valid output types and is a
+// bitmask containing a subset of |B_ASN1_PRINTABLESTRING|, |B_ASN1_IA5STRING|,
+// |B_ASN1_T61STRING|, |B_ASN1_BMPSTRING|, |B_ASN1_UNIVERSALSTRING|, and
+// |B_ASN1_UTF8STRING|, in that preference order. This function chooses the
+// first output type in |mask| which can represent |in|. It interprets T61String
+// as Latin-1, rather than T.61.
+//
+// If |mask| is zero, |DIRSTRING_TYPE| is used by default.
+//
+// On success, this function returns the |V_ASN1_*| constant corresponding to
+// the selected output type and, if |out| and |*out| are both non-NULL, updates
+// the object at |*out| with the result. If |out| is non-NULL and |*out| is
+// NULL, it instead sets |*out| to a newly-allocated |ASN1_STRING| containing
+// the result. If |out| is NULL, it returns the selected output type without
+// constructing an |ASN1_STRING|. On error, this function returns -1.
+OPENSSL_EXPORT int ASN1_mbstring_copy(ASN1_STRING **out, const uint8_t *in,
+ int len, int inform, unsigned long mask);
+
+// ASN1_mbstring_ncopy behaves like |ASN1_mbstring_copy| but returns an error if
+// the input is less than |minsize| or greater than |maxsize| codepoints long. A
+// |maxsize| value of zero is ignored. Note the sizes are measured in
+// codepoints, not output bytes.
+OPENSSL_EXPORT int ASN1_mbstring_ncopy(ASN1_STRING **out, const uint8_t *in,
+ int len, int inform, unsigned long mask,
+ long minsize, long maxsize);
+
+// TODO(davidben): Expand and document function prototypes generated in macros.
+
+
+// Bit strings.
+//
+// An ASN.1 BIT STRING type represents a string of bits. The string may not
+// necessarily be a whole number of bytes. BIT STRINGs occur in ASN.1 structures
+// in several forms:
+//
+// Some BIT STRINGs represent a bitmask of named bits, such as the X.509 key
+// usage extension in RFC 5280, section 4.2.1.3. For such bit strings, DER
+// imposes an additional restriction that trailing zero bits are removed. Some
+// functions like |ASN1_BIT_STRING_set_bit| help in maintaining this.
+//
+// Other BIT STRINGs are arbitrary strings of bits used as identifiers and do
+// not have this constraint, such as the X.509 issuerUniqueID field.
+//
+// Finally, some structures use BIT STRINGs as a container for byte strings. For
+// example, the signatureValue field in X.509 and the subjectPublicKey field in
+// SubjectPublicKeyInfo are defined as BIT STRINGs with a value specific to the
+// AlgorithmIdentifier. While some unknown algorithm could choose to store
+// arbitrary bit strings, all supported algorithms use a byte string, with bit
+// order matching the DER encoding. Callers interpreting a BIT STRING as a byte
+// string should use |ASN1_BIT_STRING_num_bytes| instead of |ASN1_STRING_length|
+// and reject bit strings that are not a whole number of bytes.
+//
+// This library represents BIT STRINGs as |ASN1_STRING|s with type
+// |V_ASN1_BIT_STRING|. The data contains the encoded form of the BIT STRING,
+// including any padding bits added to round to a whole number of bytes, but
+// excluding the leading byte containing the number of padding bits. If
+// |ASN1_STRING_FLAG_BITS_LEFT| is set, the bottom three bits contains the
+// number of padding bits. For example, DER encodes the BIT STRING {1, 0} as
+// {0x06, 0x80 = 0b10_000000}. The |ASN1_STRING| representation has data of
+// {0x80} and flags of ASN1_STRING_FLAG_BITS_LEFT | 6. If
+// |ASN1_STRING_FLAG_BITS_LEFT| is unset, trailing zero bits are implicitly
+// removed. Callers should not rely this representation when constructing bit
+// strings.
+
+// ASN1_BIT_STRING_num_bytes computes the length of |str| in bytes. If |str|'s
+// bit length is a multiple of 8, it sets |*out| to the byte length and returns
+// one. Otherwise, it returns zero.
+//
+// This function may be used with |ASN1_STRING_get0_data| to interpret |str| as
+// a byte string.
+OPENSSL_EXPORT int ASN1_BIT_STRING_num_bytes(const ASN1_BIT_STRING *str,
+ size_t *out);
+
+// ASN1_BIT_STRING_set calls |ASN1_STRING_set|. It leaves flags unchanged, so
+// the caller must set the number of unused bits.
+//
+// TODO(davidben): Maybe it should? Wrapping a byte string in a bit string is a
+// common use case.
+OPENSSL_EXPORT int ASN1_BIT_STRING_set(ASN1_BIT_STRING *str,
+ const unsigned char *d, int length);
+
+// ASN1_BIT_STRING_set_bit sets bit |n| of |str| to one if |value| is non-zero
+// and zero if |value| is zero, resizing |str| as needed. It then truncates
+// trailing zeros in |str| to align with the DER represention for a bit string
+// with named bits. It returns one on success and zero on error. |n| is indexed
+// beginning from zero.
+OPENSSL_EXPORT int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *str, int n,
+ int value);
+
+// ASN1_BIT_STRING_get_bit returns one if bit |n| of |a| is in bounds and set,
+// and zero otherwise. |n| is indexed beginning from zero.
+OPENSSL_EXPORT int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *str, int n);
+
+// ASN1_BIT_STRING_check returns one if |str| only contains bits that are set in
+// the |flags_len| bytes pointed by |flags|. Otherwise it returns zero. Bits in
+// |flags| are arranged according to the DER representation, so bit 0
+// corresponds to the MSB of |flags[0]|.
+OPENSSL_EXPORT int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *str,
+ const unsigned char *flags,
+ int flags_len);
+
+// TODO(davidben): Expand and document function prototypes generated in macros.
+
+
+// Integers and enumerated values.
+//
+// INTEGER and ENUMERATED values are represented as |ASN1_STRING|s where the
+// data contains the big-endian encoding of the absolute value of the integer.
+// The sign bit is encoded in the type: non-negative values have a type of
+// |V_ASN1_INTEGER| or |V_ASN1_ENUMERATED|, while negative values have a type of
+// |V_ASN1_NEG_INTEGER| or |V_ASN1_NEG_ENUMERATED|. Note this differs from DER's
+// two's complement representation.
+
+// ASN1_INTEGER_set sets |a| to an INTEGER with value |v|. It returns one on
+// success and zero on error.
+OPENSSL_EXPORT int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
+
+// ASN1_INTEGER_set sets |a| to an INTEGER with value |v|. It returns one on
+// success and zero on error.
+OPENSSL_EXPORT int ASN1_INTEGER_set_uint64(ASN1_INTEGER *out, uint64_t v);
+
+// ASN1_INTEGER_get returns the value of |a| as a |long|, or -1 if |a| is out of
+// range or the wrong type.
+OPENSSL_EXPORT long ASN1_INTEGER_get(const ASN1_INTEGER *a);
+
+// BN_to_ASN1_INTEGER sets |ai| to an INTEGER with value |bn| and returns |ai|
+// on success or NULL or error. If |ai| is NULL, it returns a newly-allocated
+// |ASN1_INTEGER| on success instead, which the caller must release with
+// |ASN1_INTEGER_free|.
+OPENSSL_EXPORT ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn,
+ ASN1_INTEGER *ai);
+
+// ASN1_INTEGER_to_BN sets |bn| to the value of |ai| and returns |bn| on success
+// or NULL or error. If |bn| is NULL, it returns a newly-allocated |BIGNUM| on
+// success instead, which the caller must release with |BN_free|.
+OPENSSL_EXPORT BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn);
+
+// ASN1_INTEGER_cmp compares the values of |x| and |y|. It returns an integer
+// equal to, less than, or greater than zero if |x| is equal to, less than, or
+// greater than |y|, respectively.
+OPENSSL_EXPORT int ASN1_INTEGER_cmp(const ASN1_INTEGER *x,
+ const ASN1_INTEGER *y);
+
+// ASN1_ENUMERATED_set sets |a| to an ENUMERATED with value |v|. It returns one
+// on success and zero on error.
+OPENSSL_EXPORT int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v);
+
+// ASN1_INTEGER_get returns the value of |a| as a |long|, or -1 if |a| is out of
+// range or the wrong type.
+OPENSSL_EXPORT long ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a);
+
+// BN_to_ASN1_ENUMERATED sets |ai| to an ENUMERATED with value |bn| and returns
+// |ai| on success or NULL or error. If |ai| is NULL, it returns a
+// newly-allocated |ASN1_INTEGER| on success instead, which the caller must
+// release with |ASN1_INTEGER_free|.
+OPENSSL_EXPORT ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(const BIGNUM *bn,
+ ASN1_ENUMERATED *ai);
+
+// ASN1_ENUMERATED_to_BN sets |bn| to the value of |ai| and returns |bn| on
+// success or NULL or error. If |bn| is NULL, it returns a newly-allocated
+// |BIGNUM| on success instead, which the caller must release with |BN_free|.
+OPENSSL_EXPORT BIGNUM *ASN1_ENUMERATED_to_BN(const ASN1_ENUMERATED *ai,
+ BIGNUM *bn);
+
+// TODO(davidben): Expand and document function prototypes generated in macros.
+
+
+// Time.
+//
+// GeneralizedTime and UTCTime values are represented as |ASN1_STRING|s. The
+// type field is |V_ASN1_GENERALIZEDTIME| or |V_ASN1_UTCTIME|, respectively. The
+// data field contains the DER encoding of the value. For example, the UNIX
+// epoch would be "19700101000000Z" for a GeneralizedTime and "700101000000Z"
+// for a UTCTime.
+//
+// ASN.1 does not define how to interpret UTCTime's two-digit year. RFC 5280
+// defines it as a range from 1950 to 2049 for X.509. The library uses the
+// RFC 5280 interpretation. It does not currently enforce the restrictions from
+// BER, and the additional restrictions from RFC 5280, but future versions may.
+// Callers should not rely on fractional seconds and non-UTC time zones.
+//
+// The |ASN1_TIME| typedef represents the X.509 Time type, which is a CHOICE of
+// GeneralizedTime and UTCTime, using UTCTime when the value is in range.
+
+// ASN1_UTCTIME_check returns one if |a| is a valid UTCTime and zero otherwise.
+OPENSSL_EXPORT int ASN1_UTCTIME_check(const ASN1_UTCTIME *a);
+
+// ASN1_UTCTIME_set represents |t| as a UTCTime and writes the result to |s|. It
+// returns |s| on success and NULL on error. If |s| is NULL, it returns a
+// newly-allocated |ASN1_UTCTIME| instead.
+//
+// Note this function may fail if the time is out of range for UTCTime.
+OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t);
+
+// ASN1_UTCTIME_adj adds |offset_day| days and |offset_sec| seconds to |t| and
+// writes the result to |s| as a UTCTime. It returns |s| on success and NULL on
+// error. If |s| is NULL, it returns a newly-allocated |ASN1_UTCTIME| instead.
+//
+// Note this function may fail if the time overflows or is out of range for
+// UTCTime.
+OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
+ int offset_day, long offset_sec);
+
+// ASN1_UTCTIME_set_string sets |s| to a UTCTime whose contents are a copy of
+// |str|. It returns one on success and zero on error or if |str| is not a valid
+// UTCTime.
+//
+// If |s| is NULL, this function validates |str| without copying it.
+OPENSSL_EXPORT int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str);
+
+// ASN1_UTCTIME_cmp_time_t compares |s| to |t|. It returns -1 if |s| < |t|, 0 if
+// they are equal, 1 if |s| > |t|, and -2 on error.
+OPENSSL_EXPORT int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t);
+
+// ASN1_GENERALIZEDTIME_check returns one if |a| is a valid GeneralizedTime and
+// zero otherwise.
+OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *a);
+
+// ASN1_GENERALIZEDTIME_set represents |t| as a GeneralizedTime and writes the
+// result to |s|. It returns |s| on success and NULL on error. If |s| is NULL,
+// it returns a newly-allocated |ASN1_GENERALIZEDTIME| instead.
+//
+// Note this function may fail if the time is out of range for GeneralizedTime.
+OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(
+ ASN1_GENERALIZEDTIME *s, time_t t);
+
+// ASN1_GENERALIZEDTIME_adj adds |offset_day| days and |offset_sec| seconds to
+// |t| and writes the result to |s| as a GeneralizedTime. It returns |s| on
+// success and NULL on error. If |s| is NULL, it returns a newly-allocated
+// |ASN1_GENERALIZEDTIME| instead.
+//
+// Note this function may fail if the time overflows or is out of range for
+// GeneralizedTime.
+OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(
+ ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, long offset_sec);
+
+// ASN1_GENERALIZEDTIME_set_string sets |s| to a GeneralizedTime whose contents
+// are a copy of |str|. It returns one on success and zero on error or if |str|
+// is not a valid GeneralizedTime.
+//
+// If |s| is NULL, this function validates |str| without copying it.
+OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s,
+ const char *str);
+
+// ASN1_TIME_diff computes |to| - |from|. On success, it sets |*out_days| to the
+// difference in days, rounded towards zero, sets |*out_seconds| to the
+// remainder, and returns one. On error, it returns zero.
+//
+// If |from| is before |to|, both outputs will be <= 0, with at least one
+// negative. If |from| is after |to|, both will be >= 0, with at least one
+// positive. If they are equal, ignoring fractional seconds, both will be zero.
+//
+// Note this function may fail on overflow, or if |from| or |to| cannot be
+// decoded.
+OPENSSL_EXPORT int ASN1_TIME_diff(int *out_days, int *out_seconds,
+ const ASN1_TIME *from, const ASN1_TIME *to);
+
+// ASN1_TIME_set represents |t| as a GeneralizedTime or UTCTime and writes
+// the result to |s|. As in RFC 5280, section 4.1.2.5, it uses UTCTime when the
+// time fits and GeneralizedTime otherwise. It returns |s| on success and NULL
+// on error. If |s| is NULL, it returns a newly-allocated |ASN1_TIME| instead.
+//
+// Note this function may fail if the time is out of range for GeneralizedTime.
+OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t);
+
+// ASN1_TIME_adj adds |offset_day| days and |offset_sec| seconds to
+// |t| and writes the result to |s|. As in RFC 5280, section 4.1.2.5, it uses
+// UTCTime when the time fits and GeneralizedTime otherwise. It returns |s| on
+// success and NULL on error. If |s| is NULL, it returns a newly-allocated
+// |ASN1_GENERALIZEDTIME| instead.
+//
+// Note this function may fail if the time overflows or is out of range for
+// GeneralizedTime.
+OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day,
+ long offset_sec);
+
+// ASN1_TIME_check returns one if |t| is a valid UTCTime or GeneralizedTime, and
+// zero otherwise. |t|'s type determines which check is performed. This
+// function does not enforce that UTCTime was used when possible.
+OPENSSL_EXPORT int ASN1_TIME_check(const ASN1_TIME *t);
+
+// ASN1_TIME_to_generalizedtime converts |t| to a GeneralizedTime. If |out| is
+// NULL, it returns a newly-allocated |ASN1_GENERALIZEDTIME| on success, or NULL
+// on error. If |out| is non-NULL and |*out| is NULL, it additionally sets
+// |*out| to the result. If |out| and |*out| are non-NULL, it instead updates
+// the object pointed by |*out| and returns |*out| on success or NULL on error.
+OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(
+ const ASN1_TIME *t, ASN1_GENERALIZEDTIME **out);
+
+// ASN1_TIME_set_string behaves like |ASN1_UTCTIME_set_string| if |str| is a
+// valid UTCTime, and |ASN1_GENERALIZEDTIME_set_string| if |str| is a valid
+// GeneralizedTime. If |str| is neither, it returns zero.
+OPENSSL_EXPORT int ASN1_TIME_set_string(ASN1_TIME *s, const char *str);
+
+// TODO(davidben): Expand and document function prototypes generated in macros.
+
+
+// Arbitrary elements.
+
+// ASN1_VALUE_st (aka |ASN1_VALUE|) is an opaque type used internally in the
+// library.
+typedef struct ASN1_VALUE_st ASN1_VALUE;
+
+// An asn1_type_st (aka |ASN1_TYPE|) represents an arbitrary ASN.1 element,
+// typically used used for ANY types. It contains a |type| field and a |value|
+// union dependent on |type|.
+//
+// WARNING: This struct has a complex representation. Callers must not construct
+// |ASN1_TYPE| values manually. Use |ASN1_TYPE_set| and |ASN1_TYPE_set1|
+// instead. Additionally, callers performing non-trivial operations on this type
+// are encouraged to use |CBS| and |CBB| from <openssl/bytestring.h>, and
+// convert to or from |ASN1_TYPE| with |d2i_ASN1_TYPE| or |i2d_ASN1_TYPE|.
+//
+// The |type| field corresponds to the tag of the ASN.1 element being
+// represented:
+//
+// If |type| is a |V_ASN1_*| constant for an ASN.1 string-like type, as defined
+// by |ASN1_STRING|, the tag matches the constant. |value| contains an
+// |ASN1_STRING| pointer (equivalently, one of the more specific typedefs). See
+// |ASN1_STRING| for details on the representation. Unlike |ASN1_STRING|,
+// |ASN1_TYPE| does not use the |V_ASN1_NEG| flag for negative INTEGER and
+// ENUMERATE values. For a negative value, the |ASN1_TYPE|'s |type| will be
+// |V_ASN1_INTEGER| or |V_ASN1_ENUMERATED|, but |value| will an |ASN1_STRING|
+// whose |type| is |V_ASN1_NEG_INTEGER| or |V_ASN1_NEG_ENUMERATED|.
+//
+// If |type| is |V_ASN1_OBJECT|, the tag is OBJECT IDENTIFIER and |value|
+// contains an |ASN1_OBJECT| pointer.
+//
+// If |type| is |V_ASN1_NULL|, the tag is NULL. |value| contains a NULL pointer.
+//
+// If |type| is |V_ASN1_BOOLEAN|, the tag is BOOLEAN. |value| contains an
+// |ASN1_BOOLEAN|.
+//
+// If |type| is |V_ASN1_SEQUENCE|, |V_ASN1_SET|, or |V_ASN1_OTHER|, the tag is
+// SEQUENCE, SET, or some non-universal tag, respectively. |value| is an
+// |ASN1_STRING| containing the entire element, including the tag and length.
+// The |ASN1_STRING|'s |type| field matches the containing |ASN1_TYPE|'s |type|.
+//
+// Other positive values of |type|, up to |V_ASN1_MAX_UNIVERSAL|, correspond to
+// universal primitive tags not directly supported by this library. |value| is
+// an |ASN1_STRING| containing the body of the element, excluding the tag
+// and length. The |ASN1_STRING|'s |type| field matches the containing
+// |ASN1_TYPE|'s |type|.
+struct asn1_type_st {
+ int type;
+ union {
+ char *ptr;
+ ASN1_BOOLEAN boolean;
+ ASN1_STRING *asn1_string;
+ ASN1_OBJECT *object;
+ ASN1_INTEGER *integer;
+ ASN1_ENUMERATED *enumerated;
+ ASN1_BIT_STRING *bit_string;
+ ASN1_OCTET_STRING *octet_string;
+ ASN1_PRINTABLESTRING *printablestring;
+ ASN1_T61STRING *t61string;
+ ASN1_IA5STRING *ia5string;
+ ASN1_GENERALSTRING *generalstring;
+ ASN1_BMPSTRING *bmpstring;
+ ASN1_UNIVERSALSTRING *universalstring;
+ ASN1_UTCTIME *utctime;
+ ASN1_GENERALIZEDTIME *generalizedtime;
+ ASN1_VISIBLESTRING *visiblestring;
+ ASN1_UTF8STRING *utf8string;
+ // set and sequence are left complete and still contain the entire element.
+ ASN1_STRING *set;
+ ASN1_STRING *sequence;
+ ASN1_VALUE *asn1_value;
+ } value;
};
+// ASN1_TYPE_get returns the type of |a|, which will be one of the |V_ASN1_*|
+// constants, or zero if |a| is not fully initialized.
+OPENSSL_EXPORT int ASN1_TYPE_get(const ASN1_TYPE *a);
+
+// ASN1_TYPE_set sets |a| to an |ASN1_TYPE| of type |type| and value |value|,
+// releasing the previous contents of |a|.
+//
+// If |type| is |V_ASN1_BOOLEAN|, |a| is set to FALSE if |value| is NULL and
+// TRUE otherwise. If setting |a| to TRUE, |value| may be an invalid pointer,
+// such as (void*)1.
+//
+// If |type| is |V_ASN1_NULL|, |value| must be NULL.
+//
+// For other values of |type|, this function takes ownership of |value|, which
+// must point to an object of the corresponding type. See |ASN1_TYPE| for
+// details.
+OPENSSL_EXPORT void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value);
+
+// ASN1_TYPE_set1 behaves like |ASN1_TYPE_set| except it does not take ownership
+// of |value|. It returns one on success and zero on error.
+OPENSSL_EXPORT int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value);
+
+// ASN1_TYPE_cmp returns zero if |a| and |b| are equal and some non-zero value
+// otherwise. Note this function can only be used for equality checks, not an
+// ordering.
+OPENSSL_EXPORT int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b);
+
+// TODO(davidben): Most of |ASN1_TYPE|'s APIs are hidden behind macros. Expand
+// the macros, document them, and move them to this section.
+
+
+// Human-readable output.
+//
+// The following functions output types in some human-readable format. These
+// functions may be used for debugging and logging. However, the output should
+// not be consumed programmatically. They may be ambiguous or lose information.
+
+// ASN1_UTCTIME_print writes a human-readable representation of |a| to |out|. It
+// returns one on success and zero on error.
+OPENSSL_EXPORT int ASN1_UTCTIME_print(BIO *out, const ASN1_UTCTIME *a);
+
+// ASN1_GENERALIZEDTIME_print writes a human-readable representation of |a| to
+// |out|. It returns one on success and zero on error.
+OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_print(BIO *out,
+ const ASN1_GENERALIZEDTIME *a);
+
+// ASN1_TIME_print writes a human-readable representation of |a| to |out|. It
+// returns one on success and zero on error.
+OPENSSL_EXPORT int ASN1_TIME_print(BIO *out, const ASN1_TIME *a);
+
+// ASN1_STRING_print writes a human-readable representation of |str| to |out|.
+// It returns one on success and zero on error. Unprintable characters are
+// replaced with '.'.
+OPENSSL_EXPORT int ASN1_STRING_print(BIO *out, const ASN1_STRING *str);
+
+// ASN1_STRFLGS_ESC_2253 causes characters to be escaped as in RFC 2253, section
+// 2.4.
+#define ASN1_STRFLGS_ESC_2253 1
+
+// ASN1_STRFLGS_ESC_CTRL causes all control characters to be escaped.
+#define ASN1_STRFLGS_ESC_CTRL 2
+
+// ASN1_STRFLGS_ESC_MSB causes all characters above 127 to be escaped.
+#define ASN1_STRFLGS_ESC_MSB 4
+
+// ASN1_STRFLGS_ESC_QUOTE causes the string to be surrounded by quotes, rather
+// than using backslashes, when characters are escaped. Fewer characters will
+// require escapes in this case.
+#define ASN1_STRFLGS_ESC_QUOTE 8
+
+// ASN1_STRFLGS_UTF8_CONVERT causes the string to be encoded as UTF-8, with each
+// byte in the UTF-8 encoding treated as an individual character for purposes of
+// escape sequences. If not set, each Unicode codepoint in the string is treated
+// as a character, with wide characters escaped as "\Uxxxx" or "\Wxxxxxxxx".
+// Note this can be ambiguous if |ASN1_STRFLGS_ESC_*| are all unset. In that
+// case, backslashes are not escaped, but wide characters are.
+#define ASN1_STRFLGS_UTF8_CONVERT 0x10
+
+// ASN1_STRFLGS_IGNORE_TYPE causes the string type to be ignored. The
+// |ASN1_STRING| in-memory representation will be printed directly.
+#define ASN1_STRFLGS_IGNORE_TYPE 0x20
+
+// ASN1_STRFLGS_SHOW_TYPE causes the string type to be included in the output.
+#define ASN1_STRFLGS_SHOW_TYPE 0x40
+
+// ASN1_STRFLGS_DUMP_ALL causes all strings to be printed as a hexdump, using
+// RFC 2253 hexstring notation, such as "#0123456789ABCDEF".
+#define ASN1_STRFLGS_DUMP_ALL 0x80
+
+// ASN1_STRFLGS_DUMP_UNKNOWN behaves like |ASN1_STRFLGS_DUMP_ALL| but only
+// applies to values of unknown type. If unset, unknown values will print
+// their contents as single-byte characters with escape sequences.
+#define ASN1_STRFLGS_DUMP_UNKNOWN 0x100
+
+// ASN1_STRFLGS_DUMP_DER causes hexdumped strings (as determined by
+// |ASN1_STRFLGS_DUMP_ALL| or |ASN1_STRFLGS_DUMP_UNKNOWN|) to print the entire
+// DER element as in RFC 2253, rather than only the contents of the
+// |ASN1_STRING|.
+#define ASN1_STRFLGS_DUMP_DER 0x200
+
+// ASN1_STRFLGS_RFC2253 causes the string to be escaped as in RFC 2253,
+// additionally escaping control characters.
+#define ASN1_STRFLGS_RFC2253 \
+ (ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB | \
+ ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_DUMP_UNKNOWN | \
+ ASN1_STRFLGS_DUMP_DER)
+
+// ASN1_STRING_print_ex writes a human-readable representation of |str| to
+// |out|. It returns the number of bytes written on success and -1 on error. If
+// |out| is NULL, it returns the number of bytes it would have written, without
+// writing anything.
+//
+// The |flags| should be a combination of combination of |ASN1_STRFLGS_*|
+// constants. See the documentation for each flag for how it controls the
+// output. If unsure, use |ASN1_STRFLGS_RFC2253|.
+OPENSSL_EXPORT int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str,
+ unsigned long flags);
+
+// ASN1_STRING_print_ex_fp behaves like |ASN1_STRING_print_ex| but writes to a
+// |FILE| rather than a |BIO|.
+OPENSSL_EXPORT int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str,
+ unsigned long flags);
+
+
+// Underdocumented functions.
+//
+// The following functions are not yet documented and organized.
+
DEFINE_STACK_OF(ASN1_OBJECT)
// ASN1_ENCODING structure: this is used to save the received
@@ -386,10 +865,6 @@ typedef struct ASN1_ENCODING_st {
#define STABLE_FLAGS_MALLOC 0x01
#define STABLE_NO_MASK 0x02
-#define DIRSTRING_TYPE \
- (B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_BMPSTRING | \
- B_ASN1_UTF8STRING)
-#define PKCS9STRING_TYPE (DIRSTRING_TYPE | B_ASN1_IA5STRING)
typedef struct asn1_string_table_st {
int nid;
@@ -399,23 +874,10 @@ typedef struct asn1_string_table_st {
unsigned long flags;
} ASN1_STRING_TABLE;
-// size limits: this stuff is taken straight from RFC2459
-
-#define ub_name 32768
-#define ub_common_name 64
-#define ub_locality_name 128
-#define ub_state_name 128
-#define ub_organization_name 64
-#define ub_organization_unit_name 64
-#define ub_title 64
-#define ub_email_address 128
-
// Declarations for template structures: for full definitions
// see asn1t.h
typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;
typedef struct ASN1_TLC_st ASN1_TLC;
-// This is just an opaque pointer
-typedef struct ASN1_VALUE_st ASN1_VALUE;
// Declare ASN1 functions: the implement macro in in asn1t.h
@@ -509,129 +971,15 @@ typedef const ASN1_ITEM ASN1_ITEM_EXP;
#define DECLARE_ASN1_ITEM(name) extern OPENSSL_EXPORT const ASN1_ITEM name##_it;
-// Parameters used by ASN1_STRING_print_ex()
-
-// These determine which characters to escape:
-// RFC2253 special characters, control characters and
-// MSB set characters
-
-#define ASN1_STRFLGS_ESC_2253 1
-#define ASN1_STRFLGS_ESC_CTRL 2
-#define ASN1_STRFLGS_ESC_MSB 4
-
-
-// This flag determines how we do escaping: normally
-// RC2253 backslash only, set this to use backslash and
-// quote.
-
-#define ASN1_STRFLGS_ESC_QUOTE 8
-
-
-// These three flags are internal use only.
-
-// Character is a valid PrintableString character
-#define CHARTYPE_PRINTABLESTRING 0x10
-// Character needs escaping if it is the first character
-#define CHARTYPE_FIRST_ESC_2253 0x20
-// Character needs escaping if it is the last character
-#define CHARTYPE_LAST_ESC_2253 0x40
-
-// NB the internal flags are safely reused below by flags
-// handled at the top level.
-
-// If this is set we convert all character strings
-// to UTF8 first
-
-#define ASN1_STRFLGS_UTF8_CONVERT 0x10
-
-// If this is set we don't attempt to interpret content:
-// just assume all strings are 1 byte per character. This
-// will produce some pretty odd looking output!
-
-#define ASN1_STRFLGS_IGNORE_TYPE 0x20
-
-// If this is set we include the string type in the output
-#define ASN1_STRFLGS_SHOW_TYPE 0x40
-
-// This determines which strings to display and which to
-// 'dump' (hex dump of content octets or DER encoding). We can
-// only dump non character strings or everything. If we
-// don't dump 'unknown' they are interpreted as character
-// strings with 1 octet per character and are subject to
-// the usual escaping options.
-
-#define ASN1_STRFLGS_DUMP_ALL 0x80
-#define ASN1_STRFLGS_DUMP_UNKNOWN 0x100
-
-// These determine what 'dumping' does, we can dump the
-// content octets or the DER encoding: both use the
-// RFC2253 #XXXXX notation.
-
-#define ASN1_STRFLGS_DUMP_DER 0x200
-
-// All the string flags consistent with RFC2253,
-// escaping control characters isn't essential in
-// RFC2253 but it is advisable anyway.
-
-#define ASN1_STRFLGS_RFC2253 \
- (ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB | \
- ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_DUMP_UNKNOWN | \
- ASN1_STRFLGS_DUMP_DER)
-
DEFINE_STACK_OF(ASN1_INTEGER)
-DECLARE_ASN1_SET_OF(ASN1_INTEGER)
-
-struct asn1_type_st {
- int type;
- union {
- char *ptr;
- ASN1_BOOLEAN boolean;
- ASN1_STRING *asn1_string;
- ASN1_OBJECT *object;
- ASN1_INTEGER *integer;
- ASN1_ENUMERATED *enumerated;
- ASN1_BIT_STRING *bit_string;
- ASN1_OCTET_STRING *octet_string;
- ASN1_PRINTABLESTRING *printablestring;
- ASN1_T61STRING *t61string;
- ASN1_IA5STRING *ia5string;
- ASN1_GENERALSTRING *generalstring;
- ASN1_BMPSTRING *bmpstring;
- ASN1_UNIVERSALSTRING *universalstring;
- ASN1_UTCTIME *utctime;
- ASN1_GENERALIZEDTIME *generalizedtime;
- ASN1_VISIBLESTRING *visiblestring;
- ASN1_UTF8STRING *utf8string;
- // set and sequence are left complete and still
- // contain the set or sequence bytes
- ASN1_STRING *set;
- ASN1_STRING *sequence;
- ASN1_VALUE *asn1_value;
- } value;
-};
DEFINE_STACK_OF(ASN1_TYPE)
-DECLARE_ASN1_SET_OF(ASN1_TYPE)
typedef STACK_OF(ASN1_TYPE) ASN1_SEQUENCE_ANY;
DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY)
DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SET_ANY)
-struct X509_algor_st {
- ASN1_OBJECT *algorithm;
- ASN1_TYPE *parameter;
-} /* X509_ALGOR */;
-
-DECLARE_ASN1_FUNCTIONS(X509_ALGOR)
-
-// This is used to contain a list of bit names
-typedef struct BIT_STRING_BITNAME_st {
- int bitnum;
- const char *lname;
- const char *sname;
-} BIT_STRING_BITNAME;
-
// M_ASN1_* are legacy aliases for various |ASN1_STRING| functions. Use the
// functions themselves.
#define M_ASN1_STRING_length(x) ASN1_STRING_length(x)
@@ -696,11 +1044,6 @@ typedef struct BIT_STRING_BITNAME_st {
DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE)
-OPENSSL_EXPORT int ASN1_TYPE_get(const ASN1_TYPE *a);
-OPENSSL_EXPORT void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value);
-OPENSSL_EXPORT int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value);
-OPENSSL_EXPORT int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b);
-
OPENSSL_EXPORT ASN1_OBJECT *ASN1_OBJECT_new(void);
OPENSSL_EXPORT void ASN1_OBJECT_free(ASN1_OBJECT *a);
OPENSSL_EXPORT int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp);
@@ -713,21 +1056,12 @@ OPENSSL_EXPORT ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a,
DECLARE_ASN1_ITEM(ASN1_OBJECT)
-DECLARE_ASN1_SET_OF(ASN1_OBJECT)
-
DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING)
OPENSSL_EXPORT int i2c_ASN1_BIT_STRING(const ASN1_BIT_STRING *a,
unsigned char **pp);
OPENSSL_EXPORT ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
const unsigned char **pp,
long length);
-OPENSSL_EXPORT int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d,
- int length);
-OPENSSL_EXPORT int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n,
- int value);
-OPENSSL_EXPORT int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n);
-OPENSSL_EXPORT int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *a,
- unsigned char *flags, int flags_len);
OPENSSL_EXPORT int i2d_ASN1_BOOLEAN(int a, unsigned char **pp);
OPENSSL_EXPORT int d2i_ASN1_BOOLEAN(int *a, const unsigned char **pp,
@@ -739,31 +1073,9 @@ OPENSSL_EXPORT ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a,
const unsigned char **pp,
long length);
OPENSSL_EXPORT ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x);
-OPENSSL_EXPORT int ASN1_INTEGER_cmp(const ASN1_INTEGER *x,
- const ASN1_INTEGER *y);
DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED)
-OPENSSL_EXPORT int ASN1_UTCTIME_check(const ASN1_UTCTIME *a);
-OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t);
-OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
- int offset_day, long offset_sec);
-OPENSSL_EXPORT int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str);
-OPENSSL_EXPORT int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t);
-#if 0
-time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s);
-#endif
-
-OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *a);
-OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(
- ASN1_GENERALIZEDTIME *s, time_t t);
-OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(
- ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, long offset_sec);
-OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s,
- const char *str);
-OPENSSL_EXPORT int ASN1_TIME_diff(int *pday, int *psec, const ASN1_TIME *from,
- const ASN1_TIME *to);
-
DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING)
OPENSSL_EXPORT ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(
const ASN1_OCTET_STRING *a);
@@ -790,14 +1102,6 @@ DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME)
DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME)
DECLARE_ASN1_FUNCTIONS(ASN1_TIME)
-OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t);
-OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day,
- long offset_sec);
-OPENSSL_EXPORT int ASN1_TIME_check(const ASN1_TIME *t);
-OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(
- const ASN1_TIME *t, ASN1_GENERALIZEDTIME **out);
-OPENSSL_EXPORT int ASN1_TIME_set_string(ASN1_TIME *s, const char *str);
-
OPENSSL_EXPORT int i2a_ASN1_INTEGER(BIO *bp, const ASN1_INTEGER *a);
OPENSSL_EXPORT int i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a);
OPENSSL_EXPORT int i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a);
@@ -805,27 +1109,16 @@ OPENSSL_EXPORT int i2a_ASN1_STRING(BIO *bp, const ASN1_STRING *a, int type);
OPENSSL_EXPORT int i2t_ASN1_OBJECT(char *buf, int buf_len,
const ASN1_OBJECT *a);
-OPENSSL_EXPORT ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,
+OPENSSL_EXPORT ASN1_OBJECT *ASN1_OBJECT_create(int nid,
+ const unsigned char *data,
int len, const char *sn,
const char *ln);
-OPENSSL_EXPORT int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
-OPENSSL_EXPORT int ASN1_INTEGER_set_uint64(ASN1_INTEGER *out, uint64_t v);
-OPENSSL_EXPORT long ASN1_INTEGER_get(const ASN1_INTEGER *a);
-OPENSSL_EXPORT ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn,
- ASN1_INTEGER *ai);
-OPENSSL_EXPORT BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn);
-
-OPENSSL_EXPORT int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v);
-OPENSSL_EXPORT long ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a);
-OPENSSL_EXPORT ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(const BIGNUM *bn,
- ASN1_ENUMERATED *ai);
-OPENSSL_EXPORT BIGNUM *ASN1_ENUMERATED_to_BN(const ASN1_ENUMERATED *ai,
- BIGNUM *bn);
-
-// General
-// given a string, return the correct type, max is the maximum length
-OPENSSL_EXPORT int ASN1_PRINTABLE_type(const unsigned char *s, int max);
+// ASN1_PRINTABLE_type interprets |len| bytes from |s| as a Latin-1 string. It
+// returns the first of |V_ASN1_PRINTABLESTRING|, |V_ASN1_IA5STRING|, or
+// |V_ASN1_T61STRING| that can represent every character. If |len| is negative,
+// |strlen(s)| is used instead.
+OPENSSL_EXPORT int ASN1_PRINTABLE_type(const unsigned char *s, int len);
OPENSSL_EXPORT unsigned long ASN1_tag2bit(int tag);
@@ -839,25 +1132,11 @@ OPENSSL_EXPORT int ASN1_object_size(int constructed, int length, int tag);
OPENSSL_EXPORT void *ASN1_item_dup(const ASN1_ITEM *it, void *x);
-#ifndef OPENSSL_NO_FP_API
OPENSSL_EXPORT void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
OPENSSL_EXPORT int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x);
-OPENSSL_EXPORT int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str,
- unsigned long flags);
-#endif
-
-OPENSSL_EXPORT int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in);
OPENSSL_EXPORT void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x);
OPENSSL_EXPORT int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x);
-OPENSSL_EXPORT int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a);
-OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_print(BIO *fp,
- const ASN1_GENERALIZEDTIME *a);
-OPENSSL_EXPORT int ASN1_TIME_print(BIO *fp, const ASN1_TIME *a);
-OPENSSL_EXPORT int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v);
-OPENSSL_EXPORT int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str,
- unsigned long flags);
-OPENSSL_EXPORT const char *ASN1_tag2str(int tag);
// Used to load and write netscape format cert
@@ -867,16 +1146,14 @@ OPENSSL_EXPORT void *ASN1_item_unpack(const ASN1_STRING *oct,
OPENSSL_EXPORT ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it,
ASN1_OCTET_STRING **oct);
+// ASN1_STRING_set_default_mask does nothing.
OPENSSL_EXPORT void ASN1_STRING_set_default_mask(unsigned long mask);
+
+// ASN1_STRING_set_default_mask_asc returns one.
OPENSSL_EXPORT int ASN1_STRING_set_default_mask_asc(const char *p);
+
+// ASN1_STRING_get_default_mask returns |B_ASN1_UTF8STRING|.
OPENSSL_EXPORT unsigned long ASN1_STRING_get_default_mask(void);
-OPENSSL_EXPORT int ASN1_mbstring_copy(ASN1_STRING **out,
- const unsigned char *in, int len,
- int inform, unsigned long mask);
-OPENSSL_EXPORT int ASN1_mbstring_ncopy(ASN1_STRING **out,
- const unsigned char *in, int len,
- int inform, unsigned long mask,
- long minsize, long maxsize);
OPENSSL_EXPORT ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out,
const unsigned char *in,
diff --git a/deps/boringssl/src/include/openssl/asn1t.h b/deps/boringssl/src/include/openssl/asn1t.h
index c5e2685..20c1e95 100644
--- a/deps/boringssl/src/include/openssl/asn1t.h
+++ b/deps/boringssl/src/include/openssl/asn1t.h
@@ -389,13 +389,6 @@ struct ASN1_ADB_TABLE_st {
/* Field is a SEQUENCE OF */
#define ASN1_TFLG_SEQUENCE_OF (0x2 << 1)
-/* Special case: this refers to a SET OF that
- * will be sorted into DER order when encoded *and*
- * the corresponding STACK will be modified to match
- * the new order.
- */
-#define ASN1_TFLG_SET_ORDER (0x3 << 1)
-
/* Mask for SET OF or SEQUENCE OF */
#define ASN1_TFLG_SK_MASK (0x3 << 1)
diff --git a/deps/boringssl/src/include/openssl/base.h b/deps/boringssl/src/include/openssl/base.h
index 90924e6..dd6a146 100644
--- a/deps/boringssl/src/include/openssl/base.h
+++ b/deps/boringssl/src/include/openssl/base.h
@@ -105,6 +105,10 @@ extern "C" {
#elif defined(__MIPSEL__) && defined(__LP64__)
#define OPENSSL_64_BIT
#define OPENSSL_MIPS64
+#elif defined(__riscv) && __SIZEOF_POINTER__ == 8
+#define OPENSSL_64_BIT
+#elif defined(__riscv) && __SIZEOF_POINTER__ == 4
+#define OPENSSL_32_BIT
#elif defined(__pnacl__)
#define OPENSSL_32_BIT
#define OPENSSL_PNACL
@@ -156,10 +160,10 @@ extern "C" {
#if defined(__ANDROID_API__)
#define OPENSSL_ANDROID
-#if defined(BORINGSSL_FIPS)
-// The FIPS module on Android passively receives entropy.
-#define BORINGSSL_FIPS_PASSIVE_ENTROPY
#endif
+
+#if defined(__FreeBSD__)
+#define OPENSSL_FREEBSD
#endif
// BoringSSL requires platform's locking APIs to make internal global state
@@ -191,7 +195,7 @@ extern "C" {
// A consumer may use this symbol in the preprocessor to temporarily build
// against multiple revisions of BoringSSL at the same time. It is not
// recommended to do so for longer than is necessary.
-#define BORINGSSL_API_VERSION 14
+#define BORINGSSL_API_VERSION 16
#if defined(BORINGSSL_SHARED_LIBRARY)
@@ -361,14 +365,12 @@ typedef struct X509_POLICY_NODE_st X509_POLICY_NODE;
typedef struct X509_POLICY_TREE_st X509_POLICY_TREE;
typedef struct X509_VERIFY_PARAM_st X509_VERIFY_PARAM;
typedef struct X509_algor_st X509_ALGOR;
-typedef struct X509_crl_info_st X509_CRL_INFO;
typedef struct X509_crl_st X509_CRL;
typedef struct X509_extension_st X509_EXTENSION;
typedef struct X509_info_st X509_INFO;
typedef struct X509_name_entry_st X509_NAME_ENTRY;
typedef struct X509_name_st X509_NAME;
typedef struct X509_pubkey_st X509_PUBKEY;
-typedef struct X509_req_info_st X509_REQ_INFO;
typedef struct X509_req_st X509_REQ;
typedef struct X509_sig_st X509_SIG;
typedef struct X509_val_st X509_VAL;
@@ -401,6 +403,11 @@ typedef struct evp_aead_st EVP_AEAD;
typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
typedef struct evp_cipher_st EVP_CIPHER;
typedef struct evp_encode_ctx_st EVP_ENCODE_CTX;
+typedef struct evp_hpke_aead_st EVP_HPKE_AEAD;
+typedef struct evp_hpke_ctx_st EVP_HPKE_CTX;
+typedef struct evp_hpke_kdf_st EVP_HPKE_KDF;
+typedef struct evp_hpke_kem_st EVP_HPKE_KEM;
+typedef struct evp_hpke_key_st EVP_HPKE_KEY;
typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD;
typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
typedef struct evp_pkey_method_st EVP_PKEY_METHOD;
@@ -423,6 +430,7 @@ typedef struct spake2_ctx_st SPAKE2_CTX;
typedef struct srtp_protection_profile_st SRTP_PROTECTION_PROFILE;
typedef struct ssl_cipher_st SSL_CIPHER;
typedef struct ssl_ctx_st SSL_CTX;
+typedef struct ssl_ech_keys_st SSL_ECH_KEYS;
typedef struct ssl_method_st SSL_METHOD;
typedef struct ssl_private_key_method_st SSL_PRIVATE_KEY_METHOD;
typedef struct ssl_quic_method_st SSL_QUIC_METHOD;
@@ -437,9 +445,10 @@ typedef struct trust_token_method_st TRUST_TOKEN_METHOD;
typedef struct v3_ext_ctx X509V3_CTX;
typedef struct x509_attributes_st X509_ATTRIBUTE;
typedef struct x509_cert_aux_st X509_CERT_AUX;
-typedef struct x509_cinf_st X509_CINF;
typedef struct x509_crl_method_st X509_CRL_METHOD;
typedef struct x509_lookup_st X509_LOOKUP;
+typedef struct x509_lookup_method_st X509_LOOKUP_METHOD;
+typedef struct x509_object_st X509_OBJECT;
typedef struct x509_revoked_st X509_REVOKED;
typedef struct x509_st X509;
typedef struct x509_store_ctx_st X509_STORE_CTX;
@@ -528,8 +537,39 @@ class StackAllocated {
StackAllocated() { init(&ctx_); }
~StackAllocated() { cleanup(&ctx_); }
- StackAllocated(const StackAllocated<T, CleanupRet, init, cleanup> &) = delete;
- T& operator=(const StackAllocated<T, CleanupRet, init, cleanup> &) = delete;
+ StackAllocated(const StackAllocated &) = delete;
+ StackAllocated& operator=(const StackAllocated &) = delete;
+
+ T *get() { return &ctx_; }
+ const T *get() const { return &ctx_; }
+
+ T *operator->() { return &ctx_; }
+ const T *operator->() const { return &ctx_; }
+
+ void Reset() {
+ cleanup(&ctx_);
+ init(&ctx_);
+ }
+
+ private:
+ T ctx_;
+};
+
+template <typename T, typename CleanupRet, void (*init)(T *),
+ CleanupRet (*cleanup)(T *), void (*move)(T *, T *)>
+class StackAllocatedMovable {
+ public:
+ StackAllocatedMovable() { init(&ctx_); }
+ ~StackAllocatedMovable() { cleanup(&ctx_); }
+
+ StackAllocatedMovable(StackAllocatedMovable &&other) {
+ init(&ctx_);
+ move(&ctx_, &other.ctx_);
+ }
+ StackAllocatedMovable &operator=(StackAllocatedMovable &&other) {
+ move(&ctx_, &other.ctx_);
+ return *this;
+ }
T *get() { return &ctx_; }
const T *get() const { return &ctx_; }
diff --git a/deps/boringssl/src/include/openssl/bio.h b/deps/boringssl/src/include/openssl/bio.h
index f25492a..18bc893 100644
--- a/deps/boringssl/src/include/openssl/bio.h
+++ b/deps/boringssl/src/include/openssl/bio.h
@@ -377,7 +377,9 @@ OPENSSL_EXPORT int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len,
OPENSSL_EXPORT const BIO_METHOD *BIO_s_mem(void);
// BIO_new_mem_buf creates read-only BIO that reads from |len| bytes at |buf|.
-// It does not take ownership of |buf|. It returns the BIO or NULL on error.
+// It returns the BIO or NULL on error. This function does not copy or take
+// ownership of |buf|. The caller must ensure the memory pointed to by |buf|
+// outlives the |BIO|.
//
// If |len| is negative, then |buf| is treated as a NUL-terminated string, but
// don't depend on this in new code.
diff --git a/deps/boringssl/src/include/openssl/bytestring.h b/deps/boringssl/src/include/openssl/bytestring.h
index 5ae0348..5ef3742 100644
--- a/deps/boringssl/src/include/openssl/bytestring.h
+++ b/deps/boringssl/src/include/openssl/bytestring.h
@@ -51,6 +51,7 @@ struct cbs_st {
// Defining any constructors requires we explicitly default the others.
cbs_st() = default;
cbs_st(const cbs_st &) = default;
+ cbs_st &operator=(const cbs_st &) = default;
#endif
};
@@ -153,6 +154,11 @@ OPENSSL_EXPORT int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out);
// returns one on success and zero on error.
OPENSSL_EXPORT int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out);
+// CBS_get_until_first finds the first instance of |c| in |cbs|. If found, it
+// sets |*out| to the text before the match, advances |cbs| over it, and returns
+// one. Otherwise, it returns zero and leaves |cbs| unmodified.
+OPENSSL_EXPORT int CBS_get_until_first(CBS *cbs, CBS *out, uint8_t c);
+
// Parsing ASN.1
//
@@ -462,6 +468,10 @@ OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag);
// success and zero otherwise.
OPENSSL_EXPORT int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len);
+// CBB_add_zeros append |len| bytes with value zero to |cbb|. It returns one on
+// success and zero otherwise.
+OPENSSL_EXPORT int CBB_add_zeros(CBB *cbb, size_t len);
+
// CBB_add_space appends |len| bytes to |cbb| and sets |*out_data| to point to
// the beginning of that space. The caller must then write |len| bytes of
// actual contents to |*out_data|. It returns one on success and zero
diff --git a/deps/boringssl/src/include/openssl/chacha.h b/deps/boringssl/src/include/openssl/chacha.h
index 684fc5b..cfbaa75 100644
--- a/deps/boringssl/src/include/openssl/chacha.h
+++ b/deps/boringssl/src/include/openssl/chacha.h
@@ -23,7 +23,7 @@ extern "C" {
// ChaCha20.
//
-// ChaCha20 is a stream cipher. See https://tools.ietf.org/html/rfc7539.
+// ChaCha20 is a stream cipher. See https://tools.ietf.org/html/rfc8439.
// CRYPTO_chacha_20 encrypts |in_len| bytes from |in| with the given key and
diff --git a/deps/boringssl/src/include/openssl/cipher.h b/deps/boringssl/src/include/openssl/cipher.h
index c6bec48..badd496 100644
--- a/deps/boringssl/src/include/openssl/cipher.h
+++ b/deps/boringssl/src/include/openssl/cipher.h
@@ -556,10 +556,6 @@ struct evp_cipher_ctx_st {
// final_used is non-zero if the |final| buffer contains plaintext.
int final_used;
- // block_mask contains |cipher->block_size| minus one. (The block size
- // assumed to be a power of two.)
- int block_mask;
-
uint8_t final[EVP_MAX_BLOCK_LENGTH]; // possible final block
} /* EVP_CIPHER_CTX */;
diff --git a/deps/boringssl/src/include/openssl/conf.h b/deps/boringssl/src/include/openssl/conf.h
index ae71869..6890c7d 100644
--- a/deps/boringssl/src/include/openssl/conf.h
+++ b/deps/boringssl/src/include/openssl/conf.h
@@ -100,22 +100,25 @@ OPENSSL_EXPORT void NCONF_free(CONF *conf);
// |conf|. It returns one on success and zero on error. In the event of an
// error, if |out_error_line| is not NULL, |*out_error_line| is set to the
// number of the line that contained the error.
-int NCONF_load(CONF *conf, const char *filename, long *out_error_line);
+OPENSSL_EXPORT int NCONF_load(CONF *conf, const char *filename,
+ long *out_error_line);
// NCONF_load_bio acts like |NCONF_load| but reads from |bio| rather than from
// a named file.
-int NCONF_load_bio(CONF *conf, BIO *bio, long *out_error_line);
+OPENSSL_EXPORT int NCONF_load_bio(CONF *conf, BIO *bio, long *out_error_line);
// NCONF_get_section returns a stack of values for a given section in |conf|.
// If |section| is NULL, the default section is returned. It returns NULL on
// error.
-STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section);
+OPENSSL_EXPORT STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf,
+ const char *section);
// NCONF_get_string returns the value of the key |name|, in section |section|.
// The |section| argument may be NULL to indicate the default section. It
// returns the value or NULL on error.
-const char *NCONF_get_string(const CONF *conf, const char *section,
- const char *name);
+OPENSSL_EXPORT const char *NCONF_get_string(const CONF *conf,
+ const char *section,
+ const char *name);
// Utility functions
diff --git a/deps/boringssl/src/include/openssl/cpu.h b/deps/boringssl/src/include/openssl/cpu.h
index ae55967..91cf95e 100644
--- a/deps/boringssl/src/include/openssl/cpu.h
+++ b/deps/boringssl/src/include/openssl/cpu.h
@@ -111,26 +111,18 @@ OPENSSL_INLINE const uint32_t *OPENSSL_ia32cap_get(void) {
#endif
#if !defined(OPENSSL_STATIC_ARMCAP)
-
// CRYPTO_is_NEON_capable_at_runtime returns true if the current CPU has a NEON
// unit. Note that |OPENSSL_armcap_P| also exists and contains the same
// information in a form that's easier for assembly to use.
-OPENSSL_EXPORT char CRYPTO_is_NEON_capable_at_runtime(void);
+OPENSSL_EXPORT int CRYPTO_is_NEON_capable_at_runtime(void);
-// CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. If
-// this is known statically then it returns one immediately.
-OPENSSL_INLINE int CRYPTO_is_NEON_capable(void) {
- // Only statically skip the runtime lookup on aarch64. On arm, one CPU is
- // known to have a broken NEON unit which is known to fail with on some
- // hand-written NEON assembly. For now, continue to apply the workaround even
- // when the compiler is instructed to freely emit NEON code. See
- // https://crbug.com/341598 and https://crbug.com/606629.
-#if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && !defined(OPENSSL_ARM)
- return 1;
-#else
- return CRYPTO_is_NEON_capable_at_runtime();
-#endif
-}
+// CRYPTO_is_ARMv8_AES_capable_at_runtime returns true if the current CPU
+// supports the ARMv8 AES instruction.
+int CRYPTO_is_ARMv8_AES_capable_at_runtime(void);
+
+// CRYPTO_is_ARMv8_PMULL_capable_at_runtime returns true if the current CPU
+// supports the ARMv8 PMULL instruction.
+int CRYPTO_is_ARMv8_PMULL_capable_at_runtime(void);
#if defined(OPENSSL_ARM)
// CRYPTO_has_broken_NEON returns one if the current CPU is known to have a
@@ -141,43 +133,41 @@ OPENSSL_EXPORT int CRYPTO_has_broken_NEON(void);
// workaround was needed. See https://crbug.com/boringssl/46.
OPENSSL_EXPORT int CRYPTO_needs_hwcap2_workaround(void);
#endif
+#endif // !OPENSSL_STATIC_ARMCAP
-// CRYPTO_is_ARMv8_AES_capable returns true if the current CPU supports the
-// ARMv8 AES instruction.
-int CRYPTO_is_ARMv8_AES_capable(void);
-
-// CRYPTO_is_ARMv8_PMULL_capable returns true if the current CPU supports the
-// ARMv8 PMULL instruction.
-int CRYPTO_is_ARMv8_PMULL_capable(void);
-
-#else
-
+// CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. If
+// this is known statically, it is a constant inline function.
OPENSSL_INLINE int CRYPTO_is_NEON_capable(void) {
-#if defined(OPENSSL_STATIC_ARMCAP_NEON) || \
- (defined(__ARM_NEON__) || defined(__ARM_NEON))
+#if defined(__ARM_NEON__) || defined(__ARM_NEON) || \
+ defined(OPENSSL_STATIC_ARMCAP_NEON)
return 1;
-#else
+#elif defined(OPENSSL_STATIC_ARMCAP)
return 0;
+#else
+ return CRYPTO_is_NEON_capable_at_runtime();
#endif
}
OPENSSL_INLINE int CRYPTO_is_ARMv8_AES_capable(void) {
#if defined(OPENSSL_STATIC_ARMCAP_AES) || defined(__ARM_FEATURE_CRYPTO)
return 1;
-#else
+#elif defined(OPENSSL_STATIC_ARMCAP)
return 0;
+#else
+ return CRYPTO_is_ARMv8_AES_capable_at_runtime();
#endif
}
OPENSSL_INLINE int CRYPTO_is_ARMv8_PMULL_capable(void) {
#if defined(OPENSSL_STATIC_ARMCAP_PMULL) || defined(__ARM_FEATURE_CRYPTO)
return 1;
-#else
+#elif defined(OPENSSL_STATIC_ARMCAP)
return 0;
+#else
+ return CRYPTO_is_ARMv8_PMULL_capable_at_runtime();
#endif
}
-#endif // OPENSSL_STATIC_ARMCAP
#endif // OPENSSL_ARM || OPENSSL_AARCH64
#if defined(OPENSSL_PPC64LE)
diff --git a/deps/boringssl/src/include/openssl/crypto.h b/deps/boringssl/src/include/openssl/crypto.h
index b820e40..93b1a9b 100644
--- a/deps/boringssl/src/include/openssl/crypto.h
+++ b/deps/boringssl/src/include/openssl/crypto.h
@@ -55,10 +55,6 @@ OPENSSL_EXPORT int CRYPTO_is_confidential_build(void);
// in which case it returns zero.
OPENSSL_EXPORT int CRYPTO_has_asm(void);
-// FIPS_mode returns zero unless BoringSSL is built with BORINGSSL_FIPS, in
-// which case it returns one.
-OPENSSL_EXPORT int FIPS_mode(void);
-
// BORINGSSL_self_test triggers the FIPS KAT-based self tests. It returns one on
// success and zero on error.
OPENSSL_EXPORT int BORINGSSL_self_test(void);
@@ -72,6 +68,30 @@ OPENSSL_EXPORT int BORINGSSL_self_test(void);
OPENSSL_EXPORT void CRYPTO_pre_sandbox_init(void);
+// FIPS monitoring
+
+// FIPS_mode returns zero unless BoringSSL is built with BORINGSSL_FIPS, in
+// which case it returns one.
+OPENSSL_EXPORT int FIPS_mode(void);
+
+// fips_counter_t denotes specific APIs/algorithms. A counter is maintained for
+// each in FIPS mode so that tests can be written to assert that the expected,
+// FIPS functions are being called by a certain peice of code.
+enum fips_counter_t {
+ fips_counter_evp_aes_128_gcm = 0,
+ fips_counter_evp_aes_256_gcm = 1,
+ fips_counter_evp_aes_128_ctr = 2,
+ fips_counter_evp_aes_256_ctr = 3,
+
+ fips_counter_max = 3,
+};
+
+// FIPS_read_counter returns a counter of the number of times the specific
+// function denoted by |counter| has been used. This always returns zero unless
+// BoringSSL was built with BORINGSSL_FIPS_COUNTERS defined.
+OPENSSL_EXPORT size_t FIPS_read_counter(enum fips_counter_t counter);
+
+
// Deprecated functions.
// OPENSSL_VERSION_TEXT contains a string the identifies the version of
diff --git a/deps/boringssl/src/include/openssl/digest.h b/deps/boringssl/src/include/openssl/digest.h
index 66f1b5d..fa76168 100644
--- a/deps/boringssl/src/include/openssl/digest.h
+++ b/deps/boringssl/src/include/openssl/digest.h
@@ -124,6 +124,10 @@ OPENSSL_EXPORT void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
// copy of |in|. It returns one on success and zero on allocation failure.
OPENSSL_EXPORT int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in);
+// EVP_MD_CTX_move sets |out|, which must already be initialised, to the hash
+// state in |in|. |in| is mutated and left in an empty state.
+OPENSSL_EXPORT void EVP_MD_CTX_move(EVP_MD_CTX *out, EVP_MD_CTX *in);
+
// EVP_MD_CTX_reset calls |EVP_MD_CTX_cleanup| followed by |EVP_MD_CTX_init|. It
// returns one.
OPENSSL_EXPORT int EVP_MD_CTX_reset(EVP_MD_CTX *ctx);
@@ -293,6 +297,9 @@ OPENSSL_EXPORT void EVP_MD_CTX_set_flags(EVP_MD_CTX *ctx, int flags);
// their needs). Thus this exists only to allow code to compile.
#define EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 0
+// EVP_MD_nid calls |EVP_MD_type|.
+OPENSSL_EXPORT int EVP_MD_nid(const EVP_MD *md);
+
struct evp_md_pctx_ops;
@@ -324,8 +331,8 @@ BSSL_NAMESPACE_BEGIN
BORINGSSL_MAKE_DELETER(EVP_MD_CTX, EVP_MD_CTX_free)
using ScopedEVP_MD_CTX =
- internal::StackAllocated<EVP_MD_CTX, int, EVP_MD_CTX_init,
- EVP_MD_CTX_cleanup>;
+ internal::StackAllocatedMovable<EVP_MD_CTX, int, EVP_MD_CTX_init,
+ EVP_MD_CTX_cleanup, EVP_MD_CTX_move>;
BSSL_NAMESPACE_END
diff --git a/deps/boringssl/src/include/openssl/ec.h b/deps/boringssl/src/include/openssl/ec.h
index 363c096..cc8138d 100644
--- a/deps/boringssl/src/include/openssl/ec.h
+++ b/deps/boringssl/src/include/openssl/ec.h
@@ -343,11 +343,14 @@ OPENSSL_EXPORT int EC_GROUP_set_generator(EC_GROUP *group,
OPENSSL_EXPORT int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order,
BN_CTX *ctx);
+#define OPENSSL_EC_EXPLICIT_CURVE 0
+#define OPENSSL_EC_NAMED_CURVE 1
+
// EC_GROUP_set_asn1_flag does nothing.
OPENSSL_EXPORT void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag);
-#define OPENSSL_EC_NAMED_CURVE 0
-#define OPENSSL_EC_EXPLICIT_CURVE 1
+// EC_GROUP_get_asn1_flag returns |OPENSSL_EC_NAMED_CURVE|.
+OPENSSL_EXPORT int EC_GROUP_get_asn1_flag(const EC_GROUP *group);
typedef struct ec_method_st EC_METHOD;
diff --git a/deps/boringssl/src/include/openssl/ecdsa.h b/deps/boringssl/src/include/openssl/ecdsa.h
index 9cd19a5..5443ef5 100644
--- a/deps/boringssl/src/include/openssl/ecdsa.h
+++ b/deps/boringssl/src/include/openssl/ecdsa.h
@@ -73,6 +73,9 @@ extern "C" {
// space. On successful exit, |*sig_len| is set to the actual number of bytes
// written. The |type| argument should be zero. It returns one on success and
// zero otherwise.
+//
+// WARNING: |digest| must be the output of some hash function on the data to be
+// signed. Passing unhashed inputs will not result in a secure signature scheme.
OPENSSL_EXPORT int ECDSA_sign(int type, const uint8_t *digest,
size_t digest_len, uint8_t *sig,
unsigned int *sig_len, const EC_KEY *key);
@@ -81,6 +84,10 @@ OPENSSL_EXPORT int ECDSA_sign(int type, const uint8_t *digest,
// signature by |key| of |digest|. (The |type| argument should be zero.) It
// returns one on success or zero if the signature is invalid or an error
// occurred.
+//
+// WARNING: |digest| must be the output of some hash function on the data to be
+// verified. Passing unhashed inputs will not result in a secure signature
+// scheme.
OPENSSL_EXPORT int ECDSA_verify(int type, const uint8_t *digest,
size_t digest_len, const uint8_t *sig,
size_t sig_len, const EC_KEY *key);
@@ -124,12 +131,19 @@ OPENSSL_EXPORT int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
// ECDSA_do_sign signs |digest_len| bytes from |digest| with |key| and returns
// the resulting signature structure, or NULL on error.
+//
+// WARNING: |digest| must be the output of some hash function on the data to be
+// signed. Passing unhashed inputs will not result in a secure signature scheme.
OPENSSL_EXPORT ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest,
size_t digest_len, const EC_KEY *key);
// ECDSA_do_verify verifies that |sig| constitutes a valid signature by |key|
// of |digest|. It returns one on success or zero if the signature is invalid
// or on error.
+//
+// WARNING: |digest| must be the output of some hash function on the data to be
+// verified. Passing unhashed inputs will not result in a secure signature
+// scheme.
OPENSSL_EXPORT int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
const ECDSA_SIG *sig, const EC_KEY *key);
@@ -162,6 +176,25 @@ OPENSSL_EXPORT int ECDSA_SIG_to_bytes(uint8_t **out_bytes, size_t *out_len,
OPENSSL_EXPORT size_t ECDSA_SIG_max_len(size_t order_len);
+// Testing-only functions.
+
+// ECDSA_sign_with_nonce_and_leak_private_key_for_testing behaves like
+// |ECDSA_do_sign| but uses |nonce| for the ECDSA nonce 'k', instead of a random
+// value. |nonce| is interpreted as a big-endian integer. It must be reduced
+// modulo the group order and padded with zeros up to |BN_num_bytes(order)|
+// bytes.
+//
+// WARNING: This function is only exported for testing purposes, when using test
+// vectors or fuzzing strategies. It must not be used outside tests and may leak
+// any private keys it is used with.
+OPENSSL_EXPORT ECDSA_SIG *
+ECDSA_sign_with_nonce_and_leak_private_key_for_testing(const uint8_t *digest,
+ size_t digest_len,
+ const EC_KEY *eckey,
+ const uint8_t *nonce,
+ size_t nonce_len);
+
+
// Deprecated functions.
// d2i_ECDSA_SIG parses an ASN.1, DER-encoded, signature from |len| bytes at
diff --git a/deps/boringssl/src/include/openssl/err.h b/deps/boringssl/src/include/openssl/err.h
index 0960d80..572340c 100644
--- a/deps/boringssl/src/include/openssl/err.h
+++ b/deps/boringssl/src/include/openssl/err.h
@@ -223,11 +223,12 @@ OPENSSL_EXPORT char *ERR_error_string_n(uint32_t packed_error, char *buf,
size_t len);
// ERR_lib_error_string returns a string representation of the library that
-// generated |packed_error|.
+// generated |packed_error|, or a placeholder string is the library is
+// unrecognized.
OPENSSL_EXPORT const char *ERR_lib_error_string(uint32_t packed_error);
// ERR_reason_error_string returns a string representation of the reason for
-// |packed_error|.
+// |packed_error|, or a placeholder string if the reason is unrecognized.
OPENSSL_EXPORT const char *ERR_reason_error_string(uint32_t packed_error);
// ERR_print_errors_callback_t is the type of a function used by
diff --git a/deps/boringssl/src/include/openssl/evp.h b/deps/boringssl/src/include/openssl/evp.h
index 0710792..c567875 100644
--- a/deps/boringssl/src/include/openssl/evp.h
+++ b/deps/boringssl/src/include/openssl/evp.h
@@ -59,6 +59,7 @@
#include <openssl/base.h>
+#include <openssl/evp_errors.h>
#include <openssl/thread.h>
// OpenSSL included digest and cipher functions in this header so we include
@@ -544,14 +545,15 @@ OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx);
OPENSSL_EXPORT int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
// EVP_PKEY_sign signs |digest_len| bytes from |digest| using |ctx|. If |sig| is
-// NULL, the maximum size of the signature is written to
-// |out_sig_len|. Otherwise, |*sig_len| must contain the number of bytes of
-// space available at |sig|. If sufficient, the signature will be written to
-// |sig| and |*sig_len| updated with the true length.
+// NULL, the maximum size of the signature is written to |out_sig_len|.
+// Otherwise, |*sig_len| must contain the number of bytes of space available at
+// |sig|. If sufficient, the signature will be written to |sig| and |*sig_len|
+// updated with the true length. This function will fail for signature
+// algorithms like Ed25519 that do not support signing pre-hashed inputs.
//
-// This function expects a pre-hashed input and will fail for signature
-// algorithms which do not support this. Use |EVP_DigestSignInit| to sign an
-// unhashed input.
+// WARNING: |digest| must be the output of some hash function on the data to be
+// signed. Passing unhashed inputs will not result in a secure signature scheme.
+// Use |EVP_DigestSignInit| to sign an unhashed input.
//
// WARNING: Setting |sig| to NULL only gives the maximum size of the
// signature. The actual signature may be smaller.
@@ -569,11 +571,13 @@ OPENSSL_EXPORT int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig,
OPENSSL_EXPORT int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);
// EVP_PKEY_verify verifies that |sig_len| bytes from |sig| are a valid
-// signature for |digest|.
+// signature for |digest|. This function will fail for signature
+// algorithms like Ed25519 that do not support signing pre-hashed inputs.
//
-// This function expects a pre-hashed input and will fail for signature
-// algorithms which do not support this. Use |EVP_DigestVerifyInit| to verify a
-// signature given the unhashed input.
+// WARNING: |digest| must be the output of some hash function on the data to be
+// verified. Passing unhashed inputs will not result in a secure signature
+// scheme. Use |EVP_DigestVerifyInit| to verify a signature given the unhashed
+// input.
//
// It returns one on success or zero on error.
OPENSSL_EXPORT int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
@@ -832,6 +836,11 @@ OPENSSL_EXPORT int EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx,
// Ed448 and attempts to create keys will fail.
#define EVP_PKEY_ED448 NID_ED448
+// EVP_PKEY_get0 returns NULL. This function is provided for compatibility with
+// OpenSSL but does not return anything. Use the typed |EVP_PKEY_get0_*|
+// functions instead.
+OPENSSL_EXPORT void *EVP_PKEY_get0(const EVP_PKEY *pkey);
+
// OpenSSL_add_all_algorithms does nothing.
OPENSSL_EXPORT void OpenSSL_add_all_algorithms(void);
@@ -858,6 +867,12 @@ OPENSSL_EXPORT void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
void *arg),
void *arg);
+OPENSSL_EXPORT void EVP_MD_do_all(void (*callback)(const EVP_MD *cipher,
+ const char *name,
+ const char *unused,
+ void *arg),
+ void *arg);
+
// i2d_PrivateKey marshals a private key from |key| to an ASN.1, DER
// structure. If |outp| is not NULL then the result is written to |*outp| and
// |*outp| is advanced just past the output. It returns the number of bytes in
@@ -1091,42 +1106,4 @@ BSSL_NAMESPACE_END
#endif
-#define EVP_R_BUFFER_TOO_SMALL 100
-#define EVP_R_COMMAND_NOT_SUPPORTED 101
-#define EVP_R_DECODE_ERROR 102
-#define EVP_R_DIFFERENT_KEY_TYPES 103
-#define EVP_R_DIFFERENT_PARAMETERS 104
-#define EVP_R_ENCODE_ERROR 105
-#define EVP_R_EXPECTING_AN_EC_KEY_KEY 106
-#define EVP_R_EXPECTING_AN_RSA_KEY 107
-#define EVP_R_EXPECTING_A_DSA_KEY 108
-#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 109
-#define EVP_R_INVALID_DIGEST_LENGTH 110
-#define EVP_R_INVALID_DIGEST_TYPE 111
-#define EVP_R_INVALID_KEYBITS 112
-#define EVP_R_INVALID_MGF1_MD 113
-#define EVP_R_INVALID_OPERATION 114
-#define EVP_R_INVALID_PADDING_MODE 115
-#define EVP_R_INVALID_PSS_SALTLEN 116
-#define EVP_R_KEYS_NOT_SET 117
-#define EVP_R_MISSING_PARAMETERS 118
-#define EVP_R_NO_DEFAULT_DIGEST 119
-#define EVP_R_NO_KEY_SET 120
-#define EVP_R_NO_MDC2_SUPPORT 121
-#define EVP_R_NO_NID_FOR_CURVE 122
-#define EVP_R_NO_OPERATION_SET 123
-#define EVP_R_NO_PARAMETERS_SET 124
-#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 125
-#define EVP_R_OPERATON_NOT_INITIALIZED 126
-#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 127
-#define EVP_R_UNSUPPORTED_ALGORITHM 128
-#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 129
-#define EVP_R_NOT_A_PRIVATE_KEY 130
-#define EVP_R_INVALID_SIGNATURE 131
-#define EVP_R_MEMORY_LIMIT_EXCEEDED 132
-#define EVP_R_INVALID_PARAMETERS 133
-#define EVP_R_INVALID_PEER_KEY 134
-#define EVP_R_NOT_XOF_OR_INVALID_LENGTH 135
-#define EVP_R_EMPTY_PSK 136
-
#endif // OPENSSL_HEADER_EVP_H
diff --git a/deps/boringssl/src/crypto/x509/x509_r2x.c b/deps/boringssl/src/include/openssl/evp_errors.h
index a44b172..8583f52 100644
--- a/deps/boringssl/src/crypto/x509/x509_r2x.c
+++ b/deps/boringssl/src/include/openssl/evp_errors.h
@@ -54,63 +54,46 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
-#include <openssl/asn1.h>
-#include <openssl/bn.h>
-#include <openssl/digest.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/obj.h>
-#include <openssl/x509.h>
+#ifndef OPENSSL_HEADER_EVP_ERRORS_H
+#define OPENSSL_HEADER_EVP_ERRORS_H
-X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey)
-{
- X509 *ret = NULL;
- X509_CINF *xi = NULL;
- X509_NAME *xn;
- EVP_PKEY *pubkey = NULL;
- int res;
+#define EVP_R_BUFFER_TOO_SMALL 100
+#define EVP_R_COMMAND_NOT_SUPPORTED 101
+#define EVP_R_DECODE_ERROR 102
+#define EVP_R_DIFFERENT_KEY_TYPES 103
+#define EVP_R_DIFFERENT_PARAMETERS 104
+#define EVP_R_ENCODE_ERROR 105
+#define EVP_R_EXPECTING_AN_EC_KEY_KEY 106
+#define EVP_R_EXPECTING_AN_RSA_KEY 107
+#define EVP_R_EXPECTING_A_DSA_KEY 108
+#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 109
+#define EVP_R_INVALID_DIGEST_LENGTH 110
+#define EVP_R_INVALID_DIGEST_TYPE 111
+#define EVP_R_INVALID_KEYBITS 112
+#define EVP_R_INVALID_MGF1_MD 113
+#define EVP_R_INVALID_OPERATION 114
+#define EVP_R_INVALID_PADDING_MODE 115
+#define EVP_R_INVALID_PSS_SALTLEN 116
+#define EVP_R_KEYS_NOT_SET 117
+#define EVP_R_MISSING_PARAMETERS 118
+#define EVP_R_NO_DEFAULT_DIGEST 119
+#define EVP_R_NO_KEY_SET 120
+#define EVP_R_NO_MDC2_SUPPORT 121
+#define EVP_R_NO_NID_FOR_CURVE 122
+#define EVP_R_NO_OPERATION_SET 123
+#define EVP_R_NO_PARAMETERS_SET 124
+#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 125
+#define EVP_R_OPERATON_NOT_INITIALIZED 126
+#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 127
+#define EVP_R_UNSUPPORTED_ALGORITHM 128
+#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 129
+#define EVP_R_NOT_A_PRIVATE_KEY 130
+#define EVP_R_INVALID_SIGNATURE 131
+#define EVP_R_MEMORY_LIMIT_EXCEEDED 132
+#define EVP_R_INVALID_PARAMETERS 133
+#define EVP_R_INVALID_PEER_KEY 134
+#define EVP_R_NOT_XOF_OR_INVALID_LENGTH 135
+#define EVP_R_EMPTY_PSK 136
+#define EVP_R_INVALID_BUFFER_SIZE 137
- if ((ret = X509_new()) == NULL) {
- OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
-
- /* duplicate the request */
- xi = ret->cert_info;
-
- if (sk_X509_ATTRIBUTE_num(r->req_info->attributes) != 0) {
- if ((xi->version = ASN1_INTEGER_new()) == NULL)
- goto err;
- if (!ASN1_INTEGER_set(xi->version, 2))
- goto err;
- /*
- * xi->extensions=ri->attributes; <- bad, should not ever be done
- * ri->attributes=NULL;
- */
- }
-
- xn = X509_REQ_get_subject_name(r);
- if (X509_set_subject_name(ret, xn) == 0)
- goto err;
- if (X509_set_issuer_name(ret, xn) == 0)
- goto err;
-
- if (X509_gmtime_adj(xi->validity->notBefore, 0) == NULL)
- goto err;
- if (X509_gmtime_adj(xi->validity->notAfter, (long)60 * 60 * 24 * days) ==
- NULL)
- goto err;
-
- pubkey = X509_REQ_get_pubkey(r);
- res = X509_set_pubkey(ret, pubkey);
- EVP_PKEY_free(pubkey);
-
- if (!res || !X509_sign(ret, pkey, EVP_md5()))
- goto err;
- if (0) {
- err:
- X509_free(ret);
- ret = NULL;
- }
- return (ret);
-}
+#endif // OPENSSL_HEADER_EVP_ERRORS_H
diff --git a/deps/boringssl/src/include/openssl/hkdf.h b/deps/boringssl/src/include/openssl/hkdf.h
index 59aaa49..5b27acc 100644
--- a/deps/boringssl/src/include/openssl/hkdf.h
+++ b/deps/boringssl/src/include/openssl/hkdf.h
@@ -41,6 +41,10 @@ OPENSSL_EXPORT int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
// keying material |secret| and salt |salt| using |digest|, and outputs
// |out_len| bytes to |out_key|. The maximum output size is |EVP_MAX_MD_SIZE|.
// It returns one on success and zero on error.
+//
+// WARNING: This function orders the inputs differently from RFC 5869
+// specification. Double-check which parameter is the secret/IKM and which is
+// the salt when using.
OPENSSL_EXPORT int HKDF_extract(uint8_t *out_key, size_t *out_len,
const EVP_MD *digest, const uint8_t *secret,
size_t secret_len, const uint8_t *salt,
diff --git a/deps/boringssl/src/include/openssl/hpke.h b/deps/boringssl/src/include/openssl/hpke.h
new file mode 100644
index 0000000..6958ef6
--- /dev/null
+++ b/deps/boringssl/src/include/openssl/hpke.h
@@ -0,0 +1,350 @@
+/* Copyright (c) 2020, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_CRYPTO_HPKE_INTERNAL_H
+#define OPENSSL_HEADER_CRYPTO_HPKE_INTERNAL_H
+
+#include <openssl/aead.h>
+#include <openssl/base.h>
+#include <openssl/curve25519.h>
+#include <openssl/digest.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+// Hybrid Public Key Encryption.
+//
+// Hybrid Public Key Encryption (HPKE) enables a sender to encrypt messages to a
+// receiver with a public key.
+//
+// See https://tools.ietf.org/html/draft-irtf-cfrg-hpke-08.
+
+
+// Parameters.
+//
+// An HPKE context is parameterized by KEM, KDF, and AEAD algorithms,
+// represented by |EVP_HPKE_KEM|, |EVP_HPKE_KDF|, and |EVP_HPKE_AEAD| types,
+// respectively.
+
+// The following constants are KEM identifiers.
+#define EVP_HPKE_DHKEM_X25519_HKDF_SHA256 0x0020
+
+// The following functions are KEM algorithms which may be used with HPKE. Note
+// that, while some HPKE KEMs use KDFs internally, this is separate from the
+// |EVP_HPKE_KDF| selection.
+OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_hpke_x25519_hkdf_sha256(void);
+
+// EVP_HPKE_KEM_id returns the HPKE KEM identifier for |kem|, which
+// will be one of the |EVP_HPKE_KEM_*| constants.
+OPENSSL_EXPORT uint16_t EVP_HPKE_KEM_id(const EVP_HPKE_KEM *kem);
+
+// The following constants are KDF identifiers.
+#define EVP_HPKE_HKDF_SHA256 0x0001
+
+// The following functions are KDF algorithms which may be used with HPKE.
+OPENSSL_EXPORT const EVP_HPKE_KDF *EVP_hpke_hkdf_sha256(void);
+
+// EVP_HPKE_KDF_id returns the HPKE KDF identifier for |kdf|.
+OPENSSL_EXPORT uint16_t EVP_HPKE_KDF_id(const EVP_HPKE_KDF *kdf);
+
+// The following constants are AEAD identifiers.
+#define EVP_HPKE_AES_128_GCM 0x0001
+#define EVP_HPKE_AES_256_GCM 0x0002
+#define EVP_HPKE_CHACHA20_POLY1305 0x0003
+
+// The following functions are AEAD algorithms which may be used with HPKE.
+OPENSSL_EXPORT const EVP_HPKE_AEAD *EVP_hpke_aes_128_gcm(void);
+OPENSSL_EXPORT const EVP_HPKE_AEAD *EVP_hpke_aes_256_gcm(void);
+OPENSSL_EXPORT const EVP_HPKE_AEAD *EVP_hpke_chacha20_poly1305(void);
+
+// EVP_HPKE_AEAD_id returns the HPKE AEAD identifier for |aead|.
+OPENSSL_EXPORT uint16_t EVP_HPKE_AEAD_id(const EVP_HPKE_AEAD *aead);
+
+// EVP_HPKE_AEAD_aead returns the |EVP_AEAD| corresponding to |aead|.
+OPENSSL_EXPORT const EVP_AEAD *EVP_HPKE_AEAD_aead(const EVP_HPKE_AEAD *aead);
+
+
+// Recipient keys.
+//
+// An HPKE recipient maintains a long-term KEM key. This library represents keys
+// with the |EVP_HPKE_KEY| type.
+
+// EVP_HPKE_KEY_zero sets an uninitialized |EVP_HPKE_KEY| to the zero state. The
+// caller should then use |EVP_HPKE_KEY_init|, |EVP_HPKE_KEY_copy|, or
+// |EVP_HPKE_KEY_generate| to finish initializing |key|.
+//
+// It is safe, but not necessary to call |EVP_HPKE_KEY_cleanup| in this state.
+// This may be used for more uniform cleanup of |EVP_HPKE_KEY|.
+OPENSSL_EXPORT void EVP_HPKE_KEY_zero(EVP_HPKE_KEY *key);
+
+// EVP_HPKE_KEY_cleanup releases memory referenced by |key|.
+OPENSSL_EXPORT void EVP_HPKE_KEY_cleanup(EVP_HPKE_KEY *key);
+
+// EVP_HPKE_KEY_new returns a newly-allocated |EVP_HPKE_KEY|, or NULL on error.
+// The caller must call |EVP_HPKE_KEY_free| on the result to release it.
+//
+// This is a convenience function for callers that need a heap-allocated
+// |EVP_HPKE_KEY|.
+OPENSSL_EXPORT EVP_HPKE_KEY *EVP_HPKE_KEY_new(void);
+
+// EVP_HPKE_KEY_free releases memory associated with |key|, which must have been
+// created with |EVP_HPKE_KEY_new|.
+OPENSSL_EXPORT void EVP_HPKE_KEY_free(EVP_HPKE_KEY *key);
+
+// EVP_HPKE_KEY_copy sets |dst| to a copy of |src|. It returns one on success
+// and zero on error. On success, the caller must call |EVP_HPKE_KEY_cleanup| to
+// release |dst|. On failure, calling |EVP_HPKE_KEY_cleanup| is safe, but not
+// necessary.
+OPENSSL_EXPORT int EVP_HPKE_KEY_copy(EVP_HPKE_KEY *dst,
+ const EVP_HPKE_KEY *src);
+
+// EVP_HPKE_KEY_init decodes |priv_key| as a private key for |kem| and
+// initializes |key| with the result. It returns one on success and zero if
+// |priv_key| was invalid. On success, the caller must call
+// |EVP_HPKE_KEY_cleanup| to release the key. On failure, calling
+// |EVP_HPKE_KEY_cleanup| is safe, but not necessary.
+OPENSSL_EXPORT int EVP_HPKE_KEY_init(EVP_HPKE_KEY *key, const EVP_HPKE_KEM *kem,
+ const uint8_t *priv_key,
+ size_t priv_key_len);
+
+// EVP_HPKE_KEY_generate sets |key| to a newly-generated key using |kem|.
+OPENSSL_EXPORT int EVP_HPKE_KEY_generate(EVP_HPKE_KEY *key,
+ const EVP_HPKE_KEM *kem);
+
+// EVP_HPKE_KEY_kem returns the HPKE KEM used by |key|.
+OPENSSL_EXPORT const EVP_HPKE_KEM *EVP_HPKE_KEY_kem(const EVP_HPKE_KEY *key);
+
+// EVP_HPKE_MAX_PUBLIC_KEY_LENGTH is the maximum length of a public key for all
+// KEMs supported by this library.
+#define EVP_HPKE_MAX_PUBLIC_KEY_LENGTH 32
+
+// EVP_HPKE_KEY_public_key writes |key|'s public key to |out| and sets
+// |*out_len| to the number of bytes written. On success, it returns one and
+// writes at most |max_out| bytes. If |max_out| is too small, it returns zero.
+// Setting |max_out| to |EVP_HPKE_MAX_PUBLIC_KEY_LENGTH| will ensure the public
+// key fits.
+OPENSSL_EXPORT int EVP_HPKE_KEY_public_key(const EVP_HPKE_KEY *key,
+ uint8_t *out, size_t *out_len,
+ size_t max_out);
+
+// EVP_HPKE_MAX_PRIVATE_KEY_LENGTH is the maximum length of a private key for
+// all KEMs supported by this library.
+#define EVP_HPKE_MAX_PRIVATE_KEY_LENGTH 32
+
+// EVP_HPKE_KEY_private_key writes |key|'s private key to |out| and sets
+// |*out_len| to the number of bytes written. On success, it returns one and
+// writes at most |max_out| bytes. If |max_out| is too small, it returns zero.
+// Setting |max_out| to |EVP_HPKE_MAX_PRIVATE_KEY_LENGTH| will ensure the
+// private key fits.
+OPENSSL_EXPORT int EVP_HPKE_KEY_private_key(const EVP_HPKE_KEY *key,
+ uint8_t *out, size_t *out_len,
+ size_t max_out);
+
+
+// Encryption contexts.
+//
+// An HPKE encryption context is represented by the |EVP_HPKE_CTX| type.
+
+// EVP_HPKE_CTX_zero sets an uninitialized |EVP_HPKE_CTX| to the zero state. The
+// caller should then use one of the |EVP_HPKE_CTX_setup_*| functions to finish
+// setting up |ctx|.
+//
+// It is safe, but not necessary to call |EVP_HPKE_CTX_cleanup| in this state.
+// This may be used for more uniform cleanup of |EVP_HPKE_CTX|.
+OPENSSL_EXPORT void EVP_HPKE_CTX_zero(EVP_HPKE_CTX *ctx);
+
+// EVP_HPKE_CTX_cleanup releases memory referenced by |ctx|. |ctx| must have
+// been initialized with |EVP_HPKE_CTX_zero| or one of the
+// |EVP_HPKE_CTX_setup_*| functions.
+OPENSSL_EXPORT void EVP_HPKE_CTX_cleanup(EVP_HPKE_CTX *ctx);
+
+// EVP_HPKE_CTX_new returns a newly-allocated |EVP_HPKE_CTX|, or NULL on error.
+// The caller must call |EVP_HPKE_CTX_free| on the result to release it.
+//
+// This is a convenience function for callers that need a heap-allocated
+// |EVP_HPKE_CTX|.
+OPENSSL_EXPORT EVP_HPKE_CTX *EVP_HPKE_CTX_new(void);
+
+// EVP_HPKE_CTX_free releases memory associated with |ctx|, which must have been
+// created with |EVP_HPKE_CTX_new|.
+OPENSSL_EXPORT void EVP_HPKE_CTX_free(EVP_HPKE_CTX *ctx);
+
+// EVP_HPKE_MAX_ENC_LENGTH is the maximum length of "enc", the encapsulated
+// shared secret, for all supported KEMs in this library.
+#define EVP_HPKE_MAX_ENC_LENGTH 32
+
+// EVP_HPKE_CTX_setup_sender implements the SetupBaseS HPKE operation. It
+// encapsulates a shared secret for |peer_public_key| and sets up |ctx| as a
+// sender context. It writes the encapsulated shared secret to |out_enc| and
+// sets |*out_enc_len| to the number of bytes written. It writes at most
+// |max_enc| bytes and fails if the buffer is too small. Setting |max_enc| to at
+// least |EVP_HPKE_MAX_ENC_LENGTH| will ensure the buffer is large enough.
+//
+// This function returns one on success and zero on error. Note that
+// |peer_public_key| may be invalid, in which case this function will return an
+// error.
+//
+// On success, callers may call |EVP_HPKE_CTX_seal| to encrypt messages for the
+// recipient. Callers must then call |EVP_HPKE_CTX_cleanup| when done. On
+// failure, calling |EVP_HPKE_CTX_cleanup| is safe, but not required.
+OPENSSL_EXPORT int EVP_HPKE_CTX_setup_sender(
+ EVP_HPKE_CTX *ctx, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc,
+ const EVP_HPKE_KEM *kem, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead,
+ const uint8_t *peer_public_key, size_t peer_public_key_len,
+ const uint8_t *info, size_t info_len);
+
+// EVP_HPKE_CTX_setup_sender_with_seed_for_testing behaves like
+// |EVP_HPKE_CTX_setup_sender|, but takes a seed to behave deterministically.
+// The seed's format depends on |kem|. For X25519, it is the sender's
+// ephemeral private key.
+OPENSSL_EXPORT int EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
+ EVP_HPKE_CTX *ctx, uint8_t *out_enc, size_t *out_enc_len, size_t max_enc,
+ const EVP_HPKE_KEM *kem, const EVP_HPKE_KDF *kdf, const EVP_HPKE_AEAD *aead,
+ const uint8_t *peer_public_key, size_t peer_public_key_len,
+ const uint8_t *info, size_t info_len, const uint8_t *seed, size_t seed_len);
+
+// EVP_HPKE_CTX_setup_recipient implements the SetupBaseR HPKE operation. It
+// decapsulates the shared secret in |enc| with |key| and sets up |ctx| as a
+// recipient context. It returns one on success and zero on failure. Note that
+// |enc| may be invalid, in which case this function will return an error.
+//
+// On success, callers may call |EVP_HPKE_CTX_open| to decrypt messages from the
+// sender. Callers must then call |EVP_HPKE_CTX_cleanup| when done. On failure,
+// calling |EVP_HPKE_CTX_cleanup| is safe, but not required.
+OPENSSL_EXPORT int EVP_HPKE_CTX_setup_recipient(
+ EVP_HPKE_CTX *ctx, const EVP_HPKE_KEY *key, const EVP_HPKE_KDF *kdf,
+ const EVP_HPKE_AEAD *aead, const uint8_t *enc, size_t enc_len,
+ const uint8_t *info, size_t info_len);
+
+
+// Using an HPKE context.
+//
+// Once set up, callers may encrypt or decrypt with an |EVP_HPKE_CTX| using the
+// following functions.
+
+// EVP_HPKE_CTX_open uses the HPKE context |ctx| to authenticate |in_len| bytes
+// from |in| and |ad_len| bytes from |ad| and to decrypt at most |in_len| bytes
+// into |out|. It returns one on success, and zero otherwise.
+//
+// This operation will fail if the |ctx| context is not set up as a receiver.
+//
+// Note that HPKE encryption is stateful and ordered. The sender's first call to
+// |EVP_HPKE_CTX_seal| must correspond to the recipient's first call to
+// |EVP_HPKE_CTX_open|, etc.
+//
+// At most |in_len| bytes are written to |out|. In order to ensure success,
+// |max_out_len| should be at least |in_len|. On successful return, |*out_len|
+// is set to the actual number of bytes written.
+OPENSSL_EXPORT int EVP_HPKE_CTX_open(EVP_HPKE_CTX *ctx, uint8_t *out,
+ size_t *out_len, size_t max_out_len,
+ const uint8_t *in, size_t in_len,
+ const uint8_t *ad, size_t ad_len);
+
+// EVP_HPKE_CTX_seal uses the HPKE context |ctx| to encrypt and authenticate
+// |in_len| bytes of ciphertext |in| and authenticate |ad_len| bytes from |ad|,
+// writing the result to |out|. It returns one on success and zero otherwise.
+//
+// This operation will fail if the |ctx| context is not set up as a sender.
+//
+// Note that HPKE encryption is stateful and ordered. The sender's first call to
+// |EVP_HPKE_CTX_seal| must correspond to the recipient's first call to
+// |EVP_HPKE_CTX_open|, etc.
+//
+// At most, |max_out_len| encrypted bytes are written to |out|. On successful
+// return, |*out_len| is set to the actual number of bytes written.
+//
+// To ensure success, |max_out_len| should be |in_len| plus the result of
+// |EVP_HPKE_CTX_max_overhead| or |EVP_HPKE_MAX_OVERHEAD|.
+OPENSSL_EXPORT int EVP_HPKE_CTX_seal(EVP_HPKE_CTX *ctx, uint8_t *out,
+ size_t *out_len, size_t max_out_len,
+ const uint8_t *in, size_t in_len,
+ const uint8_t *ad, size_t ad_len);
+
+// EVP_HPKE_CTX_export uses the HPKE context |ctx| to export a secret of
+// |secret_len| bytes into |out|. This function uses |context_len| bytes from
+// |context| as a context string for the secret. This is necessary to separate
+// different uses of exported secrets and bind relevant caller-specific context
+// into the output. It returns one on success and zero otherwise.
+OPENSSL_EXPORT int EVP_HPKE_CTX_export(const EVP_HPKE_CTX *ctx, uint8_t *out,
+ size_t secret_len,
+ const uint8_t *context,
+ size_t context_len);
+
+// EVP_HPKE_MAX_OVERHEAD contains the largest value that
+// |EVP_HPKE_CTX_max_overhead| would ever return for any context.
+#define EVP_HPKE_MAX_OVERHEAD EVP_AEAD_MAX_OVERHEAD
+
+// EVP_HPKE_CTX_max_overhead returns the maximum number of additional bytes
+// added by sealing data with |EVP_HPKE_CTX_seal|. The |ctx| context must be set
+// up as a sender.
+OPENSSL_EXPORT size_t EVP_HPKE_CTX_max_overhead(const EVP_HPKE_CTX *ctx);
+
+// EVP_HPKE_CTX_aead returns |ctx|'s configured AEAD, or NULL if the context has
+// not been set up.
+OPENSSL_EXPORT const EVP_HPKE_AEAD *EVP_HPKE_CTX_aead(const EVP_HPKE_CTX *ctx);
+
+// EVP_HPKE_CTX_kdf returns |ctx|'s configured KDF, or NULL if the context has
+// not been set up.
+OPENSSL_EXPORT const EVP_HPKE_KDF *EVP_HPKE_CTX_kdf(const EVP_HPKE_CTX *ctx);
+
+
+// Private structures.
+//
+// The following structures are exported so their types are stack-allocatable,
+// but accessing or modifying their fields is forbidden.
+
+struct evp_hpke_ctx_st {
+ const EVP_HPKE_AEAD *aead;
+ const EVP_HPKE_KDF *kdf;
+ EVP_AEAD_CTX aead_ctx;
+ uint8_t base_nonce[EVP_AEAD_MAX_NONCE_LENGTH];
+ uint8_t exporter_secret[EVP_MAX_MD_SIZE];
+ uint64_t seq;
+ int is_sender;
+};
+
+struct evp_hpke_key_st {
+ const EVP_HPKE_KEM *kem;
+ uint8_t private_key[X25519_PRIVATE_KEY_LEN];
+ uint8_t public_key[X25519_PUBLIC_VALUE_LEN];
+};
+
+
+#if defined(__cplusplus)
+} // extern C
+#endif
+
+#if !defined(BORINGSSL_NO_CXX)
+extern "C++" {
+
+BSSL_NAMESPACE_BEGIN
+
+using ScopedEVP_HPKE_CTX =
+ internal::StackAllocated<EVP_HPKE_CTX, void, EVP_HPKE_CTX_zero,
+ EVP_HPKE_CTX_cleanup>;
+using ScopedEVP_HPKE_KEY =
+ internal::StackAllocated<EVP_HPKE_KEY, void, EVP_HPKE_KEY_zero,
+ EVP_HPKE_KEY_cleanup>;
+
+BORINGSSL_MAKE_DELETER(EVP_HPKE_CTX, EVP_HPKE_CTX_free)
+BORINGSSL_MAKE_DELETER(EVP_HPKE_KEY, EVP_HPKE_KEY_free)
+
+BSSL_NAMESPACE_END
+
+} // extern C++
+#endif
+
+#endif // OPENSSL_HEADER_CRYPTO_HPKE_INTERNAL_H
diff --git a/deps/boringssl/src/include/openssl/hrss.h b/deps/boringssl/src/include/openssl/hrss.h
index 5390696..016fe67 100644
--- a/deps/boringssl/src/include/openssl/hrss.h
+++ b/deps/boringssl/src/include/openssl/hrss.h
@@ -59,29 +59,31 @@ struct HRSS_public_key {
(HRSS_POLY3_BYTES * 2 + HRSS_PUBLIC_KEY_BYTES + 2 + 32)
// HRSS_generate_key is a deterministic function that outputs a public and
-// private key based on the given entropy.
-OPENSSL_EXPORT void HRSS_generate_key(
+// private key based on the given entropy. It returns one on success or zero
+// on malloc failure.
+OPENSSL_EXPORT int HRSS_generate_key(
struct HRSS_public_key *out_pub, struct HRSS_private_key *out_priv,
const uint8_t input[HRSS_GENERATE_KEY_BYTES]);
// HRSS_encap is a deterministic function the generates and encrypts a random
// session key from the given entropy, writing those values to |out_shared_key|
-// and |out_ciphertext|, respectively.
-OPENSSL_EXPORT void HRSS_encap(uint8_t out_ciphertext[HRSS_CIPHERTEXT_BYTES],
- uint8_t out_shared_key[HRSS_KEY_BYTES],
- const struct HRSS_public_key *in_pub,
- const uint8_t in[HRSS_ENCAP_BYTES]);
+// and |out_ciphertext|, respectively. It returns one on success or zero on
+// malloc failure.
+OPENSSL_EXPORT int HRSS_encap(uint8_t out_ciphertext[HRSS_CIPHERTEXT_BYTES],
+ uint8_t out_shared_key[HRSS_KEY_BYTES],
+ const struct HRSS_public_key *in_pub,
+ const uint8_t in[HRSS_ENCAP_BYTES]);
// HRSS_decap decrypts a session key from |ciphertext_len| bytes of
// |ciphertext|. If the ciphertext is valid, the decrypted key is written to
// |out_shared_key|. Otherwise the HMAC of |ciphertext| under a secret key (kept
// in |in_priv|) is written. If the ciphertext is the wrong length then it will
// leak which was done via side-channels. Otherwise it should perform either
-// action in constant-time.
-OPENSSL_EXPORT void HRSS_decap(uint8_t out_shared_key[HRSS_KEY_BYTES],
- const struct HRSS_private_key *in_priv,
- const uint8_t *ciphertext,
- size_t ciphertext_len);
+// action in constant-time. It returns one on success (whether the ciphertext
+// was valid or not) and zero on malloc failure.
+OPENSSL_EXPORT int HRSS_decap(uint8_t out_shared_key[HRSS_KEY_BYTES],
+ const struct HRSS_private_key *in_priv,
+ const uint8_t *ciphertext, size_t ciphertext_len);
// HRSS_marshal_public_key serialises |in_pub| to |out|.
OPENSSL_EXPORT void HRSS_marshal_public_key(
diff --git a/deps/boringssl/src/include/openssl/lhash.h b/deps/boringssl/src/include/openssl/lhash.h
index 29e09c8..1297541 100644
--- a/deps/boringssl/src/include/openssl/lhash.h
+++ b/deps/boringssl/src/include/openssl/lhash.h
@@ -58,223 +58,22 @@
#define OPENSSL_HEADER_LHASH_H
#include <openssl/base.h>
-#include <openssl/type_check.h>
#if defined(__cplusplus)
extern "C" {
#endif
-// lhash is a traditional, chaining hash table that automatically expands and
-// contracts as needed. One should not use the lh_* functions directly, rather
-// use the type-safe macro wrappers:
-//
-// A hash table of a specific type of object has type |LHASH_OF(type)|. This
-// can be defined (once) with |DEFINE_LHASH_OF(type)| and declared where needed
-// with |DECLARE_LHASH_OF(type)|. For example:
-//
-// struct foo {
-// int bar;
-// };
-//
-// DEFINE_LHASH_OF(struct foo)
-//
-// Although note that the hash table will contain /pointers/ to |foo|.
-//
-// A macro will be defined for each of the lh_* functions below. For
-// LHASH_OF(foo), the macros would be lh_foo_new, lh_foo_num_items etc.
+// lhash is an internal library and not exported for use outside BoringSSL. This
+// header is provided for compatibility with code that expects OpenSSL.
+// These two macros are exported for compatibility with existing callers of
+// |X509V3_EXT_conf_nid|. Do not use these symbols outside BoringSSL.
#define LHASH_OF(type) struct lhash_st_##type
-
#define DECLARE_LHASH_OF(type) LHASH_OF(type);
-// lhash_item_st is an element of a hash chain. It points to the opaque data
-// for this element and to the next item in the chain. The linked-list is NULL
-// terminated.
-typedef struct lhash_item_st {
- void *data;
- struct lhash_item_st *next;
- // hash contains the cached, hash value of |data|.
- uint32_t hash;
-} LHASH_ITEM;
-
-// lhash_cmp_func is a comparison function that returns a value equal, or not
-// equal, to zero depending on whether |*a| is equal, or not equal to |*b|,
-// respectively. Note the difference between this and |stack_cmp_func| in that
-// this takes pointers to the objects directly.
-//
-// This function's actual type signature is int (*)(const T*, const T*). The
-// low-level |lh_*| functions will be passed a type-specific wrapper to call it
-// correctly.
-typedef int (*lhash_cmp_func)(const void *a, const void *b);
-typedef int (*lhash_cmp_func_helper)(lhash_cmp_func func, const void *a,
- const void *b);
-
-// lhash_hash_func is a function that maps an object to a uniformly distributed
-// uint32_t.
-//
-// This function's actual type signature is uint32_t (*)(const T*). The
-// low-level |lh_*| functions will be passed a type-specific wrapper to call it
-// correctly.
-typedef uint32_t (*lhash_hash_func)(const void *a);
-typedef uint32_t (*lhash_hash_func_helper)(lhash_hash_func func, const void *a);
-
-typedef struct lhash_st _LHASH;
-
-// lh_new returns a new, empty hash table or NULL on error.
-OPENSSL_EXPORT _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp);
-
-// lh_free frees the hash table itself but none of the elements. See
-// |lh_doall|.
-OPENSSL_EXPORT void lh_free(_LHASH *lh);
-
-// lh_num_items returns the number of items in |lh|.
-OPENSSL_EXPORT size_t lh_num_items(const _LHASH *lh);
-
-// lh_retrieve finds an element equal to |data| in the hash table and returns
-// it. If no such element exists, it returns NULL.
-OPENSSL_EXPORT void *lh_retrieve(const _LHASH *lh, const void *data,
- lhash_hash_func_helper call_hash_func,
- lhash_cmp_func_helper call_cmp_func);
-
-// lh_retrieve_key finds an element matching |key|, given the specified hash and
-// comparison function. This differs from |lh_retrieve| in that the key may be a
-// different type than the values stored in |lh|. |key_hash| and |cmp_key| must
-// be compatible with the functions passed into |lh_new|.
-OPENSSL_EXPORT void *lh_retrieve_key(const _LHASH *lh, const void *key,
- uint32_t key_hash,
- int (*cmp_key)(const void *key,
- const void *value));
-
-// lh_insert inserts |data| into the hash table. If an existing element is
-// equal to |data| (with respect to the comparison function) then |*old_data|
-// will be set to that value and it will be replaced. Otherwise, or in the
-// event of an error, |*old_data| will be set to NULL. It returns one on
-// success or zero in the case of an allocation error.
-OPENSSL_EXPORT int lh_insert(_LHASH *lh, void **old_data, void *data,
- lhash_hash_func_helper call_hash_func,
- lhash_cmp_func_helper call_cmp_func);
-
-// lh_delete removes an element equal to |data| from the hash table and returns
-// it. If no such element is found, it returns NULL.
-OPENSSL_EXPORT void *lh_delete(_LHASH *lh, const void *data,
- lhash_hash_func_helper call_hash_func,
- lhash_cmp_func_helper call_cmp_func);
-
-// lh_doall_arg calls |func| on each element of the hash table and also passes
-// |arg| as the second argument.
-// TODO(fork): rename this
-OPENSSL_EXPORT void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *),
- void *arg);
-
-// lh_strhash is the default hash function which processes NUL-terminated
-// strings.
-OPENSSL_EXPORT uint32_t lh_strhash(const char *c);
-
-#define DEFINE_LHASH_OF(type) \
- DECLARE_LHASH_OF(type) \
- \
- typedef int (*lhash_##type##_cmp_func)(const type *, const type *); \
- typedef uint32_t (*lhash_##type##_hash_func)(const type *); \
- \
- OPENSSL_INLINE int lh_##type##_call_cmp_func(lhash_cmp_func func, \
- const void *a, const void *b) { \
- return ((lhash_##type##_cmp_func)func)((const type *)a, (const type *)b); \
- } \
- \
- OPENSSL_INLINE uint32_t lh_##type##_call_hash_func(lhash_hash_func func, \
- const void *a) { \
- return ((lhash_##type##_hash_func)func)((const type *)a); \
- } \
- \
- OPENSSL_INLINE LHASH_OF(type) * \
- lh_##type##_new(lhash_##type##_hash_func hash, \
- lhash_##type##_cmp_func comp) { \
- return (LHASH_OF(type) *)lh_new((lhash_hash_func)hash, \
- (lhash_cmp_func)comp); \
- } \
- \
- OPENSSL_INLINE void lh_##type##_free(LHASH_OF(type) *lh) { \
- lh_free((_LHASH *)lh); \
- } \
- \
- OPENSSL_INLINE size_t lh_##type##_num_items(const LHASH_OF(type) *lh) { \
- return lh_num_items((const _LHASH *)lh); \
- } \
- \
- OPENSSL_INLINE type *lh_##type##_retrieve(const LHASH_OF(type) *lh, \
- const type *data) { \
- return (type *)lh_retrieve((const _LHASH *)lh, data, \
- lh_##type##_call_hash_func, \
- lh_##type##_call_cmp_func); \
- } \
- \
- typedef struct { \
- int (*cmp_key)(const void *key, const type *value); \
- const void *key; \
- } LHASH_CMP_KEY_##type; \
- \
- OPENSSL_INLINE int lh_##type##_call_cmp_key(const void *key, \
- const void *value) { \
- const LHASH_CMP_KEY_##type *cb = (const LHASH_CMP_KEY_##type *)key; \
- return cb->cmp_key(cb->key, (const type *)value); \
- } \
- \
- OPENSSL_INLINE type *lh_##type##_retrieve_key( \
- const LHASH_OF(type) *lh, const void *key, uint32_t key_hash, \
- int (*cmp_key)(const void *key, const type *value)) { \
- LHASH_CMP_KEY_##type cb = {cmp_key, key}; \
- return (type *)lh_retrieve_key((const _LHASH *)lh, &cb, key_hash, \
- lh_##type##_call_cmp_key); \
- } \
- \
- OPENSSL_INLINE int lh_##type##_insert(LHASH_OF(type) *lh, type **old_data, \
- type *data) { \
- void *old_data_void = NULL; \
- int ret = \
- lh_insert((_LHASH *)lh, &old_data_void, data, \
- lh_##type##_call_hash_func, lh_##type##_call_cmp_func); \
- *old_data = (type *)old_data_void; \
- return ret; \
- } \
- \
- OPENSSL_INLINE type *lh_##type##_delete(LHASH_OF(type) *lh, \
- const type *data) { \
- return (type *)lh_delete((_LHASH *)lh, data, lh_##type##_call_hash_func, \
- lh_##type##_call_cmp_func); \
- } \
- \
- typedef struct { \
- void (*doall)(type *); \
- void (*doall_arg)(type *, void *); \
- void *arg; \
- } LHASH_DOALL_##type; \
- \
- OPENSSL_INLINE void lh_##type##_call_doall(void *value, void *arg) { \
- const LHASH_DOALL_##type *cb = (const LHASH_DOALL_##type *)arg; \
- cb->doall((type *)value); \
- } \
- \
- OPENSSL_INLINE void lh_##type##_call_doall_arg(void *value, void *arg) { \
- const LHASH_DOALL_##type *cb = (const LHASH_DOALL_##type *)arg; \
- cb->doall_arg((type *)value, cb->arg); \
- } \
- \
- OPENSSL_INLINE void lh_##type##_doall(LHASH_OF(type) *lh, \
- void (*func)(type *)) { \
- LHASH_DOALL_##type cb = {func, NULL, NULL}; \
- lh_doall_arg((_LHASH *)lh, lh_##type##_call_doall, &cb); \
- } \
- \
- OPENSSL_INLINE void lh_##type##_doall_arg( \
- LHASH_OF(type) *lh, void (*func)(type *, void *), void *arg) { \
- LHASH_DOALL_##type cb = {NULL, func, arg}; \
- lh_doall_arg((_LHASH *)lh, lh_##type##_call_doall_arg, &cb); \
- }
-
-
#if defined(__cplusplus)
} // extern C
#endif
diff --git a/deps/boringssl/src/include/openssl/mem.h b/deps/boringssl/src/include/openssl/mem.h
index cceabcd..9906d5b 100644
--- a/deps/boringssl/src/include/openssl/mem.h
+++ b/deps/boringssl/src/include/openssl/mem.h
@@ -101,6 +101,9 @@ OPENSSL_EXPORT int CRYPTO_memcmp(const void *a, const void *b, size_t len);
// OPENSSL_hash32 implements the 32 bit, FNV-1a hash.
OPENSSL_EXPORT uint32_t OPENSSL_hash32(const void *ptr, size_t len);
+// OPENSSL_strhash calls |OPENSSL_hash32| on the NUL-terminated string |s|.
+OPENSSL_EXPORT uint32_t OPENSSL_strhash(const char *s);
+
// OPENSSL_strdup has the same behaviour as strdup(3).
OPENSSL_EXPORT char *OPENSSL_strdup(const char *s);
diff --git a/deps/boringssl/src/include/openssl/obj.h b/deps/boringssl/src/include/openssl/obj.h
index 764188f..ad7271e 100644
--- a/deps/boringssl/src/include/openssl/obj.h
+++ b/deps/boringssl/src/include/openssl/obj.h
@@ -84,17 +84,24 @@ extern "C" {
// Basic operations.
-// OBJ_dup returns a duplicate copy of |obj| or NULL on allocation failure.
+// OBJ_dup returns a duplicate copy of |obj| or NULL on allocation failure. The
+// caller must call |ASN1_OBJECT_free| on the result to release it.
OPENSSL_EXPORT ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *obj);
// OBJ_cmp returns a value less than, equal to or greater than zero if |a| is
// less than, equal to or greater than |b|, respectively.
OPENSSL_EXPORT int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b);
-// OBJ_get0_data returns a pointer to the DER representation of |obj|.
+// OBJ_get0_data returns a pointer to the DER representation of |obj|. This is
+// the contents of the DER-encoded identifier, not including the tag and length.
+// If |obj| does not have an associated object identifier (i.e. it is a nid-only
+// value), this value is the empty string.
OPENSSL_EXPORT const uint8_t *OBJ_get0_data(const ASN1_OBJECT *obj);
-// OBJ_length returns the length of the DER representation of |obj|.
+// OBJ_length returns the length of the DER representation of |obj|. This is the
+// contents of the DER-encoded identifier, not including the tag and length. If
+// |obj| does not have an associated object identifier (i.e. it is a nid-only
+// value), this value is the empty string.
OPENSSL_EXPORT size_t OBJ_length(const ASN1_OBJECT *obj);
@@ -124,9 +131,22 @@ OPENSSL_EXPORT int OBJ_txt2nid(const char *s);
// Getting information about nids.
-// OBJ_nid2obj returns the ASN1_OBJECT corresponding to |nid|, or NULL if |nid|
-// is unknown.
-OPENSSL_EXPORT const ASN1_OBJECT *OBJ_nid2obj(int nid);
+// OBJ_nid2obj returns the |ASN1_OBJECT| corresponding to |nid|, or NULL if
+// |nid| is unknown.
+//
+// Although the output is not const, this function returns a static, immutable
+// |ASN1_OBJECT|. It is not necessary to release the object with
+// |ASN1_OBJECT_free|.
+//
+// However, functions like |X509_ALGOR_set0| expect to take ownership of a
+// possibly dynamically-allocated |ASN1_OBJECT|. |ASN1_OBJECT_free| is a no-op
+// for static |ASN1_OBJECT|s, so |OBJ_nid2obj| is compatible with such
+// functions.
+//
+// Callers are encouraged to store the result of this function in a const
+// pointer. However, if using functions like |X509_ALGOR_set0|, callers may use
+// a non-const pointer and manage ownership.
+OPENSSL_EXPORT ASN1_OBJECT *OBJ_nid2obj(int nid);
// OBJ_nid2sn returns the short name for |nid|, or NULL if |nid| is unknown.
OPENSSL_EXPORT const char *OBJ_nid2sn(int nid);
diff --git a/deps/boringssl/src/include/openssl/pem.h b/deps/boringssl/src/include/openssl/pem.h
index f39989e..a94f276 100644
--- a/deps/boringssl/src/include/openssl/pem.h
+++ b/deps/boringssl/src/include/openssl/pem.h
@@ -112,15 +112,6 @@ extern "C" {
// write. Now they are all implemented with either:
// IMPLEMENT_PEM_rw(...) or IMPLEMENT_PEM_rw_cb(...)
-#ifdef OPENSSL_NO_FP_API
-
-#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) //
-#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) //
-#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) //
-#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) //
-#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) //
-
-#else
#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \
static void *pem_read_##name##_d2i(void **x, const unsigned char **inp, \
@@ -173,7 +164,6 @@ extern "C" {
cb, u); \
}
-#endif
#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \
static void *pem_read_bio_##name##_d2i(void **x, const unsigned char **inp, \
@@ -260,14 +250,6 @@ extern "C" {
// These are the same except they are for the declarations
-#if defined(OPENSSL_NO_FP_API)
-
-#define DECLARE_PEM_read_fp(name, type) //
-#define DECLARE_PEM_write_fp(name, type) //
-#define DECLARE_PEM_write_cb_fp(name, type) //
-
-#else
-
#define DECLARE_PEM_read_fp(name, type) \
OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, \
pem_password_cb *cb, void *u);
@@ -283,8 +265,6 @@ extern "C" {
FILE *fp, type *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, \
pem_password_cb *cb, void *u);
-#endif
-
#define DECLARE_PEM_read_bio(name, type) \
OPENSSL_EXPORT type *PEM_read_bio_##name(BIO *bp, type **x, \
pem_password_cb *cb, void *u);
diff --git a/deps/boringssl/src/include/openssl/pkcs7.h b/deps/boringssl/src/include/openssl/pkcs7.h
index cb6155f..8f2a885 100644
--- a/deps/boringssl/src/include/openssl/pkcs7.h
+++ b/deps/boringssl/src/include/openssl/pkcs7.h
@@ -38,7 +38,10 @@ DECLARE_STACK_OF(X509_CRL)
// success and zero on error. |cbs| is advanced passed the structure.
//
// Note that a SignedData structure may contain no certificates, in which case
-// this function succeeds but does not append any certificates.
+// this function succeeds but does not append any certificates. Additionally,
+// certificates in SignedData structures are unordered. Callers should not
+// assume a particular order in |*out_certs| and may need to search for matches
+// or run path-building algorithms.
OPENSSL_EXPORT int PKCS7_get_raw_certificates(
STACK_OF(CRYPTO_BUFFER) *out_certs, CBS *cbs, CRYPTO_BUFFER_POOL *pool);
@@ -47,7 +50,9 @@ OPENSSL_EXPORT int PKCS7_get_raw_certificates(
OPENSSL_EXPORT int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs);
// PKCS7_bundle_certificates appends a PKCS#7, SignedData structure containing
-// |certs| to |out|. It returns one on success and zero on error.
+// |certs| to |out|. It returns one on success and zero on error. Note that
+// certificates in SignedData structures are unordered. The order in |certs|
+// will not be preserved.
OPENSSL_EXPORT int PKCS7_bundle_certificates(
CBB *out, const STACK_OF(X509) *certs);
@@ -56,11 +61,15 @@ OPENSSL_EXPORT int PKCS7_bundle_certificates(
// |cbs| is advanced passed the structure.
//
// Note that a SignedData structure may contain no CRLs, in which case this
-// function succeeds but does not append any CRLs.
+// function succeeds but does not append any CRLs. Additionally, CRLs in
+// SignedData structures are unordered. Callers should not assume an order in
+// |*out_crls| and may need to search for matches.
OPENSSL_EXPORT int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs);
// PKCS7_bundle_CRLs appends a PKCS#7, SignedData structure containing
-// |crls| to |out|. It returns one on success and zero on error.
+// |crls| to |out|. It returns one on success and zero on error. Note that CRLs
+// in SignedData structures are unordered. The order in |crls| will not be
+// preserved.
OPENSSL_EXPORT int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls);
// PKCS7_get_PEM_certificates reads a PEM-encoded, PKCS#7, SignedData structure
@@ -68,7 +77,10 @@ OPENSSL_EXPORT int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls);
// returns one on success and zero on error.
//
// Note that a SignedData structure may contain no certificates, in which case
-// this function succeeds but does not append any certificates.
+// this function succeeds but does not append any certificates. Additionally,
+// certificates in SignedData structures are unordered. Callers should not
+// assume a particular order in |*out_certs| and may need to search for matches
+// or run path-building algorithms.
OPENSSL_EXPORT int PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs,
BIO *pem_bio);
@@ -77,7 +89,9 @@ OPENSSL_EXPORT int PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs,
// success and zero on error.
//
// Note that a SignedData structure may contain no CRLs, in which case this
-// function succeeds but does not append any CRLs.
+// function succeeds but does not append any CRLs. Additionally, CRLs in
+// SignedData structures are unordered. Callers should not assume an order in
+// |*out_crls| and may need to search for matches.
OPENSSL_EXPORT int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls,
BIO *pem_bio);
@@ -101,6 +115,7 @@ typedef struct {
typedef void PKCS7_ENVELOPE;
typedef void PKCS7_DIGEST;
typedef void PKCS7_ENCRYPT;
+typedef void PKCS7_SIGNER_INFO;
typedef struct {
uint8_t *ber_bytes;
@@ -183,6 +198,7 @@ OPENSSL_EXPORT int PKCS7_type_is_signedAndEnveloped(const PKCS7 *p7);
#define PKCS7_NOATTR 0x100
#define PKCS7_NOSMIMECAP 0x200
#define PKCS7_STREAM 0x1000
+#define PKCS7_PARTIAL 0x4000
// PKCS7_sign assembles |certs| into a PKCS#7 signed data ContentInfo with
// external data and no signatures. It returns a newly-allocated |PKCS7| on
@@ -190,7 +206,9 @@ OPENSSL_EXPORT int PKCS7_type_is_signedAndEnveloped(const PKCS7 *p7);
// ignored. |flags| must be equal to |PKCS7_DETACHED|.
//
// Note this function only implements a subset of the corresponding OpenSSL
-// function. It is provided for backwards compatibility only.
+// function. It is provided for backwards compatibility only. Additionally,
+// certificates in SignedData structures are unordered. The order of |certs|
+// will not be preserved.
OPENSSL_EXPORT PKCS7 *PKCS7_sign(X509 *sign_cert, EVP_PKEY *pkey,
STACK_OF(X509) *certs, BIO *data, int flags);
diff --git a/deps/boringssl/src/include/openssl/pkcs8.h b/deps/boringssl/src/include/openssl/pkcs8.h
index 385b995..4f21ef3 100644
--- a/deps/boringssl/src/include/openssl/pkcs8.h
+++ b/deps/boringssl/src/include/openssl/pkcs8.h
@@ -175,7 +175,9 @@ OPENSSL_EXPORT int i2d_PKCS12_fp(FILE *fp, const PKCS12 *p12);
//
// Note if |p12| does not contain a private key, both |*out_pkey| and
// |*out_cert| will be set to NULL and all certificates will be returned via
-// |*out_ca_certs|.
+// |*out_ca_certs|. Also note this function differs from OpenSSL in that extra
+// certificates are returned in the order they appear in the file. OpenSSL 1.1.1
+// returns them in reverse order, but this will be fixed in OpenSSL 3.0.
//
// It returns one on success and zero on error.
//
@@ -206,6 +208,12 @@ OPENSSL_EXPORT int PKCS12_verify_mac(const PKCS12 *p12, const char *password,
// Each of |key_nid|, |cert_nid|, |iterations|, and |mac_iterations| may be zero
// to use defaults, which are |NID_pbe_WithSHA1And3_Key_TripleDES_CBC|,
// |NID_pbe_WithSHA1And40BitRC2_CBC|, 2048, and one, respectively.
+//
+// |key_nid| or |cert_nid| may also be -1 to disable encryption of the key or
+// certificate, respectively. This option is not recommended and is only
+// implemented for compatibility with external packages. Note the output still
+// requires a password for the MAC. Unencrypted keys in PKCS#12 are also not
+// widely supported and may not open in other implementations.
OPENSSL_EXPORT PKCS12 *PKCS12_create(const char *password, const char *name,
const EVP_PKEY *pkey, X509 *cert,
const STACK_OF(X509) *chain, int key_nid,
diff --git a/deps/boringssl/src/include/openssl/rand.h b/deps/boringssl/src/include/openssl/rand.h
index b07015b..bd41f9e 100644
--- a/deps/boringssl/src/include/openssl/rand.h
+++ b/deps/boringssl/src/include/openssl/rand.h
@@ -103,8 +103,8 @@ OPENSSL_EXPORT RAND_METHOD *RAND_OpenSSL(void);
// RAND_get_rand_method returns |RAND_SSLeay()|.
OPENSSL_EXPORT const RAND_METHOD *RAND_get_rand_method(void);
-// RAND_set_rand_method does nothing.
-OPENSSL_EXPORT void RAND_set_rand_method(const RAND_METHOD *);
+// RAND_set_rand_method returns one.
+OPENSSL_EXPORT int RAND_set_rand_method(const RAND_METHOD *);
#if defined(__cplusplus)
diff --git a/deps/boringssl/src/include/openssl/rsa.h b/deps/boringssl/src/include/openssl/rsa.h
index ed6df69..27bc7bf 100644
--- a/deps/boringssl/src/include/openssl/rsa.h
+++ b/deps/boringssl/src/include/openssl/rsa.h
@@ -283,120 +283,155 @@ OPENSSL_EXPORT int RSA_private_decrypt(size_t flen, const uint8_t *from,
// These functions are considered non-mutating for thread-safety purposes and
// may be used concurrently.
-// RSA_sign signs |in_len| bytes of digest from |in| with |rsa| using
+// RSA_sign signs |digest_len| bytes of digest from |digest| with |rsa| using
// RSASSA-PKCS1-v1_5. It writes, at most, |RSA_size(rsa)| bytes to |out|. On
// successful return, the actual number of bytes written is written to
// |*out_len|.
//
-// The |hash_nid| argument identifies the hash function used to calculate |in|
-// and is embedded in the resulting signature. For example, it might be
+// The |hash_nid| argument identifies the hash function used to calculate
+// |digest| and is embedded in the resulting signature. For example, it might be
// |NID_sha256|.
//
// It returns 1 on success and zero on error.
-OPENSSL_EXPORT int RSA_sign(int hash_nid, const uint8_t *in,
- unsigned int in_len, uint8_t *out,
- unsigned int *out_len, RSA *rsa);
+//
+// WARNING: |digest| must be the result of hashing the data to be signed with
+// |hash_nid|. Passing unhashed inputs will not result in a secure signature
+// scheme.
+OPENSSL_EXPORT int RSA_sign(int hash_nid, const uint8_t *digest,
+ unsigned digest_len, uint8_t *out,
+ unsigned *out_len, RSA *rsa);
-// RSA_sign_pss_mgf1 signs |in_len| bytes from |in| with the public key from
-// |rsa| using RSASSA-PSS with MGF1 as the mask generation function. It writes,
-// at most, |max_out| bytes of signature data to |out|. The |max_out| argument
-// must be, at least, |RSA_size| in order to ensure success. It returns 1 on
-// success or zero on error.
+// RSA_sign_pss_mgf1 signs |digest_len| bytes from |digest| with the public key
+// from |rsa| using RSASSA-PSS with MGF1 as the mask generation function. It
+// writes, at most, |max_out| bytes of signature data to |out|. The |max_out|
+// argument must be, at least, |RSA_size| in order to ensure success. It returns
+// 1 on success or zero on error.
//
-// The |md| and |mgf1_md| arguments identify the hash used to calculate |msg|
+// The |md| and |mgf1_md| arguments identify the hash used to calculate |digest|
// and the MGF1 hash, respectively. If |mgf1_md| is NULL, |md| is
// used.
//
// |salt_len| specifies the expected salt length in bytes. If |salt_len| is -1,
// then the salt length is the same as the hash length. If -2, then the salt
// length is maximal given the size of |rsa|. If unsure, use -1.
+//
+// WARNING: |digest| must be the result of hashing the data to be signed with
+// |md|. Passing unhashed inputs will not result in a secure signature scheme.
OPENSSL_EXPORT int RSA_sign_pss_mgf1(RSA *rsa, size_t *out_len, uint8_t *out,
- size_t max_out, const uint8_t *in,
- size_t in_len, const EVP_MD *md,
+ size_t max_out, const uint8_t *digest,
+ size_t digest_len, const EVP_MD *md,
const EVP_MD *mgf1_md, int salt_len);
-// RSA_sign_raw signs |in_len| bytes from |in| with the public key from |rsa|
-// and writes, at most, |max_out| bytes of signature data to |out|. The
-// |max_out| argument must be, at least, |RSA_size| in order to ensure success.
-//
-// It returns 1 on success or zero on error.
-//
-// The |padding| argument must be one of the |RSA_*_PADDING| values. If in
-// doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_PSS_PADDING|
-// (via |RSA_sign_pss_mgf1| or the |EVP_PKEY| interface) is preferred for new
-// protocols.
+// RSA_sign_raw performs the private key portion of computing a signature with
+// |rsa|. It writes, at most, |max_out| bytes of signature data to |out|. The
+// |max_out| argument must be, at least, |RSA_size| in order to ensure the
+// output fits. It returns 1 on success or zero on error.
+//
+// If |padding| is |RSA_PKCS1_PADDING|, this function wraps |in| with the
+// padding portion of RSASSA-PKCS1-v1_5 and then performs the raw private key
+// operation. The caller is responsible for hashing the input and wrapping it in
+// a DigestInfo structure.
+//
+// If |padding| is |RSA_NO_PADDING|, this function only performs the raw private
+// key operation, interpreting |in| as a integer modulo n. The caller is
+// responsible for hashing the input and encoding it for the signature scheme
+// being implemented.
+//
+// WARNING: This function is a building block for a signature scheme, not a
+// complete one. |in| must be the result of hashing and encoding the data as
+// needed for the scheme being implemented. Passing in arbitrary inputs will not
+// result in a secure signature scheme.
OPENSSL_EXPORT int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out,
size_t max_out, const uint8_t *in,
size_t in_len, int padding);
// RSA_verify verifies that |sig_len| bytes from |sig| are a valid,
-// RSASSA-PKCS1-v1_5 signature of |msg_len| bytes at |msg| by |rsa|.
+// RSASSA-PKCS1-v1_5 signature of |digest_len| bytes at |digest| by |rsa|.
//
-// The |hash_nid| argument identifies the hash function used to calculate |msg|
-// and is embedded in the resulting signature in order to prevent hash
+// The |hash_nid| argument identifies the hash function used to calculate
+// |digest| and is embedded in the resulting signature in order to prevent hash
// confusion attacks. For example, it might be |NID_sha256|.
//
// It returns one if the signature is valid and zero otherwise.
//
// WARNING: this differs from the original, OpenSSL function which additionally
// returned -1 on error.
-OPENSSL_EXPORT int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
- const uint8_t *sig, size_t sig_len, RSA *rsa);
+//
+// WARNING: |digest| must be the result of hashing the data to be verified with
+// |hash_nid|. Passing unhashed input will not result in a secure signature
+// scheme.
+OPENSSL_EXPORT int RSA_verify(int hash_nid, const uint8_t *digest,
+ size_t digest_len, const uint8_t *sig,
+ size_t sig_len, RSA *rsa);
// RSA_verify_pss_mgf1 verifies that |sig_len| bytes from |sig| are a valid,
-// RSASSA-PSS signature of |msg_len| bytes at |msg| by |rsa|. It returns one if
-// the signature is valid and zero otherwise. MGF1 is used as the mask
+// RSASSA-PSS signature of |digest_len| bytes at |digest| by |rsa|. It returns
+// one if the signature is valid and zero otherwise. MGF1 is used as the mask
// generation function.
//
-// The |md| and |mgf1_md| arguments identify the hash used to calculate |msg|
+// The |md| and |mgf1_md| arguments identify the hash used to calculate |digest|
// and the MGF1 hash, respectively. If |mgf1_md| is NULL, |md| is
// used. |salt_len| specifies the expected salt length in bytes.
//
// If |salt_len| is -1, then the salt length is the same as the hash length. If
// -2, then the salt length is recovered and all values accepted. If unsure, use
// -1.
-OPENSSL_EXPORT int RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *msg,
- size_t msg_len, const EVP_MD *md,
+//
+// WARNING: |digest| must be the result of hashing the data to be verified with
+// |md|. Passing unhashed input will not result in a secure signature scheme.
+OPENSSL_EXPORT int RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *digest,
+ size_t digest_len, const EVP_MD *md,
const EVP_MD *mgf1_md, int salt_len,
const uint8_t *sig, size_t sig_len);
-// RSA_verify_raw verifies |in_len| bytes of signature from |in| using the
-// public key from |rsa| and writes, at most, |max_out| bytes of plaintext to
-// |out|. The |max_out| argument must be, at least, |RSA_size| in order to
-// ensure success.
+// RSA_verify_raw performs the public key portion of verifying |in_len| bytes of
+// signature from |in| using the public key from |rsa|. On success, it returns
+// one and writes, at most, |max_out| bytes of output to |out|. The |max_out|
+// argument must be, at least, |RSA_size| in order to ensure the output fits. On
+// failure or invalid input, it returns zero.
//
-// It returns 1 on success or zero on error.
+// If |padding| is |RSA_PKCS1_PADDING|, this function checks the padding portion
+// of RSASSA-PKCS1-v1_5 and outputs the remainder of the encoded digest. The
+// caller is responsible for checking the output is a DigestInfo-wrapped digest
+// of the message.
//
-// The |padding| argument must be one of the |RSA_*_PADDING| values. If in
-// doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_PSS_PADDING|
-// (via |RSA_verify_pss_mgf1| or the |EVP_PKEY| interface) is preferred for new
-// protocols.
+// If |padding| is |RSA_NO_PADDING|, this function only performs the raw public
+// key operation. The caller is responsible for checking the output is a valid
+// result for the signature scheme being implemented.
+//
+// WARNING: This function is a building block for a signature scheme, not a
+// complete one. Checking for arbitrary strings in |out| will not result in a
+// secure signature scheme.
OPENSSL_EXPORT int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out,
size_t max_out, const uint8_t *in,
size_t in_len, int padding);
-// RSA_private_encrypt encrypts |flen| bytes from |from| with the private key in
-// |rsa| and writes the encrypted data to |to|. The |to| buffer must have at
-// least |RSA_size| bytes of space. It returns the number of bytes written, or
-// -1 on error. The |padding| argument must be one of the |RSA_*_PADDING|
-// values. If in doubt, |RSA_PKCS1_PADDING| is the most common but
-// |RSA_PKCS1_PSS_PADDING| (via the |EVP_PKEY| interface) is preferred for new
-// protocols.
+// RSA_private_encrypt performs the private key portion of computing a signature
+// with |rsa|. It takes |flen| bytes from |from| as input and writes the result
+// to |to|. The |to| buffer must have at least |RSA_size| bytes of space. It
+// returns the number of bytes written, or -1 on error.
//
-// WARNING: this function is dangerous because it breaks the usual return value
+// For the interpretation of |padding| and the input, see |RSA_sign_raw|.
+//
+// WARNING: This function is a building block for a signature scheme, not a
+// complete one. See |RSA_sign_raw| for details.
+//
+// WARNING: This function is dangerous because it breaks the usual return value
// convention. Use |RSA_sign_raw| instead.
OPENSSL_EXPORT int RSA_private_encrypt(size_t flen, const uint8_t *from,
uint8_t *to, RSA *rsa, int padding);
-// RSA_public_decrypt verifies |flen| bytes of signature from |from| using the
-// public key in |rsa| and writes the plaintext to |to|. The |to| buffer must
-// have at least |RSA_size| bytes of space. It returns the number of bytes
-// written, or -1 on error. The |padding| argument must be one of the
-// |RSA_*_PADDING| values. If in doubt, |RSA_PKCS1_PADDING| is the most common
-// but |RSA_PKCS1_PSS_PADDING| (via the |EVP_PKEY| interface) is preferred for
-// new protocols.
+// RSA_public_decrypt performs the public key portion of verifying |flen| bytes
+// of signature from |from| using the public key from |rsa|. It writes the
+// result to |to|, which must have at least |RSA_size| bytes of space. It
+// returns the number of bytes written, or -1 on error.
//
-// WARNING: this function is dangerous because it breaks the usual return value
+// For the interpretation of |padding| and the result, see |RSA_verify_raw|.
+//
+// WARNING: This function is a building block for a signature scheme, not a
+// complete one. See |RSA_verify_raw| for details.
+//
+// WARNING: This function is dangerous because it breaks the usual return value
// convention. Use |RSA_verify_raw| instead.
OPENSSL_EXPORT int RSA_public_decrypt(size_t flen, const uint8_t *from,
uint8_t *to, RSA *rsa, int padding);
@@ -479,13 +514,14 @@ OPENSSL_EXPORT int RSA_padding_add_PKCS1_OAEP_mgf1(
const uint8_t *param, size_t param_len, const EVP_MD *md,
const EVP_MD *mgf1md);
-// RSA_add_pkcs1_prefix builds a version of |msg| prefixed with the DigestInfo
-// header for the given hash function and sets |out_msg| to point to it. On
-// successful return, if |*is_alloced| is one, the caller must release
+// RSA_add_pkcs1_prefix builds a version of |digest| prefixed with the
+// DigestInfo header for the given hash function and sets |out_msg| to point to
+// it. On successful return, if |*is_alloced| is one, the caller must release
// |*out_msg| with |OPENSSL_free|.
OPENSSL_EXPORT int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len,
int *is_alloced, int hash_nid,
- const uint8_t *msg, size_t msg_len);
+ const uint8_t *digest,
+ size_t digest_len);
// ASN.1 functions.
diff --git a/deps/boringssl/src/include/openssl/span.h b/deps/boringssl/src/include/openssl/span.h
index 7410bf9..79f1d41 100644
--- a/deps/boringssl/src/include/openssl/span.h
+++ b/deps/boringssl/src/include/openssl/span.h
@@ -94,18 +94,6 @@ class SpanBase {
template <typename T>
class Span : private internal::SpanBase<const T> {
private:
- // Heuristically test whether C is a container type that can be converted into
- // a Span by checking for data() and size() member functions.
- //
- // TODO(davidben): Switch everything to std::enable_if_t when we remove
- // support for MSVC 2015. Although we could write our own enable_if_t and MSVC
- // 2015 has std::enable_if_t anyway, MSVC 2015's SFINAE implementation is
- // problematic and does not work below unless we write the ::type at use.
- template <typename C>
- using EnableIfContainer = std::enable_if<
- std::is_convertible<decltype(std::declval<C>().data()), T *>::value &&
- std::is_integral<decltype(std::declval<C>().size())>::value>;
-
static const size_t npos = static_cast<size_t>(-1);
public:
@@ -116,12 +104,27 @@ class Span : private internal::SpanBase<const T> {
constexpr Span(T (&array)[N]) : Span(array, N) {}
template <
- typename C, typename = typename EnableIfContainer<C>::type,
+ typename C,
+ // TODO(davidben): Switch everything to std::enable_if_t when we remove
+ // support for MSVC 2015. Although we could write our own enable_if_t and
+ // MSVC 2015 has std::enable_if_t anyway, MSVC 2015's SFINAE
+ // implementation is problematic and does not work below unless we write
+ // the ::type at use.
+ //
+ // TODO(davidben): Move this and the identical copy below into an
+ // EnableIfContainer alias when we drop MSVC 2015 support. MSVC 2015's
+ // SFINAE support cannot handle type aliases.
+ typename = typename std::enable_if<
+ std::is_convertible<decltype(std::declval<C>().data()), T *>::value &&
+ std::is_integral<decltype(std::declval<C>().size())>::value>::type,
typename = typename std::enable_if<std::is_const<T>::value, C>::type>
Span(const C &container) : data_(container.data()), size_(container.size()) {}
template <
- typename C, typename = typename EnableIfContainer<C>::type,
+ typename C,
+ typename = typename std::enable_if<
+ std::is_convertible<decltype(std::declval<C>().data()), T *>::value &&
+ std::is_integral<decltype(std::declval<C>().size())>::value>::type,
typename = typename std::enable_if<!std::is_const<T>::value, C>::type>
explicit Span(C &container)
: data_(container.data()), size_(container.size()) {}
@@ -158,11 +161,30 @@ class Span : private internal::SpanBase<const T> {
Span subspan(size_t pos = 0, size_t len = npos) const {
if (pos > size_) {
- abort(); // absl::Span throws an exception here.
+ // absl::Span throws an exception here. Note std::span and Chromium
+ // base::span additionally forbid pos + len being out of range, with a
+ // special case at npos/dynamic_extent, while absl::Span::subspan clips
+ // the span. For now, we align with absl::Span in case we switch to it in
+ // the future.
+ abort();
}
return Span(data_ + pos, std::min(size_ - pos, len));
}
+ Span first(size_t len) {
+ if (len > size_) {
+ abort();
+ }
+ return Span(data_, len);
+ }
+
+ Span last(size_t len) {
+ if (len > size_) {
+ abort();
+ }
+ return Span(data_ + size_ - len, len);
+ }
+
private:
T *data_;
size_t size_;
diff --git a/deps/boringssl/src/include/openssl/ssl.h b/deps/boringssl/src/include/openssl/ssl.h
index 7ff7e72..eae3c4b 100644
--- a/deps/boringssl/src/include/openssl/ssl.h
+++ b/deps/boringssl/src/include/openssl/ssl.h
@@ -508,12 +508,10 @@ OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code);
// TODO(davidben): Remove this. It's used by accept BIOs which are bizarre.
#define SSL_ERROR_WANT_ACCEPT 8
-// SSL_ERROR_WANT_CHANNEL_ID_LOOKUP indicates the operation failed looking up
-// the Channel ID key. The caller may retry the operation when |channel_id_cb|
-// is ready to return a key or one has been configured with
-// |SSL_set1_tls_channel_id|.
+// SSL_ERROR_WANT_CHANNEL_ID_LOOKUP is never used.
//
-// See also |SSL_CTX_set_channel_id_cb|.
+// TODO(davidben): Remove this. Some callers reference it when stringifying
+// errors. They should use |SSL_error_description| instead.
#define SSL_ERROR_WANT_CHANNEL_ID_LOOKUP 9
// SSL_ERROR_PENDING_SESSION indicates the operation failed because the session
@@ -567,6 +565,11 @@ OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code);
// See also |ssl_renegotiate_explicit|.
#define SSL_ERROR_WANT_RENEGOTIATE 19
+// SSL_ERROR_HANDSHAKE_HINTS_READY indicates the handshake has progressed enough
+// for |SSL_serialize_handshake_hints| to be called. See also
+// |SSL_request_handshake_hints|.
+#define SSL_ERROR_HANDSHAKE_HINTS_READY 20
+
// SSL_error_description returns a string representation of |err|, where |err|
// is one of the |SSL_ERROR_*| constants returned by |SSL_get_error|, or NULL
// if the value is unrecognized.
@@ -1216,6 +1219,11 @@ enum ssl_private_key_result_t BORINGSSL_ENUM_INT {
// key hooks. This is used to off-load signing operations to a custom,
// potentially asynchronous, backend. Metadata about the key such as the type
// and size are parsed out of the certificate.
+//
+// Callers that use this structure should additionally call
+// |SSL_set_signing_algorithm_prefs| or |SSL_CTX_set_signing_algorithm_prefs|
+// with the private key's capabilities. This ensures BoringSSL will select a
+// suitable signature algorithm for the private key.
struct ssl_private_key_method_st {
// sign signs the message |in| in using the specified signature algorithm. On
// success, it returns |ssl_private_key_success| and writes at most |max_out|
@@ -1276,6 +1284,15 @@ OPENSSL_EXPORT void SSL_set_private_key_method(
OPENSSL_EXPORT void SSL_CTX_set_private_key_method(
SSL_CTX *ctx, const SSL_PRIVATE_KEY_METHOD *key_method);
+// SSL_can_release_private_key returns one if |ssl| will no longer call into the
+// private key and zero otherwise. If the function returns one, the caller can
+// release state associated with the private key.
+//
+// NOTE: This function assumes the caller does not use |SSL_clear| to reuse
+// |ssl| for a second connection. If |SSL_clear| is used, BoringSSL may still
+// use the private key on the second connection.
+OPENSSL_EXPORT int SSL_can_release_private_key(const SSL *ssl);
+
// Cipher suites.
//
@@ -1779,8 +1796,10 @@ OPENSSL_EXPORT int SSL_SESSION_set1_id_context(SSL_SESSION *session,
// used without leaking a correlator.
OPENSSL_EXPORT int SSL_SESSION_should_be_single_use(const SSL_SESSION *session);
-// SSL_SESSION_is_resumable returns one if |session| is resumable and zero
-// otherwise.
+// SSL_SESSION_is_resumable returns one if |session| is complete and contains a
+// session ID or ticket. It returns zero otherwise. Note this function does not
+// ensure |session| will be resumed. It may be expired, dropped by the server,
+// or associated with incompatible parameters.
OPENSSL_EXPORT int SSL_SESSION_is_resumable(const SSL_SESSION *session);
// SSL_SESSION_has_ticket returns one if |session| has a ticket and zero
@@ -2723,8 +2742,9 @@ OPENSSL_EXPORT SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx);
// SSL_CTX_set_alpn_protos sets the client ALPN protocol list on |ctx| to
// |protos|. |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
-// length-prefixed strings). It returns zero on success and one on failure.
-// Configuring this list enables ALPN on a client.
+// length-prefixed strings), or the empty string to disable ALPN. It returns
+// zero on success and one on failure. Configuring a non-empty string enables
+// ALPN on a client.
//
// WARNING: this function is dangerous because it breaks the usual return value
// convention.
@@ -2733,8 +2753,9 @@ OPENSSL_EXPORT int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const uint8_t *protos,
// SSL_set_alpn_protos sets the client ALPN protocol list on |ssl| to |protos|.
// |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
-// length-prefixed strings). It returns zero on success and one on failure.
-// Configuring this list enables ALPN on a client.
+// length-prefixed strings), or the empty string to disable ALPN. It returns
+// zero on success and one on failure. Configuring a non-empty string enables
+// ALPN on a client.
//
// WARNING: this function is dangerous because it breaks the usual return value
// convention.
@@ -2743,18 +2764,34 @@ OPENSSL_EXPORT int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos,
// SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is called
// during ClientHello processing in order to select an ALPN protocol from the
-// client's list of offered protocols. Configuring this callback enables ALPN on
-// a server.
+// client's list of offered protocols.
//
// The callback is passed a wire-format (i.e. a series of non-empty, 8-bit
-// length-prefixed strings) ALPN protocol list in |in|. It should set |*out| and
-// |*out_len| to the selected protocol and return |SSL_TLSEXT_ERR_OK| on
-// success. It does not pass ownership of the buffer. Otherwise, it should
-// return |SSL_TLSEXT_ERR_NOACK|. Other |SSL_TLSEXT_ERR_*| values are
-// unimplemented and will be treated as |SSL_TLSEXT_ERR_NOACK|.
+// length-prefixed strings) ALPN protocol list in |in|. To select a protocol,
+// the callback should set |*out| and |*out_len| to the selected protocol and
+// return |SSL_TLSEXT_ERR_OK| on success. It does not pass ownership of the
+// buffer, so |*out| should point to a static string, a buffer that outlives the
+// callback call, or the corresponding entry in |in|.
+//
+// If the server supports ALPN, but there are no protocols in common, the
+// callback should return |SSL_TLSEXT_ERR_ALERT_FATAL| to abort the connection
+// with a no_application_protocol alert.
+//
+// If the server does not support ALPN, it can return |SSL_TLSEXT_ERR_NOACK| to
+// continue the handshake without negotiating a protocol. This may be useful if
+// multiple server configurations share an |SSL_CTX|, only some of which have
+// ALPN protocols configured.
+//
+// |SSL_TLSEXT_ERR_ALERT_WARNING| is ignored and will be treated as
+// |SSL_TLSEXT_ERR_NOACK|.
+//
+// The callback will only be called if the client supports ALPN. Callers that
+// wish to require ALPN for all clients must check |SSL_get0_alpn_selected|
+// after the handshake. In QUIC connections, this is done automatically.
//
// The cipher suite is selected before negotiating ALPN. The callback may use
-// |SSL_get_pending_cipher| to query the cipher suite.
+// |SSL_get_pending_cipher| to query the cipher suite. This may be used to
+// implement HTTP/2's cipher suite constraints.
OPENSSL_EXPORT void SSL_CTX_set_alpn_select_cb(
SSL_CTX *ctx, int (*cb)(SSL *ssl, const uint8_t **out, uint8_t *out_len,
const uint8_t *in, unsigned in_len, void *arg),
@@ -2940,15 +2977,16 @@ OPENSSL_EXPORT int SSL_select_next_proto(uint8_t **out, uint8_t *out_len,
// Channel ID.
//
-// See draft-balfanz-tls-channelid-01.
+// See draft-balfanz-tls-channelid-01. This is an old, experimental mechanism
+// and should not be used in new code.
// SSL_CTX_set_tls_channel_id_enabled configures whether connections associated
-// with |ctx| should enable Channel ID.
+// with |ctx| should enable Channel ID as a server.
OPENSSL_EXPORT void SSL_CTX_set_tls_channel_id_enabled(SSL_CTX *ctx,
int enabled);
// SSL_set_tls_channel_id_enabled configures whether |ssl| should enable Channel
-// ID.
+// ID as a server.
OPENSSL_EXPORT void SSL_set_tls_channel_id_enabled(SSL *ssl, int enabled);
// SSL_CTX_set1_tls_channel_id configures a TLS client to send a TLS Channel ID
@@ -2962,55 +3000,15 @@ OPENSSL_EXPORT int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx,
// success and zero on error.
OPENSSL_EXPORT int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key);
-// SSL_get_tls_channel_id gets the client's TLS Channel ID from a server |SSL*|
+// SSL_get_tls_channel_id gets the client's TLS Channel ID from a server |SSL|
// and copies up to the first |max_out| bytes into |out|. The Channel ID
// consists of the client's P-256 public key as an (x,y) pair where each is a
// 32-byte, big-endian field element. It returns 0 if the client didn't offer a
-// Channel ID and the length of the complete Channel ID otherwise.
+// Channel ID and the length of the complete Channel ID otherwise. This function
+// always returns zero if |ssl| is a client.
OPENSSL_EXPORT size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out,
size_t max_out);
-// SSL_CTX_set_channel_id_cb sets a callback to be called when a TLS Channel ID
-// is requested. The callback may set |*out_pkey| to a key, passing a reference
-// to the caller. If none is returned, the handshake will pause and
-// |SSL_get_error| will return |SSL_ERROR_WANT_CHANNEL_ID_LOOKUP|.
-//
-// See also |SSL_ERROR_WANT_CHANNEL_ID_LOOKUP|.
-OPENSSL_EXPORT void SSL_CTX_set_channel_id_cb(
- SSL_CTX *ctx, void (*channel_id_cb)(SSL *ssl, EVP_PKEY **out_pkey));
-
-// SSL_CTX_get_channel_id_cb returns the callback set by
-// |SSL_CTX_set_channel_id_cb|.
-OPENSSL_EXPORT void (*SSL_CTX_get_channel_id_cb(SSL_CTX *ctx))(
- SSL *ssl, EVP_PKEY **out_pkey);
-
-
-// Token Binding.
-//
-// See draft-ietf-tokbind-protocol-16.
-
-// SSL_set_token_binding_params sets |params| as the Token Binding Key
-// parameters (section 3 of draft-ietf-tokbind-protocol-16) to negotiate on the
-// connection. If this function is not called, or if |len| is 0, then this
-// endpoint will not attempt to negotiate Token Binding. |params| are provided
-// in preference order, with the more preferred parameters at the beginning of
-// the list. This function returns 1 on success and 0 on failure.
-OPENSSL_EXPORT int SSL_set_token_binding_params(SSL *ssl, const uint8_t *params,
- size_t len);
-
-// SSL_is_token_binding_negotiated returns 1 if Token Binding was negotiated
-// on this connection and 0 otherwise. On a server, it is possible for this
-// function to return 1 when the client's view of the connection is that Token
-// Binding was not negotiated. This occurs when the server indicates a version
-// of Token Binding less than the client's minimum version.
-OPENSSL_EXPORT int SSL_is_token_binding_negotiated(const SSL *ssl);
-
-// SSL_get_negotiated_token_binding_param returns the TokenBindingKeyParameters
-// enum value that was negotiated. It is only valid to call this function if
-// SSL_is_token_binding_negotiated returned 1, otherwise this function returns
-// an undefined value.
-OPENSSL_EXPORT uint8_t SSL_get_negotiated_token_binding_param(const SSL *ssl);
-
// DTLS-SRTP.
//
@@ -3047,8 +3045,8 @@ OPENSSL_EXPORT int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx,
OPENSSL_EXPORT int SSL_set_srtp_profiles(SSL *ssl, const char *profiles);
// SSL_get_srtp_profiles returns the SRTP profiles supported by |ssl|.
-OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(
- SSL *ssl);
+OPENSSL_EXPORT const STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(
+ const SSL *ssl);
// SSL_get_selected_srtp_profile returns the selected SRTP profile, or NULL if
// SRTP was not negotiated.
@@ -3179,7 +3177,7 @@ OPENSSL_EXPORT int SSL_delegated_credential_used(const SSL *ssl);
//
// QUIC acts as an underlying transport for the TLS 1.3 handshake. The following
// functions allow a QUIC implementation to serve as the underlying transport as
-// described in draft-ietf-quic-tls.
+// described in RFC 9001.
//
// When configured for QUIC, |SSL_do_handshake| will drive the handshake as
// before, but it will not use the configured |BIO|. It will call functions on
@@ -3199,8 +3197,7 @@ OPENSSL_EXPORT int SSL_delegated_credential_used(const SSL *ssl);
// confirm the handshake. As a client, |SSL_ERROR_EARLY_DATA_REJECTED| and
// |SSL_reset_early_data_reject| behave as usual.
//
-// See https://tools.ietf.org/html/draft-ietf-quic-tls-15#section-4.1 for more
-// details.
+// See https://www.rfc-editor.org/rfc/rfc9001.html#section-4.1 for more details.
//
// To avoid DoS attacks, the QUIC implementation must limit the amount of data
// being queued up. The implementation can call
@@ -3211,7 +3208,8 @@ OPENSSL_EXPORT int SSL_delegated_credential_used(const SSL *ssl);
// |SSL_set_quic_transport_params|. |SSL_get_peer_quic_transport_params| may be
// used to query the value received from the peer. BoringSSL handles this
// extension as an opaque byte string. The caller is responsible for serializing
-// and parsing them. See draft-ietf-quic-transport (section 7.3) for details.
+// and parsing them. See https://www.rfc-editor.org/rfc/rfc9000#section-7.4 for
+// details.
//
// QUIC additionally imposes restrictions on 0-RTT. In particular, the QUIC
// transport layer requires that if a server accepts 0-RTT data, then the
@@ -3323,7 +3321,7 @@ struct ssl_quic_method_st {
// that may be received at the given encryption level. This function should be
// used to limit buffering in the QUIC implementation.
//
-// See https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-4.4.
+// See https://www.rfc-editor.org/rfc/rfc9000#section-7.5
OPENSSL_EXPORT size_t SSL_quic_max_handshake_flight_len(
const SSL *ssl, enum ssl_encryption_level_t level);
@@ -3386,8 +3384,8 @@ OPENSSL_EXPORT void SSL_get_peer_quic_transport_params(
// SSL_set_quic_use_legacy_codepoint configures whether to use the legacy QUIC
// extension codepoint 0xffa5 as opposed to the official value 57. Call with
-// |use_legacy| set to 1 to use 0xffa5 and call with 0 to use 57. The default
-// value for this is currently 1 but it will change to 0 at a later date.
+// |use_legacy| set to 1 to use 0xffa5 and call with 0 to use 57. By default,
+// the standard code point is used.
OPENSSL_EXPORT void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy);
// SSL_set_quic_early_data_context configures a context string in QUIC servers
@@ -3536,8 +3534,7 @@ enum ssl_early_data_reason_t BORINGSSL_ENUM_INT {
ssl_early_data_alpn_mismatch = 9,
// The connection negotiated Channel ID, which is incompatible with 0-RTT.
ssl_early_data_channel_id = 10,
- // The connection negotiated token binding, which is incompatible with 0-RTT.
- ssl_early_data_token_binding = 11,
+ // Value 11 is reserved. (It has historically |ssl_early_data_token_binding|.)
// The client and server ticket age were too far apart.
ssl_early_data_ticket_age_skew = 12,
// QUIC parameters differ between this connection and the original.
@@ -3559,20 +3556,183 @@ OPENSSL_EXPORT const char *SSL_early_data_reason_string(
enum ssl_early_data_reason_t reason);
-// Encrypted Client Hello.
+// Encrypted ClientHello.
//
// ECH is a mechanism for encrypting the entire ClientHello message in TLS 1.3.
// This can prevent observers from seeing cleartext information about the
// connection, such as the server_name extension.
//
+// By default, BoringSSL will treat the server name, session ticket, and client
+// certificate as secret, but most other parameters, such as the ALPN protocol
+// list will be treated as public and sent in the cleartext ClientHello. Other
+// APIs may be added for applications with different secrecy requirements.
+//
// ECH support in BoringSSL is still experimental and under development.
//
-// See https://tools.ietf.org/html/draft-ietf-tls-esni-09.
+// See https://tools.ietf.org/html/draft-ietf-tls-esni-13.
-// SSL_set_enable_ech_grease configures whether the client may send ECH GREASE
-// as part of this connection.
+// SSL_set_enable_ech_grease configures whether the client will send a GREASE
+// ECH extension when no supported ECHConfig is available.
OPENSSL_EXPORT void SSL_set_enable_ech_grease(SSL *ssl, int enable);
+// SSL_set1_ech_config_list configures |ssl| to, as a client, offer ECH with the
+// specified configuration. |ech_config_list| should contain a serialized
+// ECHConfigList structure. It returns one on success and zero on error.
+//
+// This function returns an error if the input is malformed. If the input is
+// valid but none of the ECHConfigs implement supported parameters, it will
+// return success and proceed without ECH.
+//
+// If a supported ECHConfig is found, |ssl| will encrypt the true ClientHello
+// parameters. If the server cannot decrypt it, e.g. due to a key mismatch, ECH
+// has a recovery flow. |ssl| will handshake using the cleartext parameters,
+// including a public name in the ECHConfig. If using
+// |SSL_CTX_set_custom_verify|, callers should use |SSL_get0_ech_name_override|
+// to verify the certificate with the public name. If using the built-in
+// verifier, the |X509_STORE_CTX| will be configured automatically.
+//
+// If no other errors are found in this handshake, it will fail with
+// |SSL_R_ECH_REJECTED|. Since it didn't use the true parameters, the connection
+// cannot be used for application data. Instead, callers should handle this
+// error by calling |SSL_get0_ech_retry_configs| and retrying the connection
+// with updated ECH parameters. If the retry also fails with
+// |SSL_R_ECH_REJECTED|, the caller should report a connection failure.
+OPENSSL_EXPORT int SSL_set1_ech_config_list(SSL *ssl,
+ const uint8_t *ech_config_list,
+ size_t ech_config_list_len);
+
+// SSL_get0_ech_name_override, if |ssl| is a client and the server rejected ECH,
+// sets |*out_name| and |*out_name_len| to point to a buffer containing the ECH
+// public name. Otherwise, the buffer will be empty.
+//
+// When offering ECH as a client, this function should be called during the
+// certificate verification callback (see |SSL_CTX_set_custom_verify|). If
+// |*out_name_len| is non-zero, the caller should verify the certificate against
+// the result, interpreted as a DNS name, rather than the true server name. In
+// this case, the handshake will never succeed and is only used to authenticate
+// retry configs. See also |SSL_get0_ech_retry_configs|.
+OPENSSL_EXPORT void SSL_get0_ech_name_override(const SSL *ssl,
+ const char **out_name,
+ size_t *out_name_len);
+
+// SSL_get0_ech_retry_configs sets |*out_retry_configs| and
+// |*out_retry_configs_len| to a buffer containing a serialized ECHConfigList.
+// If the server did not provide an ECHConfigList, |*out_retry_configs_len| will
+// be zero.
+//
+// When handling an |SSL_R_ECH_REJECTED| error code as a client, callers should
+// use this function to recover from potential key mismatches. If the result is
+// non-empty, the caller should retry the connection, passing this buffer to
+// |SSL_set1_ech_config_list|. If the result is empty, the server has rolled
+// back ECH support, and the caller should retry without ECH.
+//
+// This function must only be called in response to an |SSL_R_ECH_REJECTED|
+// error code. Calling this function on |ssl|s that have not authenticated the
+// rejection handshake will assert in debug builds and otherwise return an
+// unparsable list.
+OPENSSL_EXPORT void SSL_get0_ech_retry_configs(
+ const SSL *ssl, const uint8_t **out_retry_configs,
+ size_t *out_retry_configs_len);
+
+// SSL_marshal_ech_config constructs a new serialized ECHConfig. On success, it
+// sets |*out| to a newly-allocated buffer containing the result and |*out_len|
+// to the size of the buffer. The caller must call |OPENSSL_free| on |*out| to
+// release the memory. On failure, it returns zero.
+//
+// The |config_id| field is a single byte identifer for the ECHConfig. Reusing
+// config IDs is allowed, but if multiple ECHConfigs with the same config ID are
+// active at a time, server load may increase. See
+// |SSL_ECH_KEYS_has_duplicate_config_id|.
+//
+// The public key and KEM algorithm are taken from |key|. |public_name| is the
+// DNS name used to authenticate the recovery flow. |max_name_len| should be the
+// length of the longest name in the ECHConfig's anonymity set and influences
+// client padding decisions.
+OPENSSL_EXPORT int SSL_marshal_ech_config(uint8_t **out, size_t *out_len,
+ uint8_t config_id,
+ const EVP_HPKE_KEY *key,
+ const char *public_name,
+ size_t max_name_len);
+
+// SSL_ECH_KEYS_new returns a newly-allocated |SSL_ECH_KEYS| or NULL on error.
+OPENSSL_EXPORT SSL_ECH_KEYS *SSL_ECH_KEYS_new(void);
+
+// SSL_ECH_KEYS_up_ref increments the reference count of |keys|.
+OPENSSL_EXPORT void SSL_ECH_KEYS_up_ref(SSL_ECH_KEYS *keys);
+
+// SSL_ECH_KEYS_free releases memory associated with |keys|.
+OPENSSL_EXPORT void SSL_ECH_KEYS_free(SSL_ECH_KEYS *keys);
+
+// SSL_ECH_KEYS_add decodes |ech_config| as an ECHConfig and appends it with
+// |key| to |keys|. If |is_retry_config| is non-zero, this config will be
+// returned to the client on configuration mismatch. It returns one on success
+// and zero on error.
+//
+// This function should be called successively to register each ECHConfig in
+// decreasing order of preference. This configuration must be completed before
+// setting |keys| on an |SSL_CTX| with |SSL_CTX_set1_ech_keys|. After that
+// point, |keys| is immutable; no more ECHConfig values may be added.
+//
+// See also |SSL_CTX_set1_ech_keys|.
+OPENSSL_EXPORT int SSL_ECH_KEYS_add(SSL_ECH_KEYS *keys, int is_retry_config,
+ const uint8_t *ech_config,
+ size_t ech_config_len,
+ const EVP_HPKE_KEY *key);
+
+// SSL_ECH_KEYS_has_duplicate_config_id returns one if |keys| has duplicate
+// config IDs or zero otherwise. Duplicate config IDs still work, but may
+// increase server load due to trial decryption.
+OPENSSL_EXPORT int SSL_ECH_KEYS_has_duplicate_config_id(
+ const SSL_ECH_KEYS *keys);
+
+// SSL_ECH_KEYS_marshal_retry_configs serializes the retry configs in |keys| as
+// an ECHConfigList. On success, it sets |*out| to a newly-allocated buffer
+// containing the result and |*out_len| to the size of the buffer. The caller
+// must call |OPENSSL_free| on |*out| to release the memory. On failure, it
+// returns zero.
+//
+// This output may be advertised to clients in DNS.
+OPENSSL_EXPORT int SSL_ECH_KEYS_marshal_retry_configs(const SSL_ECH_KEYS *keys,
+ uint8_t **out,
+ size_t *out_len);
+
+// SSL_CTX_set1_ech_keys configures |ctx| to use |keys| to decrypt encrypted
+// ClientHellos. It returns one on success, and zero on failure. If |keys| does
+// not contain any retry configs, this function will fail. Retry configs are
+// marked as such when they are added to |keys| with |SSL_ECH_KEYS_add|.
+//
+// Once |keys| has been passed to this function, it is immutable. Unlike most
+// |SSL_CTX| configuration functions, this function may be called even if |ctx|
+// already has associated connections on multiple threads. This may be used to
+// rotate keys in a long-lived server process.
+//
+// The configured ECHConfig values should also be advertised out-of-band via DNS
+// (see draft-ietf-dnsop-svcb-https). Before advertising an ECHConfig in DNS,
+// deployments should ensure all instances of the service are configured with
+// the ECHConfig and corresponding private key.
+//
+// Only the most recent fully-deployed ECHConfigs should be advertised in DNS.
+// |keys| may contain a newer set if those ECHConfigs are mid-deployment. It
+// should also contain older sets, until the DNS change has rolled out and the
+// old records have expired from caches.
+//
+// If there is a mismatch, |SSL| objects associated with |ctx| will complete the
+// handshake using the cleartext ClientHello and send updated ECHConfig values
+// to the client. The client will then retry to recover, but with a latency
+// penalty. This recovery flow depends on the public name in the ECHConfig.
+// Before advertising an ECHConfig in DNS, deployments must ensure all instances
+// of the service can present a valid certificate for the public name.
+//
+// BoringSSL negotiates ECH before certificate selection callbacks are called,
+// including |SSL_CTX_set_select_certificate_cb|. If ECH is negotiated, the
+// reported |SSL_CLIENT_HELLO| structure and |SSL_get_servername| function will
+// transparently reflect the inner ClientHello. Callers should select parameters
+// based on these values to correctly handle ECH as well as the recovery flow.
+OPENSSL_EXPORT int SSL_CTX_set1_ech_keys(SSL_CTX *ctx, SSL_ECH_KEYS *keys);
+
+// SSL_ech_accepted returns one if |ssl| negotiated ECH and zero otherwise.
+OPENSSL_EXPORT int SSL_ech_accepted(const SSL *ssl);
+
// Alerts.
//
@@ -3627,6 +3787,7 @@ OPENSSL_EXPORT void SSL_set_enable_ech_grease(SSL *ssl, int enable);
#define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY
#define SSL_AD_CERTIFICATE_REQUIRED TLS1_AD_CERTIFICATE_REQUIRED
#define SSL_AD_NO_APPLICATION_PROTOCOL TLS1_AD_NO_APPLICATION_PROTOCOL
+#define SSL_AD_ECH_REQUIRED TLS1_AD_ECH_REQUIRED
// SSL_alert_type_string_long returns a string description of |value| as an
// alert type (warning or fatal).
@@ -3709,6 +3870,101 @@ OPENSSL_EXPORT uint64_t SSL_get_read_sequence(const SSL *ssl);
OPENSSL_EXPORT uint64_t SSL_get_write_sequence(const SSL *ssl);
+// Handshake hints.
+//
+// *** EXPERIMENTAL — DO NOT USE WITHOUT CHECKING ***
+//
+// Some server deployments make asynchronous RPC calls in both ClientHello
+// dispatch and private key operations. In TLS handshakes where the private key
+// operation occurs in the first round-trip, this results in two consecutive RPC
+// round-trips. Handshake hints allow the RPC service to predicte a signature.
+// If correctly predicted, this can skip the second RPC call.
+//
+// First, the server installs a certificate selection callback (see
+// |SSL_CTX_set_select_certificate_cb|). When that is called, it performs the
+// RPC as before, but includes the ClientHello and a capabilities string from
+// |SSL_serialize_capabilities|.
+//
+// Next, the RPC service creates its own |SSL| object, applies the results of
+// certificate selection, calls |SSL_request_handshake_hints|, and runs the
+// handshake. If this successfully computes handshake hints (see
+// |SSL_serialize_handshake_hints|), the RPC server should send the hints
+// alongside any certificate selection results.
+//
+// Finally, the server calls |SSL_set_handshake_hints| and applies any
+// configuration from the RPC server. It then completes the handshake as before.
+// If the hints apply, BoringSSL will use the predicted signature and skip the
+// private key callbacks. Otherwise, BoringSSL will call private key callbacks
+// to generate a signature as before.
+//
+// Callers should synchronize configuration across the two services.
+// Configuration mismatches and some cases of version skew are not fatal, but
+// may result in the hints not applying. Additionally, some handshake flows use
+// the private key in later round-trips, such as TLS 1.3 HelloRetryRequest. In
+// those cases, BoringSSL will not predict a signature as there is no benefit.
+// Callers must allow for handshakes to complete without a predicted signature.
+//
+// For now, only TLS 1.3 is hinted. TLS 1.2 will work, but the hints will be
+// empty.
+
+// SSL_serialize_capabilities writes an opaque byte string to |out| describing
+// some of |ssl|'s capabilities. It returns one on success and zero on error.
+//
+// This string is used by BoringSSL internally to reduce the impact of version
+// skew.
+OPENSSL_EXPORT int SSL_serialize_capabilities(const SSL *ssl, CBB *out);
+
+// SSL_request_handshake_hints configures |ssl| to generate a handshake hint for
+// |client_hello|. It returns one on success and zero on error. |client_hello|
+// should contain a serialized ClientHello structure, from the |client_hello|
+// and |client_hello_len| fields of the |SSL_CLIENT_HELLO| structure.
+// |capabilities| should contain the output of |SSL_serialize_capabilities|.
+//
+// When configured, |ssl| will perform no I/O (so there is no need to configure
+// |BIO|s). For QUIC, the caller should still configure an |SSL_QUIC_METHOD|,
+// but the callbacks themselves will never be called and may be left NULL or
+// report failure. |SSL_provide_quic_data| also should not be called.
+//
+// If hint generation is successful, |SSL_do_handshake| will stop the handshake
+// early with |SSL_get_error| returning |SSL_ERROR_HANDSHAKE_HINTS_READY|. At
+// this point, the caller should run |SSL_serialize_handshake_hints| to extract
+// the resulting hints.
+//
+// Hint generation may fail if, e.g., |ssl| was unable to process the
+// ClientHello. Callers should then complete the certificate selection RPC and
+// continue the original handshake with no hint. It will likely fail, but this
+// reports the correct alert to the client and is more robust in case of
+// mismatch.
+OPENSSL_EXPORT int SSL_request_handshake_hints(SSL *ssl,
+ const uint8_t *client_hello,
+ size_t client_hello_len,
+ const uint8_t *capabilities,
+ size_t capabilities_len);
+
+// SSL_serialize_handshake_hints writes an opaque byte string to |out|
+// containing the handshake hints computed by |out|. It returns one on success
+// and zero on error. This function should only be called if
+// |SSL_request_handshake_hints| was configured and the handshake terminated
+// with |SSL_ERROR_HANDSHAKE_HINTS_READY|.
+//
+// This string may be passed to |SSL_set_handshake_hints| on another |SSL| to
+// avoid an extra signature call.
+OPENSSL_EXPORT int SSL_serialize_handshake_hints(const SSL *ssl, CBB *out);
+
+// SSL_set_handshake_hints configures |ssl| to use |hints| as handshake hints.
+// It returns one on success and zero on error. The handshake will then continue
+// as before, but apply predicted values from |hints| where applicable.
+//
+// Hints may contain connection and session secrets, so they must not leak and
+// must come from a source trusted to terminate the connection. However, they
+// will not change |ssl|'s configuration. The caller is responsible for
+// serializing and applying options from the RPC server as needed. This ensures
+// |ssl|'s behavior is self-consistent and consistent with the caller's local
+// decisions.
+OPENSSL_EXPORT int SSL_set_handshake_hints(SSL *ssl, const uint8_t *hints,
+ size_t hints_len);
+
+
// Obscure functions.
// SSL_CTX_set_msg_callback installs |cb| as the message callback for |ctx|.
@@ -4093,9 +4349,17 @@ OPENSSL_EXPORT void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx,
int enable);
// SSL_CTX_set_grease_enabled configures whether sockets on |ctx| should enable
-// GREASE. See draft-davidben-tls-grease-01.
+// GREASE. See RFC 8701.
OPENSSL_EXPORT void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled);
+// SSL_CTX_set_permute_extensions configures whether sockets on |ctx| should
+// permute extensions. For now, this is only implemented for the ClientHello.
+OPENSSL_EXPORT void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled);
+
+// SSL_set_permute_extensions configures whether sockets on |ssl| should
+// permute extensions. For now, this is only implemented for the ClientHello.
+OPENSSL_EXPORT void SSL_set_permute_extensions(SSL *ssl, int enabled);
+
// SSL_max_seal_overhead returns the maximum overhead, in bytes, of sealing a
// record with |ssl|.
OPENSSL_EXPORT size_t SSL_max_seal_overhead(const SSL *ssl);
@@ -4630,12 +4894,6 @@ OPENSSL_EXPORT int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key);
OPENSSL_EXPORT int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *out,
const char *dir);
-// SSL_set_verify_result calls |abort| unless |result| is |X509_V_OK|.
-//
-// TODO(davidben): Remove this function once it has been removed from
-// netty-tcnative.
-OPENSSL_EXPORT void SSL_set_verify_result(SSL *ssl, long result);
-
// SSL_CTX_enable_tls_channel_id calls |SSL_CTX_set_tls_channel_id_enabled|.
OPENSSL_EXPORT int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx);
@@ -4782,18 +5040,6 @@ OPENSSL_EXPORT int SSL_CTX_set_tlsext_status_arg(SSL_CTX *ctx, void *arg);
// name and remove this one.
OPENSSL_EXPORT uint16_t SSL_CIPHER_get_value(const SSL_CIPHER *cipher);
-// SSL_CTX_set_ignore_tls13_downgrade does nothing.
-OPENSSL_EXPORT void SSL_CTX_set_ignore_tls13_downgrade(SSL_CTX *ctx,
- int ignore);
-
-// SSL_set_ignore_tls13_downgrade does nothing.
-OPENSSL_EXPORT void SSL_set_ignore_tls13_downgrade(SSL *ssl, int ignore);
-
-// SSL_is_tls13_downgrade returns zero. Historically, this function returned
-// whether the TLS 1.3 downgrade signal would have been enforced if not
-// disabled. The TLS 1.3 downgrade signal is now always enforced.
-OPENSSL_EXPORT int SSL_is_tls13_downgrade(const SSL *ssl);
-
// Nodejs compatibility section (hidden).
//
@@ -4956,6 +5202,8 @@ BSSL_NAMESPACE_BEGIN
BORINGSSL_MAKE_DELETER(SSL, SSL_free)
BORINGSSL_MAKE_DELETER(SSL_CTX, SSL_CTX_free)
BORINGSSL_MAKE_UP_REF(SSL_CTX, SSL_CTX_up_ref)
+BORINGSSL_MAKE_DELETER(SSL_ECH_KEYS, SSL_ECH_KEYS_free)
+BORINGSSL_MAKE_UP_REF(SSL_ECH_KEYS, SSL_ECH_KEYS_up_ref)
BORINGSSL_MAKE_DELETER(SSL_SESSION, SSL_SESSION_free)
BORINGSSL_MAKE_UP_REF(SSL_SESSION, SSL_SESSION_up_ref)
@@ -5072,6 +5320,7 @@ OPENSSL_EXPORT bool SSL_get_traffic_secrets(
const SSL *ssl, Span<const uint8_t> *out_read_traffic_secret,
Span<const uint8_t> *out_write_traffic_secret);
+
BSSL_NAMESPACE_END
} // extern C++
@@ -5286,9 +5535,21 @@ BSSL_NAMESPACE_END
#define SSL_R_CIPHER_MISMATCH_ON_EARLY_DATA 304
#define SSL_R_QUIC_TRANSPORT_PARAMETERS_MISCONFIGURED 305
#define SSL_R_UNEXPECTED_COMPATIBILITY_MODE 306
-#define SSL_R_MISSING_ALPN 307
+#define SSL_R_NO_APPLICATION_PROTOCOL 307
#define SSL_R_NEGOTIATED_ALPS_WITHOUT_ALPN 308
#define SSL_R_ALPS_MISMATCH_ON_EARLY_DATA 309
+#define SSL_R_ECH_SERVER_CONFIG_AND_PRIVATE_KEY_MISMATCH 310
+#define SSL_R_ECH_SERVER_CONFIG_UNSUPPORTED_EXTENSION 311
+#define SSL_R_UNSUPPORTED_ECH_SERVER_CONFIG 312
+#define SSL_R_ECH_SERVER_WOULD_HAVE_NO_RETRY_CONFIGS 313
+#define SSL_R_INVALID_CLIENT_HELLO_INNER 314
+#define SSL_R_INVALID_ALPN_PROTOCOL_LIST 315
+#define SSL_R_COULD_NOT_PARSE_HINTS 316
+#define SSL_R_INVALID_ECH_PUBLIC_NAME 317
+#define SSL_R_INVALID_ECH_CONFIG_LIST 318
+#define SSL_R_ECH_REJECTED 319
+#define SSL_R_OUTER_EXTENSION_NOT_FOUND 320
+#define SSL_R_INCONSISTENT_ECH_NEGOTIATION 321
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
@@ -5322,5 +5583,6 @@ BSSL_NAMESPACE_END
#define SSL_R_TLSV1_ALERT_UNKNOWN_PSK_IDENTITY 1115
#define SSL_R_TLSV1_ALERT_CERTIFICATE_REQUIRED 1116
#define SSL_R_TLSV1_ALERT_NO_APPLICATION_PROTOCOL 1120
+#define SSL_R_TLSV1_ALERT_ECH_REQUIRED 1121
#endif // OPENSSL_HEADER_SSL_H
diff --git a/deps/boringssl/src/include/openssl/tls1.h b/deps/boringssl/src/include/openssl/tls1.h
index da79a08..a3136c0 100644
--- a/deps/boringssl/src/include/openssl/tls1.h
+++ b/deps/boringssl/src/include/openssl/tls1.h
@@ -171,7 +171,6 @@ extern "C" {
#define TLS1_AD_USER_CANCELLED 90
#define TLS1_AD_NO_RENEGOTIATION 100
#define TLS1_AD_MISSING_EXTENSION 109
-// codes 110-114 are from RFC3546
#define TLS1_AD_UNSUPPORTED_EXTENSION 110
#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111
#define TLS1_AD_UNRECOGNIZED_NAME 112
@@ -180,59 +179,53 @@ extern "C" {
#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115
#define TLS1_AD_CERTIFICATE_REQUIRED 116
#define TLS1_AD_NO_APPLICATION_PROTOCOL 120
+#define TLS1_AD_ECH_REQUIRED 121 // draft-ietf-tls-esni-13
-// ExtensionType values from RFC6066
+// ExtensionType values from RFC 6066
#define TLSEXT_TYPE_server_name 0
#define TLSEXT_TYPE_status_request 5
-// ExtensionType values from RFC4492
+// ExtensionType values from RFC 4492
#define TLSEXT_TYPE_ec_point_formats 11
-// ExtensionType values from RFC5246
+// ExtensionType values from RFC 5246
#define TLSEXT_TYPE_signature_algorithms 13
-// ExtensionType value from RFC5764
+// ExtensionType value from RFC 5764
#define TLSEXT_TYPE_srtp 14
-// ExtensionType value from RFC7301
+// ExtensionType value from RFC 7301
#define TLSEXT_TYPE_application_layer_protocol_negotiation 16
-// ExtensionType value from RFC7685
+// ExtensionType value from RFC 7685
#define TLSEXT_TYPE_padding 21
-// ExtensionType value from RFC7627
+// ExtensionType value from RFC 7627
#define TLSEXT_TYPE_extended_master_secret 23
-// ExtensionType value from draft-ietf-tokbind-negotiation-10
-#define TLSEXT_TYPE_token_binding 24
-
// ExtensionType value from draft-ietf-quic-tls. Drafts 00 through 32 use
// 0xffa5 which is part of the Private Use section of the registry, and it
// collides with TLS-LTS and, based on scans, something else too (though this
// hasn't been a problem in practice since it's QUIC-only). Drafts 33 onward
// use the value 57 which was officially registered with IANA.
#define TLSEXT_TYPE_quic_transport_parameters_legacy 0xffa5
-#define TLSEXT_TYPE_quic_transport_parameters_standard 57
-
-// TLSEXT_TYPE_quic_transport_parameters is an alias for
-// |TLSEXT_TYPE_quic_transport_parameters_legacy|. It will switch to
-// |TLSEXT_TYPE_quic_transport_parameters_standard| at a later date.
-//
-// Callers using |SSL_set_quic_use_legacy_codepoint| should use
-// |TLSEXT_TYPE_quic_transport_parameters_legacy| or
-// |TLSEXT_TYPE_quic_transport_parameters_standard| rather than this constant.
-// When the default code point is switched to the standard one, this value will
-// be updated and we will transition callers back to the unsuffixed constant.
-#define TLSEXT_TYPE_quic_transport_parameters \
- TLSEXT_TYPE_quic_transport_parameters_legacy
-
-// ExtensionType value from RFC8879
+
+// ExtensionType value from RFC 9000
+#define TLSEXT_TYPE_quic_transport_parameters 57
+
+// TLSEXT_TYPE_quic_transport_parameters_standard is an alias for
+// |TLSEXT_TYPE_quic_transport_parameters|. Use
+// |TLSEXT_TYPE_quic_transport_parameters| instead.
+#define TLSEXT_TYPE_quic_transport_parameters_standard \
+ TLSEXT_TYPE_quic_transport_parameters
+
+// ExtensionType value from RFC 8879
#define TLSEXT_TYPE_cert_compression 27
-// ExtensionType value from RFC4507
+// ExtensionType value from RFC 4507
#define TLSEXT_TYPE_session_ticket 35
-// ExtensionType values from RFC8446
+// ExtensionType values from RFC 8446
#define TLSEXT_TYPE_supported_groups 10
#define TLSEXT_TYPE_pre_shared_key 41
#define TLSEXT_TYPE_early_data 42
@@ -243,7 +236,7 @@ extern "C" {
#define TLSEXT_TYPE_signature_algorithms_cert 50
#define TLSEXT_TYPE_key_share 51
-// ExtensionType value from RFC5746
+// ExtensionType value from RFC 5746
#define TLSEXT_TYPE_renegotiate 0xff01
// ExtensionType value from draft-ietf-tls-subcerts.
@@ -253,12 +246,12 @@ extern "C" {
// extension number.
#define TLSEXT_TYPE_application_settings 17513
-// ExtensionType values from draft-ietf-tls-esni-09. This is not an IANA defined
+// ExtensionType values from draft-ietf-tls-esni-13. This is not an IANA defined
// extension number.
-#define TLSEXT_TYPE_encrypted_client_hello 0xfe09
-#define TLSEXT_TYPE_ech_is_inner 0xda09
+#define TLSEXT_TYPE_encrypted_client_hello 0xfe0d
+#define TLSEXT_TYPE_ech_outer_extensions 0xfd00
-// ExtensionType value from RFC6962
+// ExtensionType value from RFC 6962
#define TLSEXT_TYPE_certificate_timestamp 18
// This is not an IANA defined extension number
@@ -319,7 +312,7 @@ extern "C" {
#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x03000065
#define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA 0x03000066
-// AES ciphersuites from RFC3268
+// AES ciphersuites from RFC 3268
#define TLS1_CK_RSA_WITH_AES_128_SHA 0x0300002F
#define TLS1_CK_DH_DSS_WITH_AES_128_SHA 0x03000030
@@ -343,7 +336,7 @@ extern "C" {
#define TLS1_CK_DH_RSA_WITH_AES_128_SHA256 0x0300003F
#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA256 0x03000040
-// Camellia ciphersuites from RFC4132
+// Camellia ciphersuites from RFC 4132
#define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000041
#define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000042
#define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000043
@@ -360,7 +353,7 @@ extern "C" {
#define TLS1_CK_ADH_WITH_AES_128_SHA256 0x0300006C
#define TLS1_CK_ADH_WITH_AES_256_SHA256 0x0300006D
-// Camellia ciphersuites from RFC4132
+// Camellia ciphersuites from RFC 4132
#define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000084
#define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000085
#define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000086
@@ -368,7 +361,7 @@ extern "C" {
#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000088
#define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA 0x03000089
-// SEED ciphersuites from RFC4162
+// SEED ciphersuites from RFC 4162
#define TLS1_CK_RSA_WITH_SEED_SHA 0x03000096
#define TLS1_CK_DH_DSS_WITH_SEED_SHA 0x03000097
#define TLS1_CK_DH_RSA_WITH_SEED_SHA 0x03000098
@@ -376,7 +369,7 @@ extern "C" {
#define TLS1_CK_DHE_RSA_WITH_SEED_SHA 0x0300009A
#define TLS1_CK_ADH_WITH_SEED_SHA 0x0300009B
-// TLS v1.2 GCM ciphersuites from RFC5288
+// TLS v1.2 GCM ciphersuites from RFC 5288
#define TLS1_CK_RSA_WITH_AES_128_GCM_SHA256 0x0300009C
#define TLS1_CK_RSA_WITH_AES_256_GCM_SHA384 0x0300009D
#define TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 0x0300009E
@@ -390,7 +383,7 @@ extern "C" {
#define TLS1_CK_ADH_WITH_AES_128_GCM_SHA256 0x030000A6
#define TLS1_CK_ADH_WITH_AES_256_GCM_SHA384 0x030000A7
-// ECC ciphersuites from RFC4492
+// ECC ciphersuites from RFC 4492
#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA 0x0300C001
#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA 0x0300C002
#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C003
@@ -432,7 +425,7 @@ extern "C" {
#define TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA 0x0300C021
#define TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA 0x0300C022
-// ECDH HMAC based ciphersuites from RFC5289
+// ECDH HMAC based ciphersuites from RFC 5289
#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256 0x0300C023
#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384 0x0300C024
@@ -443,7 +436,7 @@ extern "C" {
#define TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256 0x0300C029
#define TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384 0x0300C02A
-// ECDH GCM based ciphersuites from RFC5289
+// ECDH GCM based ciphersuites from RFC 5289
#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02B
#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02C
#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02D
@@ -479,7 +472,7 @@ extern "C" {
#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA "EXP1024-DHE-DSS-RC4-SHA"
#define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA "DHE-DSS-RC4-SHA"
-// AES ciphersuites from RFC3268
+// AES ciphersuites from RFC 3268
#define TLS1_TXT_RSA_WITH_AES_128_SHA "AES128-SHA"
#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA "DH-DSS-AES128-SHA"
#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA "DH-RSA-AES128-SHA"
@@ -494,7 +487,7 @@ extern "C" {
#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA "DHE-RSA-AES256-SHA"
#define TLS1_TXT_ADH_WITH_AES_256_SHA "ADH-AES256-SHA"
-// ECC ciphersuites from RFC4492
+// ECC ciphersuites from RFC 4492
#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA "ECDH-ECDSA-NULL-SHA"
#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA "ECDH-ECDSA-RC4-SHA"
#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA "ECDH-ECDSA-DES-CBC3-SHA"
@@ -546,7 +539,7 @@ extern "C" {
#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA "SRP-RSA-AES-256-CBC-SHA"
#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA "SRP-DSS-AES-256-CBC-SHA"
-// Camellia ciphersuites from RFC4132
+// Camellia ciphersuites from RFC 4132
#define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA "CAMELLIA128-SHA"
#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA "DH-DSS-CAMELLIA128-SHA"
#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA "DH-RSA-CAMELLIA128-SHA"
@@ -561,7 +554,7 @@ extern "C" {
#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA "DHE-RSA-CAMELLIA256-SHA"
#define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA "ADH-CAMELLIA256-SHA"
-// SEED ciphersuites from RFC4162
+// SEED ciphersuites from RFC 4162
#define TLS1_TXT_RSA_WITH_SEED_SHA "SEED-SHA"
#define TLS1_TXT_DH_DSS_WITH_SEED_SHA "DH-DSS-SEED-SHA"
#define TLS1_TXT_DH_RSA_WITH_SEED_SHA "DH-RSA-SEED-SHA"
@@ -584,7 +577,7 @@ extern "C" {
#define TLS1_TXT_ADH_WITH_AES_128_SHA256 "ADH-AES128-SHA256"
#define TLS1_TXT_ADH_WITH_AES_256_SHA256 "ADH-AES256-SHA256"
-// TLS v1.2 GCM ciphersuites from RFC5288
+// TLS v1.2 GCM ciphersuites from RFC 5288
#define TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256 "AES128-GCM-SHA256"
#define TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384 "AES256-GCM-SHA384"
#define TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 "DHE-RSA-AES128-GCM-SHA256"
@@ -598,7 +591,7 @@ extern "C" {
#define TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256 "ADH-AES128-GCM-SHA256"
#define TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384 "ADH-AES256-GCM-SHA384"
-// ECDH HMAC based ciphersuites from RFC5289
+// ECDH HMAC based ciphersuites from RFC 5289
#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256 "ECDHE-ECDSA-AES128-SHA256"
#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384 "ECDHE-ECDSA-AES256-SHA384"
@@ -609,7 +602,7 @@ extern "C" {
#define TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256 "ECDH-RSA-AES128-SHA256"
#define TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384 "ECDH-RSA-AES256-SHA384"
-// ECDH GCM based ciphersuites from RFC5289
+// ECDH GCM based ciphersuites from RFC 5289
#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \
"ECDHE-ECDSA-AES128-GCM-SHA256"
#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 \
diff --git a/deps/boringssl/src/include/openssl/x509.h b/deps/boringssl/src/include/openssl/x509.h
index a75442f..f4444c9 100644
--- a/deps/boringssl/src/include/openssl/x509.h
+++ b/deps/boringssl/src/include/openssl/x509.h
@@ -110,148 +110,36 @@ extern "C" {
#define X509v3_KU_DECIPHER_ONLY 0x8000
#define X509v3_KU_UNDEF 0xffff
-DEFINE_STACK_OF(X509_ALGOR)
-DECLARE_ASN1_SET_OF(X509_ALGOR)
-
-typedef STACK_OF(X509_ALGOR) X509_ALGORS;
+struct X509_algor_st {
+ ASN1_OBJECT *algorithm;
+ ASN1_TYPE *parameter;
+} /* X509_ALGOR */;
-struct X509_val_st {
- ASN1_TIME *notBefore;
- ASN1_TIME *notAfter;
-} /* X509_VAL */;
+DECLARE_ASN1_FUNCTIONS(X509_ALGOR)
-struct X509_pubkey_st {
- X509_ALGOR *algor;
- ASN1_BIT_STRING *public_key;
- EVP_PKEY *pkey;
-};
-
-struct X509_sig_st {
- X509_ALGOR *algor;
- ASN1_OCTET_STRING *digest;
-} /* X509_SIG */;
+DEFINE_STACK_OF(X509_ALGOR)
-struct X509_name_entry_st {
- ASN1_OBJECT *object;
- ASN1_STRING *value;
- int set;
- int size; // temp variable
-} /* X509_NAME_ENTRY */;
+typedef STACK_OF(X509_ALGOR) X509_ALGORS;
DEFINE_STACK_OF(X509_NAME_ENTRY)
-DECLARE_ASN1_SET_OF(X509_NAME_ENTRY)
-
-// we always keep X509_NAMEs in 2 forms.
-struct X509_name_st {
- STACK_OF(X509_NAME_ENTRY) *entries;
- int modified; // true if 'bytes' needs to be built
- BUF_MEM *bytes;
- // unsigned long hash; Keep the hash around for lookups
- unsigned char *canon_enc;
- int canon_enclen;
-} /* X509_NAME */;
DEFINE_STACK_OF(X509_NAME)
-struct X509_extension_st {
- ASN1_OBJECT *object;
- ASN1_BOOLEAN critical;
- ASN1_OCTET_STRING *value;
-} /* X509_EXTENSION */;
-
typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
DEFINE_STACK_OF(X509_EXTENSION)
-DECLARE_ASN1_SET_OF(X509_EXTENSION)
-
-// a sequence of these are used
-struct x509_attributes_st {
- ASN1_OBJECT *object;
- int single; // 0 for a set, 1 for a single item (which is wrong)
- union {
- char *ptr;
- /* 0 */ STACK_OF(ASN1_TYPE) *set;
- /* 1 */ ASN1_TYPE *single;
- } value;
-} /* X509_ATTRIBUTE */;
DEFINE_STACK_OF(X509_ATTRIBUTE)
-DECLARE_ASN1_SET_OF(X509_ATTRIBUTE)
-
-
-struct X509_req_info_st {
- ASN1_ENCODING enc;
- ASN1_INTEGER *version;
- X509_NAME *subject;
- X509_PUBKEY *pubkey;
- // d=2 hl=2 l= 0 cons: cont: 00
- STACK_OF(X509_ATTRIBUTE) *attributes; // [ 0 ]
-} /* X509_REQ_INFO */;
-
-struct X509_req_st {
- X509_REQ_INFO *req_info;
- X509_ALGOR *sig_alg;
- ASN1_BIT_STRING *signature;
- CRYPTO_refcount_t references;
-} /* X509_REQ */;
-
-struct x509_cinf_st {
- ASN1_INTEGER *version; // [ 0 ] default of v1
- ASN1_INTEGER *serialNumber;
- X509_ALGOR *signature;
- X509_NAME *issuer;
- X509_VAL *validity;
- X509_NAME *subject;
- X509_PUBKEY *key;
- ASN1_BIT_STRING *issuerUID; // [ 1 ] optional in v2
- ASN1_BIT_STRING *subjectUID; // [ 2 ] optional in v2
- STACK_OF(X509_EXTENSION) *extensions; // [ 3 ] optional in v3
- ASN1_ENCODING enc;
-} /* X509_CINF */;
// This stuff is certificate "auxiliary info"
// it contains details which are useful in certificate
// stores and databases. When used this is tagged onto
// the end of the certificate itself
-struct x509_cert_aux_st {
- STACK_OF(ASN1_OBJECT) *trust; // trusted uses
- STACK_OF(ASN1_OBJECT) *reject; // rejected uses
- ASN1_UTF8STRING *alias; // "friendly name"
- ASN1_OCTET_STRING *keyid; // key id of private key
- STACK_OF(X509_ALGOR) *other; // other unspecified info
-} /* X509_CERT_AUX */;
-
DECLARE_STACK_OF(DIST_POINT)
DECLARE_STACK_OF(GENERAL_NAME)
-struct x509_st {
- X509_CINF *cert_info;
- X509_ALGOR *sig_alg;
- ASN1_BIT_STRING *signature;
- CRYPTO_refcount_t references;
- CRYPTO_EX_DATA ex_data;
- // These contain copies of various extension values
- long ex_pathlen;
- long ex_pcpathlen;
- unsigned long ex_flags;
- unsigned long ex_kusage;
- unsigned long ex_xkusage;
- unsigned long ex_nscert;
- ASN1_OCTET_STRING *skid;
- AUTHORITY_KEYID *akid;
- X509_POLICY_CACHE *policy_cache;
- STACK_OF(DIST_POINT) *crldp;
- STACK_OF(GENERAL_NAME) *altname;
- NAME_CONSTRAINTS *nc;
- unsigned char sha1_hash[SHA_DIGEST_LENGTH];
- X509_CERT_AUX *aux;
- CRYPTO_BUFFER *buf;
- CRYPTO_MUTEX lock;
-} /* X509 */;
-
DEFINE_STACK_OF(X509)
-DECLARE_ASN1_SET_OF(X509)
// This is used for a table of trust checking functions
@@ -318,7 +206,7 @@ DEFINE_STACK_OF(X509_TRUST)
#define XN_FLAG_SEP_MASK (0xf << 16)
#define XN_FLAG_COMPAT 0 // Traditional SSLeay: use old X509_NAME_print
-#define XN_FLAG_SEP_COMMA_PLUS (1 << 16) // RFC2253 ,+
+#define XN_FLAG_SEP_COMMA_PLUS (1 << 16) // RFC 2253 ,+
#define XN_FLAG_SEP_CPLUS_SPC (2 << 16) // ,+ spaced: more readable
#define XN_FLAG_SEP_SPLUS_SPC (3 << 16) // ;+ spaced
#define XN_FLAG_SEP_MULTILINE (4 << 16) // One line per field
@@ -337,13 +225,13 @@ DEFINE_STACK_OF(X509_TRUST)
#define XN_FLAG_SPC_EQ (1 << 23) // Put spaces round '='
// This determines if we dump fields we don't recognise:
-// RFC2253 requires this.
+// RFC 2253 requires this.
#define XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24)
#define XN_FLAG_FN_ALIGN (1 << 25) // Align field names to 20 characters
-// Complete set of RFC2253 flags
+// Complete set of RFC 2253 flags
#define XN_FLAG_RFC2253 \
(ASN1_STRFLGS_RFC2253 | XN_FLAG_SEP_COMMA_PLUS | XN_FLAG_DN_REV | \
@@ -373,45 +261,10 @@ struct x509_revoked_st {
};
DEFINE_STACK_OF(X509_REVOKED)
-DECLARE_ASN1_SET_OF(X509_REVOKED)
-
-struct X509_crl_info_st {
- ASN1_INTEGER *version;
- X509_ALGOR *sig_alg;
- X509_NAME *issuer;
- ASN1_TIME *lastUpdate;
- ASN1_TIME *nextUpdate;
- STACK_OF(X509_REVOKED) *revoked;
- STACK_OF(X509_EXTENSION) /* [0] */ *extensions;
- ASN1_ENCODING enc;
-} /* X509_CRL_INFO */;
DECLARE_STACK_OF(GENERAL_NAMES)
-struct X509_crl_st {
- // actual signature
- X509_CRL_INFO *crl;
- X509_ALGOR *sig_alg;
- ASN1_BIT_STRING *signature;
- CRYPTO_refcount_t references;
- int flags;
- // Copies of various extensions
- AUTHORITY_KEYID *akid;
- ISSUING_DIST_POINT *idp;
- // Convenient breakdown of IDP
- int idp_flags;
- int idp_reasons;
- // CRL and base CRL numbers for delta processing
- ASN1_INTEGER *crl_number;
- ASN1_INTEGER *base_crl_number;
- unsigned char sha1_hash[SHA_DIGEST_LENGTH];
- STACK_OF(GENERAL_NAMES) *issuers;
- const X509_CRL_METHOD *meth;
- void *meth_data;
-} /* X509_CRL */;
-
DEFINE_STACK_OF(X509_CRL)
-DECLARE_ASN1_SET_OF(X509_CRL)
struct private_key_st {
int version;
@@ -475,16 +328,33 @@ extern "C" {
// it is safe to call mutating functions is a little tricky due to various
// internal caches.
-// X509_get_version returns the numerical value of |x509|'s version. That is,
-// it returns zero for X.509v1, one for X.509v2, and two for X.509v3. Unknown
-// versions are rejected by the parser, but a manually-created |X509| object may
-// encode invalid versions. In that case, the function will return the invalid
-// version, or -1 on overflow.
+// X509_VERSION_* are X.509 version numbers. Note the numerical values of all
+// defined X.509 versions are one less than the named version.
+#define X509_VERSION_1 0
+#define X509_VERSION_2 1
+#define X509_VERSION_3 2
+
+// X509_get_version returns the numerical value of |x509|'s version. Callers may
+// compare the result to the |X509_VERSION_*| constants. Unknown versions are
+// rejected by the parser, but a manually-created |X509| object may encode
+// invalid versions. In that case, the function will return the invalid version,
+// or -1 on overflow.
OPENSSL_EXPORT long X509_get_version(const X509 *x509);
+// X509_set_version sets |x509|'s version to |version|, which should be one of
+// the |X509V_VERSION_*| constants. It returns one on success and zero on error.
+//
+// If unsure, use |X509_VERSION_3|.
+OPENSSL_EXPORT int X509_set_version(X509 *x509, long version);
+
// X509_get0_serialNumber returns |x509|'s serial number.
OPENSSL_EXPORT const ASN1_INTEGER *X509_get0_serialNumber(const X509 *x509);
+// X509_set_serialNumber sets |x509|'s serial number to |serial|. It returns one
+// on success and zero on error.
+OPENSSL_EXPORT int X509_set_serialNumber(X509 *x509,
+ const ASN1_INTEGER *serial);
+
// X509_get0_notBefore returns |x509|'s notBefore time.
OPENSSL_EXPORT const ASN1_TIME *X509_get0_notBefore(const X509 *x509);
@@ -523,26 +393,22 @@ OPENSSL_EXPORT int X509_set_notBefore(X509 *x509, const ASN1_TIME *tm);
// instead.
OPENSSL_EXPORT int X509_set_notAfter(X509 *x509, const ASN1_TIME *tm);
-// X509_get0_uids sets |*out_issuer_uid| and |*out_subject_uid| to non-owning
-// pointers to the issuerUID and subjectUID fields, respectively, of |x509|.
-// Either output pointer may be NULL to skip the field.
+// X509_get0_uids sets |*out_issuer_uid| to a non-owning pointer to the
+// issuerUID field of |x509|, or NULL if |x509| has no issuerUID. It similarly
+// outputs |x509|'s subjectUID field to |*out_subject_uid|.
+//
+// Callers may pass NULL to either |out_issuer_uid| or |out_subject_uid| to
+// ignore the corresponding field.
OPENSSL_EXPORT void X509_get0_uids(const X509 *x509,
const ASN1_BIT_STRING **out_issuer_uid,
const ASN1_BIT_STRING **out_subject_uid);
-// X509_get_cert_info returns |x509|'s TBSCertificate structure. Note this
-// function is not const-correct for legacy reasons.
-//
-// This function is deprecated and may be removed in the future. It is not
-// present in OpenSSL and constrains some improvements to the library.
-OPENSSL_EXPORT X509_CINF *X509_get_cert_info(const X509 *x509);
-
// X509_extract_key is a legacy alias to |X509_get_pubkey|. Use
// |X509_get_pubkey| instead.
#define X509_extract_key(x) X509_get_pubkey(x)
// X509_get_pathlen returns path length constraint from the basic constraints
-// extension in |x509|. (See RFC5280, section 4.2.1.9.) It returns -1 if the
+// extension in |x509|. (See RFC 5280, section 4.2.1.9.) It returns -1 if the
// constraint is not present, or if some extension in |x509| was invalid.
//
// Note that decoding an |X509| object will not check for invalid extensions. To
@@ -550,9 +416,15 @@ OPENSSL_EXPORT X509_CINF *X509_get_cert_info(const X509 *x509);
// |EXFLAG_INVALID| bit.
OPENSSL_EXPORT long X509_get_pathlen(X509 *x509);
-// X509_REQ_get_version returns the numerical value of |req|'s version. That is,
-// it returns zero for a v1 request. If |req| is invalid, it may return another
-// value, or -1 on overflow.
+// X509_REQ_VERSION_1 is the version constant for |X509_REQ| objects. Note no
+// other versions are defined.
+#define X509_REQ_VERSION_1 0
+
+// X509_REQ_get_version returns the numerical value of |req|'s version. This
+// will be |X509_REQ_VERSION_1| for valid certificate requests. If |req| is
+// invalid, it may return another value, or -1 on overflow.
+//
+// TODO(davidben): Enforce the version number in the parser.
OPENSSL_EXPORT long X509_REQ_get_version(const X509_REQ *req);
// X509_REQ_get_subject_name returns |req|'s subject name. Note this function is
@@ -565,9 +437,14 @@ OPENSSL_EXPORT X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req);
// X509_name_cmp is a legacy alias for |X509_NAME_cmp|.
#define X509_name_cmp(a, b) X509_NAME_cmp((a), (b))
-// X509_REQ_get_version returns the numerical value of |crl|'s version. That is,
-// it returns zero for a v1 CRL and one for a v2 CRL. If |crl| is invalid, it
-// may return another value, or -1 on overflow.
+#define X509_CRL_VERSION_1 0
+#define X509_CRL_VERSION_2 1
+
+// X509_CRL_get_version returns the numerical value of |crl|'s version. Callers
+// may compare the result to |X509_CRL_VERSION_*| constants. If |crl| is
+// invalid, it may return another value, or -1 on overflow.
+//
+// TODO(davidben): Enforce the version number in the parser.
OPENSSL_EXPORT long X509_CRL_get_version(const X509_CRL *crl);
// X509_CRL_get0_lastUpdate returns |crl|'s lastUpdate time.
@@ -602,33 +479,19 @@ OPENSSL_EXPORT ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *crl);
// const-correct for legacy reasons.
OPENSSL_EXPORT X509_NAME *X509_CRL_get_issuer(const X509_CRL *crl);
-// X509_CRL_get_REVOKED returns the list of revoked certificates in |crl|.
+// X509_CRL_get_REVOKED returns the list of revoked certificates in |crl|, or
+// NULL if |crl| omits it.
//
// TOOD(davidben): This function was originally a macro, without clear const
// semantics. It should take a const input and give const output, but the latter
// would break existing callers. For now, we match upstream.
OPENSSL_EXPORT STACK_OF(X509_REVOKED) *X509_CRL_get_REVOKED(X509_CRL *crl);
-// X509_CRL_get0_extensions returns |crl|'s extension list.
+// X509_CRL_get0_extensions returns |crl|'s extension list, or NULL if |crl|
+// omits it.
OPENSSL_EXPORT const STACK_OF(X509_EXTENSION) *X509_CRL_get0_extensions(
const X509_CRL *crl);
-// X509_CINF_set_modified marks |cinf| as modified so that changes will be
-// reflected in serializing the structure.
-//
-// This function is deprecated and may be removed in the future. It is not
-// present in OpenSSL and constrains some improvements to the library.
-OPENSSL_EXPORT void X509_CINF_set_modified(X509_CINF *cinf);
-
-// X509_CINF_get_signature returns the signature algorithm in |cinf|. Note this
-// isn't the signature itself, but the extra copy of the signature algorithm
-// in the TBSCertificate.
-//
-// This function is deprecated and may be removed in the future. It is not
-// present in OpenSSL and constrains some improvements to the library. Use
-// |X509_get0_tbs_sigalg| instead.
-OPENSSL_EXPORT const X509_ALGOR *X509_CINF_get_signature(const X509_CINF *cinf);
-
// X509_SIG_get0 sets |*out_alg| and |*out_digest| to non-owning pointers to
// |sig|'s algorithm and digest fields, respectively. Either |out_alg| and
// |out_digest| may be NULL to skip those fields.
@@ -813,7 +676,6 @@ OPENSSL_EXPORT int X509_NAME_digest(const X509_NAME *name, const EVP_MD *md,
// copying parts of it as a normal |d2i_X509| call would do.
OPENSSL_EXPORT X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf);
-#ifndef OPENSSL_NO_FP_API
OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509);
OPENSSL_EXPORT int i2d_X509_fp(FILE *fp, X509 *x509);
OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl);
@@ -847,7 +709,6 @@ OPENSSL_EXPORT int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey);
OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a);
OPENSSL_EXPORT int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey);
OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a);
-#endif
OPENSSL_EXPORT X509 *d2i_X509_bio(BIO *bp, X509 **x509);
OPENSSL_EXPORT int i2d_X509_bio(BIO *bp, X509 *x509);
@@ -892,12 +753,54 @@ OPENSSL_EXPORT X509_CRL *X509_CRL_dup(X509_CRL *crl);
OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev);
OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req);
OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn);
-OPENSSL_EXPORT int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj,
- int ptype, void *pval);
-OPENSSL_EXPORT void X509_ALGOR_get0(const ASN1_OBJECT **paobj, int *pptype,
- const void **ppval,
- const X509_ALGOR *algor);
+
+// X509_ALGOR_set0 sets |alg| to an AlgorithmIdentifier with algorithm |obj| and
+// parameter determined by |param_type| and |param_value|. It returns one on
+// success and zero on error. This function takes ownership of |obj| and
+// |param_value| on success.
+//
+// If |param_type| is |V_ASN1_UNDEF|, the parameter is omitted. If |param_type|
+// is zero, the parameter is left unchanged. Otherwise, |param_type| and
+// |param_value| are interpreted as in |ASN1_TYPE_set|.
+//
+// Note omitting the parameter (|V_ASN1_UNDEF|) and encoding an explicit NULL
+// value (|V_ASN1_NULL|) are different. Some algorithms require one and some the
+// other. Consult the relevant specification before calling this function. The
+// correct parameter for an RSASSA-PKCS1-v1_5 signature is |V_ASN1_NULL|. The
+// correct one for an ECDSA or Ed25519 signature is |V_ASN1_UNDEF|.
+OPENSSL_EXPORT int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *obj,
+ int param_type, void *param_value);
+
+// X509_ALGOR_get0 sets |*out_obj| to the |alg|'s algorithm. If |alg|'s
+// parameter is omitted, it sets |*out_param_type| and |*out_param_value| to
+// |V_ASN1_UNDEF| and NULL. Otherwise, it sets |*out_param_type| and
+// |*out_param_value| to the parameter, using the same representation as
+// |ASN1_TYPE_set0|. See |ASN1_TYPE_set0| and |ASN1_TYPE| for details.
+//
+// Callers that require the parameter in serialized form should, after checking
+// for |V_ASN1_UNDEF|, use |ASN1_TYPE_set1| and |d2i_ASN1_TYPE|, rather than
+// inspecting |*out_param_value|.
+//
+// Each of |out_obj|, |out_param_type|, and |out_param_value| may be NULL to
+// ignore the output. If |out_param_type| is NULL, |out_param_value| is ignored.
+//
+// WARNING: If |*out_param_type| is set to |V_ASN1_UNDEF|, OpenSSL and older
+// revisions of BoringSSL leave |*out_param_value| unset rather than setting it
+// to NULL. Callers that support both OpenSSL and BoringSSL should not assume
+// |*out_param_value| is uniformly initialized.
+OPENSSL_EXPORT void X509_ALGOR_get0(const ASN1_OBJECT **out_obj,
+ int *out_param_type,
+ const void **out_param_value,
+ const X509_ALGOR *alg);
+
+// X509_ALGOR_set_md sets |alg| to the hash function |md|. Note this
+// AlgorithmIdentifier represents the hash function itself, not a signature
+// algorithm that uses |md|.
OPENSSL_EXPORT void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md);
+
+// X509_ALGOR_cmp returns zero if |a| and |b| are equal, and some non-zero value
+// otherwise. Note this function can only be used for equality checks, not an
+// ordering.
OPENSSL_EXPORT int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b);
OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *xn);
@@ -907,12 +810,30 @@ OPENSSL_EXPORT int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne);
OPENSSL_EXPORT int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder,
size_t *pderlen);
+// X509_cmp_time compares |s| against |*t|. On success, it returns a negative
+// number if |s| <= |*t| and a positive number if |s| > |*t|. On error, it
+// returns zero. If |t| is NULL, it uses the current time instead of |*t|.
+//
+// WARNING: Unlike most comparison functions, this function returns zero on
+// error, not equality.
OPENSSL_EXPORT int X509_cmp_time(const ASN1_TIME *s, time_t *t);
+
+// X509_cmp_current_time behaves like |X509_cmp_time| but compares |s| against
+// the current time.
OPENSSL_EXPORT int X509_cmp_current_time(const ASN1_TIME *s);
-OPENSSL_EXPORT ASN1_TIME *X509_time_adj(ASN1_TIME *s, long adj, time_t *t);
+
+// X509_time_adj calls |X509_time_adj_ex| with |offset_day| equal to zero.
+OPENSSL_EXPORT ASN1_TIME *X509_time_adj(ASN1_TIME *s, long offset_sec,
+ time_t *t);
+
+// X509_time_adj_ex behaves like |ASN1_TIME_adj|, but adds an offset to |*t|. If
+// |t| is NULL, it uses the current time instead of |*t|.
OPENSSL_EXPORT ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s, int offset_day,
long offset_sec, time_t *t);
-OPENSSL_EXPORT ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj);
+
+// X509_gmtime_adj behaves like |X509_time_adj_ex| but adds |offset_sec| to the
+// current time.
+OPENSSL_EXPORT ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long offset_sec);
OPENSSL_EXPORT const char *X509_get_default_cert_area(void);
OPENSSL_EXPORT const char *X509_get_default_cert_dir(void);
@@ -923,22 +844,33 @@ OPENSSL_EXPORT const char *X509_get_default_private_dir(void);
OPENSSL_EXPORT X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey,
const EVP_MD *md);
-OPENSSL_EXPORT X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey);
DECLARE_ASN1_ENCODE_FUNCTIONS(X509_ALGORS, X509_ALGORS, X509_ALGORS)
DECLARE_ASN1_FUNCTIONS(X509_VAL)
DECLARE_ASN1_FUNCTIONS(X509_PUBKEY)
+// X509_PUBKEY_set serializes |pkey| into a newly-allocated |X509_PUBKEY|
+// structure. On success, it frees |*x|, sets |*x| to the new object, and
+// returns one. Otherwise, it returns zero.
OPENSSL_EXPORT int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey);
+
+// X509_PUBKEY_get decodes the public key in |key| and returns an |EVP_PKEY| on
+// success, or NULL on error. The caller must release the result with
+// |EVP_PKEY_free| when done. The |EVP_PKEY| is cached in |key|, so callers must
+// not mutate the result.
OPENSSL_EXPORT EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key);
DECLARE_ASN1_FUNCTIONS(X509_SIG)
-DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO)
DECLARE_ASN1_FUNCTIONS(X509_REQ)
DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE)
-OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype,
+
+// X509_ATTRIBUTE_create returns a newly-allocated |X509_ATTRIBUTE|, or NULL on
+// error. The attribute has type |nid| and contains a single value determined by
+// |attrtype| and |value|, which are interpreted as in |ASN1_TYPE_set|. Note
+// this function takes ownership of |value|.
+OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int attrtype,
void *value);
DECLARE_ASN1_FUNCTIONS(X509_EXTENSION)
@@ -948,15 +880,15 @@ DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY)
DECLARE_ASN1_FUNCTIONS(X509_NAME)
+// X509_NAME_set makes a copy of |name|. On success, it frees |*xn|, sets |*xn|
+// to the copy, and returns one. Otherwise, it returns zero.
OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name);
-DECLARE_ASN1_FUNCTIONS(X509_CINF)
-
DECLARE_ASN1_FUNCTIONS(X509)
DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX)
-// X509_up_ref adds one to the reference count of |x| and returns one.
-OPENSSL_EXPORT int X509_up_ref(X509 *x);
+// X509_up_ref adds one to the reference count of |x509| and returns one.
+OPENSSL_EXPORT int X509_up_ref(X509 *x509);
OPENSSL_EXPORT int X509_get_ex_new_index(long argl, void *argp,
CRYPTO_EX_unused *unused,
@@ -1014,9 +946,22 @@ OPENSSL_EXPORT int X509_set1_signature_algo(X509 *x509, const X509_ALGOR *algo);
OPENSSL_EXPORT int X509_set1_signature_value(X509 *x509, const uint8_t *sig,
size_t sig_len);
-OPENSSL_EXPORT void X509_get0_signature(const ASN1_BIT_STRING **psig,
- const X509_ALGOR **palg, const X509 *x);
-OPENSSL_EXPORT int X509_get_signature_nid(const X509 *x);
+// X509_get0_signature sets |*out_sig| and |*out_alg| to the signature and
+// signature algorithm of |x509|, respectively. Either output pointer may be
+// NULL to ignore the value.
+//
+// This function outputs the outer signature algorithm. For the one in the
+// TBSCertificate, see |X509_get0_tbs_sigalg|. Certificates with mismatched
+// signature algorithms will successfully parse, but they will be rejected when
+// verifying.
+OPENSSL_EXPORT void X509_get0_signature(const ASN1_BIT_STRING **out_sig,
+ const X509_ALGOR **out_alg,
+ const X509 *x509);
+
+// X509_get_signature_nid returns the NID corresponding to |x509|'s signature
+// algorithm, or |NID_undef| if the signature algorithm does not correspond to
+// a known NID.
+OPENSSL_EXPORT int X509_get_signature_nid(const X509 *x509);
OPENSSL_EXPORT int X509_alias_set1(X509 *x, const unsigned char *name, int len);
OPENSSL_EXPORT int X509_keyid_set1(X509 *x, const unsigned char *id, int len);
@@ -1032,7 +977,6 @@ OPENSSL_EXPORT void X509_trust_clear(X509 *x);
OPENSSL_EXPORT void X509_reject_clear(X509 *x);
DECLARE_ASN1_FUNCTIONS(X509_REVOKED)
-DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO)
DECLARE_ASN1_FUNCTIONS(X509_CRL)
OPENSSL_EXPORT int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
@@ -1058,9 +1002,10 @@ OPENSSL_EXPORT int ASN1_item_digest(const ASN1_ITEM *it, const EVP_MD *type,
void *data, unsigned char *md,
unsigned int *len);
-OPENSSL_EXPORT int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *algor1,
- ASN1_BIT_STRING *signature, void *data,
- EVP_PKEY *pkey);
+OPENSSL_EXPORT int ASN1_item_verify(const ASN1_ITEM *it,
+ const X509_ALGOR *algor1,
+ const ASN1_BIT_STRING *signature,
+ void *data, EVP_PKEY *pkey);
OPENSSL_EXPORT int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1,
X509_ALGOR *algor2,
@@ -1071,66 +1016,220 @@ OPENSSL_EXPORT int ASN1_item_sign_ctx(const ASN1_ITEM *it, X509_ALGOR *algor1,
ASN1_BIT_STRING *signature, void *asn,
EVP_MD_CTX *ctx);
-OPENSSL_EXPORT int X509_set_version(X509 *x, long version);
-OPENSSL_EXPORT int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial);
-OPENSSL_EXPORT ASN1_INTEGER *X509_get_serialNumber(X509 *x);
-OPENSSL_EXPORT int X509_set_issuer_name(X509 *x, X509_NAME *name);
-OPENSSL_EXPORT X509_NAME *X509_get_issuer_name(const X509 *a);
-OPENSSL_EXPORT int X509_set_subject_name(X509 *x, X509_NAME *name);
-OPENSSL_EXPORT X509_NAME *X509_get_subject_name(const X509 *a);
-OPENSSL_EXPORT int X509_set_pubkey(X509 *x, EVP_PKEY *pkey);
-OPENSSL_EXPORT EVP_PKEY *X509_get_pubkey(X509 *x);
-OPENSSL_EXPORT ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x);
+// X509_get_serialNumber returns a mutable pointer to |x509|'s serial number.
+// Prefer |X509_get0_serialNumber|.
+OPENSSL_EXPORT ASN1_INTEGER *X509_get_serialNumber(X509 *x509);
+
+// X509_set_issuer_name sets |x509|'s issuer to a copy of |name|. It returns one
+// on success and zero on error.
+OPENSSL_EXPORT int X509_set_issuer_name(X509 *x509, X509_NAME *name);
+
+// X509_get_issuer_name returns |x509|'s issuer.
+OPENSSL_EXPORT X509_NAME *X509_get_issuer_name(const X509 *x509);
+
+// X509_set_subject_name sets |x509|'s subject to a copy of |name|. It returns
+// one on success and zero on error.
+OPENSSL_EXPORT int X509_set_subject_name(X509 *x509, X509_NAME *name);
+
+// X509_get_issuer_name returns |x509|'s subject.
+OPENSSL_EXPORT X509_NAME *X509_get_subject_name(const X509 *x509);
+
+// X509_set_pubkey sets |x509|'s public key to |pkey|. It returns one on success
+// and zero on error. This function does not take ownership of |pkey| and
+// internally copies and updates reference counts as needed.
+OPENSSL_EXPORT int X509_set_pubkey(X509 *x509, EVP_PKEY *pkey);
+
+// X509_get_pubkey returns |x509|'s public key as an |EVP_PKEY|, or NULL if the
+// public key was unsupported or could not be decoded. This function returns a
+// reference to the |EVP_PKEY|. The caller must release the result with
+// |EVP_PKEY_free| when done.
+OPENSSL_EXPORT EVP_PKEY *X509_get_pubkey(X509 *x509);
+
+// X509_get0_pubkey_bitstr returns the BIT STRING portion of |x509|'s public
+// key. Note this does not contain the AlgorithmIdentifier portion.
+//
+// WARNING: This function returns a non-const pointer for OpenSSL compatibility,
+// but the caller must not modify the resulting object. Doing so will break
+// internal invariants in |x509|.
+OPENSSL_EXPORT ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x509);
+
+// X509_get0_extensions returns |x509|'s extension list, or NULL if |x509| omits
+// it.
OPENSSL_EXPORT const STACK_OF(X509_EXTENSION) *X509_get0_extensions(
- const X509 *x);
-OPENSSL_EXPORT const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x);
+ const X509 *x509);
+
+// X509_get0_tbs_sigalg returns the signature algorithm in |x509|'s
+// TBSCertificate. For the outer signature algorithm, see |X509_get0_signature|.
+//
+// Certificates with mismatched signature algorithms will successfully parse,
+// but they will be rejected when verifying.
+OPENSSL_EXPORT const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x509);
+
+// X509_REQ_set_version sets |req|'s version to |version|, which should be
+// |X509_REQ_VERSION_1|. It returns one on success and zero on error.
+//
+// Note no versions other than |X509_REQ_VERSION_1| are defined for CSRs.
+OPENSSL_EXPORT int X509_REQ_set_version(X509_REQ *req, long version);
-OPENSSL_EXPORT int X509_REQ_set_version(X509_REQ *x, long version);
+// X509_REQ_set_subject_name sets |req|'s subject to a copy of |name|. It
+// returns one on success and zero on error.
OPENSSL_EXPORT int X509_REQ_set_subject_name(X509_REQ *req, X509_NAME *name);
+
+// X509_REQ_get0_signature sets |*out_sig| and |*out_alg| to the signature and
+// signature algorithm of |req|, respectively. Either output pointer may be NULL
+// to ignore the value.
OPENSSL_EXPORT void X509_REQ_get0_signature(const X509_REQ *req,
- const ASN1_BIT_STRING **psig,
- const X509_ALGOR **palg);
+ const ASN1_BIT_STRING **out_sig,
+ const X509_ALGOR **out_alg);
+
+// X509_REQ_get_signature_nid returns the NID corresponding to |req|'s signature
+// algorithm, or |NID_undef| if the signature algorithm does not correspond to
+// a known NID.
OPENSSL_EXPORT int X509_REQ_get_signature_nid(const X509_REQ *req);
-OPENSSL_EXPORT int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp);
-OPENSSL_EXPORT int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
+
+// i2d_re_X509_REQ_tbs serializes the CertificationRequestInfo (see RFC 2986)
+// portion of |req|. If |outp| is NULL, nothing is written. Otherwise, if
+// |*outp| is not NULL, the result is written to |*outp|, which must have enough
+// space available, and |*outp| is advanced just past the output. If |outp| is
+// non-NULL and |*outp| is NULL, it sets |*outp| to a newly-allocated buffer
+// containing the result. The caller is responsible for releasing the buffer
+// with |OPENSSL_free|. In all cases, this function returns the number of bytes
+// in the result, whether written or not, or a negative value on error.
+//
+// This function re-encodes the CertificationRequestInfo and may not reflect
+// |req|'s original encoding. It may be used to manually generate a signature
+// for a new certificate request.
+OPENSSL_EXPORT int i2d_re_X509_REQ_tbs(X509_REQ *req, uint8_t **outp);
+
+// X509_REQ_set_pubkey sets |req|'s public key to |pkey|. It returns one on
+// success and zero on error. This function does not take ownership of |pkey|
+// and internally copies and updates reference counts as needed.
+OPENSSL_EXPORT int X509_REQ_set_pubkey(X509_REQ *req, EVP_PKEY *pkey);
+
+// X509_REQ_get_pubkey returns |req|'s public key as an |EVP_PKEY|, or NULL if
+// the public key was unsupported or could not be decoded. This function returns
+// a reference to the |EVP_PKEY|. The caller must release the result with
+// |EVP_PKEY_free| when done.
OPENSSL_EXPORT EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req);
+
+// X509_REQ_extension_nid returns one if |nid| is a supported CSR attribute type
+// for carrying extensions and zero otherwise. The supported types are
+// |NID_ext_req| (pkcs-9-at-extensionRequest from RFC 2985) and |NID_ms_ext_req|
+// (a Microsoft szOID_CERT_EXTENSIONS variant).
OPENSSL_EXPORT int X509_REQ_extension_nid(int nid);
-OPENSSL_EXPORT const int *X509_REQ_get_extension_nids(void);
-OPENSSL_EXPORT void X509_REQ_set_extension_nids(const int *nids);
+
+// X509_REQ_get_extensions decodes the list of requested extensions in |req| and
+// returns a newly-allocated |STACK_OF(X509_EXTENSION)| containing the result.
+// It returns NULL on error, or if |req| did not request extensions.
+//
+// This function supports both pkcs-9-at-extensionRequest from RFC 2985 and the
+// Microsoft szOID_CERT_EXTENSIONS variant.
OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req);
-OPENSSL_EXPORT int X509_REQ_add_extensions_nid(X509_REQ *req,
- STACK_OF(X509_EXTENSION) *exts,
- int nid);
-OPENSSL_EXPORT int X509_REQ_add_extensions(X509_REQ *req,
- STACK_OF(X509_EXTENSION) *exts);
+
+// X509_REQ_add_extensions_nid adds an attribute to |req| of type |nid|, to
+// request the certificate extensions in |exts|. It returns one on success and
+// zero on error. |nid| should be |NID_ext_req| or |NID_ms_ext_req|.
+OPENSSL_EXPORT int X509_REQ_add_extensions_nid(
+ X509_REQ *req, const STACK_OF(X509_EXTENSION) *exts, int nid);
+
+// X509_REQ_add_extensions behaves like |X509_REQ_add_extensions_nid|, using the
+// standard |NID_ext_req| for the attribute type.
+OPENSSL_EXPORT int X509_REQ_add_extensions(
+ X509_REQ *req, const STACK_OF(X509_EXTENSION) *exts);
+
+// X509_REQ_get_attr_count returns the number of attributes in |req|.
OPENSSL_EXPORT int X509_REQ_get_attr_count(const X509_REQ *req);
+
+// X509_REQ_get_attr_by_NID returns the index of the attribute in |req| of type
+// |nid|, or a negative number if not found. If found, callers can use
+// |X509_REQ_get_attr| to look up the attribute by index.
+//
+// If |lastpos| is non-negative, it begins searching at |lastpos| + 1. Callers
+// can thus loop over all matching attributes by first passing -1 and then
+// passing the previously-returned value until no match is returned.
OPENSSL_EXPORT int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid,
int lastpos);
+
+// X509_REQ_get_attr_by_OBJ behaves like |X509_REQ_get_attr_by_NID| but looks
+// for attributes of type |obj|.
OPENSSL_EXPORT int X509_REQ_get_attr_by_OBJ(const X509_REQ *req,
- ASN1_OBJECT *obj, int lastpos);
+ const ASN1_OBJECT *obj,
+ int lastpos);
+
+// X509_REQ_get_attr returns the attribute at index |loc| in |req|, or NULL if
+// out of bounds.
OPENSSL_EXPORT X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc);
+
+// X509_REQ_delete_attr removes the attribute at index |loc| in |req|. It
+// returns the removed attribute to the caller, or NULL if |loc| was out of
+// bounds. If non-NULL, the caller must release the result with
+// |X509_ATTRIBUTE_free| when done. It is also safe, but not necessary, to call
+// |X509_ATTRIBUTE_free| if the result is NULL.
OPENSSL_EXPORT X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc);
+
+// X509_REQ_add1_attr appends a copy of |attr| to |req|'s list of attributes. It
+// returns one on success and zero on error.
+//
+// TODO(https://crbug.com/boringssl/407): |attr| should be const.
OPENSSL_EXPORT int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr);
+
+// X509_REQ_add1_attr_by_OBJ appends a new attribute to |req| with type |obj|.
+// It returns one on success and zero on error. The value is determined by
+// |X509_ATTRIBUTE_set1_data|.
+//
+// WARNING: The interpretation of |attrtype|, |data|, and |len| is complex and
+// error-prone. See |X509_ATTRIBUTE_set1_data| for details.
OPENSSL_EXPORT int X509_REQ_add1_attr_by_OBJ(X509_REQ *req,
- const ASN1_OBJECT *obj, int type,
- const unsigned char *bytes,
+ const ASN1_OBJECT *obj,
+ int attrtype,
+ const unsigned char *data,
int len);
-OPENSSL_EXPORT int X509_REQ_add1_attr_by_NID(X509_REQ *req, int nid, int type,
- const unsigned char *bytes,
+
+// X509_REQ_add1_attr_by_NID behaves like |X509_REQ_add1_attr_by_OBJ| except the
+// attribute type is determined by |nid|.
+OPENSSL_EXPORT int X509_REQ_add1_attr_by_NID(X509_REQ *req, int nid,
+ int attrtype,
+ const unsigned char *data,
int len);
+
+// X509_REQ_add1_attr_by_txt behaves like |X509_REQ_add1_attr_by_OBJ| except the
+// attribute type is determined by calling |OBJ_txt2obj| with |attrname|.
OPENSSL_EXPORT int X509_REQ_add1_attr_by_txt(X509_REQ *req,
- const char *attrname, int type,
- const unsigned char *bytes,
+ const char *attrname, int attrtype,
+ const unsigned char *data,
int len);
-OPENSSL_EXPORT int X509_CRL_set_version(X509_CRL *x, long version);
-OPENSSL_EXPORT int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name);
+// X509_CRL_set_version sets |crl|'s version to |version|, which should be one
+// of the |X509_CRL_VERSION_*| constants. It returns one on success and zero on
+// error.
+//
+// If unsure, use |X509_CRL_VERSION_2|. Note that, unlike certificates, CRL
+// versions are only defined up to v2. Callers should not use |X509_VERSION_3|.
+OPENSSL_EXPORT int X509_CRL_set_version(X509_CRL *crl, long version);
+
+// X509_CRL_set_issuer_name sets |crl|'s issuer to a copy of |name|. It returns
+// one on success and zero on error.
+OPENSSL_EXPORT int X509_CRL_set_issuer_name(X509_CRL *crl, X509_NAME *name);
+
OPENSSL_EXPORT int X509_CRL_sort(X509_CRL *crl);
+
+// X509_CRL_up_ref adds one to the reference count of |crl| and returns one.
OPENSSL_EXPORT int X509_CRL_up_ref(X509_CRL *crl);
+// X509_CRL_get0_signature sets |*out_sig| and |*out_alg| to the signature and
+// signature algorithm of |crl|, respectively. Either output pointer may be NULL
+// to ignore the value.
+//
+// This function outputs the outer signature algorithm, not the one in the
+// TBSCertList. CRLs with mismatched signature algorithms will successfully
+// parse, but they will be rejected when verifying.
OPENSSL_EXPORT void X509_CRL_get0_signature(const X509_CRL *crl,
- const ASN1_BIT_STRING **psig,
- const X509_ALGOR **palg);
+ const ASN1_BIT_STRING **out_sig,
+ const X509_ALGOR **out_alg);
+
+// X509_CRL_get_signature_nid returns the NID corresponding to |crl|'s signature
+// algorithm, or |NID_undef| if the signature algorithm does not correspond to
+// a known NID.
OPENSSL_EXPORT int X509_CRL_get_signature_nid(const X509_CRL *crl);
// i2d_re_X509_CRL_tbs serializes the TBSCertList portion of |crl|. If |outp| is
@@ -1162,6 +1261,25 @@ OPENSSL_EXPORT int i2d_re_X509_CRL_tbs(X509_CRL *crl, unsigned char **outp);
// instead.
OPENSSL_EXPORT int i2d_X509_CRL_tbs(X509_CRL *crl, unsigned char **outp);
+// X509_CRL_set1_signature_algo sets |crl|'s signature algorithm to |algo| and
+// returns one on success or zero on error. It updates both the signature field
+// of the TBSCertList structure, and the signatureAlgorithm field of the CRL.
+OPENSSL_EXPORT int X509_CRL_set1_signature_algo(X509_CRL *crl,
+ const X509_ALGOR *algo);
+
+// X509_CRL_set1_signature_value sets |crl|'s signature to a copy of the
+// |sig_len| bytes pointed by |sig|. It returns one on success and zero on
+// error.
+//
+// Due to a specification error, X.509 CRLs store signatures in ASN.1 BIT
+// STRINGs, but signature algorithms return byte strings rather than bit
+// strings. This function creates a BIT STRING containing a whole number of
+// bytes, with the bit order matching the DER encoding. This matches the
+// encoding used by all X.509 signature algorithms.
+OPENSSL_EXPORT int X509_CRL_set1_signature_value(X509_CRL *crl,
+ const uint8_t *sig,
+ size_t sig_len);
+
// X509_REVOKED_get0_serialNumber returns the serial number of the certificate
// revoked by |revoked|.
OPENSSL_EXPORT const ASN1_INTEGER *X509_REVOKED_get0_serialNumber(
@@ -1182,7 +1300,8 @@ OPENSSL_EXPORT const ASN1_TIME *X509_REVOKED_get0_revocationDate(
OPENSSL_EXPORT int X509_REVOKED_set_revocationDate(X509_REVOKED *revoked,
const ASN1_TIME *tm);
-// X509_REVOKED_get0_extensions returns |r|'s extensions.
+// X509_REVOKED_get0_extensions returns |r|'s extensions list, or NULL if |r|
+// omits it.
OPENSSL_EXPORT const STACK_OF(X509_EXTENSION) *X509_REVOKED_get0_extensions(
const X509_REVOKED *r);
@@ -1198,10 +1317,14 @@ OPENSSL_EXPORT int X509_chain_check_suiteb(int *perror_depth, X509 *x,
unsigned long flags);
OPENSSL_EXPORT int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk,
unsigned long flags);
+
+// X509_chain_up_ref returns a newly-allocated |STACK_OF(X509)| containing a
+// shallow copy of |chain|, or NULL on error. That is, the return value has the
+// same contents as |chain|, and each |X509|'s reference count is incremented by
+// one.
OPENSSL_EXPORT STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain);
OPENSSL_EXPORT int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b);
-OPENSSL_EXPORT unsigned long X509_issuer_and_serial_hash(X509 *a);
OPENSSL_EXPORT int X509_issuer_name_cmp(const X509 *a, const X509 *b);
OPENSSL_EXPORT unsigned long X509_issuer_name_hash(X509 *a);
@@ -1219,7 +1342,6 @@ OPENSSL_EXPORT unsigned long X509_NAME_hash_old(X509_NAME *x);
OPENSSL_EXPORT int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b);
OPENSSL_EXPORT int X509_CRL_match(const X509_CRL *a, const X509_CRL *b);
-#ifndef OPENSSL_NO_FP_API
OPENSSL_EXPORT int X509_print_ex_fp(FILE *bp, X509 *x, unsigned long nmflag,
unsigned long cflag);
OPENSSL_EXPORT int X509_print_fp(FILE *bp, X509 *x);
@@ -1227,7 +1349,6 @@ OPENSSL_EXPORT int X509_CRL_print_fp(FILE *bp, X509_CRL *x);
OPENSSL_EXPORT int X509_REQ_print_fp(FILE *bp, X509_REQ *req);
OPENSSL_EXPORT int X509_NAME_print_ex_fp(FILE *fp, const X509_NAME *nm,
int indent, unsigned long flags);
-#endif
OPENSSL_EXPORT int X509_NAME_print(BIO *bp, const X509_NAME *name, int obase);
OPENSSL_EXPORT int X509_NAME_print_ex(BIO *out, const X509_NAME *nm, int indent,
@@ -1292,28 +1413,90 @@ OPENSSL_EXPORT ASN1_OBJECT *X509_NAME_ENTRY_get_object(
const X509_NAME_ENTRY *ne);
OPENSSL_EXPORT ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne);
+// X509v3_get_ext_count returns the number of extensions in |x|.
OPENSSL_EXPORT int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x);
+
+// X509v3_get_ext_by_NID returns the index of the first extension in |x| with
+// type |nid|, or a negative number if not found. If found, callers can use
+// |X509v3_get_ext| to look up the extension by index.
+//
+// If |lastpos| is non-negative, it begins searching at |lastpos| + 1. Callers
+// can thus loop over all matching extensions by first passing -1 and then
+// passing the previously-returned value until no match is returned.
OPENSSL_EXPORT int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x,
int nid, int lastpos);
+
+// X509v3_get_ext_by_OBJ behaves like |X509v3_get_ext_by_NID| but looks for
+// extensions matching |obj|.
OPENSSL_EXPORT int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x,
const ASN1_OBJECT *obj, int lastpos);
+
+// X509v3_get_ext_by_critical returns the index of the first extension in |x|
+// whose critical bit matches |crit|, or a negative number if no such extension
+// was found.
+//
+// If |lastpos| is non-negative, it begins searching at |lastpos| + 1. Callers
+// can thus loop over all matching extensions by first passing -1 and then
+// passing the previously-returned value until no match is returned.
OPENSSL_EXPORT int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x,
int crit, int lastpos);
+
+// X509v3_get_ext returns the extension in |x| at index |loc|, or NULL if |loc|
+// is out of bounds.
OPENSSL_EXPORT X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x,
int loc);
+
+// X509v3_delete_ext removes the extension in |x| at index |loc| and returns the
+// removed extension, or NULL if |loc| was out of bounds. If an extension was
+// returned, the caller must release it with |X509_EXTENSION_free|.
OPENSSL_EXPORT X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x,
int loc);
+
+// X509v3_add_ext adds a copy of |ex| to the extension list in |*x|. If |*x| is
+// NULL, it allocates a new |STACK_OF(X509_EXTENSION)| to hold the copy and sets
+// |*x| to the new list. It returns |*x| on success and NULL on error. The
+// caller retains ownership of |ex| and can release it independently of |*x|.
+//
+// The new extension is inserted at index |loc|, shifting extensions to the
+// right. If |loc| is -1 or out of bounds, the new extension is appended to the
+// list.
OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509v3_add_ext(
STACK_OF(X509_EXTENSION) **x, X509_EXTENSION *ex, int loc);
+// X509_get_ext_count returns the number of extensions in |x|.
OPENSSL_EXPORT int X509_get_ext_count(const X509 *x);
+
+// X509_get_ext_by_NID behaves like |X509v3_get_ext_by_NID| but searches for
+// extensions in |x|.
OPENSSL_EXPORT int X509_get_ext_by_NID(const X509 *x, int nid, int lastpos);
+
+// X509_get_ext_by_OBJ behaves like |X509v3_get_ext_by_OBJ| but searches for
+// extensions in |x|.
OPENSSL_EXPORT int X509_get_ext_by_OBJ(const X509 *x, const ASN1_OBJECT *obj,
int lastpos);
+
+// X509_get_ext_by_critical behaves like |X509v3_get_ext_by_critical| but
+// searches for extensions in |x|.
OPENSSL_EXPORT int X509_get_ext_by_critical(const X509 *x, int crit,
int lastpos);
+
+// X509_get_ext returns the extension in |x| at index |loc|, or NULL if |loc| is
+// out of bounds.
OPENSSL_EXPORT X509_EXTENSION *X509_get_ext(const X509 *x, int loc);
+
+// X509_delete_ext removes the extension in |x| at index |loc| and returns the
+// removed extension, or NULL if |loc| was out of bounds. If non-NULL, the
+// caller must release the result with |X509_EXTENSION_free|. It is also safe,
+// but not necessary, to call |X509_EXTENSION_free| if the result is NULL.
OPENSSL_EXPORT X509_EXTENSION *X509_delete_ext(X509 *x, int loc);
+
+// X509_add_ext adds a copy of |ex| to |x|. It returns one on success and zero
+// on failure. The caller retains ownership of |ex| and can release it
+// independently of |x|.
+//
+// The new extension is inserted at index |loc|, shifting extensions to the
+// right. If |loc| is -1 or out of bounds, the new extension is appended to the
+// list.
OPENSSL_EXPORT int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
// X509_get_ext_d2i behaves like |X509V3_get_d2i| but looks for the extension in
@@ -1333,15 +1516,41 @@ OPENSSL_EXPORT void *X509_get_ext_d2i(const X509 *x509, int nid,
OPENSSL_EXPORT int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit,
unsigned long flags);
+// X509_CRL_get_ext_count returns the number of extensions in |x|.
OPENSSL_EXPORT int X509_CRL_get_ext_count(const X509_CRL *x);
+
+// X509_CRL_get_ext_by_NID behaves like |X509v3_get_ext_by_NID| but searches for
+// extensions in |x|.
OPENSSL_EXPORT int X509_CRL_get_ext_by_NID(const X509_CRL *x, int nid,
int lastpos);
+
+// X509_CRL_get_ext_by_OBJ behaves like |X509v3_get_ext_by_OBJ| but searches for
+// extensions in |x|.
OPENSSL_EXPORT int X509_CRL_get_ext_by_OBJ(const X509_CRL *x,
const ASN1_OBJECT *obj, int lastpos);
+
+// X509_CRL_get_ext_by_critical behaves like |X509v3_get_ext_by_critical| but
+// searches for extensions in |x|.
OPENSSL_EXPORT int X509_CRL_get_ext_by_critical(const X509_CRL *x, int crit,
int lastpos);
+
+// X509_CRL_get_ext returns the extension in |x| at index |loc|, or NULL if
+// |loc| is out of bounds.
OPENSSL_EXPORT X509_EXTENSION *X509_CRL_get_ext(const X509_CRL *x, int loc);
+
+// X509_CRL_delete_ext removes the extension in |x| at index |loc| and returns
+// the removed extension, or NULL if |loc| was out of bounds. If non-NULL, the
+// caller must release the result with |X509_EXTENSION_free|. It is also safe,
+// but not necessary, to call |X509_EXTENSION_free| if the result is NULL.
OPENSSL_EXPORT X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc);
+
+// X509_CRL_add_ext adds a copy of |ex| to |x|. It returns one on success and
+// zero on failure. The caller retains ownership of |ex| and can release it
+// independently of |x|.
+//
+// The new extension is inserted at index |loc|, shifting extensions to the
+// right. If |loc| is -1 or out of bounds, the new extension is appended to the
+// list.
OPENSSL_EXPORT int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc);
// X509_CRL_get_ext_d2i behaves like |X509V3_get_d2i| but looks for the
@@ -1361,18 +1570,45 @@ OPENSSL_EXPORT void *X509_CRL_get_ext_d2i(const X509_CRL *crl, int nid,
OPENSSL_EXPORT int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value,
int crit, unsigned long flags);
+// X509_REVOKED_get_ext_count returns the number of extensions in |x|.
OPENSSL_EXPORT int X509_REVOKED_get_ext_count(const X509_REVOKED *x);
+
+// X509_REVOKED_get_ext_by_NID behaves like |X509v3_get_ext_by_NID| but searches
+// for extensions in |x|.
OPENSSL_EXPORT int X509_REVOKED_get_ext_by_NID(const X509_REVOKED *x, int nid,
int lastpos);
+
+// X509_REVOKED_get_ext_by_OBJ behaves like |X509v3_get_ext_by_OBJ| but searches
+// for extensions in |x|.
OPENSSL_EXPORT int X509_REVOKED_get_ext_by_OBJ(const X509_REVOKED *x,
const ASN1_OBJECT *obj,
int lastpos);
+
+// X509_REVOKED_get_ext_by_critical behaves like |X509v3_get_ext_by_critical|
+// but searches for extensions in |x|.
OPENSSL_EXPORT int X509_REVOKED_get_ext_by_critical(const X509_REVOKED *x,
int crit, int lastpos);
+
+// X509_REVOKED_get_ext returns the extension in |x| at index |loc|, or NULL if
+// |loc| is out of bounds.
OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_get_ext(const X509_REVOKED *x,
int loc);
+
+// X509_REVOKED_delete_ext removes the extension in |x| at index |loc| and
+// returns the removed extension, or NULL if |loc| was out of bounds. If
+// non-NULL, the caller must release the result with |X509_EXTENSION_free|. It
+// is also safe, but not necessary, to call |X509_EXTENSION_free| if the result
+// is NULL.
OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x,
int loc);
+
+// X509_REVOKED_add_ext adds a copy of |ex| to |x|. It returns one on success
+// and zero on failure. The caller retains ownership of |ex| and can release it
+// independently of |x|.
+//
+// The new extension is inserted at index |loc|, shifting extensions to the
+// right. If |loc| is -1 or out of bounds, the new extension is appended to the
+// list.
OPENSSL_EXPORT int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex,
int loc);
@@ -1395,59 +1631,193 @@ OPENSSL_EXPORT int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid,
void *value, int crit,
unsigned long flags);
+// X509_EXTENSION_create_by_NID creates a new |X509_EXTENSION| with type |nid|,
+// value |data|, and critical bit |crit|. It returns the newly-allocated
+// |X509_EXTENSION| on success, and false on error. |nid| should be a |NID_*|
+// constant.
+//
+// If |ex| and |*ex| are both non-NULL, it modifies and returns |*ex| instead of
+// creating a new object. If |ex| is non-NULL, but |*ex| is NULL, it sets |*ex|
+// to the new |X509_EXTENSION|, in addition to returning the result.
OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_NID(
X509_EXTENSION **ex, int nid, int crit, const ASN1_OCTET_STRING *data);
+
+// X509_EXTENSION_create_by_OBJ behaves like |X509_EXTENSION_create_by_NID|, but
+// the extension type is determined by an |ASN1_OBJECT|.
OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_OBJ(
X509_EXTENSION **ex, const ASN1_OBJECT *obj, int crit,
const ASN1_OCTET_STRING *data);
+
+// X509_EXTENSION_set_object sets |ex|'s extension type to |obj|. It returns one
+// on success and zero on error.
OPENSSL_EXPORT int X509_EXTENSION_set_object(X509_EXTENSION *ex,
const ASN1_OBJECT *obj);
+
+// X509_EXTENSION_set_critical sets |ex| to critical if |crit| is non-zero and
+// to non-critical if |crit| is zero.
OPENSSL_EXPORT int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit);
+
+// X509_EXTENSION_set_data set's |ex|'s extension value to a copy of |data|. It
+// returns one on success and zero on error.
OPENSSL_EXPORT int X509_EXTENSION_set_data(X509_EXTENSION *ex,
const ASN1_OCTET_STRING *data);
+
+// X509_EXTENSION_get_object returns |ex|'s extension type.
OPENSSL_EXPORT ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *ex);
+
+// X509_EXTENSION_get_data returns |ne|'s extension value.
OPENSSL_EXPORT ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne);
-OPENSSL_EXPORT int X509_EXTENSION_get_critical(X509_EXTENSION *ex);
+// X509_EXTENSION_get_critical returns one if |ex| is critical and zero
+// otherwise.
+OPENSSL_EXPORT int X509_EXTENSION_get_critical(const X509_EXTENSION *ex);
+
+// X509at_get_attr_count returns the number of attributes in |x|.
OPENSSL_EXPORT int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x);
+
+// X509at_get_attr_by_NID returns the index of the attribute in |x| of type
+// |nid|, or a negative number if not found. If found, callers can use
+// |X509at_get_attr| to look up the attribute by index.
+//
+// If |lastpos| is non-negative, it begins searching at |lastpos| + 1. Callers
+// can thus loop over all matching attributes by first passing -1 and then
+// passing the previously-returned value until no match is returned.
OPENSSL_EXPORT int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x,
int nid, int lastpos);
+
+// X509at_get_attr_by_OBJ behaves like |X509at_get_attr_by_NID| but looks for
+// attributes of type |obj|.
OPENSSL_EXPORT int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk,
const ASN1_OBJECT *obj, int lastpos);
+
+// X509at_get_attr returns the attribute at index |loc| in |x|, or NULL if
+// out of bounds.
OPENSSL_EXPORT X509_ATTRIBUTE *X509at_get_attr(
const STACK_OF(X509_ATTRIBUTE) *x, int loc);
+
+// X509at_delete_attr removes the attribute at index |loc| in |x|. It returns
+// the removed attribute to the caller, or NULL if |loc| was out of bounds. If
+// non-NULL, the caller must release the result with |X509_ATTRIBUTE_free| when
+// done. It is also safe, but not necessary, to call |X509_ATTRIBUTE_free| if
+// the result is NULL.
OPENSSL_EXPORT X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x,
int loc);
+
+// X509at_add1_attr appends a copy of |attr| to the attribute list in |*x|. If
+// |*x| is NULL, it allocates a new |STACK_OF(X509_ATTRIBUTE)| to hold the copy
+// and sets |*x| to the new list. It returns |*x| on success and NULL on error.
+// The caller retains ownership of |attr| and can release it independently of
+// |*x|.
OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(
STACK_OF(X509_ATTRIBUTE) **x, X509_ATTRIBUTE *attr);
+
+// X509at_add1_attr_by_OBJ behaves like |X509at_add1_attr|, but adds an
+// attribute created by |X509_ATTRIBUTE_create_by_OBJ|.
OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(
STACK_OF(X509_ATTRIBUTE) **x, const ASN1_OBJECT *obj, int type,
const unsigned char *bytes, int len);
+
+// X509at_add1_attr_by_NID behaves like |X509at_add1_attr|, but adds an
+// attribute created by |X509_ATTRIBUTE_create_by_NID|.
OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(
STACK_OF(X509_ATTRIBUTE) **x, int nid, int type, const unsigned char *bytes,
int len);
+
+// X509at_add1_attr_by_txt behaves like |X509at_add1_attr|, but adds an
+// attribute created by |X509_ATTRIBUTE_create_by_txt|.
OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(
STACK_OF(X509_ATTRIBUTE) **x, const char *attrname, int type,
const unsigned char *bytes, int len);
-OPENSSL_EXPORT void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x,
- ASN1_OBJECT *obj, int lastpos,
- int type);
+
+// X509_ATTRIBUTE_create_by_NID returns a newly-allocated |X509_ATTRIBUTE| of
+// type |nid|, or NULL on error. The value is determined as in
+// |X509_ATTRIBUTE_set1_data|.
+//
+// If |attr| is non-NULL, the resulting |X509_ATTRIBUTE| is also written to
+// |*attr|. If |*attr| was non-NULL when the function was called, |*attr| is
+// reused instead of creating a new object.
+//
+// WARNING: The interpretation of |attrtype|, |data|, and |len| is complex and
+// error-prone. See |X509_ATTRIBUTE_set1_data| for details.
+//
+// WARNING: The object reuse form is deprecated and may be removed in the
+// future. It also currently incorrectly appends to the reused object's value
+// set rather than overwriting it.
OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(
- X509_ATTRIBUTE **attr, int nid, int atrtype, const void *data, int len);
+ X509_ATTRIBUTE **attr, int nid, int attrtype, const void *data, int len);
+
+// X509_ATTRIBUTE_create_by_OBJ behaves like |X509_ATTRIBUTE_create_by_NID|
+// except the attribute's type is determined by |obj|.
OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(
- X509_ATTRIBUTE **attr, const ASN1_OBJECT *obj, int atrtype,
+ X509_ATTRIBUTE **attr, const ASN1_OBJECT *obj, int attrtype,
const void *data, int len);
+
+// X509_ATTRIBUTE_create_by_txt behaves like |X509_ATTRIBUTE_create_by_NID|
+// except the attribute's type is determined by calling |OBJ_txt2obj| with
+// |attrname|.
OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(
- X509_ATTRIBUTE **attr, const char *atrname, int type,
+ X509_ATTRIBUTE **attr, const char *attrname, int type,
const unsigned char *bytes, int len);
+
+// X509_ATTRIBUTE_set1_object sets |attr|'s type to |obj|. It returns one on
+// success and zero on error.
OPENSSL_EXPORT int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr,
const ASN1_OBJECT *obj);
+
+// X509_ATTRIBUTE_set1_data appends a value to |attr|'s value set and returns
+// one on success or zero on error. The value is determined as follows:
+//
+// If |attrtype| is a |MBSTRING_*| constant, the value is an ASN.1 string. The
+// string is determined by decoding |len| bytes from |data| in the encoding
+// specified by |attrtype|, and then re-encoding it in a form appropriate for
+// |attr|'s type. If |len| is -1, |strlen(data)| is used instead. See
+// |ASN1_STRING_set_by_NID| for details.
+//
+// TODO(davidben): Document |ASN1_STRING_set_by_NID| so the reference is useful.
+//
+// Otherwise, if |len| is not -1, the value is an ASN.1 string. |attrtype| is an
+// |ASN1_STRING| type value and the |len| bytes from |data| are copied as the
+// type-specific representation of |ASN1_STRING|. See |ASN1_STRING| for details.
+//
+// WARNING: If this form is used to construct a negative INTEGER or ENUMERATED,
+// |attrtype| includes the |V_ASN1_NEG| flag for |ASN1_STRING|, but the function
+// forgets to clear the flag for |ASN1_TYPE|. This matches OpenSSL but is
+// probably a bug. For now, do not use this form with negative values.
+//
+// Otherwise, if |len| is -1, the value is constructed by passing |attrtype| and
+// |data| to |ASN1_TYPE_set1|. That is, |attrtype| is an |ASN1_TYPE| type value,
+// and |data| is cast to the corresponding pointer type.
+//
+// WARNING: Despite the name, this function appends to |attr|'s value set,
+// rather than overwriting it. To overwrite the value set, create a new
+// |X509_ATTRIBUTE| with |X509_ATTRIBUTE_new|.
+//
+// WARNING: If using the |MBSTRING_*| form, pass a length rather than relying on
+// |strlen|. In particular, |strlen| will not behave correctly if the input is
+// |MBSTRING_BMP| or |MBSTRING_UNIV|.
+//
+// WARNING: This function currently misinterprets |V_ASN1_OTHER| as an
+// |MBSTRING_*| constant. This matches OpenSSL but means it is impossible to
+// construct a value with a non-universal tag.
OPENSSL_EXPORT int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
const void *data, int len);
+
+// X509_ATTRIBUTE_get0_data returns the |idx|th value of |attr| in a
+// type-specific representation to |attrtype|, or NULL if out of bounds or the
+// type does not match. |attrtype| is one of the type values in |ASN1_TYPE|. On
+// match, the return value uses the same representation as |ASN1_TYPE_set0|. See
+// |ASN1_TYPE| for details.
OPENSSL_EXPORT void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx,
- int atrtype, void *data);
-OPENSSL_EXPORT int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr);
+ int attrtype, void *unused);
+
+// X509_ATTRIBUTE_count returns the number of values in |attr|.
+OPENSSL_EXPORT int X509_ATTRIBUTE_count(const X509_ATTRIBUTE *attr);
+
+// X509_ATTRIBUTE_get0_object returns the type of |attr|.
OPENSSL_EXPORT ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr);
+
+// X509_ATTRIBUTE_get0_type returns the |idx|th value in |attr|, or NULL if out
+// of bounds. Note this function returns one of |attr|'s values, not the type.
OPENSSL_EXPORT ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr,
int idx);
@@ -1473,13 +1843,36 @@ OPENSSL_EXPORT int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg,
const unsigned char **pk, int *ppklen,
X509_ALGOR **pa, PKCS8_PRIV_KEY_INFO *p8);
-OPENSSL_EXPORT int X509_PUBKEY_set0_param(X509_PUBKEY *pub,
- const ASN1_OBJECT *aobj, int ptype,
- void *pval, unsigned char *penc,
- int penclen);
-OPENSSL_EXPORT int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg,
- const unsigned char **pk, int *ppklen,
- X509_ALGOR **pa, X509_PUBKEY *pub);
+// X509_PUBKEY_set0_param sets |pub| to a key with AlgorithmIdentifier
+// determined by |obj|, |param_type|, and |param_value|, and an encoded
+// public key of |key|. On success, it takes ownership of all its parameters and
+// returns one. Otherwise, it returns zero. |key| must have been allocated by
+// |OPENSSL_malloc|.
+//
+// |obj|, |param_type|, and |param_value| are interpreted as in
+// |X509_ALGOR_set0|. See |X509_ALGOR_set0| for details.
+OPENSSL_EXPORT int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *obj,
+ int param_type, void *param_value,
+ uint8_t *key, int key_len);
+
+// X509_PUBKEY_get0_param outputs fields of |pub| and returns one. If |out_obj|
+// is not NULL, it sets |*out_obj| to AlgorithmIdentifier's OID. If |out_key|
+// is not NULL, it sets |*out_key| and |*out_key_len| to the encoded public key.
+// If |out_alg| is not NULL, it sets |*out_alg| to the AlgorithmIdentifier.
+//
+// Note: X.509 SubjectPublicKeyInfo structures store the encoded public key as a
+// BIT STRING. |*out_key| and |*out_key_len| will silently pad the key with zero
+// bits if |pub| did not contain a whole number of bytes. Use
+// |X509_PUBKEY_get0_public_key| to preserve this information.
+OPENSSL_EXPORT int X509_PUBKEY_get0_param(ASN1_OBJECT **out_obj,
+ const uint8_t **out_key,
+ int *out_key_len,
+ X509_ALGOR **out_alg,
+ X509_PUBKEY *pub);
+
+// X509_PUBKEY_get0_public_key returns |pub|'s encoded public key.
+OPENSSL_EXPORT const ASN1_BIT_STRING *X509_PUBKEY_get0_public_key(
+ const X509_PUBKEY *pub);
OPENSSL_EXPORT int X509_check_trust(X509 *x, int id, int flags);
OPENSSL_EXPORT int X509_TRUST_get_count(void);
@@ -1519,6 +1912,7 @@ BORINGSSL_MAKE_DELETER(RSA_PSS_PARAMS, RSA_PSS_PARAMS_free)
BORINGSSL_MAKE_DELETER(X509, X509_free)
BORINGSSL_MAKE_UP_REF(X509, X509_up_ref)
BORINGSSL_MAKE_DELETER(X509_ALGOR, X509_ALGOR_free)
+BORINGSSL_MAKE_DELETER(X509_ATTRIBUTE, X509_ATTRIBUTE_free)
BORINGSSL_MAKE_DELETER(X509_CRL, X509_CRL_free)
BORINGSSL_MAKE_UP_REF(X509_CRL, X509_CRL_up_ref)
BORINGSSL_MAKE_DELETER(X509_CRL_METHOD, X509_CRL_METHOD_free)
@@ -1534,13 +1928,10 @@ BORINGSSL_MAKE_DELETER(X509_REQ, X509_REQ_free)
BORINGSSL_MAKE_DELETER(X509_REVOKED, X509_REVOKED_free)
BORINGSSL_MAKE_DELETER(X509_SIG, X509_SIG_free)
BORINGSSL_MAKE_DELETER(X509_STORE, X509_STORE_free)
+BORINGSSL_MAKE_UP_REF(X509_STORE, X509_STORE_up_ref)
BORINGSSL_MAKE_DELETER(X509_STORE_CTX, X509_STORE_CTX_free)
BORINGSSL_MAKE_DELETER(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
-using ScopedX509_STORE_CTX =
- internal::StackAllocated<X509_STORE_CTX, void, X509_STORE_CTX_zero,
- X509_STORE_CTX_cleanup>;
-
BSSL_NAMESPACE_END
} // extern C++
diff --git a/deps/boringssl/src/include/openssl/x509_vfy.h b/deps/boringssl/src/include/openssl/x509_vfy.h
index 73dd470..d8781af 100644
--- a/deps/boringssl/src/include/openssl/x509_vfy.h
+++ b/deps/boringssl/src/include/openssl/x509_vfy.h
@@ -4,21 +4,21 @@
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
- *
+ *
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
+ *
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,10 +33,10 @@
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
+ * 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
+ *
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -48,7 +48,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
@@ -57,8 +57,8 @@
#ifndef HEADER_X509_H
#include <openssl/x509.h>
-/* openssl/x509.h ends up #include-ing this file at about the only
- * appropriate moment. */
+// openssl/x509.h ends up #include-ing this file at about the only
+// appropriate moment.
#endif
#ifndef HEADER_X509_VFY_H
@@ -66,28 +66,27 @@
#include <openssl/thread.h>
-#ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
#endif
-/* Legacy X.509 library.
- *
- * This header is part of OpenSSL's X.509 implementation. It is retained for
- * compatibility but otherwise underdocumented and not actively maintained. In
- * the future, a replacement library will be available. Meanwhile, minimize
- * dependencies on this header where possible. */
+// Legacy X.509 library.
+//
+// This header is part of OpenSSL's X.509 implementation. It is retained for
+// compatibility but otherwise underdocumented and not actively maintained. In
+// the future, a replacement library will be available. Meanwhile, minimize
+// dependencies on this header where possible.
-/*******************************/
/*
-SSL_CTX -> X509_STORE
- -> X509_LOOKUP
- ->X509_LOOKUP_METHOD
- -> X509_LOOKUP
- ->X509_LOOKUP_METHOD
-
+SSL_CTX -> X509_STORE
+ -> X509_LOOKUP
+ ->X509_LOOKUP_METHOD
+ -> X509_LOOKUP
+ ->X509_LOOKUP_METHOD
+
SSL -> X509_STORE_CTX
- ->X509_STORE
+ ->X509_STORE
The X509_STORE holds the tables etc for verification stuff.
A X509_STORE_CTX is used while validating a single certificate.
@@ -96,366 +95,220 @@ The X509_STORE then calls a function to actually verify the
certificate chain.
*/
-#define X509_LU_X509 1
-#define X509_LU_CRL 2
-#define X509_LU_PKEY 3
-
-typedef struct x509_object_st
- {
- /* one of the above types */
- int type;
- union {
- char *ptr;
- X509 *x509;
- X509_CRL *crl;
- EVP_PKEY *pkey;
- } data;
- } X509_OBJECT;
+#define X509_LU_X509 1
+#define X509_LU_CRL 2
+#define X509_LU_PKEY 3
DEFINE_STACK_OF(X509_LOOKUP)
DEFINE_STACK_OF(X509_OBJECT)
-
-/* This is a static that defines the function interface */
-typedef struct x509_lookup_method_st
- {
- const char *name;
- int (*new_item)(X509_LOOKUP *ctx);
- void (*free)(X509_LOOKUP *ctx);
- int (*init)(X509_LOOKUP *ctx);
- int (*shutdown)(X509_LOOKUP *ctx);
- int (*ctrl)(X509_LOOKUP *ctx,int cmd,const char *argc,long argl,
- char **ret);
- int (*get_by_subject)(X509_LOOKUP *ctx,int type,X509_NAME *name,
- X509_OBJECT *ret);
- int (*get_by_issuer_serial)(X509_LOOKUP *ctx,int type,X509_NAME *name,
- ASN1_INTEGER *serial,X509_OBJECT *ret);
- int (*get_by_fingerprint)(X509_LOOKUP *ctx,int type,
- unsigned char *bytes,int len,
- X509_OBJECT *ret);
- int (*get_by_alias)(X509_LOOKUP *ctx,int type,char *str,int len,
- X509_OBJECT *ret);
- } X509_LOOKUP_METHOD;
-
-typedef struct X509_VERIFY_PARAM_ID_st X509_VERIFY_PARAM_ID;
-
-/* This structure hold all parameters associated with a verify operation
- * by including an X509_VERIFY_PARAM structure in related structures the
- * parameters used can be customized
- */
-
-struct X509_VERIFY_PARAM_st
- {
- char *name;
- time_t check_time; /* Time to use */
- unsigned long inh_flags; /* Inheritance flags */
- unsigned long flags; /* Various verify flags */
- int purpose; /* purpose to check untrusted certificates */
- int trust; /* trust setting to check */
- int depth; /* Verify depth */
- STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */
- X509_VERIFY_PARAM_ID *id; /* opaque ID data */
- };
-
DEFINE_STACK_OF(X509_VERIFY_PARAM)
typedef int (*X509_STORE_CTX_verify_cb)(int, X509_STORE_CTX *);
typedef int (*X509_STORE_CTX_verify_fn)(X509_STORE_CTX *);
-typedef int (*X509_STORE_CTX_get_issuer_fn)(X509 **issuer,
- X509_STORE_CTX *ctx, X509 *x);
-typedef int (*X509_STORE_CTX_check_issued_fn)(X509_STORE_CTX *ctx,
- X509 *x, X509 *issuer);
+typedef int (*X509_STORE_CTX_get_issuer_fn)(X509 **issuer, X509_STORE_CTX *ctx,
+ X509 *x);
+typedef int (*X509_STORE_CTX_check_issued_fn)(X509_STORE_CTX *ctx, X509 *x,
+ X509 *issuer);
typedef int (*X509_STORE_CTX_check_revocation_fn)(X509_STORE_CTX *ctx);
-typedef int (*X509_STORE_CTX_get_crl_fn)(X509_STORE_CTX *ctx,
- X509_CRL **crl, X509 *x);
+typedef int (*X509_STORE_CTX_get_crl_fn)(X509_STORE_CTX *ctx, X509_CRL **crl,
+ X509 *x);
typedef int (*X509_STORE_CTX_check_crl_fn)(X509_STORE_CTX *ctx, X509_CRL *crl);
-typedef int (*X509_STORE_CTX_cert_crl_fn)(X509_STORE_CTX *ctx,
- X509_CRL *crl, X509 *x);
+typedef int (*X509_STORE_CTX_cert_crl_fn)(X509_STORE_CTX *ctx, X509_CRL *crl,
+ X509 *x);
typedef int (*X509_STORE_CTX_check_policy_fn)(X509_STORE_CTX *ctx);
typedef STACK_OF(X509) *(*X509_STORE_CTX_lookup_certs_fn)(X509_STORE_CTX *ctx,
X509_NAME *nm);
-typedef STACK_OF(X509_CRL) *(*X509_STORE_CTX_lookup_crls_fn)(X509_STORE_CTX *ctx,
- X509_NAME *nm);
+typedef STACK_OF(X509_CRL) *(*X509_STORE_CTX_lookup_crls_fn)(
+ X509_STORE_CTX *ctx, X509_NAME *nm);
typedef int (*X509_STORE_CTX_cleanup_fn)(X509_STORE_CTX *ctx);
-/* This is used to hold everything. It is used for all certificate
- * validation. Once we have a certificate chain, the 'verify'
- * function is then called to actually check the cert chain. */
-struct x509_store_st
- {
- /* The following is a cache of trusted certs */
- int cache; /* if true, stash any hits */
- STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */
- CRYPTO_MUTEX objs_lock;
- STACK_OF(X509) *additional_untrusted;
-
- /* These are external lookup methods */
- STACK_OF(X509_LOOKUP) *get_cert_methods;
-
- X509_VERIFY_PARAM *param;
-
- /* Callbacks for various operations */
- X509_STORE_CTX_verify_fn verify; /* called to verify a certificate */
- X509_STORE_CTX_verify_cb verify_cb; /* error callback */
- X509_STORE_CTX_get_issuer_fn get_issuer; /* get issuers cert from ctx */
- X509_STORE_CTX_check_issued_fn check_issued; /* check issued */
- X509_STORE_CTX_check_revocation_fn check_revocation; /* Check revocation status of chain */
- X509_STORE_CTX_get_crl_fn get_crl; /* retrieve CRL */
- X509_STORE_CTX_check_crl_fn check_crl; /* Check CRL validity */
- X509_STORE_CTX_cert_crl_fn cert_crl; /* Check certificate against CRL */
- X509_STORE_CTX_lookup_certs_fn lookup_certs;
- X509_STORE_CTX_lookup_crls_fn lookup_crls;
- X509_STORE_CTX_cleanup_fn cleanup;
-
- CRYPTO_refcount_t references;
- } /* X509_STORE */;
-
OPENSSL_EXPORT int X509_STORE_set_depth(X509_STORE *store, int depth);
-/* This is the functions plus an instance of the local variables. */
-struct x509_lookup_st
- {
- int init; /* have we been started */
- int skip; /* don't use us. */
- X509_LOOKUP_METHOD *method; /* the functions */
- char *method_data; /* method data */
-
- X509_STORE *store_ctx; /* who owns us */
- } /* X509_LOOKUP */;
-
-/* This is a used when verifying cert chains. Since the
- * gathering of the cert chain can take some time (and have to be
- * 'retried', this needs to be kept and passed around. */
-struct x509_store_ctx_st /* X509_STORE_CTX */
- {
- X509_STORE *ctx;
-
- /* The following are set by the caller */
- X509 *cert; /* The cert to check */
- STACK_OF(X509) *untrusted; /* chain of X509s - untrusted - passed in */
- STACK_OF(X509_CRL) *crls; /* set of CRLs passed in */
-
- X509_VERIFY_PARAM *param;
- void *other_ctx; /* Other info for use with get_issuer() */
-
- /* Callbacks for various operations */
- X509_STORE_CTX_verify_fn verify; /* called to verify a certificate */
- X509_STORE_CTX_verify_cb verify_cb; /* error callback */
- X509_STORE_CTX_get_issuer_fn get_issuer; /* get issuers cert from ctx */
- X509_STORE_CTX_check_issued_fn check_issued; /* check issued */
- X509_STORE_CTX_check_revocation_fn check_revocation; /* Check revocation status of chain */
- X509_STORE_CTX_get_crl_fn get_crl; /* retrieve CRL */
- X509_STORE_CTX_check_crl_fn check_crl; /* Check CRL validity */
- X509_STORE_CTX_cert_crl_fn cert_crl; /* Check certificate against CRL */
- X509_STORE_CTX_check_policy_fn check_policy;
- X509_STORE_CTX_lookup_certs_fn lookup_certs;
- X509_STORE_CTX_lookup_crls_fn lookup_crls;
- X509_STORE_CTX_cleanup_fn cleanup;
-
- /* The following is built up */
- int valid; /* if 0, rebuild chain */
- int last_untrusted; /* index of last untrusted cert */
- STACK_OF(X509) *chain; /* chain of X509s - built up and trusted */
- X509_POLICY_TREE *tree; /* Valid policy tree */
-
- int explicit_policy; /* Require explicit policy value */
-
- /* When something goes wrong, this is why */
- int error_depth;
- int error;
- X509 *current_cert;
- X509 *current_issuer; /* cert currently being tested as valid issuer */
- X509_CRL *current_crl; /* current CRL */
-
- int current_crl_score; /* score of current CRL */
- unsigned int current_reasons; /* Reason mask */
-
- X509_STORE_CTX *parent; /* For CRL path validation: parent context */
-
- CRYPTO_EX_DATA ex_data;
- } /* X509_STORE_CTX */;
-
OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
-#define X509_STORE_CTX_set_app_data(ctx,data) \
- X509_STORE_CTX_set_ex_data(ctx,0,data)
-#define X509_STORE_CTX_get_app_data(ctx) \
- X509_STORE_CTX_get_ex_data(ctx,0)
-
-#define X509_L_FILE_LOAD 1
-#define X509_L_ADD_DIR 2
-
-#define X509_LOOKUP_load_file(x,name,type) \
- X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL)
-
-#define X509_LOOKUP_add_dir(x,name,type) \
- X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL)
-
-#define X509_V_OK 0
-#define X509_V_ERR_UNSPECIFIED 1
-
-#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2
-#define X509_V_ERR_UNABLE_TO_GET_CRL 3
-#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4
-#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5
-#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6
-#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7
-#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8
-#define X509_V_ERR_CERT_NOT_YET_VALID 9
-#define X509_V_ERR_CERT_HAS_EXPIRED 10
-#define X509_V_ERR_CRL_NOT_YET_VALID 11
-#define X509_V_ERR_CRL_HAS_EXPIRED 12
-#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13
-#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14
-#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15
-#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16
-#define X509_V_ERR_OUT_OF_MEM 17
-#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18
-#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19
-#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20
-#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21
-#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22
-#define X509_V_ERR_CERT_REVOKED 23
-#define X509_V_ERR_INVALID_CA 24
-#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25
-#define X509_V_ERR_INVALID_PURPOSE 26
-#define X509_V_ERR_CERT_UNTRUSTED 27
-#define X509_V_ERR_CERT_REJECTED 28
-/* These are 'informational' when looking for issuer cert */
-#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29
-#define X509_V_ERR_AKID_SKID_MISMATCH 30
-#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31
-#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32
-
-#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33
-#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34
-#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35
-#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36
-#define X509_V_ERR_INVALID_NON_CA 37
-#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38
-#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39
-#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40
-
-#define X509_V_ERR_INVALID_EXTENSION 41
-#define X509_V_ERR_INVALID_POLICY_EXTENSION 42
-#define X509_V_ERR_NO_EXPLICIT_POLICY 43
-#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44
-#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45
-
-#define X509_V_ERR_UNNESTED_RESOURCE 46
-
-#define X509_V_ERR_PERMITTED_VIOLATION 47
-#define X509_V_ERR_EXCLUDED_VIOLATION 48
-#define X509_V_ERR_SUBTREE_MINMAX 49
-#define X509_V_ERR_APPLICATION_VERIFICATION 50
-#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51
-#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52
-#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53
-#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54
-
-/* Suite B mode algorithm violation */
-#define X509_V_ERR_SUITE_B_INVALID_VERSION 56
-#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57
-#define X509_V_ERR_SUITE_B_INVALID_CURVE 58
-#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59
-#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60
-#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61
-
-/* Host, email and IP check errors */
-#define X509_V_ERR_HOSTNAME_MISMATCH 62
-#define X509_V_ERR_EMAIL_MISMATCH 63
-#define X509_V_ERR_IP_ADDRESS_MISMATCH 64
-
-/* Caller error */
-#define X509_V_ERR_INVALID_CALL 65
-/* Issuer lookup error */
-#define X509_V_ERR_STORE_LOOKUP 66
-
-#define X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS 67
-
-/* Certificate verify flags */
-
-/* Send issuer+subject checks to verify_cb */
-#define X509_V_FLAG_CB_ISSUER_CHECK 0x1
-/* Use check time instead of current time */
-#define X509_V_FLAG_USE_CHECK_TIME 0x2
-/* Lookup CRLs */
-#define X509_V_FLAG_CRL_CHECK 0x4
-/* Lookup CRLs for whole chain */
-#define X509_V_FLAG_CRL_CHECK_ALL 0x8
-/* Ignore unhandled critical extensions */
-#define X509_V_FLAG_IGNORE_CRITICAL 0x10
-/* Does nothing as its functionality has been enabled by default. */
-#define X509_V_FLAG_X509_STRICT 0x00
-/* Enable proxy certificate validation */
-#define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40
-/* Enable policy checking */
-#define X509_V_FLAG_POLICY_CHECK 0x80
-/* Policy variable require-explicit-policy */
-#define X509_V_FLAG_EXPLICIT_POLICY 0x100
-/* Policy variable inhibit-any-policy */
-#define X509_V_FLAG_INHIBIT_ANY 0x200
-/* Policy variable inhibit-policy-mapping */
-#define X509_V_FLAG_INHIBIT_MAP 0x400
-/* Notify callback that policy is OK */
-#define X509_V_FLAG_NOTIFY_POLICY 0x800
-/* Extended CRL features such as indirect CRLs, alternate CRL signing keys */
-#define X509_V_FLAG_EXTENDED_CRL_SUPPORT 0x1000
-/* Delta CRL support */
-#define X509_V_FLAG_USE_DELTAS 0x2000
-/* Check selfsigned CA signature */
-#define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000
-/* Use trusted store first */
-#define X509_V_FLAG_TRUSTED_FIRST 0x8000
-/* Suite B 128 bit only mode: not normally used */
-#define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000
-/* Suite B 192 bit only mode */
-#define X509_V_FLAG_SUITEB_192_LOS 0x20000
-/* Suite B 128 bit mode allowing 192 bit algorithms */
-#define X509_V_FLAG_SUITEB_128_LOS 0x30000
-
-/* Allow partial chains if at least one certificate is in trusted store */
-#define X509_V_FLAG_PARTIAL_CHAIN 0x80000
-
-/* If the initial chain is not trusted, do not attempt to build an alternative
- * chain. Alternate chain checking was introduced in 1.0.2b. Setting this flag
- * will force the behaviour to match that of previous versions. */
-#define X509_V_FLAG_NO_ALT_CHAINS 0x100000
-
-#define X509_VP_FLAG_DEFAULT 0x1
-#define X509_VP_FLAG_OVERWRITE 0x2
-#define X509_VP_FLAG_RESET_FLAGS 0x4
-#define X509_VP_FLAG_LOCKED 0x8
-#define X509_VP_FLAG_ONCE 0x10
-
-/* Internal use: mask of policy related options */
-#define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \
- | X509_V_FLAG_EXPLICIT_POLICY \
- | X509_V_FLAG_INHIBIT_ANY \
- | X509_V_FLAG_INHIBIT_MAP)
-
-OPENSSL_EXPORT int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
- X509_NAME *name);
-OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name);
-OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x);
+#define X509_STORE_CTX_set_app_data(ctx, data) \
+ X509_STORE_CTX_set_ex_data(ctx, 0, data)
+#define X509_STORE_CTX_get_app_data(ctx) X509_STORE_CTX_get_ex_data(ctx, 0)
+
+#define X509_L_FILE_LOAD 1
+#define X509_L_ADD_DIR 2
+
+#define X509_LOOKUP_load_file(x, name, type) \
+ X509_LOOKUP_ctrl((x), X509_L_FILE_LOAD, (name), (long)(type), NULL)
+
+#define X509_LOOKUP_add_dir(x, name, type) \
+ X509_LOOKUP_ctrl((x), X509_L_ADD_DIR, (name), (long)(type), NULL)
+
+#define X509_V_OK 0
+#define X509_V_ERR_UNSPECIFIED 1
+
+#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2
+#define X509_V_ERR_UNABLE_TO_GET_CRL 3
+#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4
+#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5
+#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6
+#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7
+#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8
+#define X509_V_ERR_CERT_NOT_YET_VALID 9
+#define X509_V_ERR_CERT_HAS_EXPIRED 10
+#define X509_V_ERR_CRL_NOT_YET_VALID 11
+#define X509_V_ERR_CRL_HAS_EXPIRED 12
+#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13
+#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14
+#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15
+#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16
+#define X509_V_ERR_OUT_OF_MEM 17
+#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18
+#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19
+#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20
+#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21
+#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22
+#define X509_V_ERR_CERT_REVOKED 23
+#define X509_V_ERR_INVALID_CA 24
+#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25
+#define X509_V_ERR_INVALID_PURPOSE 26
+#define X509_V_ERR_CERT_UNTRUSTED 27
+#define X509_V_ERR_CERT_REJECTED 28
+// These are 'informational' when looking for issuer cert
+#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29
+#define X509_V_ERR_AKID_SKID_MISMATCH 30
+#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31
+#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32
+
+#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33
+#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34
+#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35
+#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36
+#define X509_V_ERR_INVALID_NON_CA 37
+#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38
+#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39
+#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40
+
+#define X509_V_ERR_INVALID_EXTENSION 41
+#define X509_V_ERR_INVALID_POLICY_EXTENSION 42
+#define X509_V_ERR_NO_EXPLICIT_POLICY 43
+#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44
+#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45
+
+#define X509_V_ERR_UNNESTED_RESOURCE 46
+
+#define X509_V_ERR_PERMITTED_VIOLATION 47
+#define X509_V_ERR_EXCLUDED_VIOLATION 48
+#define X509_V_ERR_SUBTREE_MINMAX 49
+#define X509_V_ERR_APPLICATION_VERIFICATION 50
+#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51
+#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52
+#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53
+#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54
+
+// Suite B mode algorithm violation
+#define X509_V_ERR_SUITE_B_INVALID_VERSION 56
+#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57
+#define X509_V_ERR_SUITE_B_INVALID_CURVE 58
+#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59
+#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60
+#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61
+
+// Host, email and IP check errors
+#define X509_V_ERR_HOSTNAME_MISMATCH 62
+#define X509_V_ERR_EMAIL_MISMATCH 63
+#define X509_V_ERR_IP_ADDRESS_MISMATCH 64
+
+// Caller error
+#define X509_V_ERR_INVALID_CALL 65
+// Issuer lookup error
+#define X509_V_ERR_STORE_LOOKUP 66
+
+#define X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS 67
+
+// Certificate verify flags
+
+// Send issuer+subject checks to verify_cb
+#define X509_V_FLAG_CB_ISSUER_CHECK 0x1
+// Use check time instead of current time
+#define X509_V_FLAG_USE_CHECK_TIME 0x2
+// Lookup CRLs
+#define X509_V_FLAG_CRL_CHECK 0x4
+// Lookup CRLs for whole chain
+#define X509_V_FLAG_CRL_CHECK_ALL 0x8
+// Ignore unhandled critical extensions
+#define X509_V_FLAG_IGNORE_CRITICAL 0x10
+// Does nothing as its functionality has been enabled by default.
+#define X509_V_FLAG_X509_STRICT 0x00
+// Enable proxy certificate validation
+#define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40
+// Enable policy checking
+#define X509_V_FLAG_POLICY_CHECK 0x80
+// Policy variable require-explicit-policy
+#define X509_V_FLAG_EXPLICIT_POLICY 0x100
+// Policy variable inhibit-any-policy
+#define X509_V_FLAG_INHIBIT_ANY 0x200
+// Policy variable inhibit-policy-mapping
+#define X509_V_FLAG_INHIBIT_MAP 0x400
+// Notify callback that policy is OK
+#define X509_V_FLAG_NOTIFY_POLICY 0x800
+// Extended CRL features such as indirect CRLs, alternate CRL signing keys
+#define X509_V_FLAG_EXTENDED_CRL_SUPPORT 0x1000
+// Delta CRL support
+#define X509_V_FLAG_USE_DELTAS 0x2000
+// Check selfsigned CA signature
+#define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000
+// Use trusted store first
+#define X509_V_FLAG_TRUSTED_FIRST 0x8000
+// Suite B 128 bit only mode: not normally used
+#define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000
+// Suite B 192 bit only mode
+#define X509_V_FLAG_SUITEB_192_LOS 0x20000
+// Suite B 128 bit mode allowing 192 bit algorithms
+#define X509_V_FLAG_SUITEB_128_LOS 0x30000
+
+// Allow partial chains if at least one certificate is in trusted store
+#define X509_V_FLAG_PARTIAL_CHAIN 0x80000
+
+// If the initial chain is not trusted, do not attempt to build an alternative
+// chain. Alternate chain checking was introduced in 1.0.2b. Setting this flag
+// will force the behaviour to match that of previous versions.
+#define X509_V_FLAG_NO_ALT_CHAINS 0x100000
+
+#define X509_VP_FLAG_DEFAULT 0x1
+#define X509_VP_FLAG_OVERWRITE 0x2
+#define X509_VP_FLAG_RESET_FLAGS 0x4
+#define X509_VP_FLAG_LOCKED 0x8
+#define X509_VP_FLAG_ONCE 0x10
+
+// Internal use: mask of policy related options
+#define X509_V_FLAG_POLICY_MASK \
+ (X509_V_FLAG_POLICY_CHECK | X509_V_FLAG_EXPLICIT_POLICY | \
+ X509_V_FLAG_INHIBIT_ANY | X509_V_FLAG_INHIBIT_MAP)
+
+OPENSSL_EXPORT int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h,
+ int type, X509_NAME *name);
+OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_by_subject(
+ STACK_OF(X509_OBJECT) *h, int type, X509_NAME *name);
+OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h,
+ X509_OBJECT *x);
OPENSSL_EXPORT int X509_OBJECT_up_ref_count(X509_OBJECT *a);
OPENSSL_EXPORT void X509_OBJECT_free_contents(X509_OBJECT *a);
OPENSSL_EXPORT int X509_OBJECT_get_type(const X509_OBJECT *a);
OPENSSL_EXPORT X509 *X509_OBJECT_get0_X509(const X509_OBJECT *a);
-OPENSSL_EXPORT X509_STORE *X509_STORE_new(void );
+OPENSSL_EXPORT X509_STORE *X509_STORE_new(void);
OPENSSL_EXPORT int X509_STORE_up_ref(X509_STORE *store);
OPENSSL_EXPORT void X509_STORE_free(X509_STORE *v);
OPENSSL_EXPORT STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *st);
-OPENSSL_EXPORT STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *st, X509_NAME *nm);
-OPENSSL_EXPORT STACK_OF(X509_CRL)* X509_STORE_get1_crls(X509_STORE_CTX *st, X509_NAME *nm);
+OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_get1_certs(X509_STORE_CTX *st,
+ X509_NAME *nm);
+OPENSSL_EXPORT STACK_OF(X509_CRL) *X509_STORE_get1_crls(X509_STORE_CTX *st,
+ X509_NAME *nm);
OPENSSL_EXPORT int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags);
OPENSSL_EXPORT int X509_STORE_set_purpose(X509_STORE *ctx, int purpose);
OPENSSL_EXPORT int X509_STORE_set_trust(X509_STORE *ctx, int trust);
-OPENSSL_EXPORT int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm);
+OPENSSL_EXPORT int X509_STORE_set1_param(X509_STORE *ctx,
+ X509_VERIFY_PARAM *pm);
OPENSSL_EXPORT X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *ctx);
-/* X509_STORE_set0_additional_untrusted sets a stack of additional, untrusted
- * certificates that are available for chain building. This function does not
- * take ownership of the stack. */
+// X509_STORE_set0_additional_untrusted sets a stack of additional, untrusted
+// certificates that are available for chain building. This function does not
+// take ownership of the stack.
OPENSSL_EXPORT void X509_STORE_set0_additional_untrusted(
X509_STORE *ctx, STACK_OF(X509) *untrusted);
@@ -514,19 +367,22 @@ X509_STORE_get_cleanup(X509_STORE *ctx);
OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_new(void);
-OPENSSL_EXPORT int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
+OPENSSL_EXPORT int X509_STORE_CTX_get1_issuer(X509 **issuer,
+ X509_STORE_CTX *ctx, X509 *x);
OPENSSL_EXPORT void X509_STORE_CTX_zero(X509_STORE_CTX *ctx);
OPENSSL_EXPORT void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
OPENSSL_EXPORT int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
- X509 *x509, STACK_OF(X509) *chain);
-OPENSSL_EXPORT void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk);
+ X509 *x509, STACK_OF(X509) *chain);
+OPENSSL_EXPORT void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx,
+ STACK_OF(X509) *sk);
OPENSSL_EXPORT void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
OPENSSL_EXPORT X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx);
OPENSSL_EXPORT X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx);
-OPENSSL_EXPORT X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m);
+OPENSSL_EXPORT X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v,
+ X509_LOOKUP_METHOD *m);
OPENSSL_EXPORT X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void);
OPENSSL_EXPORT X509_LOOKUP_METHOD *X509_LOOKUP_file(void);
@@ -534,148 +390,182 @@ OPENSSL_EXPORT X509_LOOKUP_METHOD *X509_LOOKUP_file(void);
OPENSSL_EXPORT int X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
OPENSSL_EXPORT int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);
-OPENSSL_EXPORT int X509_STORE_get_by_subject(X509_STORE_CTX *vs,int type,X509_NAME *name,
- X509_OBJECT *ret);
+OPENSSL_EXPORT int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type,
+ X509_NAME *name, X509_OBJECT *ret);
OPENSSL_EXPORT int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc,
- long argl, char **ret);
+ long argl, char **ret);
#ifndef OPENSSL_NO_STDIO
-OPENSSL_EXPORT int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type);
-OPENSSL_EXPORT int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type);
-OPENSSL_EXPORT int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type);
+OPENSSL_EXPORT int X509_load_cert_file(X509_LOOKUP *ctx, const char *file,
+ int type);
+OPENSSL_EXPORT int X509_load_crl_file(X509_LOOKUP *ctx, const char *file,
+ int type);
+OPENSSL_EXPORT int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file,
+ int type);
#endif
OPENSSL_EXPORT X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method);
OPENSSL_EXPORT void X509_LOOKUP_free(X509_LOOKUP *ctx);
OPENSSL_EXPORT int X509_LOOKUP_init(X509_LOOKUP *ctx);
-OPENSSL_EXPORT int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name,
- X509_OBJECT *ret);
-OPENSSL_EXPORT int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name,
- ASN1_INTEGER *serial, X509_OBJECT *ret);
+OPENSSL_EXPORT int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type,
+ X509_NAME *name, X509_OBJECT *ret);
+OPENSSL_EXPORT int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type,
+ X509_NAME *name,
+ ASN1_INTEGER *serial,
+ X509_OBJECT *ret);
OPENSSL_EXPORT int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type,
- unsigned char *bytes, int len, X509_OBJECT *ret);
+ unsigned char *bytes, int len,
+ X509_OBJECT *ret);
OPENSSL_EXPORT int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str,
- int len, X509_OBJECT *ret);
+ int len, X509_OBJECT *ret);
OPENSSL_EXPORT int X509_LOOKUP_shutdown(X509_LOOKUP *ctx);
#ifndef OPENSSL_NO_STDIO
-OPENSSL_EXPORT int X509_STORE_load_locations (X509_STORE *ctx,
- const char *file, const char *dir);
-OPENSSL_EXPORT int X509_STORE_set_default_paths(X509_STORE *ctx);
+OPENSSL_EXPORT int X509_STORE_load_locations(X509_STORE *ctx, const char *file,
+ const char *dir);
+OPENSSL_EXPORT int X509_STORE_set_default_paths(X509_STORE *ctx);
#endif
-OPENSSL_EXPORT int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
- CRYPTO_EX_dup *dup_unused, CRYPTO_EX_free *free_func);
-OPENSSL_EXPORT int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx,int idx,void *data);
-OPENSSL_EXPORT void * X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx);
-OPENSSL_EXPORT int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
-OPENSSL_EXPORT void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx,int s);
-OPENSSL_EXPORT int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
-OPENSSL_EXPORT X509 * X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
+OPENSSL_EXPORT int X509_STORE_CTX_get_ex_new_index(long argl, void *argp,
+ CRYPTO_EX_unused *unused,
+ CRYPTO_EX_dup *dup_unused,
+ CRYPTO_EX_free *free_func);
+OPENSSL_EXPORT int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx,
+ void *data);
+OPENSSL_EXPORT void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx);
+OPENSSL_EXPORT int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
+OPENSSL_EXPORT void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx, int s);
+OPENSSL_EXPORT int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
+OPENSSL_EXPORT X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
OPENSSL_EXPORT X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx);
OPENSSL_EXPORT X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx);
-OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx);
+OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(
+ X509_STORE_CTX *ctx);
OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx);
OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx);
-OPENSSL_EXPORT void X509_STORE_CTX_set_cert(X509_STORE_CTX *c,X509 *x);
-OPENSSL_EXPORT void X509_STORE_CTX_set_chain(X509_STORE_CTX *c,STACK_OF(X509) *sk);
-OPENSSL_EXPORT STACK_OF(X509) *
- X509_STORE_CTX_get0_untrusted(X509_STORE_CTX *ctx);
-OPENSSL_EXPORT void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,STACK_OF(X509_CRL) *sk);
+OPENSSL_EXPORT void X509_STORE_CTX_set_cert(X509_STORE_CTX *c, X509 *x);
+OPENSSL_EXPORT void X509_STORE_CTX_set_chain(X509_STORE_CTX *c,
+ STACK_OF(X509) *sk);
+OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get0_untrusted(
+ X509_STORE_CTX *ctx);
+OPENSSL_EXPORT void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,
+ STACK_OF(X509_CRL) *sk);
OPENSSL_EXPORT int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
OPENSSL_EXPORT int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust);
-OPENSSL_EXPORT int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
- int purpose, int trust);
-OPENSSL_EXPORT void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags);
-OPENSSL_EXPORT void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags,
- time_t t);
-OPENSSL_EXPORT void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx,
- int (*verify_cb)(int, X509_STORE_CTX *));
-
-OPENSSL_EXPORT X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx);
+OPENSSL_EXPORT int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx,
+ int def_purpose, int purpose,
+ int trust);
+OPENSSL_EXPORT void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx,
+ unsigned long flags);
+OPENSSL_EXPORT void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx,
+ unsigned long flags, time_t t);
+OPENSSL_EXPORT void X509_STORE_CTX_set_verify_cb(
+ X509_STORE_CTX *ctx, int (*verify_cb)(int, X509_STORE_CTX *));
+
+OPENSSL_EXPORT X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(
+ X509_STORE_CTX *ctx);
OPENSSL_EXPORT int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx);
-OPENSSL_EXPORT X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx);
-OPENSSL_EXPORT void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param);
-OPENSSL_EXPORT int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name);
+OPENSSL_EXPORT X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(
+ X509_STORE_CTX *ctx);
+OPENSSL_EXPORT void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx,
+ X509_VERIFY_PARAM *param);
+OPENSSL_EXPORT int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx,
+ const char *name);
-/* X509_VERIFY_PARAM functions */
+// X509_VERIFY_PARAM functions
OPENSSL_EXPORT X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
OPENSSL_EXPORT void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param);
OPENSSL_EXPORT int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to,
- const X509_VERIFY_PARAM *from);
-OPENSSL_EXPORT int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
- const X509_VERIFY_PARAM *from);
-OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name);
-OPENSSL_EXPORT int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags);
+ const X509_VERIFY_PARAM *from);
+OPENSSL_EXPORT int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
+ const X509_VERIFY_PARAM *from);
+OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param,
+ const char *name);
+OPENSSL_EXPORT int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param,
+ unsigned long flags);
OPENSSL_EXPORT int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param,
- unsigned long flags);
-OPENSSL_EXPORT unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param);
-OPENSSL_EXPORT int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose);
-OPENSSL_EXPORT int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust);
-OPENSSL_EXPORT void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth);
-OPENSSL_EXPORT void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t);
+ unsigned long flags);
+OPENSSL_EXPORT unsigned long X509_VERIFY_PARAM_get_flags(
+ X509_VERIFY_PARAM *param);
+OPENSSL_EXPORT int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param,
+ int purpose);
+OPENSSL_EXPORT int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param,
+ int trust);
+OPENSSL_EXPORT void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param,
+ int depth);
+OPENSSL_EXPORT void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param,
+ time_t t);
OPENSSL_EXPORT int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
- ASN1_OBJECT *policy);
-OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
- STACK_OF(ASN1_OBJECT) *policies);
+ ASN1_OBJECT *policy);
+OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_policies(
+ X509_VERIFY_PARAM *param, STACK_OF(ASN1_OBJECT) *policies);
OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
- const char *name, size_t namelen);
+ const char *name,
+ size_t namelen);
OPENSSL_EXPORT int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param,
- const char *name,
- size_t namelen);
+ const char *name,
+ size_t namelen);
OPENSSL_EXPORT void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
- unsigned int flags);
+ unsigned int flags);
OPENSSL_EXPORT char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *);
OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
- const char *email, size_t emaillen);
+ const char *email,
+ size_t emaillen);
OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
- const unsigned char *ip, size_t iplen);
-OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc);
+ const unsigned char *ip,
+ size_t iplen);
+OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param,
+ const char *ipasc);
OPENSSL_EXPORT int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param);
-OPENSSL_EXPORT const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param);
+OPENSSL_EXPORT const char *X509_VERIFY_PARAM_get0_name(
+ const X509_VERIFY_PARAM *param);
OPENSSL_EXPORT int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param);
OPENSSL_EXPORT int X509_VERIFY_PARAM_get_count(void);
OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id);
-OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name);
+OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(
+ const char *name);
OPENSSL_EXPORT void X509_VERIFY_PARAM_table_cleanup(void);
-OPENSSL_EXPORT int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
- STACK_OF(X509) *certs,
- STACK_OF(ASN1_OBJECT) *policy_oids,
- unsigned int flags);
+OPENSSL_EXPORT int X509_policy_check(X509_POLICY_TREE **ptree,
+ int *pexplicit_policy,
+ STACK_OF(X509) *certs,
+ STACK_OF(ASN1_OBJECT) *policy_oids,
+ unsigned int flags);
OPENSSL_EXPORT void X509_policy_tree_free(X509_POLICY_TREE *tree);
OPENSSL_EXPORT int X509_policy_tree_level_count(const X509_POLICY_TREE *tree);
-OPENSSL_EXPORT X509_POLICY_LEVEL *
- X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i);
+OPENSSL_EXPORT X509_POLICY_LEVEL *X509_policy_tree_get0_level(
+ const X509_POLICY_TREE *tree, int i);
-OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) *
- X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree);
+OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_policies(
+ const X509_POLICY_TREE *tree);
-OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) *
- X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree);
+OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) *X509_policy_tree_get0_user_policies(
+ const X509_POLICY_TREE *tree);
OPENSSL_EXPORT int X509_policy_level_node_count(X509_POLICY_LEVEL *level);
-OPENSSL_EXPORT X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i);
+OPENSSL_EXPORT X509_POLICY_NODE *X509_policy_level_get0_node(
+ X509_POLICY_LEVEL *level, int i);
-OPENSSL_EXPORT const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node);
+OPENSSL_EXPORT const ASN1_OBJECT *X509_policy_node_get0_policy(
+ const X509_POLICY_NODE *node);
-OPENSSL_EXPORT STACK_OF(POLICYQUALINFO) *
- X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node);
-OPENSSL_EXPORT const X509_POLICY_NODE *
- X509_policy_node_get0_parent(const X509_POLICY_NODE *node);
+OPENSSL_EXPORT STACK_OF(POLICYQUALINFO) *X509_policy_node_get0_qualifiers(
+ const X509_POLICY_NODE *node);
+OPENSSL_EXPORT const X509_POLICY_NODE *X509_policy_node_get0_parent(
+ const X509_POLICY_NODE *node);
-#ifdef __cplusplus
+#ifdef __cplusplus
}
#endif
#endif
diff --git a/deps/boringssl/src/include/openssl/x509v3.h b/deps/boringssl/src/include/openssl/x509v3.h
index 2c9ba73..8e4a511 100644
--- a/deps/boringssl/src/include/openssl/x509v3.h
+++ b/deps/boringssl/src/include/openssl/x509v3.h
@@ -154,8 +154,6 @@ DEFINE_STACK_OF(X509V3_EXT_METHOD)
#define X509V3_EXT_CTX_DEP 0x2
#define X509V3_EXT_MULTILINE 0x4
-typedef BIT_STRING_BITNAME ENUMERATED_NAMES;
-
struct BASIC_CONSTRAINTS_st {
int ca;
ASN1_INTEGER *pathlen;
@@ -206,7 +204,6 @@ typedef struct GENERAL_NAME_st {
} GENERAL_NAME;
DEFINE_STACK_OF(GENERAL_NAME)
-DECLARE_ASN1_SET_OF(GENERAL_NAME)
typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES;
@@ -218,7 +215,6 @@ typedef struct ACCESS_DESCRIPTION_st {
} ACCESS_DESCRIPTION;
DEFINE_STACK_OF(ACCESS_DESCRIPTION)
-DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION)
typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS;
@@ -258,7 +254,6 @@ struct DIST_POINT_st {
typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS;
DEFINE_STACK_OF(DIST_POINT)
-DECLARE_ASN1_SET_OF(DIST_POINT)
struct AUTHORITY_KEYID_st {
ASN1_OCTET_STRING *keyid;
@@ -286,7 +281,6 @@ typedef struct POLICYQUALINFO_st {
} POLICYQUALINFO;
DEFINE_STACK_OF(POLICYQUALINFO)
-DECLARE_ASN1_SET_OF(POLICYQUALINFO)
typedef struct POLICYINFO_st {
ASN1_OBJECT *policyid;
@@ -296,7 +290,6 @@ typedef struct POLICYINFO_st {
typedef STACK_OF(POLICYINFO) CERTIFICATEPOLICIES;
DEFINE_STACK_OF(POLICYINFO)
-DECLARE_ASN1_SET_OF(POLICYINFO)
typedef struct POLICY_MAPPING_st {
ASN1_OBJECT *issuerDomainPolicy;
@@ -490,12 +483,30 @@ OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(
X509V3_EXT_METHOD *method, ASN1_BIT_STRING *bits,
STACK_OF(CONF_VALUE) *extlist);
+// i2v_GENERAL_NAME serializes |gen| as a |CONF_VALUE|. If |ret| is non-NULL, it
+// appends the value to |ret| and returns |ret| on success or NULL on error. If
+// it returns NULL, the caller is still responsible for freeing |ret|. If |ret|
+// is NULL, it returns a newly-allocated |STACK_OF(CONF_VALUE)| containing the
+// result. |method| is ignored.
+//
+// Do not use this function. This is an internal implementation detail of the
+// human-readable print functions. If extracting a SAN list from a certificate,
+// look at |gen| directly.
OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(
X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret);
OPENSSL_EXPORT int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen);
DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES)
+// i2v_GENERAL_NAMES serializes |gen| as a list of |CONF_VALUE|s. If |ret| is
+// non-NULL, it appends the values to |ret| and returns |ret| on success or NULL
+// on error. If it returns NULL, the caller is still responsible for freeing
+// |ret|. If |ret| is NULL, it returns a newly-allocated |STACK_OF(CONF_VALUE)|
+// containing the results. |method| is ignored.
+//
+// Do not use this function. This is an internal implementation detail of the
+// human-readable print functions. If extracting a SAN list from a certificate,
+// look at |gen| directly.
OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(
X509V3_EXT_METHOD *method, GENERAL_NAMES *gen,
STACK_OF(CONF_VALUE) *extlist);
@@ -609,15 +620,35 @@ OPENSSL_EXPORT void X509V3_section_free(X509V3_CTX *ctx,
OPENSSL_EXPORT void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
X509_REQ *req, X509_CRL *crl, int flags);
+// X509V3_add_value appends a |CONF_VALUE| containing |name| and |value| to
+// |*extlist|. It returns one on success and zero on error. If |*extlist| is
+// NULL, it sets |*extlist| to a newly-allocated |STACK_OF(CONF_VALUE)|
+// containing the result. Either |name| or |value| may be NULL to omit the
+// field.
+//
+// On failure, if |*extlist| was NULL, |*extlist| will remain NULL when the
+// function returns.
OPENSSL_EXPORT int X509V3_add_value(const char *name, const char *value,
STACK_OF(CONF_VALUE) **extlist);
+
+// X509V3_add_value_uchar behaves like |X509V3_add_value| but takes an
+// |unsigned char| pointer.
OPENSSL_EXPORT int X509V3_add_value_uchar(const char *name,
const unsigned char *value,
STACK_OF(CONF_VALUE) **extlist);
+
+// X509V3_add_value_bool behaves like |X509V3_add_value| but stores the value
+// "TRUE" if |asn1_bool| is non-zero and "FALSE" otherwise.
OPENSSL_EXPORT int X509V3_add_value_bool(const char *name, int asn1_bool,
STACK_OF(CONF_VALUE) **extlist);
-OPENSSL_EXPORT int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
+
+// X509V3_add_value_bool behaves like |X509V3_add_value| but stores a string
+// representation of |aint|. Note this string representation may be decimal or
+// hexadecimal, depending on the size of |aint|.
+OPENSSL_EXPORT int X509V3_add_value_int(const char *name,
+ const ASN1_INTEGER *aint,
STACK_OF(CONF_VALUE) **extlist);
+
OPENSSL_EXPORT char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth,
const ASN1_INTEGER *aint);
OPENSSL_EXPORT ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth,
@@ -664,7 +695,7 @@ OPENSSL_EXPORT void *X509V3_EXT_d2i(const X509_EXTENSION *ext);
// extension, or -1 if not found. If |out_idx| is non-NULL, duplicate extensions
// are not treated as an error. Callers, however, should not rely on this
// behavior as it may be removed in the future. Duplicate extensions are
-// forbidden in RFC5280.
+// forbidden in RFC 5280.
//
// WARNING: This function is difficult to use correctly. Callers should pass a
// non-NULL |out_critical| and check both the return value and |*out_critical|
@@ -794,7 +825,7 @@ OPENSSL_EXPORT uint32_t X509_get_key_usage(X509 *x);
OPENSSL_EXPORT uint32_t X509_get_extended_key_usage(X509 *x);
// X509_get0_subject_key_id returns |x509|'s subject key identifier, if present.
-// (See RFC5280, section 4.2.1.2.) It returns NULL if the extension is not
+// (See RFC 5280, section 4.2.1.2.) It returns NULL if the extension is not
// present or if some extension in |x509| was invalid.
//
// Note that decoding an |X509| object will not check for invalid extensions. To
@@ -803,7 +834,7 @@ OPENSSL_EXPORT uint32_t X509_get_extended_key_usage(X509 *x);
OPENSSL_EXPORT const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x509);
// X509_get0_authority_key_id returns keyIdentifier of |x509|'s authority key
-// identifier, if the extension and field are present. (See RFC5280,
+// identifier, if the extension and field are present. (See RFC 5280,
// section 4.2.1.1.) It returns NULL if the extension is not present, if it is
// present but lacks a keyIdentifier field, or if some extension in |x509| was
// invalid.
@@ -815,7 +846,7 @@ OPENSSL_EXPORT const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x509);
// X509_get0_authority_issuer returns the authorityCertIssuer of |x509|'s
// authority key identifier, if the extension and field are present. (See
-// RFC5280, section 4.2.1.1.) It returns NULL if the extension is not present,
+// RFC 5280, section 4.2.1.1.) It returns NULL if the extension is not present,
// if it is present but lacks a authorityCertIssuer field, or if some extension
// in |x509| was invalid.
//
@@ -826,7 +857,7 @@ OPENSSL_EXPORT const GENERAL_NAMES *X509_get0_authority_issuer(X509 *x509);
// X509_get0_authority_serial returns the authorityCertSerialNumber of |x509|'s
// authority key identifier, if the extension and field are present. (See
-// RFC5280, section 4.2.1.1.) It returns NULL if the extension is not present,
+// RFC 5280, section 4.2.1.1.) It returns NULL if the extension is not present,
// if it is present but lacks a authorityCertSerialNumber field, or if some
// extension in |x509| was invalid.
//
@@ -884,7 +915,6 @@ OPENSSL_EXPORT int X509_check_ip_asc(X509 *x, const char *ipasc,
OPENSSL_EXPORT ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
OPENSSL_EXPORT ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);
-OPENSSL_EXPORT int a2i_ipadd(unsigned char *ipout, const char *ipasc);
OPENSSL_EXPORT int X509V3_NAME_from_section(X509_NAME *nm,
STACK_OF(CONF_VALUE) *dn_sk,
unsigned long chtype);
@@ -908,8 +938,13 @@ BSSL_NAMESPACE_BEGIN
BORINGSSL_MAKE_DELETER(ACCESS_DESCRIPTION, ACCESS_DESCRIPTION_free)
BORINGSSL_MAKE_DELETER(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
BORINGSSL_MAKE_DELETER(BASIC_CONSTRAINTS, BASIC_CONSTRAINTS_free)
+// TODO(davidben): Move this to conf.h and rename to CONF_VALUE_free.
+BORINGSSL_MAKE_DELETER(CONF_VALUE, X509V3_conf_free)
BORINGSSL_MAKE_DELETER(DIST_POINT, DIST_POINT_free)
BORINGSSL_MAKE_DELETER(GENERAL_NAME, GENERAL_NAME_free)
+BORINGSSL_MAKE_DELETER(GENERAL_SUBTREE, GENERAL_SUBTREE_free)
+BORINGSSL_MAKE_DELETER(NAME_CONSTRAINTS, NAME_CONSTRAINTS_free)
+BORINGSSL_MAKE_DELETER(POLICY_MAPPING, POLICY_MAPPING_free)
BORINGSSL_MAKE_DELETER(POLICYINFO, POLICYINFO_free)
BSSL_NAMESPACE_END
@@ -980,5 +1015,6 @@ BSSL_NAMESPACE_END
#define X509V3_R_UNSUPPORTED_OPTION 160
#define X509V3_R_UNSUPPORTED_TYPE 161
#define X509V3_R_USER_TOO_LONG 162
+#define X509V3_R_INVALID_VALUE 163
#endif
diff --git a/deps/boringssl/src/sources.cmake b/deps/boringssl/src/sources.cmake
index 9ac55d5..ef9cac1 100644
--- a/deps/boringssl/src/sources.cmake
+++ b/deps/boringssl/src/sources.cmake
@@ -9,7 +9,6 @@ set(
crypto/blake2/blake2b256_tests.txt
crypto/cipher_extra/test/aes_128_cbc_sha1_tls_implicit_iv_tests.txt
crypto/cipher_extra/test/aes_128_cbc_sha1_tls_tests.txt
- crypto/cipher_extra/test/aes_128_cbc_sha256_tls_tests.txt
crypto/cipher_extra/test/aes_128_ccm_bluetooth_tests.txt
crypto/cipher_extra/test/aes_128_ccm_bluetooth_8_tests.txt
crypto/cipher_extra/test/aes_128_ctr_hmac_sha256.txt
@@ -19,8 +18,6 @@ set(
crypto/cipher_extra/test/aes_192_gcm_tests.txt
crypto/cipher_extra/test/aes_256_cbc_sha1_tls_implicit_iv_tests.txt
crypto/cipher_extra/test/aes_256_cbc_sha1_tls_tests.txt
- crypto/cipher_extra/test/aes_256_cbc_sha256_tls_tests.txt
- crypto/cipher_extra/test/aes_256_cbc_sha384_tls_tests.txt
crypto/cipher_extra/test/aes_256_ctr_hmac_sha256.txt
crypto/cipher_extra/test/aes_256_gcm_randnonce_tests.txt
crypto/cipher_extra/test/aes_256_gcm_siv_tests.txt
@@ -59,6 +56,15 @@ set(
crypto/fipsmodule/rand/ctrdrbg_vectors.txt
crypto/hmac_extra/hmac_tests.txt
crypto/hpke/hpke_test_vectors.txt
+ crypto/pkcs8/test/empty_password.p12
+ crypto/pkcs8/test/no_encryption.p12
+ crypto/pkcs8/test/nss.p12
+ crypto/pkcs8/test/null_password.p12
+ crypto/pkcs8/test/openssl.p12
+ crypto/pkcs8/test/pbes2_sha1.p12
+ crypto/pkcs8/test/pbes2_sha256.p12
+ crypto/pkcs8/test/unicode_password.p12
+ crypto/pkcs8/test/windows.p12
crypto/poly1305/poly1305_tests.txt
crypto/siphash/siphash_tests.txt
crypto/x509/test/basic_constraints_ca.pem
diff --git a/deps/boringssl/src/ssl/CMakeLists.txt b/deps/boringssl/src/ssl/CMakeLists.txt
index 0fb532e..4f4abf8 100644
--- a/deps/boringssl/src/ssl/CMakeLists.txt
+++ b/deps/boringssl/src/ssl/CMakeLists.txt
@@ -10,6 +10,8 @@ add_library(
d1_srtp.cc
dtls_method.cc
dtls_record.cc
+ encrypted_client_hello.cc
+ extensions.cc
handoff.cc
handshake.cc
handshake_client.cc
@@ -32,7 +34,6 @@ add_library(
ssl_versions.cc
ssl_x509.cc
t1_enc.cc
- t1_lib.cc
tls_method.cc
tls_record.cc
tls13_both.cc
diff --git a/deps/boringssl/src/ssl/d1_both.cc b/deps/boringssl/src/ssl/d1_both.cc
index c7f85c7..f8c04b7 100644
--- a/deps/boringssl/src/ssl/d1_both.cc
+++ b/deps/boringssl/src/ssl/d1_both.cc
@@ -503,7 +503,7 @@ void dtls_clear_outgoing_messages(SSL *ssl) {
ssl->d1->flight_has_reply = false;
}
-bool dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
+bool dtls1_init_message(const SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
// Pick a modest size hint to save most of the |realloc| calls.
if (!CBB_init(cbb, 64) ||
!CBB_add_u8(cbb, type) ||
@@ -517,7 +517,7 @@ bool dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
return true;
}
-bool dtls1_finish_message(SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg) {
+bool dtls1_finish_message(const SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg) {
if (!CBBFinishArray(cbb, out_msg) ||
out_msg->size() < DTLS1_HM_HEADER_LENGTH) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
@@ -771,13 +771,16 @@ static int send_flight(SSL *ssl) {
return -1;
}
+ if (ssl->wbio == nullptr) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
+ return -1;
+ }
+
dtls1_update_mtu(ssl);
- int ret = -1;
- uint8_t *packet = (uint8_t *)OPENSSL_malloc(ssl->d1->mtu);
- if (packet == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
+ Array<uint8_t> packet;
+ if (!packet.Init(ssl->d1->mtu)) {
+ return -1;
}
while (ssl->d1->outgoing_written < ssl->d1->outgoing_messages_len) {
@@ -785,31 +788,26 @@ static int send_flight(SSL *ssl) {
uint32_t old_offset = ssl->d1->outgoing_offset;
size_t packet_len;
- if (!seal_next_packet(ssl, packet, &packet_len, ssl->d1->mtu)) {
- goto err;
+ if (!seal_next_packet(ssl, packet.data(), &packet_len, packet.size())) {
+ return -1;
}
- int bio_ret = BIO_write(ssl->wbio.get(), packet, packet_len);
+ int bio_ret = BIO_write(ssl->wbio.get(), packet.data(), packet_len);
if (bio_ret <= 0) {
// Retry this packet the next time around.
ssl->d1->outgoing_written = old_written;
ssl->d1->outgoing_offset = old_offset;
ssl->s3->rwstate = SSL_ERROR_WANT_WRITE;
- ret = bio_ret;
- goto err;
+ return bio_ret;
}
}
if (BIO_flush(ssl->wbio.get()) <= 0) {
ssl->s3->rwstate = SSL_ERROR_WANT_WRITE;
- goto err;
+ return -1;
}
- ret = 1;
-
-err:
- OPENSSL_free(packet);
- return ret;
+ return 1;
}
int dtls1_flush_flight(SSL *ssl) {
diff --git a/deps/boringssl/src/ssl/d1_srtp.cc b/deps/boringssl/src/ssl/d1_srtp.cc
index 96d7d51..12c8075 100644
--- a/deps/boringssl/src/ssl/d1_srtp.cc
+++ b/deps/boringssl/src/ssl/d1_srtp.cc
@@ -202,7 +202,7 @@ int SSL_set_srtp_profiles(SSL *ssl, const char *profiles) {
ssl_ctx_make_profiles(profiles, &ssl->config->srtp_profiles);
}
-STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *ssl) {
+const STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(const SSL *ssl) {
if (ssl == nullptr) {
return nullptr;
}
diff --git a/deps/boringssl/src/ssl/encrypted_client_hello.cc b/deps/boringssl/src/ssl/encrypted_client_hello.cc
new file mode 100644
index 0000000..5192cc6
--- /dev/null
+++ b/deps/boringssl/src/ssl/encrypted_client_hello.cc
@@ -0,0 +1,1126 @@
+/* Copyright (c) 2021, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <algorithm>
+#include <utility>
+
+#include <openssl/aead.h>
+#include <openssl/bytestring.h>
+#include <openssl/curve25519.h>
+#include <openssl/err.h>
+#include <openssl/hkdf.h>
+#include <openssl/hpke.h>
+#include <openssl/rand.h>
+
+#include "internal.h"
+
+
+BSSL_NAMESPACE_BEGIN
+
+// ECH reuses the extension code point for the version number.
+static constexpr uint16_t kECHConfigVersion =
+ TLSEXT_TYPE_encrypted_client_hello;
+
+static const decltype(&EVP_hpke_aes_128_gcm) kSupportedAEADs[] = {
+ &EVP_hpke_aes_128_gcm,
+ &EVP_hpke_aes_256_gcm,
+ &EVP_hpke_chacha20_poly1305,
+};
+
+static const EVP_HPKE_AEAD *get_ech_aead(uint16_t aead_id) {
+ for (const auto aead_func : kSupportedAEADs) {
+ const EVP_HPKE_AEAD *aead = aead_func();
+ if (aead_id == EVP_HPKE_AEAD_id(aead)) {
+ return aead;
+ }
+ }
+ return nullptr;
+}
+
+// ssl_client_hello_write_without_extensions serializes |client_hello| into
+// |out|, omitting the length-prefixed extensions. It serializes individual
+// fields, starting with |client_hello->version|, and ignores the
+// |client_hello->client_hello| field. It returns true on success and false on
+// failure.
+static bool ssl_client_hello_write_without_extensions(
+ const SSL_CLIENT_HELLO *client_hello, CBB *out) {
+ CBB cbb;
+ if (!CBB_add_u16(out, client_hello->version) ||
+ !CBB_add_bytes(out, client_hello->random, client_hello->random_len) ||
+ !CBB_add_u8_length_prefixed(out, &cbb) ||
+ !CBB_add_bytes(&cbb, client_hello->session_id,
+ client_hello->session_id_len) ||
+ !CBB_add_u16_length_prefixed(out, &cbb) ||
+ !CBB_add_bytes(&cbb, client_hello->cipher_suites,
+ client_hello->cipher_suites_len) ||
+ !CBB_add_u8_length_prefixed(out, &cbb) ||
+ !CBB_add_bytes(&cbb, client_hello->compression_methods,
+ client_hello->compression_methods_len) ||
+ !CBB_flush(out)) {
+ return false;
+ }
+ return true;
+}
+
+static bool is_valid_client_hello_inner(SSL *ssl, uint8_t *out_alert,
+ Span<const uint8_t> body) {
+ // See draft-ietf-tls-esni-13, section 7.1.
+ SSL_CLIENT_HELLO client_hello;
+ CBS extension;
+ if (!ssl_client_hello_init(ssl, &client_hello, body) ||
+ !ssl_client_hello_get_extension(&client_hello, &extension,
+ TLSEXT_TYPE_encrypted_client_hello) ||
+ CBS_len(&extension) != 1 || //
+ CBS_data(&extension)[0] != ECH_CLIENT_INNER ||
+ !ssl_client_hello_get_extension(&client_hello, &extension,
+ TLSEXT_TYPE_supported_versions)) {
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_CLIENT_HELLO_INNER);
+ return false;
+ }
+ // Parse supported_versions and reject TLS versions prior to TLS 1.3. Older
+ // versions are incompatible with ECH.
+ CBS versions;
+ if (!CBS_get_u8_length_prefixed(&extension, &versions) ||
+ CBS_len(&extension) != 0 || //
+ CBS_len(&versions) == 0) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ while (CBS_len(&versions) != 0) {
+ uint16_t version;
+ if (!CBS_get_u16(&versions, &version)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ if (version == SSL3_VERSION || version == TLS1_VERSION ||
+ version == TLS1_1_VERSION || version == TLS1_2_VERSION ||
+ version == DTLS1_VERSION || version == DTLS1_2_VERSION) {
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_CLIENT_HELLO_INNER);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ssl_decode_client_hello_inner(
+ SSL *ssl, uint8_t *out_alert, Array<uint8_t> *out_client_hello_inner,
+ Span<const uint8_t> encoded_client_hello_inner,
+ const SSL_CLIENT_HELLO *client_hello_outer) {
+ SSL_CLIENT_HELLO client_hello_inner;
+ CBS cbs = encoded_client_hello_inner;
+ if (!ssl_parse_client_hello_with_trailing_data(ssl, &cbs,
+ &client_hello_inner)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ // The remaining data is padding.
+ uint8_t padding;
+ while (CBS_get_u8(&cbs, &padding)) {
+ if (padding != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return false;
+ }
+ }
+
+ // TLS 1.3 ClientHellos must have extensions, and EncodedClientHelloInners use
+ // ClientHelloOuter's session_id.
+ if (client_hello_inner.extensions_len == 0 ||
+ client_hello_inner.session_id_len != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ client_hello_inner.session_id = client_hello_outer->session_id;
+ client_hello_inner.session_id_len = client_hello_outer->session_id_len;
+
+ // Begin serializing a message containing the ClientHelloInner in |cbb|.
+ ScopedCBB cbb;
+ CBB body, extensions_cbb;
+ if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CLIENT_HELLO) ||
+ !ssl_client_hello_write_without_extensions(&client_hello_inner, &body) ||
+ !CBB_add_u16_length_prefixed(&body, &extensions_cbb)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ auto inner_extensions = MakeConstSpan(client_hello_inner.extensions,
+ client_hello_inner.extensions_len);
+ CBS ext_list_wrapper;
+ if (!ssl_client_hello_get_extension(&client_hello_inner, &ext_list_wrapper,
+ TLSEXT_TYPE_ech_outer_extensions)) {
+ // No ech_outer_extensions. Copy everything.
+ if (!CBB_add_bytes(&extensions_cbb, inner_extensions.data(),
+ inner_extensions.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+ } else {
+ const size_t offset = CBS_data(&ext_list_wrapper) - inner_extensions.data();
+ auto inner_extensions_before =
+ inner_extensions.subspan(0, offset - 4 /* extension header */);
+ auto inner_extensions_after =
+ inner_extensions.subspan(offset + CBS_len(&ext_list_wrapper));
+ if (!CBB_add_bytes(&extensions_cbb, inner_extensions_before.data(),
+ inner_extensions_before.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ // Expand ech_outer_extensions. See draft-ietf-tls-esni-13, Appendix B.
+ CBS ext_list;
+ if (!CBS_get_u8_length_prefixed(&ext_list_wrapper, &ext_list) ||
+ CBS_len(&ext_list) == 0 || CBS_len(&ext_list_wrapper) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ CBS outer_extensions;
+ CBS_init(&outer_extensions, client_hello_outer->extensions,
+ client_hello_outer->extensions_len);
+ while (CBS_len(&ext_list) != 0) {
+ // Find the next extension to copy.
+ uint16_t want;
+ if (!CBS_get_u16(&ext_list, &want)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ // Seek to |want| in |outer_extensions|. |ext_list| is required to match
+ // ClientHelloOuter in order.
+ uint16_t found;
+ CBS ext_body;
+ do {
+ if (CBS_len(&outer_extensions) == 0) {
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OUTER_EXTENSION_NOT_FOUND);
+ return false;
+ }
+ if (!CBS_get_u16(&outer_extensions, &found) ||
+ !CBS_get_u16_length_prefixed(&outer_extensions, &ext_body)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ } while (found != want);
+ // Copy the extension.
+ if (!CBB_add_u16(&extensions_cbb, found) ||
+ !CBB_add_u16(&extensions_cbb, CBS_len(&ext_body)) ||
+ !CBB_add_bytes(&extensions_cbb, CBS_data(&ext_body),
+ CBS_len(&ext_body))) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ }
+
+ if (!CBB_add_bytes(&extensions_cbb, inner_extensions_after.data(),
+ inner_extensions_after.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+ }
+ if (!CBB_flush(&body)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ if (!is_valid_client_hello_inner(
+ ssl, out_alert, MakeConstSpan(CBB_data(&body), CBB_len(&body)))) {
+ return false;
+ }
+
+ if (!ssl->method->finish_message(ssl, cbb.get(), out_client_hello_inner)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+ return true;
+}
+
+bool ssl_client_hello_decrypt(EVP_HPKE_CTX *hpke_ctx, Array<uint8_t> *out,
+ bool *out_is_decrypt_error,
+ const SSL_CLIENT_HELLO *client_hello_outer,
+ Span<const uint8_t> payload) {
+ *out_is_decrypt_error = false;
+
+ // The ClientHelloOuterAAD is |client_hello_outer| with |payload| (which must
+ // point within |client_hello_outer->extensions|) replaced with zeros. See
+ // draft-ietf-tls-esni-13, section 5.2.
+ Array<uint8_t> aad;
+ if (!aad.CopyFrom(MakeConstSpan(client_hello_outer->client_hello,
+ client_hello_outer->client_hello_len))) {
+ return false;
+ }
+
+ // We assert with |uintptr_t| because the comparison would be UB if they
+ // didn't alias.
+ assert(reinterpret_cast<uintptr_t>(client_hello_outer->extensions) <=
+ reinterpret_cast<uintptr_t>(payload.data()));
+ assert(reinterpret_cast<uintptr_t>(client_hello_outer->extensions +
+ client_hello_outer->extensions_len) >=
+ reinterpret_cast<uintptr_t>(payload.data() + payload.size()));
+ Span<uint8_t> payload_aad = MakeSpan(aad).subspan(
+ payload.data() - client_hello_outer->client_hello, payload.size());
+ OPENSSL_memset(payload_aad.data(), 0, payload_aad.size());
+
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ // In fuzzer mode, disable encryption to improve coverage. We reserve a short
+ // input to signal decryption failure, so the fuzzer can explore fallback to
+ // ClientHelloOuter.
+ const uint8_t kBadPayload[] = {0xff};
+ if (payload == kBadPayload) {
+ *out_is_decrypt_error = true;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
+ return false;
+ }
+ if (!out->CopyFrom(payload)) {
+ return false;
+ }
+#else
+ // Attempt to decrypt into |out|.
+ if (!out->Init(payload.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return false;
+ }
+ size_t len;
+ if (!EVP_HPKE_CTX_open(hpke_ctx, out->data(), &len, out->size(),
+ payload.data(), payload.size(), aad.data(),
+ aad.size())) {
+ *out_is_decrypt_error = true;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
+ return false;
+ }
+ out->Shrink(len);
+#endif
+ return true;
+}
+
+static bool parse_ipv4_number(Span<const uint8_t> in, uint32_t *out) {
+ // See https://url.spec.whatwg.org/#ipv4-number-parser.
+ uint32_t base = 10;
+ if (in.size() >= 2 && in[0] == '0' && (in[1] == 'x' || in[1] == 'X')) {
+ in = in.subspan(2);
+ base = 16;
+ } else if (in.size() >= 1 && in[0] == '0') {
+ in = in.subspan(1);
+ base = 8;
+ }
+ *out = 0;
+ for (uint8_t c : in) {
+ uint32_t d;
+ if ('0' <= c && c <= '9') {
+ d = c - '0';
+ } else if ('a' <= c && c <= 'f') {
+ d = c - 'a' + 10;
+ } else if ('A' <= c && c <= 'F') {
+ d = c - 'A' + 10;
+ } else {
+ return false;
+ }
+ if (d >= base ||
+ *out > UINT32_MAX / base) {
+ return false;
+ }
+ *out *= base;
+ if (*out > UINT32_MAX - d) {
+ return false;
+ }
+ *out += d;
+ }
+ return true;
+}
+
+static bool is_ipv4_address(Span<const uint8_t> in) {
+ // See https://url.spec.whatwg.org/#concept-ipv4-parser
+ //
+ // TODO(https://crbug.com/boringssl/275): Revise this, and maybe the spec, per
+ // https://groups.google.com/a/chromium.org/g/blink-dev/c/7QN5nxjwIfM/m/q9dw9MxoAwAJ
+ uint32_t numbers[4];
+ size_t num_numbers = 0;
+ while (!in.empty()) {
+ if (num_numbers == 4) {
+ // Too many components.
+ return false;
+ }
+ // Find the next dot-separated component.
+ auto dot = std::find(in.begin(), in.end(), '.');
+ if (dot == in.begin()) {
+ // Empty components are not allowed.
+ return false;
+ }
+ Span<const uint8_t> component;
+ if (dot == in.end()) {
+ component = in;
+ in = Span<const uint8_t>();
+ } else {
+ component = in.subspan(0, dot - in.begin());
+ in = in.subspan(dot - in.begin() + 1); // Skip the dot.
+ }
+ if (!parse_ipv4_number(component, &numbers[num_numbers])) {
+ return false;
+ }
+ num_numbers++;
+ }
+ if (num_numbers == 0) {
+ return false;
+ }
+ for (size_t i = 0; i < num_numbers - 1; i++) {
+ if (numbers[i] > 255) {
+ return false;
+ }
+ }
+ return num_numbers == 1 ||
+ numbers[num_numbers - 1] < 1u << (8 * (5 - num_numbers));
+}
+
+bool ssl_is_valid_ech_public_name(Span<const uint8_t> public_name) {
+ // See draft-ietf-tls-esni-13, Section 4 and RFC 5890, Section 2.3.1. The
+ // public name must be a dot-separated sequence of LDH labels and not begin or
+ // end with a dot.
+ auto copy = public_name;
+ if (copy.empty()) {
+ return false;
+ }
+ while (!copy.empty()) {
+ // Find the next dot-separated component.
+ auto dot = std::find(copy.begin(), copy.end(), '.');
+ Span<const uint8_t> component;
+ if (dot == copy.end()) {
+ component = copy;
+ copy = Span<const uint8_t>();
+ } else {
+ component = copy.subspan(0, dot - copy.begin());
+ copy = copy.subspan(dot - copy.begin() + 1); // Skip the dot.
+ if (copy.empty()) {
+ // Trailing dots are not allowed.
+ return false;
+ }
+ }
+ // |component| must be a valid LDH label. Checking for empty components also
+ // rejects leading dots.
+ if (component.empty() || component.size() > 63 ||
+ component.front() == '-' || component.back() == '-') {
+ return false;
+ }
+ for (uint8_t c : component) {
+ if (!('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z') &&
+ !('0' <= c && c <= '9') && c != '-') {
+ return false;
+ }
+ }
+ }
+
+ return !is_ipv4_address(public_name);
+}
+
+static bool parse_ech_config(CBS *cbs, ECHConfig *out, bool *out_supported,
+ bool all_extensions_mandatory) {
+ uint16_t version;
+ CBS orig = *cbs;
+ CBS contents;
+ if (!CBS_get_u16(cbs, &version) ||
+ !CBS_get_u16_length_prefixed(cbs, &contents)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+
+ if (version != kECHConfigVersion) {
+ *out_supported = false;
+ return true;
+ }
+
+ // Make a copy of the ECHConfig and parse from it, so the results alias into
+ // the saved copy.
+ if (!out->raw.CopyFrom(
+ MakeConstSpan(CBS_data(&orig), CBS_len(&orig) - CBS_len(cbs)))) {
+ return false;
+ }
+
+ CBS ech_config(out->raw);
+ CBS public_name, public_key, cipher_suites, extensions;
+ if (!CBS_skip(&ech_config, 2) || // version
+ !CBS_get_u16_length_prefixed(&ech_config, &contents) ||
+ !CBS_get_u8(&contents, &out->config_id) ||
+ !CBS_get_u16(&contents, &out->kem_id) ||
+ !CBS_get_u16_length_prefixed(&contents, &public_key) ||
+ CBS_len(&public_key) == 0 ||
+ !CBS_get_u16_length_prefixed(&contents, &cipher_suites) ||
+ CBS_len(&cipher_suites) == 0 || CBS_len(&cipher_suites) % 4 != 0 ||
+ !CBS_get_u8(&contents, &out->maximum_name_length) ||
+ !CBS_get_u8_length_prefixed(&contents, &public_name) ||
+ CBS_len(&public_name) == 0 ||
+ !CBS_get_u16_length_prefixed(&contents, &extensions) ||
+ CBS_len(&contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+
+ if (!ssl_is_valid_ech_public_name(public_name)) {
+ // TODO(https://crbug.com/boringssl/275): The draft says ECHConfigs with
+ // invalid public names should be ignored, but LDH syntax failures are
+ // unambiguously invalid.
+ *out_supported = false;
+ return true;
+ }
+
+ out->public_key = public_key;
+ out->public_name = public_name;
+ // This function does not ensure |out->kem_id| and |out->cipher_suites| use
+ // supported algorithms. The caller must do this.
+ out->cipher_suites = cipher_suites;
+
+ bool has_unknown_mandatory_extension = false;
+ while (CBS_len(&extensions) != 0) {
+ uint16_t type;
+ CBS body;
+ if (!CBS_get_u16(&extensions, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions, &body)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ // We currently do not support any extensions.
+ if (type & 0x8000 || all_extensions_mandatory) {
+ // Extension numbers with the high bit set are mandatory. Continue parsing
+ // to enforce syntax, but we will ultimately ignore this ECHConfig as a
+ // client and reject it as a server.
+ has_unknown_mandatory_extension = true;
+ }
+ }
+
+ *out_supported = !has_unknown_mandatory_extension;
+ return true;
+}
+
+bool ECHServerConfig::Init(Span<const uint8_t> ech_config,
+ const EVP_HPKE_KEY *key, bool is_retry_config) {
+ is_retry_config_ = is_retry_config;
+
+ // Parse the ECHConfig, rejecting all unsupported parameters and extensions.
+ // Unlike most server options, ECH's server configuration is serialized and
+ // configured in both the server and DNS. If the caller configures an
+ // unsupported parameter, this is a deployment error. To catch these errors,
+ // we fail early.
+ CBS cbs = ech_config;
+ bool supported;
+ if (!parse_ech_config(&cbs, &ech_config_, &supported,
+ /*all_extensions_mandatory=*/true)) {
+ return false;
+ }
+ if (CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ if (!supported) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ECH_SERVER_CONFIG);
+ return false;
+ }
+
+ CBS cipher_suites = ech_config_.cipher_suites;
+ while (CBS_len(&cipher_suites) > 0) {
+ uint16_t kdf_id, aead_id;
+ if (!CBS_get_u16(&cipher_suites, &kdf_id) ||
+ !CBS_get_u16(&cipher_suites, &aead_id)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ // The server promises to support every option in the ECHConfig, so reject
+ // any unsupported cipher suites.
+ if (kdf_id != EVP_HPKE_HKDF_SHA256 || get_ech_aead(aead_id) == nullptr) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ECH_SERVER_CONFIG);
+ return false;
+ }
+ }
+
+ // Check the public key in the ECHConfig matches |key|.
+ uint8_t expected_public_key[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH];
+ size_t expected_public_key_len;
+ if (!EVP_HPKE_KEY_public_key(key, expected_public_key,
+ &expected_public_key_len,
+ sizeof(expected_public_key))) {
+ return false;
+ }
+ if (ech_config_.kem_id != EVP_HPKE_KEM_id(EVP_HPKE_KEY_kem(key)) ||
+ MakeConstSpan(expected_public_key, expected_public_key_len) !=
+ ech_config_.public_key) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ECH_SERVER_CONFIG_AND_PRIVATE_KEY_MISMATCH);
+ return false;
+ }
+
+ if (!EVP_HPKE_KEY_copy(key_.get(), key)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ECHServerConfig::SetupContext(EVP_HPKE_CTX *ctx, uint16_t kdf_id,
+ uint16_t aead_id,
+ Span<const uint8_t> enc) const {
+ // Check the cipher suite is supported by this ECHServerConfig.
+ CBS cbs(ech_config_.cipher_suites);
+ bool cipher_ok = false;
+ while (CBS_len(&cbs) != 0) {
+ uint16_t supported_kdf_id, supported_aead_id;
+ if (!CBS_get_u16(&cbs, &supported_kdf_id) ||
+ !CBS_get_u16(&cbs, &supported_aead_id)) {
+ return false;
+ }
+ if (kdf_id == supported_kdf_id && aead_id == supported_aead_id) {
+ cipher_ok = true;
+ break;
+ }
+ }
+ if (!cipher_ok) {
+ return false;
+ }
+
+ static const uint8_t kInfoLabel[] = "tls ech";
+ ScopedCBB info_cbb;
+ if (!CBB_init(info_cbb.get(), sizeof(kInfoLabel) + ech_config_.raw.size()) ||
+ !CBB_add_bytes(info_cbb.get(), kInfoLabel,
+ sizeof(kInfoLabel) /* includes trailing NUL */) ||
+ !CBB_add_bytes(info_cbb.get(), ech_config_.raw.data(),
+ ech_config_.raw.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return false;
+ }
+
+ assert(kdf_id == EVP_HPKE_HKDF_SHA256);
+ assert(get_ech_aead(aead_id) != NULL);
+ return EVP_HPKE_CTX_setup_recipient(
+ ctx, key_.get(), EVP_hpke_hkdf_sha256(), get_ech_aead(aead_id), enc.data(),
+ enc.size(), CBB_data(info_cbb.get()), CBB_len(info_cbb.get()));
+}
+
+bool ssl_is_valid_ech_config_list(Span<const uint8_t> ech_config_list) {
+ CBS cbs = ech_config_list, child;
+ if (!CBS_get_u16_length_prefixed(&cbs, &child) || //
+ CBS_len(&child) == 0 || //
+ CBS_len(&cbs) > 0) {
+ return false;
+ }
+ while (CBS_len(&child) > 0) {
+ ECHConfig ech_config;
+ bool supported;
+ if (!parse_ech_config(&child, &ech_config, &supported,
+ /*all_extensions_mandatory=*/false)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool select_ech_cipher_suite(const EVP_HPKE_KDF **out_kdf,
+ const EVP_HPKE_AEAD **out_aead,
+ Span<const uint8_t> cipher_suites) {
+ const bool has_aes_hardware = EVP_has_aes_hardware();
+ const EVP_HPKE_AEAD *aead = nullptr;
+ CBS cbs = cipher_suites;
+ while (CBS_len(&cbs) != 0) {
+ uint16_t kdf_id, aead_id;
+ if (!CBS_get_u16(&cbs, &kdf_id) || //
+ !CBS_get_u16(&cbs, &aead_id)) {
+ return false;
+ }
+ // Pick the first common cipher suite, but prefer ChaCha20-Poly1305 if we
+ // don't have AES hardware.
+ const EVP_HPKE_AEAD *candidate = get_ech_aead(aead_id);
+ if (kdf_id != EVP_HPKE_HKDF_SHA256 || candidate == nullptr) {
+ continue;
+ }
+ if (aead == nullptr ||
+ (!has_aes_hardware && aead_id == EVP_HPKE_CHACHA20_POLY1305)) {
+ aead = candidate;
+ }
+ }
+ if (aead == nullptr) {
+ return false;
+ }
+
+ *out_kdf = EVP_hpke_hkdf_sha256();
+ *out_aead = aead;
+ return true;
+}
+
+bool ssl_select_ech_config(SSL_HANDSHAKE *hs, Span<uint8_t> out_enc,
+ size_t *out_enc_len) {
+ *out_enc_len = 0;
+ if (hs->max_version < TLS1_3_VERSION) {
+ // ECH requires TLS 1.3.
+ return true;
+ }
+
+ if (!hs->config->client_ech_config_list.empty()) {
+ CBS cbs = MakeConstSpan(hs->config->client_ech_config_list);
+ CBS child;
+ if (!CBS_get_u16_length_prefixed(&cbs, &child) || //
+ CBS_len(&child) == 0 || //
+ CBS_len(&cbs) > 0) {
+ return false;
+ }
+ // Look for the first ECHConfig with supported parameters.
+ while (CBS_len(&child) > 0) {
+ ECHConfig ech_config;
+ bool supported;
+ if (!parse_ech_config(&child, &ech_config, &supported,
+ /*all_extensions_mandatory=*/false)) {
+ return false;
+ }
+ const EVP_HPKE_KEM *kem = EVP_hpke_x25519_hkdf_sha256();
+ const EVP_HPKE_KDF *kdf;
+ const EVP_HPKE_AEAD *aead;
+ if (supported && //
+ ech_config.kem_id == EVP_HPKE_DHKEM_X25519_HKDF_SHA256 &&
+ select_ech_cipher_suite(&kdf, &aead, ech_config.cipher_suites)) {
+ ScopedCBB info;
+ static const uint8_t kInfoLabel[] = "tls ech"; // includes trailing NUL
+ if (!CBB_init(info.get(), sizeof(kInfoLabel) + ech_config.raw.size()) ||
+ !CBB_add_bytes(info.get(), kInfoLabel, sizeof(kInfoLabel)) ||
+ !CBB_add_bytes(info.get(), ech_config.raw.data(),
+ ech_config.raw.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return false;
+ }
+
+ if (!EVP_HPKE_CTX_setup_sender(
+ hs->ech_hpke_ctx.get(), out_enc.data(), out_enc_len,
+ out_enc.size(), kem, kdf, aead, ech_config.public_key.data(),
+ ech_config.public_key.size(), CBB_data(info.get()),
+ CBB_len(info.get())) ||
+ !hs->inner_transcript.Init()) {
+ return false;
+ }
+
+ hs->selected_ech_config = MakeUnique<ECHConfig>(std::move(ech_config));
+ return hs->selected_ech_config != nullptr;
+ }
+ }
+ }
+
+ return true;
+}
+
+static size_t aead_overhead(const EVP_HPKE_AEAD *aead) {
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ // TODO(https://crbug.com/boringssl/275): Having to adjust the overhead
+ // everywhere is tedious. Change fuzzer mode to append a fake tag but still
+ // otherwise be cleartext, refresh corpora, and then inline this function.
+ return 0;
+#else
+ return EVP_AEAD_max_overhead(EVP_HPKE_AEAD_aead(aead));
+#endif
+}
+
+// random_size returns a random value between |min| and |max|, inclusive.
+static size_t random_size(size_t min, size_t max) {
+ assert(min < max);
+ size_t value;
+ RAND_bytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
+ return value % (max - min + 1) + min;
+}
+
+static bool setup_ech_grease(SSL_HANDSHAKE *hs) {
+ assert(!hs->selected_ech_config);
+ if (hs->max_version < TLS1_3_VERSION || !hs->config->ech_grease_enabled) {
+ return true;
+ }
+
+ const uint16_t kdf_id = EVP_HPKE_HKDF_SHA256;
+ const EVP_HPKE_AEAD *aead = EVP_has_aes_hardware()
+ ? EVP_hpke_aes_128_gcm()
+ : EVP_hpke_chacha20_poly1305();
+ static_assert(ssl_grease_ech_config_id < sizeof(hs->grease_seed),
+ "hs->grease_seed is too small");
+ uint8_t config_id = hs->grease_seed[ssl_grease_ech_config_id];
+
+ uint8_t enc[X25519_PUBLIC_VALUE_LEN];
+ uint8_t private_key_unused[X25519_PRIVATE_KEY_LEN];
+ X25519_keypair(enc, private_key_unused);
+
+ // To determine a plausible length for the payload, we estimate the size of a
+ // typical EncodedClientHelloInner without resumption:
+ //
+ // 2+32+1+2 version, random, legacy_session_id, legacy_compression_methods
+ // 2+4*2 cipher_suites (three TLS 1.3 ciphers, GREASE)
+ // 2 extensions prefix
+ // 5 inner encrypted_client_hello
+ // 4+1+2*2 supported_versions (TLS 1.3, GREASE)
+ // 4+1+10*2 outer_extensions (key_share, sigalgs, sct, alpn,
+ // supported_groups, status_request, psk_key_exchange_modes,
+ // compress_certificate, GREASE x2)
+ //
+ // The server_name extension has an overhead of 9 bytes. For now, arbitrarily
+ // estimate maximum_name_length to be between 32 and 100 bytes. Then round up
+ // to a multiple of 32, to match draft-ietf-tls-esni-13, section 6.1.3.
+ const size_t payload_len =
+ 32 * random_size(128 / 32, 224 / 32) + aead_overhead(aead);
+ bssl::ScopedCBB cbb;
+ CBB enc_cbb, payload_cbb;
+ uint8_t *payload;
+ if (!CBB_init(cbb.get(), 256) ||
+ !CBB_add_u16(cbb.get(), kdf_id) ||
+ !CBB_add_u16(cbb.get(), EVP_HPKE_AEAD_id(aead)) ||
+ !CBB_add_u8(cbb.get(), config_id) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &enc_cbb) ||
+ !CBB_add_bytes(&enc_cbb, enc, sizeof(enc)) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &payload_cbb) ||
+ !CBB_add_space(&payload_cbb, &payload, payload_len) ||
+ !RAND_bytes(payload, payload_len) ||
+ !CBBFinishArray(cbb.get(), &hs->ech_client_outer)) {
+ return false;
+ }
+ return true;
+}
+
+bool ssl_encrypt_client_hello(SSL_HANDSHAKE *hs, Span<const uint8_t> enc) {
+ SSL *const ssl = hs->ssl;
+ if (!hs->selected_ech_config) {
+ return setup_ech_grease(hs);
+ }
+
+ // Construct ClientHelloInner and EncodedClientHelloInner. See
+ // draft-ietf-tls-esni-13, sections 5.1 and 6.1.
+ ScopedCBB cbb, encoded_cbb;
+ CBB body;
+ bool needs_psk_binder;
+ Array<uint8_t> hello_inner;
+ if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CLIENT_HELLO) ||
+ !CBB_init(encoded_cbb.get(), 256) ||
+ !ssl_write_client_hello_without_extensions(hs, &body,
+ ssl_client_hello_inner,
+ /*empty_session_id=*/false) ||
+ !ssl_write_client_hello_without_extensions(hs, encoded_cbb.get(),
+ ssl_client_hello_inner,
+ /*empty_session_id=*/true) ||
+ !ssl_add_clienthello_tlsext(hs, &body, encoded_cbb.get(),
+ &needs_psk_binder, ssl_client_hello_inner,
+ CBB_len(&body)) ||
+ !ssl->method->finish_message(ssl, cbb.get(), &hello_inner)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ if (needs_psk_binder) {
+ size_t binder_len;
+ if (!tls13_write_psk_binder(hs, hs->inner_transcript, MakeSpan(hello_inner),
+ &binder_len)) {
+ return false;
+ }
+ // Also update the EncodedClientHelloInner.
+ auto encoded_binder =
+ MakeSpan(const_cast<uint8_t *>(CBB_data(encoded_cbb.get())),
+ CBB_len(encoded_cbb.get()))
+ .last(binder_len);
+ auto hello_inner_binder = MakeConstSpan(hello_inner).last(binder_len);
+ OPENSSL_memcpy(encoded_binder.data(), hello_inner_binder.data(),
+ binder_len);
+ }
+
+ if (!hs->inner_transcript.Update(hello_inner)) {
+ return false;
+ }
+
+ // Pad the EncodedClientHelloInner. See draft-ietf-tls-esni-13, section 6.1.3.
+ size_t padding_len = 0;
+ size_t maximum_name_length = hs->selected_ech_config->maximum_name_length;
+ if (ssl->hostname) {
+ size_t hostname_len = strlen(ssl->hostname.get());
+ if (hostname_len <= maximum_name_length) {
+ padding_len = maximum_name_length - hostname_len;
+ }
+ } else {
+ // No SNI. Pad up to |maximum_name_length|, including server_name extension
+ // overhead.
+ padding_len = 9 + maximum_name_length;
+ }
+ // Pad the whole thing to a multiple of 32 bytes.
+ padding_len += 31 - ((CBB_len(encoded_cbb.get()) + padding_len - 1) % 32);
+ Array<uint8_t> encoded;
+ if (!CBB_add_zeros(encoded_cbb.get(), padding_len) ||
+ !CBBFinishArray(encoded_cbb.get(), &encoded)) {
+ return false;
+ }
+
+ // Encrypt |encoded|. See draft-ietf-tls-esni-13, section 6.1.1. First,
+ // assemble the extension with a placeholder value for ClientHelloOuterAAD.
+ // See draft-ietf-tls-esni-13, section 5.2.
+ const EVP_HPKE_KDF *kdf = EVP_HPKE_CTX_kdf(hs->ech_hpke_ctx.get());
+ const EVP_HPKE_AEAD *aead = EVP_HPKE_CTX_aead(hs->ech_hpke_ctx.get());
+ size_t payload_len = encoded.size() + aead_overhead(aead);
+ CBB enc_cbb, payload_cbb;
+ if (!CBB_init(cbb.get(), 256) ||
+ !CBB_add_u16(cbb.get(), EVP_HPKE_KDF_id(kdf)) ||
+ !CBB_add_u16(cbb.get(), EVP_HPKE_AEAD_id(aead)) ||
+ !CBB_add_u8(cbb.get(), hs->selected_ech_config->config_id) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &enc_cbb) ||
+ !CBB_add_bytes(&enc_cbb, enc.data(), enc.size()) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &payload_cbb) ||
+ !CBB_add_zeros(&payload_cbb, payload_len) ||
+ !CBBFinishArray(cbb.get(), &hs->ech_client_outer)) {
+ return false;
+ }
+
+ // Construct ClientHelloOuterAAD.
+ // TODO(https://crbug.com/boringssl/275): This ends up constructing the
+ // ClientHelloOuter twice. Instead, reuse |aad| for the ClientHello, now that
+ // draft-12 made the length prefixes match.
+ bssl::ScopedCBB aad;
+ if (!CBB_init(aad.get(), 256) ||
+ !ssl_write_client_hello_without_extensions(hs, aad.get(),
+ ssl_client_hello_outer,
+ /*empty_session_id=*/false) ||
+ !ssl_add_clienthello_tlsext(hs, aad.get(), /*out_encoded=*/nullptr,
+ &needs_psk_binder, ssl_client_hello_outer,
+ CBB_len(aad.get()))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ // ClientHelloOuter may not require a PSK binder. Otherwise, we have a
+ // circular dependency.
+ assert(!needs_psk_binder);
+
+ // Replace the payload in |hs->ech_client_outer| with the encrypted value.
+ auto payload_span = MakeSpan(hs->ech_client_outer).last(payload_len);
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ // In fuzzer mode, the server expects a cleartext payload.
+ assert(payload_span.size() == encoded.size());
+ OPENSSL_memcpy(payload_span.data(), encoded.data(), encoded.size());
+#else
+ if (!EVP_HPKE_CTX_seal(hs->ech_hpke_ctx.get(), payload_span.data(),
+ &payload_len, payload_span.size(), encoded.data(),
+ encoded.size(), CBB_data(aad.get()),
+ CBB_len(aad.get())) ||
+ payload_len != payload_span.size()) {
+ return false;
+ }
+#endif // BORINGSSL_UNSAFE_FUZZER_MODE
+
+ return true;
+}
+
+BSSL_NAMESPACE_END
+
+using namespace bssl;
+
+void SSL_set_enable_ech_grease(SSL *ssl, int enable) {
+ if (!ssl->config) {
+ return;
+ }
+ ssl->config->ech_grease_enabled = !!enable;
+}
+
+int SSL_set1_ech_config_list(SSL *ssl, const uint8_t *ech_config_list,
+ size_t ech_config_list_len) {
+ if (!ssl->config) {
+ return 0;
+ }
+
+ auto span = MakeConstSpan(ech_config_list, ech_config_list_len);
+ if (!ssl_is_valid_ech_config_list(span)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ECH_CONFIG_LIST);
+ return 0;
+ }
+ return ssl->config->client_ech_config_list.CopyFrom(span);
+}
+
+void SSL_get0_ech_name_override(const SSL *ssl, const char **out_name,
+ size_t *out_name_len) {
+ // When ECH is rejected, we use the public name. Note that, if
+ // |SSL_CTX_set_reverify_on_resume| is enabled, we reverify the certificate
+ // before the 0-RTT point. If also offering ECH, we verify as if
+ // ClientHelloInner was accepted and do not override. This works because, at
+ // this point, |ech_status| will be |ssl_ech_none|. See the
+ // ECH-Client-Reject-EarlyDataReject-OverrideNameOnRetry tests in runner.go.
+ const SSL_HANDSHAKE *hs = ssl->s3->hs.get();
+ if (!ssl->server && hs && ssl->s3->ech_status == ssl_ech_rejected) {
+ *out_name = reinterpret_cast<const char *>(
+ hs->selected_ech_config->public_name.data());
+ *out_name_len = hs->selected_ech_config->public_name.size();
+ } else {
+ *out_name = nullptr;
+ *out_name_len = 0;
+ }
+}
+
+void SSL_get0_ech_retry_configs(
+ const SSL *ssl, const uint8_t **out_retry_configs,
+ size_t *out_retry_configs_len) {
+ const SSL_HANDSHAKE *hs = ssl->s3->hs.get();
+ if (!hs || !hs->ech_authenticated_reject) {
+ // It is an error to call this function except in response to
+ // |SSL_R_ECH_REJECTED|. Returning an empty string risks the caller
+ // mistakenly believing the server has disabled ECH. Instead, return a
+ // non-empty ECHConfigList with a syntax error, so the subsequent
+ // |SSL_set1_ech_config_list| call will fail.
+ assert(0);
+ static const uint8_t kPlaceholder[] = {
+ kECHConfigVersion >> 8, kECHConfigVersion & 0xff, 0xff, 0xff, 0xff};
+ *out_retry_configs = kPlaceholder;
+ *out_retry_configs_len = sizeof(kPlaceholder);
+ return;
+ }
+
+ *out_retry_configs = hs->ech_retry_configs.data();
+ *out_retry_configs_len = hs->ech_retry_configs.size();
+}
+
+int SSL_marshal_ech_config(uint8_t **out, size_t *out_len, uint8_t config_id,
+ const EVP_HPKE_KEY *key, const char *public_name,
+ size_t max_name_len) {
+ Span<const uint8_t> public_name_u8 = MakeConstSpan(
+ reinterpret_cast<const uint8_t *>(public_name), strlen(public_name));
+ if (!ssl_is_valid_ech_public_name(public_name_u8)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ECH_PUBLIC_NAME);
+ return 0;
+ }
+
+ // The maximum name length is encoded in one byte.
+ if (max_name_len > 0xff) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_LENGTH);
+ return 0;
+ }
+
+ // See draft-ietf-tls-esni-13, section 4.
+ ScopedCBB cbb;
+ CBB contents, child;
+ uint8_t *public_key;
+ size_t public_key_len;
+ if (!CBB_init(cbb.get(), 128) || //
+ !CBB_add_u16(cbb.get(), kECHConfigVersion) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &contents) ||
+ !CBB_add_u8(&contents, config_id) ||
+ !CBB_add_u16(&contents, EVP_HPKE_KEM_id(EVP_HPKE_KEY_kem(key))) ||
+ !CBB_add_u16_length_prefixed(&contents, &child) ||
+ !CBB_reserve(&child, &public_key, EVP_HPKE_MAX_PUBLIC_KEY_LENGTH) ||
+ !EVP_HPKE_KEY_public_key(key, public_key, &public_key_len,
+ EVP_HPKE_MAX_PUBLIC_KEY_LENGTH) ||
+ !CBB_did_write(&child, public_key_len) ||
+ !CBB_add_u16_length_prefixed(&contents, &child) ||
+ // Write a default cipher suite configuration.
+ !CBB_add_u16(&child, EVP_HPKE_HKDF_SHA256) ||
+ !CBB_add_u16(&child, EVP_HPKE_AES_128_GCM) ||
+ !CBB_add_u16(&child, EVP_HPKE_HKDF_SHA256) ||
+ !CBB_add_u16(&child, EVP_HPKE_CHACHA20_POLY1305) ||
+ !CBB_add_u8(&contents, max_name_len) ||
+ !CBB_add_u8_length_prefixed(&contents, &child) ||
+ !CBB_add_bytes(&child, public_name_u8.data(), public_name_u8.size()) ||
+ // TODO(https://crbug.com/boringssl/275): Reserve some GREASE extensions
+ // and include some.
+ !CBB_add_u16(&contents, 0 /* no extensions */) ||
+ !CBB_finish(cbb.get(), out, out_len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ return 1;
+}
+
+SSL_ECH_KEYS *SSL_ECH_KEYS_new() { return New<SSL_ECH_KEYS>(); }
+
+void SSL_ECH_KEYS_up_ref(SSL_ECH_KEYS *keys) {
+ CRYPTO_refcount_inc(&keys->references);
+}
+
+void SSL_ECH_KEYS_free(SSL_ECH_KEYS *keys) {
+ if (keys == nullptr ||
+ !CRYPTO_refcount_dec_and_test_zero(&keys->references)) {
+ return;
+ }
+
+ keys->~ssl_ech_keys_st();
+ OPENSSL_free(keys);
+}
+
+int SSL_ECH_KEYS_add(SSL_ECH_KEYS *configs, int is_retry_config,
+ const uint8_t *ech_config, size_t ech_config_len,
+ const EVP_HPKE_KEY *key) {
+ UniquePtr<ECHServerConfig> parsed_config = MakeUnique<ECHServerConfig>();
+ if (!parsed_config) {
+ return 0;
+ }
+ if (!parsed_config->Init(MakeConstSpan(ech_config, ech_config_len), key,
+ !!is_retry_config)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return 0;
+ }
+ if (!configs->configs.Push(std::move(parsed_config))) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+}
+
+int SSL_ECH_KEYS_has_duplicate_config_id(const SSL_ECH_KEYS *keys) {
+ bool seen[256] = {false};
+ for (const auto &config : keys->configs) {
+ if (seen[config->ech_config().config_id]) {
+ return 1;
+ }
+ seen[config->ech_config().config_id] = true;
+ }
+ return 0;
+}
+
+int SSL_ECH_KEYS_marshal_retry_configs(const SSL_ECH_KEYS *keys, uint8_t **out,
+ size_t *out_len) {
+ ScopedCBB cbb;
+ CBB child;
+ if (!CBB_init(cbb.get(), 128) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &child)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return false;
+ }
+ for (const auto &config : keys->configs) {
+ if (config->is_retry_config() &&
+ !CBB_add_bytes(&child, config->ech_config().raw.data(),
+ config->ech_config().raw.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return false;
+ }
+ }
+ return CBB_finish(cbb.get(), out, out_len);
+}
+
+int SSL_CTX_set1_ech_keys(SSL_CTX *ctx, SSL_ECH_KEYS *keys) {
+ bool has_retry_config = false;
+ for (const auto &config : keys->configs) {
+ if (config->is_retry_config()) {
+ has_retry_config = true;
+ break;
+ }
+ }
+ if (!has_retry_config) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ECH_SERVER_WOULD_HAVE_NO_RETRY_CONFIGS);
+ return 0;
+ }
+ UniquePtr<SSL_ECH_KEYS> owned_keys = UpRef(keys);
+ MutexWriteLock lock(&ctx->lock);
+ ctx->ech_keys.swap(owned_keys);
+ return 1;
+}
+
+int SSL_ech_accepted(const SSL *ssl) {
+ if (SSL_in_early_data(ssl) && !ssl->server) {
+ // In the client early data state, we report properties as if the server
+ // accepted early data. The server can only accept early data with
+ // ClientHelloInner.
+ return ssl->s3->hs->selected_ech_config != nullptr;
+ }
+
+ return ssl->s3->ech_status == ssl_ech_accepted;
+}
diff --git a/deps/boringssl/src/ssl/t1_lib.cc b/deps/boringssl/src/ssl/extensions.cc
index 342c170..ba55c93 100644
--- a/deps/boringssl/src/ssl/t1_lib.cc
+++ b/deps/boringssl/src/ssl/extensions.cc
@@ -124,11 +124,11 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include <openssl/hpke.h>
#include <openssl/mem.h>
#include <openssl/nid.h>
#include <openssl/rand.h>
-#include "../crypto/hpke/internal.h"
#include "../crypto/internal.h"
#include "internal.h"
@@ -209,17 +209,25 @@ static bool is_post_quantum_group(uint16_t id) {
}
bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out,
- const SSLMessage &msg) {
+ Span<const uint8_t> body) {
+ CBS cbs = body;
+ if (!ssl_parse_client_hello_with_trailing_data(ssl, &cbs, out) ||
+ CBS_len(&cbs) != 0) {
+ return false;
+ }
+ return true;
+}
+
+bool ssl_parse_client_hello_with_trailing_data(const SSL *ssl, CBS *cbs,
+ SSL_CLIENT_HELLO *out) {
OPENSSL_memset(out, 0, sizeof(*out));
out->ssl = const_cast<SSL *>(ssl);
- out->client_hello = CBS_data(&msg.body);
- out->client_hello_len = CBS_len(&msg.body);
-
- CBS client_hello, random, session_id;
- CBS_init(&client_hello, out->client_hello, out->client_hello_len);
- if (!CBS_get_u16(&client_hello, &out->version) ||
- !CBS_get_bytes(&client_hello, &random, SSL3_RANDOM_SIZE) ||
- !CBS_get_u8_length_prefixed(&client_hello, &session_id) ||
+
+ CBS copy = *cbs;
+ CBS random, session_id;
+ if (!CBS_get_u16(cbs, &out->version) ||
+ !CBS_get_bytes(cbs, &random, SSL3_RANDOM_SIZE) ||
+ !CBS_get_u8_length_prefixed(cbs, &session_id) ||
CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) {
return false;
}
@@ -232,16 +240,16 @@ bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out,
// Skip past DTLS cookie
if (SSL_is_dtls(out->ssl)) {
CBS cookie;
- if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) ||
+ if (!CBS_get_u8_length_prefixed(cbs, &cookie) ||
CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) {
return false;
}
}
CBS cipher_suites, compression_methods;
- if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) ||
+ if (!CBS_get_u16_length_prefixed(cbs, &cipher_suites) ||
CBS_len(&cipher_suites) < 2 || (CBS_len(&cipher_suites) & 1) != 0 ||
- !CBS_get_u8_length_prefixed(&client_hello, &compression_methods) ||
+ !CBS_get_u8_length_prefixed(cbs, &compression_methods) ||
CBS_len(&compression_methods) < 1) {
return false;
}
@@ -253,23 +261,22 @@ bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out,
// If the ClientHello ends here then it's valid, but doesn't have any
// extensions.
- if (CBS_len(&client_hello) == 0) {
- out->extensions = NULL;
+ if (CBS_len(cbs) == 0) {
+ out->extensions = nullptr;
out->extensions_len = 0;
- return true;
- }
-
- // Extract extensions and check it is valid.
- CBS extensions;
- if (!CBS_get_u16_length_prefixed(&client_hello, &extensions) ||
- !tls1_check_duplicate_extensions(&extensions) ||
- CBS_len(&client_hello) != 0) {
- return false;
+ } else {
+ // Extract extensions and check it is valid.
+ CBS extensions;
+ if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
+ !tls1_check_duplicate_extensions(&extensions)) {
+ return false;
+ }
+ out->extensions = CBS_data(&extensions);
+ out->extensions_len = CBS_len(&extensions);
}
- out->extensions = CBS_data(&extensions);
- out->extensions_len = CBS_len(&extensions);
-
+ out->client_hello = CBS_data(&copy);
+ out->client_hello_len = CBS_len(&copy) - CBS_len(cbs);
return true;
}
@@ -405,6 +412,11 @@ bool tls1_check_group_id(const SSL_HANDSHAKE *hs, uint16_t group_id) {
return false;
}
+ // We internally assume zero is never allocated as a group ID.
+ if (group_id == 0) {
+ return false;
+ }
+
for (uint16_t supported : tls1_get_grouplist(hs)) {
if (supported == group_id) {
return true;
@@ -488,9 +500,7 @@ bool tls12_check_peer_sigalg(const SSL_HANDSHAKE *hs, uint8_t *out_alert,
return false;
}
-// tls_extension represents a TLS extension that is handled internally. The
-// |init| function is called for each handshake, before any other functions of
-// the extension. Then the add and parse callbacks are called as needed.
+// tls_extension represents a TLS extension that is handled internally.
//
// The parse callbacks receive a |CBS| that contains the contents of the
// extension (i.e. not including the type and length bytes). If an extension is
@@ -500,14 +510,27 @@ bool tls12_check_peer_sigalg(const SSL_HANDSHAKE *hs, uint8_t *out_alert,
// The add callbacks receive a |CBB| to which the extension can be appended but
// the function is responsible for appending the type and length bytes too.
//
+// |add_clienthello| may be called multiple times and must not mutate |hs|. It
+// is additionally passed two output |CBB|s. If the extension is the same
+// independent of the value of |type|, the callback may write to
+// |out_compressible| instead of |out|. When serializing the ClientHelloInner,
+// all compressible extensions will be made continguous and replaced with
+// ech_outer_extensions when encrypted. When serializing the ClientHelloOuter
+// or not offering ECH, |out| will be equal to |out_compressible|, so writing to
+// |out_compressible| still works.
+//
+// Note the |parse_serverhello| and |add_serverhello| callbacks refer to the
+// TLS 1.2 ServerHello. In TLS 1.3, these callbacks act on EncryptedExtensions,
+// with ServerHello extensions handled elsewhere in the handshake.
+//
// All callbacks return true for success and false for error. If a parse
// function returns zero then a fatal alert with value |*out_alert| will be
// sent. If |*out_alert| isn't set, then a |decode_error| alert will be sent.
struct tls_extension {
uint16_t value;
- void (*init)(SSL_HANDSHAKE *hs);
- bool (*add_clienthello)(SSL_HANDSHAKE *hs, CBB *out);
+ bool (*add_clienthello)(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible, ssl_client_hello_type_t type);
bool (*parse_serverhello)(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents);
@@ -542,10 +565,21 @@ static bool dont_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc6066#section-3.
-static bool ext_sni_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
- if (ssl->hostname == nullptr) {
- return true;
+static bool ext_sni_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
+ // If offering ECH, send the public name instead of the configured name.
+ Span<const uint8_t> hostname;
+ if (type == ssl_client_hello_outer) {
+ hostname = hs->selected_ech_config->public_name;
+ } else {
+ if (ssl->hostname == nullptr) {
+ return true;
+ }
+ hostname =
+ MakeConstSpan(reinterpret_cast<const uint8_t *>(ssl->hostname.get()),
+ strlen(ssl->hostname.get()));
}
CBB contents, server_name_list, name;
@@ -554,8 +588,7 @@ static bool ext_sni_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
!CBB_add_u16_length_prefixed(&contents, &server_name_list) ||
!CBB_add_u8(&server_name_list, TLSEXT_NAMETYPE_host_name) ||
!CBB_add_u16_length_prefixed(&server_name_list, &name) ||
- !CBB_add_bytes(&name, (const uint8_t *)ssl->hostname.get(),
- strlen(ssl->hostname.get())) ||
+ !CBB_add_bytes(&name, hostname.data(), hostname.size()) ||
!CBB_flush(out)) {
return false;
}
@@ -591,179 +624,117 @@ static bool ext_sni_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
}
-// Encrypted Client Hello (ECH)
+// Encrypted ClientHello (ECH)
//
-// https://tools.ietf.org/html/draft-ietf-tls-esni-09
-
-// random_size returns a random value between |min| and |max|, inclusive.
-static size_t random_size(size_t min, size_t max) {
- assert(min < max);
- size_t value;
- RAND_bytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
- return value % (max - min + 1) + min;
-}
+// https://tools.ietf.org/html/draft-ietf-tls-esni-13
-static bool ext_ech_add_clienthello_grease(SSL_HANDSHAKE *hs, CBB *out) {
- // If we are responding to the server's HelloRetryRequest, we repeat the bytes
- // of the first ECH GREASE extension.
- if (hs->ssl->s3->used_hello_retry_request) {
- CBB ech_body;
+static bool ext_ech_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ if (type == ssl_client_hello_inner) {
if (!CBB_add_u16(out, TLSEXT_TYPE_encrypted_client_hello) ||
- !CBB_add_u16_length_prefixed(out, &ech_body) ||
- !CBB_add_bytes(&ech_body, hs->ech_grease.data(),
- hs->ech_grease.size()) ||
- !CBB_flush(out)) {
+ !CBB_add_u16(out, /* length */ 1) ||
+ !CBB_add_u8(out, ECH_CLIENT_INNER)) {
return false;
}
return true;
}
- constexpr uint16_t kdf_id = EVP_HPKE_HKDF_SHA256;
- const uint16_t aead_id = EVP_has_aes_hardware()
- ? EVP_HPKE_AEAD_AES_GCM_128
- : EVP_HPKE_AEAD_CHACHA20POLY1305;
- const EVP_AEAD *aead = EVP_HPKE_get_aead(aead_id);
- assert(aead != nullptr);
-
- uint8_t ech_config_id[8];
- RAND_bytes(ech_config_id, sizeof(ech_config_id));
-
- uint8_t ech_enc[X25519_PUBLIC_VALUE_LEN];
- uint8_t private_key_unused[X25519_PRIVATE_KEY_LEN];
- X25519_keypair(ech_enc, private_key_unused);
+ if (hs->ech_client_outer.empty()) {
+ return true;
+ }
- // To determine a plausible length for the payload, we first estimate the size
- // of a typical EncodedClientHelloInner, with an expected use of
- // outer_extensions. To limit the size, we only consider initial ClientHellos
- // that do not offer resumption.
- //
- // Field/Extension Size
- // ---------------------------------------------------------------------
- // version 2
- // random 32
- // legacy_session_id 1
- // - Has a U8 length prefix, but body is
- // always empty string in inner CH.
- // cipher_suites 2 (length prefix)
- // - Only includes TLS 1.3 ciphers (3). 6
- // - Maybe also include a GREASE suite. 2
- // legacy_compression_methods 2 (length prefix)
- // - Always has "null" compression method. 1
- // extensions: 2 (length prefix)
- // - encrypted_client_hello (empty). 4 (id + length prefix)
- // - supported_versions. 4 (id + length prefix)
- // - U8 length prefix 1
- // - U16 protocol version (TLS 1.3) 2
- // - outer_extensions. 4 (id + length prefix)
- // - U8 length prefix 1
- // - N extension IDs (2 bytes each):
- // - key_share 2
- // - sigalgs 2
- // - sct 2
- // - alpn 2
- // - supported_groups. 2
- // - status_request. 2
- // - psk_key_exchange_modes. 2
- // - compress_certificate. 2
- //
- // The server_name extension has an overhead of 9 bytes, plus up to an
- // estimated 100 bytes of hostname. Rounding up to a multiple of 32 yields a
- // range of 96 to 192. Note that this estimate does not fully capture
- // optional extensions like GREASE, but the rounding gives some leeway.
-
- uint8_t payload[EVP_AEAD_MAX_OVERHEAD + 192];
- const size_t payload_len =
- EVP_AEAD_max_overhead(aead) + 32 * random_size(96 / 32, 192 / 32);
- assert(payload_len <= sizeof(payload));
- RAND_bytes(payload, payload_len);
-
- // Inside the TLS extension contents, write a serialized ClientEncryptedCH.
- CBB ech_body, config_id_cbb, enc_cbb, payload_cbb;
+ CBB ech_body;
if (!CBB_add_u16(out, TLSEXT_TYPE_encrypted_client_hello) ||
!CBB_add_u16_length_prefixed(out, &ech_body) ||
- !CBB_add_u16(&ech_body, kdf_id) || //
- !CBB_add_u16(&ech_body, aead_id) ||
- !CBB_add_u8_length_prefixed(&ech_body, &config_id_cbb) ||
- !CBB_add_bytes(&config_id_cbb, ech_config_id, sizeof(ech_config_id)) ||
- !CBB_add_u16_length_prefixed(&ech_body, &enc_cbb) ||
- !CBB_add_bytes(&enc_cbb, ech_enc, OPENSSL_ARRAY_SIZE(ech_enc)) ||
- !CBB_add_u16_length_prefixed(&ech_body, &payload_cbb) ||
- !CBB_add_bytes(&payload_cbb, payload, payload_len) || //
- !CBB_flush(&ech_body)) {
- return false;
- }
- // Save the bytes of the newly-generated extension in case the server sends
- // a HelloRetryRequest.
- if (!hs->ech_grease.CopyFrom(
- MakeConstSpan(CBB_data(&ech_body), CBB_len(&ech_body)))) {
+ !CBB_add_u8(&ech_body, ECH_CLIENT_OUTER) ||
+ !CBB_add_bytes(&ech_body, hs->ech_client_outer.data(),
+ hs->ech_client_outer.size()) ||
+ !CBB_flush(out)) {
return false;
}
- return CBB_flush(out);
-}
-
-static bool ext_ech_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- if (hs->max_version < TLS1_3_VERSION) {
- return true;
- }
- if (hs->config->ech_grease_enabled) {
- return ext_ech_add_clienthello_grease(hs, out);
- }
- // Nothing to do, since we don't yet implement the non-GREASE parts of ECH.
return true;
}
static bool ext_ech_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents) {
+ SSL *const ssl = hs->ssl;
if (contents == NULL) {
return true;
}
- // If the client only sent GREASE, we must check the extension syntactically.
- CBS ech_configs;
- if (!CBS_get_u16_length_prefixed(contents, &ech_configs) ||
- CBS_len(&ech_configs) == 0 || //
- CBS_len(contents) > 0) {
+ // The ECH extension may not be sent in TLS 1.2 ServerHello, only TLS 1.3
+ // EncryptedExtensions. It also may not be sent in response to an inner ECH
+ // extension.
+ if (ssl_protocol_version(ssl) < TLS1_3_VERSION ||
+ ssl->s3->ech_status == ssl_ech_accepted) {
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ return false;
+ }
+
+ if (!ssl_is_valid_ech_config_list(*contents)) {
*out_alert = SSL_AD_DECODE_ERROR;
return false;
}
- while (CBS_len(&ech_configs) > 0) {
- // Do a top-level parse of the ECHConfig, stopping before ECHConfigContents.
- uint16_t version;
- CBS ech_config_contents;
- if (!CBS_get_u16(&ech_configs, &version) ||
- !CBS_get_u16_length_prefixed(&ech_configs, &ech_config_contents)) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return false;
- }
+
+ if (ssl->s3->ech_status == ssl_ech_rejected &&
+ !hs->ech_retry_configs.CopyFrom(*contents)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return false;
}
+
return true;
}
static bool ext_ech_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents) {
- if (contents != nullptr) {
- hs->ech_present = true;
+ if (contents == nullptr) {
return true;
}
- return true;
-}
-static bool ext_ech_is_inner_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+ uint8_t type;
+ if (!CBS_get_u8(contents, &type)) {
+ return false;
+ }
+ if (type == ECH_CLIENT_OUTER) {
+ // Outer ECH extensions are handled outside the callback.
+ return true;
+ }
+ if (type != ECH_CLIENT_INNER || CBS_len(contents) != 0) {
+ return false;
+ }
+
+ hs->ech_is_inner = true;
return true;
}
-static bool ext_ech_is_inner_parse_clienthello(SSL_HANDSHAKE *hs,
- uint8_t *out_alert,
- CBS *contents) {
- if (contents == nullptr) {
+static bool ext_ech_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+ SSL *const ssl = hs->ssl;
+ if (ssl_protocol_version(ssl) < TLS1_3_VERSION ||
+ ssl->s3->ech_status == ssl_ech_accepted || //
+ hs->ech_keys == nullptr) {
return true;
}
- if (CBS_len(contents) > 0) {
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+
+ // Write the list of retry configs to |out|. Note |SSL_CTX_set1_ech_keys|
+ // ensures |ech_keys| contains at least one retry config.
+ CBB body, retry_configs;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_encrypted_client_hello) ||
+ !CBB_add_u16_length_prefixed(out, &body) ||
+ !CBB_add_u16_length_prefixed(&body, &retry_configs)) {
return false;
}
- hs->ech_is_inner_present = true;
- return true;
+ for (const auto &config : hs->ech_keys->configs) {
+ if (!config->is_retry_config()) {
+ continue;
+ }
+ if (!CBB_add_bytes(&retry_configs, config->ech_config().raw.data(),
+ config->ech_config().raw.size())) {
+ return false;
+ }
+ }
+ return CBB_flush(out);
}
@@ -771,10 +742,13 @@ static bool ext_ech_is_inner_parse_clienthello(SSL_HANDSHAKE *hs,
//
// https://tools.ietf.org/html/rfc5746
-static bool ext_ri_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
+static bool ext_ri_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
// Renegotiation indication is not necessary in TLS 1.3.
- if (hs->min_version >= TLS1_3_VERSION) {
+ if (hs->min_version >= TLS1_3_VERSION ||
+ type == ssl_client_hello_inner) {
return true;
}
@@ -936,9 +910,11 @@ static bool ext_ri_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc7627
-static bool ext_ems_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+static bool ext_ems_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
// Extended master secret is not necessary in TLS 1.3.
- if (hs->min_version >= TLS1_3_VERSION) {
+ if (hs->min_version >= TLS1_3_VERSION || type == ssl_client_hello_inner) {
return true;
}
@@ -1011,10 +987,12 @@ static bool ext_ems_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc5077
-static bool ext_ticket_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
+static bool ext_ticket_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
// TLS 1.3 uses a different ticket extension.
- if (hs->min_version >= TLS1_3_VERSION ||
+ if (hs->min_version >= TLS1_3_VERSION || type == ssl_client_hello_inner ||
SSL_get_options(ssl) & SSL_OP_NO_TICKET) {
return true;
}
@@ -1089,17 +1067,19 @@ static bool ext_ticket_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
-static bool ext_sigalgs_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+static bool ext_sigalgs_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
if (hs->max_version < TLS1_2_VERSION) {
return true;
}
CBB contents, sigalgs_cbb;
- if (!CBB_add_u16(out, TLSEXT_TYPE_signature_algorithms) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_signature_algorithms) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
!CBB_add_u16_length_prefixed(&contents, &sigalgs_cbb) ||
!tls12_add_verify_sigalgs(hs, &sigalgs_cbb) ||
- !CBB_flush(out)) {
+ !CBB_flush(out_compressible)) {
return false;
}
@@ -1128,18 +1108,20 @@ static bool ext_sigalgs_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
//
// https://tools.ietf.org/html/rfc6066#section-8
-static bool ext_ocsp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+static bool ext_ocsp_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
if (!hs->config->ocsp_stapling_enabled) {
return true;
}
CBB contents;
- if (!CBB_add_u16(out, TLSEXT_TYPE_status_request) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_status_request) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
!CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) ||
!CBB_add_u16(&contents, 0 /* empty responder ID list */) ||
!CBB_add_u16(&contents, 0 /* empty request extensions */) ||
- !CBB_flush(out)) {
+ !CBB_flush(out_compressible)) {
return false;
}
@@ -1210,11 +1192,16 @@ static bool ext_ocsp_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://htmlpreview.github.io/?https://github.com/agl/technotes/blob/master/nextprotoneg.html
-static bool ext_npn_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
- if (ssl->s3->initial_handshake_complete ||
- ssl->ctx->next_proto_select_cb == NULL ||
- SSL_is_dtls(ssl)) {
+static bool ext_npn_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
+ if (ssl->ctx->next_proto_select_cb == NULL ||
+ // Do not allow NPN to change on renegotiation.
+ ssl->s3->initial_handshake_complete ||
+ // NPN is not defined in DTLS or TLS 1.3.
+ SSL_is_dtls(ssl) || hs->min_version >= TLS1_3_VERSION ||
+ type == ssl_client_hello_inner) {
return true;
}
@@ -1333,13 +1320,15 @@ static bool ext_npn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc6962#section-3.3.1
-static bool ext_sct_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+static bool ext_sct_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
if (!hs->config->signed_cert_timestamps_enabled) {
return true;
}
- if (!CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) ||
- !CBB_add_u16(out, 0 /* length */)) {
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_certificate_timestamp) ||
+ !CBB_add_u16(out_compressible, 0 /* length */)) {
return false;
}
@@ -1424,11 +1413,13 @@ static bool ext_sct_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc7301
-static bool ext_alpn_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
+static bool ext_alpn_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
if (hs->config->alpn_client_proto_list.empty() && ssl->quic_method) {
// ALPN MUST be used with QUIC.
- OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_ALPN);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_APPLICATION_PROTOCOL);
return false;
}
@@ -1438,12 +1429,13 @@ static bool ext_alpn_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
}
CBB contents, proto_list;
- if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
+ if (!CBB_add_u16(out_compressible,
+ TLSEXT_TYPE_application_layer_protocol_negotiation) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
!CBB_add_u16_length_prefixed(&contents, &proto_list) ||
!CBB_add_bytes(&proto_list, hs->config->alpn_client_proto_list.data(),
hs->config->alpn_client_proto_list.size()) ||
- !CBB_flush(out)) {
+ !CBB_flush(out_compressible)) {
return false;
}
@@ -1456,7 +1448,7 @@ static bool ext_alpn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
if (contents == NULL) {
if (ssl->quic_method) {
// ALPN is required when QUIC is used.
- OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_ALPN);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_APPLICATION_PROTOCOL);
*out_alert = SSL_AD_NO_APPLICATION_PROTOCOL;
return false;
}
@@ -1499,6 +1491,22 @@ static bool ext_alpn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
return true;
}
+bool ssl_is_valid_alpn_list(Span<const uint8_t> in) {
+ CBS protocol_name_list = in;
+ if (CBS_len(&protocol_name_list) == 0) {
+ return false;
+ }
+ while (CBS_len(&protocol_name_list) > 0) {
+ CBS protocol_name;
+ if (!CBS_get_u8_length_prefixed(&protocol_name_list, &protocol_name) ||
+ // Empty protocol names are forbidden.
+ CBS_len(&protocol_name) == 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool ssl_is_alpn_protocol_allowed(const SSL_HANDSHAKE *hs,
Span<const uint8_t> protocol) {
if (hs->config->alpn_client_proto_list.empty()) {
@@ -1537,7 +1545,7 @@ bool ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert,
TLSEXT_TYPE_application_layer_protocol_negotiation)) {
if (ssl->quic_method) {
// ALPN is required when QUIC is used.
- OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_ALPN);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_APPLICATION_PROTOCOL);
*out_alert = SSL_AD_NO_APPLICATION_PROTOCOL;
return false;
}
@@ -1551,46 +1559,47 @@ bool ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS protocol_name_list;
if (!CBS_get_u16_length_prefixed(&contents, &protocol_name_list) ||
CBS_len(&contents) != 0 ||
- CBS_len(&protocol_name_list) < 2) {
+ !ssl_is_valid_alpn_list(protocol_name_list)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
*out_alert = SSL_AD_DECODE_ERROR;
return false;
}
- // Validate the protocol list.
- CBS protocol_name_list_copy = protocol_name_list;
- while (CBS_len(&protocol_name_list_copy) > 0) {
- CBS protocol_name;
- if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) ||
- // Empty protocol names are forbidden.
- CBS_len(&protocol_name) == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
- *out_alert = SSL_AD_DECODE_ERROR;
- return false;
- }
- }
-
const uint8_t *selected;
uint8_t selected_len;
- if (ssl->ctx->alpn_select_cb(
- ssl, &selected, &selected_len, CBS_data(&protocol_name_list),
- CBS_len(&protocol_name_list),
- ssl->ctx->alpn_select_cb_arg) == SSL_TLSEXT_ERR_OK) {
- if (selected_len == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL);
- *out_alert = SSL_AD_INTERNAL_ERROR;
+ int ret = ssl->ctx->alpn_select_cb(
+ ssl, &selected, &selected_len, CBS_data(&protocol_name_list),
+ CBS_len(&protocol_name_list), ssl->ctx->alpn_select_cb_arg);
+ // ALPN is required when QUIC is used.
+ if (ssl->quic_method &&
+ (ret == SSL_TLSEXT_ERR_NOACK || ret == SSL_TLSEXT_ERR_ALERT_WARNING)) {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ switch (ret) {
+ case SSL_TLSEXT_ERR_OK:
+ if (selected_len == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL);
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return false;
+ }
+ if (!ssl->s3->alpn_selected.CopyFrom(
+ MakeConstSpan(selected, selected_len))) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return false;
+ }
+ break;
+ case SSL_TLSEXT_ERR_NOACK:
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ break;
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ *out_alert = SSL_AD_NO_APPLICATION_PROTOCOL;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_APPLICATION_PROTOCOL);
return false;
- }
- if (!ssl->s3->alpn_selected.CopyFrom(
- MakeConstSpan(selected, selected_len))) {
+ default:
+ // Invalid return value.
*out_alert = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
- }
- } else if (ssl->quic_method) {
- // ALPN is required when QUIC is used.
- OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_ALPN);
- *out_alert = SSL_AD_NO_APPLICATION_PROTOCOL;
- return false;
}
return true;
@@ -1621,13 +1630,20 @@ static bool ext_alpn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/draft-balfanz-tls-channelid-01
-static void ext_channel_id_init(SSL_HANDSHAKE *hs) {
- hs->ssl->s3->channel_id_valid = false;
-}
-
-static bool ext_channel_id_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
- if (!hs->config->channel_id_enabled || SSL_is_dtls(ssl)) {
+static bool ext_channel_id_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
+ if (!hs->config->channel_id_private || SSL_is_dtls(ssl) ||
+ // Don't offer Channel ID in ClientHelloOuter. ClientHelloOuter handshakes
+ // are not authenticated for the name that can learn the Channel ID.
+ //
+ // We could alternatively offer the extension but sign with a random key.
+ // For other extensions, we try to align |ssl_client_hello_outer| and
+ // |ssl_client_hello_unencrypted|, to improve the effectiveness of ECH
+ // GREASE. However, Channel ID is deprecated and unlikely to be used with
+ // ECH, so do the simplest thing.
+ type == ssl_client_hello_outer) {
return true;
}
@@ -1642,19 +1658,18 @@ static bool ext_channel_id_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
static bool ext_channel_id_parse_serverhello(SSL_HANDSHAKE *hs,
uint8_t *out_alert,
CBS *contents) {
- SSL *const ssl = hs->ssl;
if (contents == NULL) {
return true;
}
- assert(!SSL_is_dtls(ssl));
- assert(hs->config->channel_id_enabled);
+ assert(!SSL_is_dtls(hs->ssl));
+ assert(hs->config->channel_id_private);
if (CBS_len(contents) != 0) {
return false;
}
- ssl->s3->channel_id_valid = true;
+ hs->channel_id_negotiated = true;
return true;
}
@@ -1670,13 +1685,12 @@ static bool ext_channel_id_parse_clienthello(SSL_HANDSHAKE *hs,
return false;
}
- ssl->s3->channel_id_valid = true;
+ hs->channel_id_negotiated = true;
return true;
}
static bool ext_channel_id_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
- if (!ssl->s3->channel_id_valid) {
+ if (!hs->channel_id_negotiated) {
return true;
}
@@ -1693,22 +1707,21 @@ static bool ext_channel_id_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc5764
-
-static void ext_srtp_init(SSL_HANDSHAKE *hs) {
- hs->ssl->s3->srtp_profile = NULL;
-}
-
-static bool ext_srtp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
- STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl);
+static bool ext_srtp_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
+ const STACK_OF(SRTP_PROTECTION_PROFILE) *profiles =
+ SSL_get_srtp_profiles(ssl);
if (profiles == NULL ||
- sk_SRTP_PROTECTION_PROFILE_num(profiles) == 0) {
+ sk_SRTP_PROTECTION_PROFILE_num(profiles) == 0 ||
+ !SSL_is_dtls(ssl)) {
return true;
}
CBB contents, profile_ids;
- if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_srtp) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
!CBB_add_u16_length_prefixed(&contents, &profile_ids)) {
return false;
}
@@ -1720,7 +1733,7 @@ static bool ext_srtp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
}
if (!CBB_add_u8(&contents, 0 /* empty use_mki value */) ||
- !CBB_flush(out)) {
+ !CBB_flush(out_compressible)) {
return false;
}
@@ -1738,6 +1751,7 @@ static bool ext_srtp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
// single uint16_t profile ID, then followed by a u8-prefixed srtp_mki field.
//
// See https://tools.ietf.org/html/rfc5764#section-4.1.1
+ assert(SSL_is_dtls(ssl));
CBS profile_ids, srtp_mki;
uint16_t profile_id;
if (!CBS_get_u16_length_prefixed(contents, &profile_ids) ||
@@ -1756,11 +1770,8 @@ static bool ext_srtp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
return false;
}
- STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl);
-
- // Check to see if the server gave us something we support (and presumably
- // offered).
- for (const SRTP_PROTECTION_PROFILE *profile : profiles) {
+ // Check to see if the server gave us something we support and offered.
+ for (const SRTP_PROTECTION_PROFILE *profile : SSL_get_srtp_profiles(ssl)) {
if (profile->id == profile_id) {
ssl->s3->srtp_profile = profile;
return true;
@@ -1775,7 +1786,8 @@ static bool ext_srtp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
static bool ext_srtp_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents) {
SSL *const ssl = hs->ssl;
- if (contents == NULL) {
+ // DTLS-SRTP is only defined for DTLS.
+ if (contents == NULL || !SSL_is_dtls(ssl)) {
return true;
}
@@ -1819,6 +1831,7 @@ static bool ext_srtp_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
return true;
}
+ assert(SSL_is_dtls(ssl));
CBB contents, profile_ids;
if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) ||
!CBB_add_u16_length_prefixed(out, &contents) ||
@@ -1837,7 +1850,7 @@ static bool ext_srtp_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc4492#section-5.1.2
-static bool ext_ec_point_add_extension(SSL_HANDSHAKE *hs, CBB *out) {
+static bool ext_ec_point_add_extension(const SSL_HANDSHAKE *hs, CBB *out) {
CBB contents, formats;
if (!CBB_add_u16(out, TLSEXT_TYPE_ec_point_formats) ||
!CBB_add_u16_length_prefixed(out, &contents) ||
@@ -1850,9 +1863,11 @@ static bool ext_ec_point_add_extension(SSL_HANDSHAKE *hs, CBB *out) {
return true;
}
-static bool ext_ec_point_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+static bool ext_ec_point_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
// The point format extension is unnecessary in TLS 1.3.
- if (hs->min_version >= TLS1_3_VERSION) {
+ if (hs->min_version >= TLS1_3_VERSION || type == ssl_client_hello_inner) {
return true;
}
@@ -1918,10 +1933,34 @@ static bool ext_ec_point_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc8446#section-4.2.11
-static size_t ext_pre_shared_key_clienthello_length(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
+static bool should_offer_psk(const SSL_HANDSHAKE *hs,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
if (hs->max_version < TLS1_3_VERSION || ssl->session == nullptr ||
- ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION) {
+ ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION ||
+ // TODO(https://crbug.com/boringssl/275): Should we synthesize a
+ // placeholder PSK, at least when we offer early data? Otherwise
+ // ClientHelloOuter will contain an early_data extension without a
+ // pre_shared_key extension and potentially break the recovery flow.
+ type == ssl_client_hello_outer) {
+ return false;
+ }
+
+ // Per RFC 8446 section 4.1.4, skip offering the session if the selected
+ // cipher in HelloRetryRequest does not match. This avoids performing the
+ // transcript hash transformation for multiple hashes.
+ if (ssl->s3->used_hello_retry_request &&
+ ssl->session->cipher->algorithm_prf != hs->new_cipher->algorithm_prf) {
+ return false;
+ }
+
+ return true;
+}
+
+static size_t ext_pre_shared_key_clienthello_length(
+ const SSL_HANDSHAKE *hs, ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
+ if (!should_offer_psk(hs, type)) {
return 0;
}
@@ -1929,19 +1968,12 @@ static size_t ext_pre_shared_key_clienthello_length(SSL_HANDSHAKE *hs) {
return 15 + ssl->session->ticket.size() + binder_len;
}
-static bool ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
- hs->needs_psk_binder = false;
- if (hs->max_version < TLS1_3_VERSION || ssl->session == nullptr ||
- ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION) {
- return true;
- }
-
- // Per RFC 8446 section 4.1.4, skip offering the session if the selected
- // cipher in HelloRetryRequest does not match. This avoids performing the
- // transcript hash transformation for multiple hashes.
- if (ssl->s3 && ssl->s3->used_hello_retry_request &&
- ssl->session->cipher->algorithm_prf != hs->new_cipher->algorithm_prf) {
+static bool ext_pre_shared_key_add_clienthello(const SSL_HANDSHAKE *hs,
+ CBB *out, bool *out_needs_binder,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
+ *out_needs_binder = false;
+ if (!should_offer_psk(hs, type)) {
return true;
}
@@ -1952,7 +1984,6 @@ static bool ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
// Fill in a placeholder zero binder of the appropriate length. It will be
// computed and filled in later after length prefixes are computed.
- uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0};
size_t binder_len = EVP_MD_size(ssl_session_get_digest(ssl->session.get()));
CBB contents, identity, ticket, binders, binder;
@@ -1965,11 +1996,11 @@ static bool ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
!CBB_add_u32(&identity, obfuscated_ticket_age) ||
!CBB_add_u16_length_prefixed(&contents, &binders) ||
!CBB_add_u8_length_prefixed(&binders, &binder) ||
- !CBB_add_bytes(&binder, zero_binder, binder_len)) {
+ !CBB_add_zeros(&binder, binder_len)) {
return false;
}
- hs->needs_psk_binder = true;
+ *out_needs_binder = true;
return CBB_flush(out);
}
@@ -2082,21 +2113,22 @@ bool ssl_ext_pre_shared_key_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc8446#section-4.2.9
-static bool ext_psk_key_exchange_modes_add_clienthello(SSL_HANDSHAKE *hs,
- CBB *out) {
+static bool ext_psk_key_exchange_modes_add_clienthello(
+ const SSL_HANDSHAKE *hs, CBB *out, CBB *out_compressible,
+ ssl_client_hello_type_t type) {
if (hs->max_version < TLS1_3_VERSION) {
return true;
}
CBB contents, ke_modes;
- if (!CBB_add_u16(out, TLSEXT_TYPE_psk_key_exchange_modes) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_psk_key_exchange_modes) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
!CBB_add_u8_length_prefixed(&contents, &ke_modes) ||
!CBB_add_u8(&ke_modes, SSL_PSK_DHE_KE)) {
return false;
}
- return CBB_flush(out);
+ return CBB_flush(out_compressible);
}
static bool ext_psk_key_exchange_modes_parse_clienthello(SSL_HANDSHAKE *hs,
@@ -2126,23 +2158,10 @@ static bool ext_psk_key_exchange_modes_parse_clienthello(SSL_HANDSHAKE *hs,
//
// https://tools.ietf.org/html/rfc8446#section-4.2.10
-// ssl_get_local_application_settings looks up the configured ALPS value for
-// |protocol|. If found, it sets |*out_settings| to the value and returns true.
-// Otherwise, it returns false.
-static bool ssl_get_local_application_settings(
- const SSL_HANDSHAKE *hs, Span<const uint8_t> *out_settings,
- Span<const uint8_t> protocol) {
- for (const ALPSConfig &config : hs->config->alps_configs) {
- if (protocol == config.protocol) {
- *out_settings = config.settings;
- return true;
- }
- }
- return false;
-}
-
-static bool ext_early_data_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
+static bool ext_early_data_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
// The second ClientHello never offers early data, and we must have already
// filled in |early_data_reason| by this point.
if (ssl->s3->used_hello_retry_request) {
@@ -2150,56 +2169,20 @@ static bool ext_early_data_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
return true;
}
- if (!ssl->enable_early_data) {
- ssl->s3->early_data_reason = ssl_early_data_disabled;
- return true;
- }
-
- if (hs->max_version < TLS1_3_VERSION) {
- // We discard inapplicable sessions, so this is redundant with the session
- // checks below, but we check give a more useful reason.
- ssl->s3->early_data_reason = ssl_early_data_protocol_version;
- return true;
- }
-
- if (ssl->session == nullptr) {
- ssl->s3->early_data_reason = ssl_early_data_no_session_offered;
- return true;
- }
-
- if (ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION ||
- ssl->session->ticket_max_early_data == 0) {
- ssl->s3->early_data_reason = ssl_early_data_unsupported_for_session;
+ if (!hs->early_data_offered) {
return true;
}
- if (!ssl->session->early_alpn.empty()) {
- if (!ssl_is_alpn_protocol_allowed(hs, ssl->session->early_alpn)) {
- // Avoid reporting a confusing value in |SSL_get0_alpn_selected|.
- ssl->s3->early_data_reason = ssl_early_data_alpn_mismatch;
- return true;
- }
-
- // If the previous connection negotiated ALPS, only offer 0-RTT when the
- // local are settings are consistent with what we'd offer for this
- // connection.
- if (ssl->session->has_application_settings) {
- Span<const uint8_t> settings;
- if (!ssl_get_local_application_settings(hs, &settings,
- ssl->session->early_alpn) ||
- settings != ssl->session->local_application_settings) {
- ssl->s3->early_data_reason = ssl_early_data_alps_mismatch;
- return true;
- }
- }
- }
-
- // |early_data_reason| will be filled in later when the server responds.
- hs->early_data_offered = true;
-
- if (!CBB_add_u16(out, TLSEXT_TYPE_early_data) ||
- !CBB_add_u16(out, 0) ||
- !CBB_flush(out)) {
+ // If offering ECH, the extension only applies to ClientHelloInner, but we
+ // send the extension in both ClientHellos. This ensures that, if the server
+ // handshakes with ClientHelloOuter, it can skip past early data. See
+ // https://github.com/tlswg/draft-ietf-tls-esni/pull/415
+ //
+ // TODO(https://crbug.com/boringssl/275): Replace this with a reference to the
+ // right section in the next draft.
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_early_data) ||
+ !CBB_add_u16(out_compressible, 0) ||
+ !CBB_flush(out_compressible)) {
return false;
}
@@ -2280,43 +2263,33 @@ static bool ext_early_data_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/rfc8446#section-4.2.8
-static bool ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+bool ssl_setup_key_shares(SSL_HANDSHAKE *hs, uint16_t override_group_id) {
SSL *const ssl = hs->ssl;
+ hs->key_shares[0].reset();
+ hs->key_shares[1].reset();
+ hs->key_share_bytes.Reset();
+
if (hs->max_version < TLS1_3_VERSION) {
return true;
}
- CBB contents, kse_bytes;
- if (!CBB_add_u16(out, TLSEXT_TYPE_key_share) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
- !CBB_add_u16_length_prefixed(&contents, &kse_bytes)) {
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 64)) {
return false;
}
- uint16_t group_id = hs->retry_group;
- uint16_t second_group_id = 0;
- if (ssl->s3 && ssl->s3->used_hello_retry_request) {
- // We received a HelloRetryRequest without a new curve, so there is no new
- // share to append. Leave |hs->key_share| as-is.
- if (group_id == 0 &&
- !CBB_add_bytes(&kse_bytes, hs->key_share_bytes.data(),
- hs->key_share_bytes.size())) {
- return false;
- }
- hs->key_share_bytes.Reset();
- if (group_id == 0) {
- return CBB_flush(out);
- }
- } else {
- // Add a fake group. See draft-davidben-tls-grease-01.
- if (ssl->ctx->grease_enabled &&
- (!CBB_add_u16(&kse_bytes,
- ssl_get_grease_value(hs, ssl_grease_group)) ||
- !CBB_add_u16(&kse_bytes, 1 /* length */) ||
- !CBB_add_u8(&kse_bytes, 0 /* one byte key share */))) {
+ if (override_group_id == 0 && ssl->ctx->grease_enabled) {
+ // Add a fake group. See RFC 8701.
+ if (!CBB_add_u16(cbb.get(), ssl_get_grease_value(hs, ssl_grease_group)) ||
+ !CBB_add_u16(cbb.get(), 1 /* length */) ||
+ !CBB_add_u8(cbb.get(), 0 /* one byte key share */)) {
return false;
}
+ }
+ uint16_t group_id = override_group_id;
+ uint16_t second_group_id = 0;
+ if (override_group_id == 0) {
// Predict the most preferred group.
Span<const uint16_t> groups = tls1_get_grouplist(hs);
if (groups.empty()) {
@@ -2336,34 +2309,45 @@ static bool ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
CBB key_exchange;
hs->key_shares[0] = SSLKeyShare::Create(group_id);
- if (!hs->key_shares[0] ||
- !CBB_add_u16(&kse_bytes, group_id) ||
- !CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) ||
- !hs->key_shares[0]->Offer(&key_exchange) ||
- !CBB_flush(&kse_bytes)) {
+ if (!hs->key_shares[0] || //
+ !CBB_add_u16(cbb.get(), group_id) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &key_exchange) ||
+ !hs->key_shares[0]->Offer(&key_exchange)) {
return false;
}
if (second_group_id != 0) {
hs->key_shares[1] = SSLKeyShare::Create(second_group_id);
- if (!hs->key_shares[1] ||
- !CBB_add_u16(&kse_bytes, second_group_id) ||
- !CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) ||
- !hs->key_shares[1]->Offer(&key_exchange) ||
- !CBB_flush(&kse_bytes)) {
+ if (!hs->key_shares[1] || //
+ !CBB_add_u16(cbb.get(), second_group_id) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &key_exchange) ||
+ !hs->key_shares[1]->Offer(&key_exchange)) {
return false;
}
}
- // Save the contents of the extension to repeat it in the second
- // ClientHello.
- if (ssl->s3 && !ssl->s3->used_hello_retry_request &&
- !hs->key_share_bytes.CopyFrom(
- MakeConstSpan(CBB_data(&kse_bytes), CBB_len(&kse_bytes)))) {
+ return CBBFinishArray(cbb.get(), &hs->key_share_bytes);
+}
+
+static bool ext_key_share_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ if (hs->max_version < TLS1_3_VERSION) {
+ return true;
+ }
+
+ assert(!hs->key_share_bytes.empty());
+ CBB contents, kse_bytes;
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_key_share) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &kse_bytes) ||
+ !CBB_add_bytes(&kse_bytes, hs->key_share_bytes.data(),
+ hs->key_share_bytes.size()) ||
+ !CBB_flush(out_compressible)) {
return false;
}
- return CBB_flush(out);
+ return true;
}
bool ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs,
@@ -2401,25 +2385,29 @@ bool ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs,
}
bool ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, bool *out_found,
- Array<uint8_t> *out_secret,
- uint8_t *out_alert, CBS *contents) {
- uint16_t group_id;
- CBS key_shares;
- if (!tls1_get_shared_group(hs, &group_id)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_GROUP);
- *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+ Span<const uint8_t> *out_peer_key,
+ uint8_t *out_alert,
+ const SSL_CLIENT_HELLO *client_hello) {
+ // We only support connections that include an ECDHE key exchange.
+ CBS contents;
+ if (!ssl_client_hello_get_extension(client_hello, &contents,
+ TLSEXT_TYPE_key_share)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
+ *out_alert = SSL_AD_MISSING_EXTENSION;
return false;
}
- if (!CBS_get_u16_length_prefixed(contents, &key_shares) ||
- CBS_len(contents) != 0) {
+ CBS key_shares;
+ if (!CBS_get_u16_length_prefixed(&contents, &key_shares) ||
+ CBS_len(&contents) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return false;
}
// Find the corresponding key share.
+ const uint16_t group_id = hs->new_session->group_id;
CBS peer_key;
- CBS_init(&peer_key, NULL, 0);
+ CBS_init(&peer_key, nullptr, 0);
while (CBS_len(&key_shares) > 0) {
uint16_t id;
CBS peer_key_tmp;
@@ -2442,47 +2430,24 @@ bool ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, bool *out_found,
}
}
- if (CBS_len(&peer_key) == 0) {
- *out_found = false;
- out_secret->Reset();
- return true;
+ if (out_peer_key != nullptr) {
+ *out_peer_key = peer_key;
}
-
- // Compute the DH secret.
- Array<uint8_t> secret;
- ScopedCBB public_key;
- UniquePtr<SSLKeyShare> key_share = SSLKeyShare::Create(group_id);
- if (!key_share ||
- !CBB_init(public_key.get(), 32) ||
- !key_share->Accept(public_key.get(), &secret, out_alert, peer_key) ||
- !CBBFinishArray(public_key.get(), &hs->ecdh_public_key)) {
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return false;
- }
-
- *out_secret = std::move(secret);
- *out_found = true;
+ *out_found = CBS_len(&peer_key) != 0;
return true;
}
-bool ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out,
- bool dry_run) {
- uint16_t group_id;
+bool ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
CBB kse_bytes, public_key;
- if (!tls1_get_shared_group(hs, &group_id) ||
- !CBB_add_u16(out, TLSEXT_TYPE_key_share) ||
+ if (!CBB_add_u16(out, TLSEXT_TYPE_key_share) ||
!CBB_add_u16_length_prefixed(out, &kse_bytes) ||
- !CBB_add_u16(&kse_bytes, group_id) ||
+ !CBB_add_u16(&kse_bytes, hs->new_session->group_id) ||
!CBB_add_u16_length_prefixed(&kse_bytes, &public_key) ||
!CBB_add_bytes(&public_key, hs->ecdh_public_key.data(),
hs->ecdh_public_key.size()) ||
!CBB_flush(out)) {
return false;
}
- if (!dry_run) {
- hs->ecdh_public_key.Reset();
- hs->new_session->group_id = group_id;
- }
return true;
}
@@ -2491,12 +2456,20 @@ bool ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out,
//
// https://tools.ietf.org/html/rfc8446#section-4.2.1
-static bool ext_supported_versions_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
+static bool ext_supported_versions_add_clienthello(
+ const SSL_HANDSHAKE *hs, CBB *out, CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
if (hs->max_version <= TLS1_2_VERSION) {
return true;
}
+ // supported_versions is compressible in ECH if ClientHelloOuter already
+ // requires TLS 1.3. Otherwise the extensions differ in the older versions.
+ if (hs->min_version >= TLS1_3_VERSION) {
+ out = out_compressible;
+ }
+
CBB contents, versions;
if (!CBB_add_u16(out, TLSEXT_TYPE_supported_versions) ||
!CBB_add_u16_length_prefixed(out, &contents) ||
@@ -2504,13 +2477,16 @@ static bool ext_supported_versions_add_clienthello(SSL_HANDSHAKE *hs, CBB *out)
return false;
}
- // Add a fake version. See draft-davidben-tls-grease-01.
+ // Add a fake version. See RFC 8701.
if (ssl->ctx->grease_enabled &&
!CBB_add_u16(&versions, ssl_get_grease_value(hs, ssl_grease_version))) {
return false;
}
- if (!ssl_add_supported_versions(hs, &versions) ||
+ // Encrypted ClientHellos requires TLS 1.3 or later.
+ uint16_t extra_min_version =
+ type == ssl_client_hello_inner ? TLS1_3_VERSION : 0;
+ if (!ssl_add_supported_versions(hs, &versions, extra_min_version) ||
!CBB_flush(out)) {
return false;
}
@@ -2523,22 +2499,22 @@ static bool ext_supported_versions_add_clienthello(SSL_HANDSHAKE *hs, CBB *out)
//
// https://tools.ietf.org/html/rfc8446#section-4.2.2
-static bool ext_cookie_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+static bool ext_cookie_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
if (hs->cookie.empty()) {
return true;
}
CBB contents, cookie;
- if (!CBB_add_u16(out, TLSEXT_TYPE_cookie) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_cookie) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
!CBB_add_u16_length_prefixed(&contents, &cookie) ||
!CBB_add_bytes(&cookie, hs->cookie.data(), hs->cookie.size()) ||
- !CBB_flush(out)) {
+ !CBB_flush(out_compressible)) {
return false;
}
- // The cookie is no longer needed in memory.
- hs->cookie.Reset();
return true;
}
@@ -2548,16 +2524,19 @@ static bool ext_cookie_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
// https://tools.ietf.org/html/rfc4492#section-5.1.1
// https://tools.ietf.org/html/rfc8446#section-4.2.7
-static bool ext_supported_groups_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
+static bool ext_supported_groups_add_clienthello(const SSL_HANDSHAKE *hs,
+ CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
CBB contents, groups_bytes;
- if (!CBB_add_u16(out, TLSEXT_TYPE_supported_groups) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_supported_groups) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
!CBB_add_u16_length_prefixed(&contents, &groups_bytes)) {
return false;
}
- // Add a fake group. See draft-davidben-tls-grease-01.
+ // Add a fake group. See RFC 8701.
if (ssl->ctx->grease_enabled &&
!CBB_add_u16(&groups_bytes,
ssl_get_grease_value(hs, ssl_grease_group))) {
@@ -2574,7 +2553,7 @@ static bool ext_supported_groups_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
}
}
- return CBB_flush(out);
+ return CBB_flush(out_compressible);
}
static bool ext_supported_groups_parse_serverhello(SSL_HANDSHAKE *hs,
@@ -2626,158 +2605,11 @@ static bool ext_supported_groups_parse_clienthello(SSL_HANDSHAKE *hs,
return true;
}
-// Token Binding
-//
-// https://tools.ietf.org/html/draft-ietf-tokbind-negotiation-10
-
-// The Token Binding version number currently matches the draft number of
-// draft-ietf-tokbind-protocol, and when published as an RFC it will be 0x0100.
-// Since there are no wire changes to the protocol from draft 13 through the
-// current draft (16), this implementation supports all versions in that range.
-static uint16_t kTokenBindingMaxVersion = 16;
-static uint16_t kTokenBindingMinVersion = 13;
-
-static bool ext_token_binding_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
- if (hs->config->token_binding_params.empty() || SSL_is_dtls(ssl)) {
- return true;
- }
-
- CBB contents, params;
- if (!CBB_add_u16(out, TLSEXT_TYPE_token_binding) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
- !CBB_add_u16(&contents, kTokenBindingMaxVersion) ||
- !CBB_add_u8_length_prefixed(&contents, &params) ||
- !CBB_add_bytes(&params, hs->config->token_binding_params.data(),
- hs->config->token_binding_params.size()) ||
- !CBB_flush(out)) {
- return false;
- }
-
- return true;
-}
-
-static bool ext_token_binding_parse_serverhello(SSL_HANDSHAKE *hs,
- uint8_t *out_alert,
- CBS *contents) {
- SSL *const ssl = hs->ssl;
- if (contents == nullptr) {
- return true;
- }
-
- CBS params_list;
- uint16_t version;
- uint8_t param;
- if (!CBS_get_u16(contents, &version) ||
- !CBS_get_u8_length_prefixed(contents, &params_list) ||
- !CBS_get_u8(&params_list, &param) ||
- CBS_len(&params_list) > 0 ||
- CBS_len(contents) > 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return false;
- }
-
- // The server-negotiated version must be less than or equal to our version.
- if (version > kTokenBindingMaxVersion) {
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return false;
- }
-
- // If the server-selected version is less than what we support, then Token
- // Binding wasn't negotiated (but the extension was parsed successfully).
- if (version < kTokenBindingMinVersion) {
- return true;
- }
-
- for (uint8_t config_param : hs->config->token_binding_params) {
- if (param == config_param) {
- ssl->s3->negotiated_token_binding_param = param;
- ssl->s3->token_binding_negotiated = true;
- return true;
- }
- }
-
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return false;
-}
-
-// select_tb_param looks for the first token binding param in
-// |hs->ssl->token_binding_params| that is also in |params| and puts it in
-// |hs->ssl->negotiated_token_binding_param|. It returns true if a token binding
-// param is found, and false otherwise.
-static bool select_tb_param(SSL_HANDSHAKE *hs,
- Span<const uint8_t> peer_params) {
- for (uint8_t tb_param : hs->config->token_binding_params) {
- for (uint8_t peer_param : peer_params) {
- if (tb_param == peer_param) {
- hs->ssl->s3->negotiated_token_binding_param = tb_param;
- return true;
- }
- }
- }
- return false;
-}
-
-static bool ext_token_binding_parse_clienthello(SSL_HANDSHAKE *hs,
- uint8_t *out_alert,
- CBS *contents) {
- SSL *const ssl = hs->ssl;
- if (contents == nullptr || hs->config->token_binding_params.empty()) {
- return true;
- }
-
- CBS params;
- uint16_t version;
- if (!CBS_get_u16(contents, &version) ||
- !CBS_get_u8_length_prefixed(contents, &params) ||
- CBS_len(&params) == 0 ||
- CBS_len(contents) > 0) {
- *out_alert = SSL_AD_DECODE_ERROR;
- return false;
- }
-
- // If the client-selected version is less than what we support, then Token
- // Binding wasn't negotiated (but the extension was parsed successfully).
- if (version < kTokenBindingMinVersion) {
- return true;
- }
-
- // If the client-selected version is higher than we support, use our max
- // version. Otherwise, use the client's version.
- hs->negotiated_token_binding_version =
- std::min(version, kTokenBindingMaxVersion);
- if (!select_tb_param(hs, params)) {
- return true;
- }
-
- ssl->s3->token_binding_negotiated = true;
- return true;
-}
-
-static bool ext_token_binding_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
-
- if (!ssl->s3->token_binding_negotiated) {
- return true;
- }
-
- CBB contents, params;
- if (!CBB_add_u16(out, TLSEXT_TYPE_token_binding) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
- !CBB_add_u16(&contents, hs->negotiated_token_binding_version) ||
- !CBB_add_u8_length_prefixed(&contents, &params) ||
- !CBB_add_u8(&params, ssl->s3->negotiated_token_binding_param) ||
- !CBB_flush(out)) {
- return false;
- }
-
- return true;
-}
// QUIC Transport Parameters
static bool ext_quic_transport_params_add_clienthello_impl(
- SSL_HANDSHAKE *hs, CBB *out, bool use_legacy_codepoint) {
+ const SSL_HANDSHAKE *hs, CBB *out, bool use_legacy_codepoint) {
if (hs->config->quic_transport_params.empty() && !hs->ssl->quic_method) {
return true;
}
@@ -2794,7 +2626,7 @@ static bool ext_quic_transport_params_add_clienthello_impl(
return true;
}
- uint16_t extension_type = TLSEXT_TYPE_quic_transport_parameters_standard;
+ uint16_t extension_type = TLSEXT_TYPE_quic_transport_parameters;
if (hs->config->quic_use_legacy_codepoint) {
extension_type = TLSEXT_TYPE_quic_transport_parameters_legacy;
}
@@ -2810,16 +2642,18 @@ static bool ext_quic_transport_params_add_clienthello_impl(
return true;
}
-static bool ext_quic_transport_params_add_clienthello(SSL_HANDSHAKE *hs,
- CBB *out) {
+static bool ext_quic_transport_params_add_clienthello(
+ const SSL_HANDSHAKE *hs, CBB *out, CBB *out_compressible,
+ ssl_client_hello_type_t type) {
return ext_quic_transport_params_add_clienthello_impl(
- hs, out, /*use_legacy_codepoint=*/false);
+ hs, out_compressible, /*use_legacy_codepoint=*/false);
}
-static bool ext_quic_transport_params_add_clienthello_legacy(SSL_HANDSHAKE *hs,
- CBB *out) {
+static bool ext_quic_transport_params_add_clienthello_legacy(
+ const SSL_HANDSHAKE *hs, CBB *out, CBB *out_compressible,
+ ssl_client_hello_type_t type) {
return ext_quic_transport_params_add_clienthello_impl(
- hs, out, /*use_legacy_codepoint=*/true);
+ hs, out_compressible, /*use_legacy_codepoint=*/true);
}
static bool ext_quic_transport_params_parse_serverhello_impl(
@@ -2930,7 +2764,7 @@ static bool ext_quic_transport_params_add_serverhello_impl(
return true;
}
- uint16_t extension_type = TLSEXT_TYPE_quic_transport_parameters_standard;
+ uint16_t extension_type = TLSEXT_TYPE_quic_transport_parameters;
if (hs->config->quic_use_legacy_codepoint) {
extension_type = TLSEXT_TYPE_quic_transport_parameters_legacy;
}
@@ -2963,8 +2797,9 @@ static bool ext_quic_transport_params_add_serverhello_legacy(SSL_HANDSHAKE *hs,
//
// https://tools.ietf.org/html/draft-ietf-tls-subcerts
-static bool ext_delegated_credential_add_clienthello(SSL_HANDSHAKE *hs,
- CBB *out) {
+static bool ext_delegated_credential_add_clienthello(
+ const SSL_HANDSHAKE *hs, CBB *out, CBB *out_compressible,
+ ssl_client_hello_type_t type) {
return true;
}
@@ -2993,7 +2828,9 @@ static bool ext_delegated_credential_parse_clienthello(SSL_HANDSHAKE *hs,
// Certificate compression
-static bool cert_compression_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+static bool cert_compression_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
bool first = true;
CBB contents, algs;
@@ -3002,9 +2839,10 @@ static bool cert_compression_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
continue;
}
- if (first && (!CBB_add_u16(out, TLSEXT_TYPE_cert_compression) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
- !CBB_add_u8_length_prefixed(&contents, &algs))) {
+ if (first &&
+ (!CBB_add_u16(out_compressible, TLSEXT_TYPE_cert_compression) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &algs))) {
return false;
}
first = false;
@@ -3013,7 +2851,7 @@ static bool cert_compression_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
}
}
- return first || CBB_flush(out);
+ return first || CBB_flush(out_compressible);
}
static bool cert_compression_parse_serverhello(SSL_HANDSHAKE *hs,
@@ -3099,8 +2937,22 @@ static bool cert_compression_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
//
// https://tools.ietf.org/html/draft-vvv-tls-alps-01
-static bool ext_alps_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
+bool ssl_get_local_application_settings(const SSL_HANDSHAKE *hs,
+ Span<const uint8_t> *out_settings,
+ Span<const uint8_t> protocol) {
+ for (const ALPSConfig &config : hs->config->alps_configs) {
+ if (protocol == config.protocol) {
+ *out_settings = config.settings;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool ext_alps_add_clienthello(const SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_compressible,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
if (// ALPS requires TLS 1.3.
hs->max_version < TLS1_3_VERSION ||
// Do not offer ALPS without ALPN.
@@ -3113,8 +2965,8 @@ static bool ext_alps_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
}
CBB contents, proto_list, proto;
- if (!CBB_add_u16(out, TLSEXT_TYPE_application_settings) ||
- !CBB_add_u16_length_prefixed(out, &contents) ||
+ if (!CBB_add_u16(out_compressible, TLSEXT_TYPE_application_settings) ||
+ !CBB_add_u16_length_prefixed(out_compressible, &contents) ||
!CBB_add_u16_length_prefixed(&contents, &proto_list)) {
return false;
}
@@ -3127,7 +2979,7 @@ static bool ext_alps_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
}
}
- return CBB_flush(out);
+ return CBB_flush(out_compressible);
}
static bool ext_alps_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
@@ -3238,7 +3090,6 @@ bool ssl_negotiate_alps(SSL_HANDSHAKE *hs, uint8_t *out_alert,
static const struct tls_extension kExtensions[] = {
{
TLSEXT_TYPE_server_name,
- NULL,
ext_sni_add_clienthello,
ext_sni_parse_serverhello,
ext_sni_parse_clienthello,
@@ -3246,23 +3097,13 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_encrypted_client_hello,
- NULL,
ext_ech_add_clienthello,
ext_ech_parse_serverhello,
ext_ech_parse_clienthello,
- dont_add_serverhello,
- },
- {
- TLSEXT_TYPE_ech_is_inner,
- NULL,
- ext_ech_is_inner_add_clienthello,
- forbid_parse_serverhello,
- ext_ech_is_inner_parse_clienthello,
- dont_add_serverhello,
+ ext_ech_add_serverhello,
},
{
TLSEXT_TYPE_extended_master_secret,
- NULL,
ext_ems_add_clienthello,
ext_ems_parse_serverhello,
ext_ems_parse_clienthello,
@@ -3270,7 +3111,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_renegotiate,
- NULL,
ext_ri_add_clienthello,
ext_ri_parse_serverhello,
ext_ri_parse_clienthello,
@@ -3278,7 +3118,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_supported_groups,
- NULL,
ext_supported_groups_add_clienthello,
ext_supported_groups_parse_serverhello,
ext_supported_groups_parse_clienthello,
@@ -3286,7 +3125,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_ec_point_formats,
- NULL,
ext_ec_point_add_clienthello,
ext_ec_point_parse_serverhello,
ext_ec_point_parse_clienthello,
@@ -3294,7 +3132,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_session_ticket,
- NULL,
ext_ticket_add_clienthello,
ext_ticket_parse_serverhello,
// Ticket extension client parsing is handled in ssl_session.c
@@ -3303,7 +3140,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_application_layer_protocol_negotiation,
- NULL,
ext_alpn_add_clienthello,
ext_alpn_parse_serverhello,
// ALPN is negotiated late in |ssl_negotiate_alpn|.
@@ -3312,7 +3148,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_status_request,
- NULL,
ext_ocsp_add_clienthello,
ext_ocsp_parse_serverhello,
ext_ocsp_parse_clienthello,
@@ -3320,7 +3155,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_signature_algorithms,
- NULL,
ext_sigalgs_add_clienthello,
forbid_parse_serverhello,
ext_sigalgs_parse_clienthello,
@@ -3328,7 +3162,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_next_proto_neg,
- NULL,
ext_npn_add_clienthello,
ext_npn_parse_serverhello,
ext_npn_parse_clienthello,
@@ -3336,7 +3169,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_certificate_timestamp,
- NULL,
ext_sct_add_clienthello,
ext_sct_parse_serverhello,
ext_sct_parse_clienthello,
@@ -3344,7 +3176,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_channel_id,
- ext_channel_id_init,
ext_channel_id_add_clienthello,
ext_channel_id_parse_serverhello,
ext_channel_id_parse_clienthello,
@@ -3352,7 +3183,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_srtp,
- ext_srtp_init,
ext_srtp_add_clienthello,
ext_srtp_parse_serverhello,
ext_srtp_parse_clienthello,
@@ -3360,7 +3190,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_key_share,
- NULL,
ext_key_share_add_clienthello,
forbid_parse_serverhello,
ignore_parse_clienthello,
@@ -3368,7 +3197,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_psk_key_exchange_modes,
- NULL,
ext_psk_key_exchange_modes_add_clienthello,
forbid_parse_serverhello,
ext_psk_key_exchange_modes_parse_clienthello,
@@ -3376,7 +3204,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_early_data,
- NULL,
ext_early_data_add_clienthello,
ext_early_data_parse_serverhello,
ext_early_data_parse_clienthello,
@@ -3384,7 +3211,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_supported_versions,
- NULL,
ext_supported_versions_add_clienthello,
forbid_parse_serverhello,
ignore_parse_clienthello,
@@ -3392,15 +3218,13 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_cookie,
- NULL,
ext_cookie_add_clienthello,
forbid_parse_serverhello,
ignore_parse_clienthello,
dont_add_serverhello,
},
{
- TLSEXT_TYPE_quic_transport_parameters_standard,
- NULL,
+ TLSEXT_TYPE_quic_transport_parameters,
ext_quic_transport_params_add_clienthello,
ext_quic_transport_params_parse_serverhello,
ext_quic_transport_params_parse_clienthello,
@@ -3408,23 +3232,13 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_quic_transport_parameters_legacy,
- NULL,
ext_quic_transport_params_add_clienthello_legacy,
ext_quic_transport_params_parse_serverhello_legacy,
ext_quic_transport_params_parse_clienthello_legacy,
ext_quic_transport_params_add_serverhello_legacy,
},
{
- TLSEXT_TYPE_token_binding,
- NULL,
- ext_token_binding_add_clienthello,
- ext_token_binding_parse_serverhello,
- ext_token_binding_parse_clienthello,
- ext_token_binding_add_serverhello,
- },
- {
TLSEXT_TYPE_cert_compression,
- NULL,
cert_compression_add_clienthello,
cert_compression_parse_serverhello,
cert_compression_parse_clienthello,
@@ -3432,7 +3246,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_delegated_credential,
- NULL,
ext_delegated_credential_add_clienthello,
forbid_parse_serverhello,
ext_delegated_credential_parse_clienthello,
@@ -3440,7 +3253,6 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_application_settings,
- NULL,
ext_alps_add_clienthello,
ext_alps_parse_serverhello,
// ALPS is negotiated late in |ssl_negotiate_alpn|.
@@ -3458,6 +3270,30 @@ static_assert(kNumExtensions <=
sizeof(((SSL_HANDSHAKE *)NULL)->extensions.received) * 8,
"too many extensions for received bitset");
+bool ssl_setup_extension_permutation(SSL_HANDSHAKE *hs) {
+ if (!hs->config->permute_extensions) {
+ return true;
+ }
+
+ static_assert(kNumExtensions <= UINT8_MAX,
+ "extensions_permutation type is too small");
+ uint32_t seeds[kNumExtensions - 1];
+ Array<uint8_t> permutation;
+ if (!RAND_bytes(reinterpret_cast<uint8_t *>(seeds), sizeof(seeds)) ||
+ !permutation.Init(kNumExtensions)) {
+ return false;
+ }
+ for (size_t i = 0; i < kNumExtensions; i++) {
+ permutation[i] = i;
+ }
+ for (size_t i = kNumExtensions - 1; i > 0; i--) {
+ // Set element |i| to a randomly-selected element 0 <= j <= i.
+ std::swap(permutation[i], permutation[seeds[i - 1] % (i + 1)]);
+ }
+ hs->extension_permutation = std::move(permutation);
+ return true;
+}
+
static const struct tls_extension *tls_extension_find(uint32_t *out_index,
uint16_t value) {
unsigned i;
@@ -3471,8 +3307,137 @@ static const struct tls_extension *tls_extension_find(uint32_t *out_index,
return NULL;
}
-bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out,
+static bool add_padding_extension(CBB *cbb, uint16_t ext, size_t len) {
+ CBB child;
+ if (!CBB_add_u16(cbb, ext) || //
+ !CBB_add_u16_length_prefixed(cbb, &child) ||
+ !CBB_add_zeros(&child, len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+ return CBB_flush(cbb);
+}
+
+static bool ssl_add_clienthello_tlsext_inner(SSL_HANDSHAKE *hs, CBB *out,
+ CBB *out_encoded,
+ bool *out_needs_psk_binder) {
+ // When writing ClientHelloInner, we construct the real and encoded
+ // ClientHellos concurrently, to handle compression. Uncompressed extensions
+ // are written to |extensions| and copied to |extensions_encoded|. Compressed
+ // extensions are buffered in |compressed| and written to the end. (ECH can
+ // only compress continguous extensions.)
+ SSL *const ssl = hs->ssl;
+ bssl::ScopedCBB compressed, outer_extensions;
+ CBB extensions, extensions_encoded;
+ if (!CBB_add_u16_length_prefixed(out, &extensions) ||
+ !CBB_add_u16_length_prefixed(out_encoded, &extensions_encoded) ||
+ !CBB_init(compressed.get(), 64) ||
+ !CBB_init(outer_extensions.get(), 64)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ hs->inner_extensions_sent = 0;
+
+ if (ssl->ctx->grease_enabled) {
+ // Add a fake empty extension. See RFC 8701. This always matches
+ // |ssl_add_clienthello_tlsext|, so compress it.
+ uint16_t grease_ext = ssl_get_grease_value(hs, ssl_grease_extension1);
+ if (!add_padding_extension(compressed.get(), grease_ext, 0) ||
+ !CBB_add_u16(outer_extensions.get(), grease_ext)) {
+ return false;
+ }
+ }
+
+ for (size_t unpermuted = 0; unpermuted < kNumExtensions; unpermuted++) {
+ size_t i = hs->extension_permutation.empty()
+ ? unpermuted
+ : hs->extension_permutation[unpermuted];
+ const size_t len_before = CBB_len(&extensions);
+ const size_t len_compressed_before = CBB_len(compressed.get());
+ if (!kExtensions[i].add_clienthello(hs, &extensions, compressed.get(),
+ ssl_client_hello_inner)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
+ ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
+ return false;
+ }
+
+ const size_t bytes_written = CBB_len(&extensions) - len_before;
+ const size_t bytes_written_compressed =
+ CBB_len(compressed.get()) - len_compressed_before;
+ // The callback may write to at most one output.
+ assert(bytes_written == 0 || bytes_written_compressed == 0);
+ if (bytes_written != 0 || bytes_written_compressed != 0) {
+ hs->inner_extensions_sent |= (1u << i);
+ }
+ // If compressed, update the running ech_outer_extensions extension.
+ if (bytes_written_compressed != 0 &&
+ !CBB_add_u16(outer_extensions.get(), kExtensions[i].value)) {
+ return false;
+ }
+ }
+
+ if (ssl->ctx->grease_enabled) {
+ // Add a fake non-empty extension. See RFC 8701. This always matches
+ // |ssl_add_clienthello_tlsext|, so compress it.
+ uint16_t grease_ext = ssl_get_grease_value(hs, ssl_grease_extension2);
+ if (!add_padding_extension(compressed.get(), grease_ext, 1) ||
+ !CBB_add_u16(outer_extensions.get(), grease_ext)) {
+ return false;
+ }
+ }
+
+ // Uncompressed extensions are encoded as-is.
+ if (!CBB_add_bytes(&extensions_encoded, CBB_data(&extensions),
+ CBB_len(&extensions))) {
+ return false;
+ }
+
+ // Flush all the compressed extensions.
+ if (CBB_len(compressed.get()) != 0) {
+ CBB extension, child;
+ // Copy them as-is in the real ClientHelloInner.
+ if (!CBB_add_bytes(&extensions, CBB_data(compressed.get()),
+ CBB_len(compressed.get())) ||
+ // Replace with ech_outer_extensions in the encoded form.
+ !CBB_add_u16(&extensions_encoded, TLSEXT_TYPE_ech_outer_extensions) ||
+ !CBB_add_u16_length_prefixed(&extensions_encoded, &extension) ||
+ !CBB_add_u8_length_prefixed(&extension, &child) ||
+ !CBB_add_bytes(&child, CBB_data(outer_extensions.get()),
+ CBB_len(outer_extensions.get())) ||
+ !CBB_flush(&extensions_encoded)) {
+ return false;
+ }
+ }
+
+ // The PSK extension must be last. It is never compressed. Note, if there is a
+ // binder, the caller will need to update both ClientHelloInner and
+ // EncodedClientHelloInner after computing it.
+ const size_t len_before = CBB_len(&extensions);
+ if (!ext_pre_shared_key_add_clienthello(hs, &extensions, out_needs_psk_binder,
+ ssl_client_hello_inner) ||
+ !CBB_add_bytes(&extensions_encoded, CBB_data(&extensions) + len_before,
+ CBB_len(&extensions) - len_before) ||
+ !CBB_flush(out) || //
+ !CBB_flush(out_encoded)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, CBB *out_encoded,
+ bool *out_needs_psk_binder,
+ ssl_client_hello_type_t type,
size_t header_len) {
+ *out_needs_psk_binder = false;
+
+ if (type == ssl_client_hello_inner) {
+ return ssl_add_clienthello_tlsext_inner(hs, out, out_encoded,
+ out_needs_psk_binder);
+ }
+
+ assert(out_encoded == nullptr); // Only ClientHelloInner needs two outputs.
SSL *const ssl = hs->ssl;
CBB extensions;
if (!CBB_add_u16_length_prefixed(out, &extensions)) {
@@ -3485,27 +3450,20 @@ bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out,
// important to reset this value.
hs->extensions.sent = 0;
- for (size_t i = 0; i < kNumExtensions; i++) {
- if (kExtensions[i].init != NULL) {
- kExtensions[i].init(hs);
- }
- }
-
- uint16_t grease_ext1 = 0;
- if (ssl->ctx->grease_enabled) {
- // Add a fake empty extension. See draft-davidben-tls-grease-01.
- grease_ext1 = ssl_get_grease_value(hs, ssl_grease_extension1);
- if (!CBB_add_u16(&extensions, grease_ext1) ||
- !CBB_add_u16(&extensions, 0 /* zero length */)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return false;
- }
+ // Add a fake empty extension. See RFC 8701.
+ if (ssl->ctx->grease_enabled &&
+ !add_padding_extension(
+ &extensions, ssl_get_grease_value(hs, ssl_grease_extension1), 0)) {
+ return false;
}
bool last_was_empty = false;
- for (size_t i = 0; i < kNumExtensions; i++) {
+ for (size_t unpermuted = 0; unpermuted < kNumExtensions; unpermuted++) {
+ size_t i = hs->extension_permutation.empty()
+ ? unpermuted
+ : hs->extension_permutation[unpermuted];
const size_t len_before = CBB_len(&extensions);
- if (!kExtensions[i].add_clienthello(hs, &extensions)) {
+ if (!kExtensions[i].add_clienthello(hs, &extensions, &extensions, type)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
return false;
@@ -3521,29 +3479,22 @@ bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out,
}
if (ssl->ctx->grease_enabled) {
- // Add a fake non-empty extension. See draft-davidben-tls-grease-01.
- uint16_t grease_ext2 = ssl_get_grease_value(hs, ssl_grease_extension2);
-
- // The two fake extensions must not have the same value. GREASE values are
- // of the form 0x1a1a, 0x2a2a, 0x3a3a, etc., so XOR to generate a different
- // one.
- if (grease_ext1 == grease_ext2) {
- grease_ext2 ^= 0x1010;
- }
-
- if (!CBB_add_u16(&extensions, grease_ext2) ||
- !CBB_add_u16(&extensions, 1 /* one byte length */) ||
- !CBB_add_u8(&extensions, 0 /* single zero byte as contents */)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ // Add a fake non-empty extension. See RFC 8701.
+ if (!add_padding_extension(
+ &extensions, ssl_get_grease_value(hs, ssl_grease_extension2), 1)) {
return false;
}
-
last_was_empty = false;
}
- if (!SSL_is_dtls(ssl) && !ssl->quic_method) {
- size_t psk_extension_len = ext_pre_shared_key_clienthello_length(hs);
- header_len += 2 + CBB_len(&extensions) + psk_extension_len;
+ // In cleartext ClientHellos, we add the padding extension to work around
+ // bugs. We also apply this padding to ClientHelloOuter, to keep the wire
+ // images aligned.
+ size_t psk_extension_len = ext_pre_shared_key_clienthello_length(hs, type);
+ if (!SSL_is_dtls(ssl) && !ssl->quic_method &&
+ !ssl->s3->used_hello_retry_request) {
+ header_len +=
+ SSL3_HM_HEADER_LENGTH + 2 + CBB_len(&extensions) + psk_extension_len;
size_t padding_len = 0;
// The final extension must be non-empty. WebSphere Application
@@ -3577,24 +3528,21 @@ bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out,
}
}
- if (padding_len != 0) {
- uint8_t *padding_bytes;
- if (!CBB_add_u16(&extensions, TLSEXT_TYPE_padding) ||
- !CBB_add_u16(&extensions, padding_len) ||
- !CBB_add_space(&extensions, &padding_bytes, padding_len)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return false;
- }
-
- OPENSSL_memset(padding_bytes, 0, padding_len);
+ if (padding_len != 0 &&
+ !add_padding_extension(&extensions, TLSEXT_TYPE_padding, padding_len)) {
+ return false;
}
}
// The PSK extension must be last, including after the padding.
- if (!ext_pre_shared_key_add_clienthello(hs, &extensions)) {
+ const size_t len_before = CBB_len(&extensions);
+ if (!ext_pre_shared_key_add_clienthello(hs, &extensions, out_needs_psk_binder,
+ type)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
+ assert(psk_extension_len == CBB_len(&extensions) - len_before);
+ (void)len_before; // |assert| is omitted in release builds.
// Discard empty extensions blocks.
if (CBB_len(&extensions) == 0) {
@@ -3640,12 +3588,6 @@ err:
static bool ssl_scan_clienthello_tlsext(SSL_HANDSHAKE *hs,
const SSL_CLIENT_HELLO *client_hello,
int *out_alert) {
- for (size_t i = 0; i < kNumExtensions; i++) {
- if (kExtensions[i].init != NULL) {
- kExtensions[i].init(hs);
- }
- }
-
hs->extensions.received = 0;
CBS extensions;
CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
@@ -3726,18 +3668,10 @@ bool ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs,
return true;
}
-static bool ssl_scan_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs,
+static bool ssl_scan_serverhello_tlsext(SSL_HANDSHAKE *hs, const CBS *cbs,
int *out_alert) {
- SSL *const ssl = hs->ssl;
- // Before TLS 1.3, ServerHello extensions blocks may be omitted if empty.
- if (CBS_len(cbs) == 0 && ssl_protocol_version(ssl) < TLS1_3_VERSION) {
- return true;
- }
-
- // Decode the extensions block and check it is valid.
- CBS extensions;
- if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
- !tls1_check_duplicate_extensions(&extensions)) {
+ CBS extensions = *cbs;
+ if (!tls1_check_duplicate_extensions(&extensions)) {
*out_alert = SSL_AD_DECODE_ERROR;
return false;
}
@@ -3806,18 +3740,8 @@ static bool ssl_scan_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs,
static bool ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
-
- if (ssl->s3->token_binding_negotiated &&
- !(SSL_get_secure_renegotiation_support(ssl) &&
- SSL_get_extms_support(ssl))) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_TB_WITHOUT_EMS_OR_RI);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return false;
- }
-
int ret = SSL_TLSEXT_ERR_NOACK;
int al = SSL_AD_UNRECOGNIZED_NAME;
-
if (ssl->ctx->servername_callback != 0) {
ret = ssl->ctx->servername_callback(ssl, &al, ssl->ctx->servername_arg);
} else if (ssl->session_ctx->servername_callback != 0) {
@@ -3869,7 +3793,7 @@ static bool ssl_check_serverhello_tlsext(SSL_HANDSHAKE *hs) {
return true;
}
-bool ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs) {
+bool ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, const CBS *cbs) {
SSL *const ssl = hs->ssl;
int alert = SSL_AD_DECODE_ERROR;
if (!ssl_scan_serverhello_tlsext(hs, cbs, &alert)) {
@@ -3897,8 +3821,8 @@ static enum ssl_ticket_aead_result_t decrypt_ticket_with_cipher_ctx(
return ssl_ticket_aead_ignore_ticket;
}
// Split the ticket into the ticket and the MAC.
- auto ticket_mac = ticket.subspan(ticket.size() - mac_len);
- ticket = ticket.subspan(0, ticket.size() - mac_len);
+ auto ticket_mac = ticket.last(mac_len);
+ ticket = ticket.first(ticket.size() - mac_len);
HMAC_Update(hmac_ctx, ticket.data(), ticket.size());
HMAC_Final(hmac_ctx, mac, NULL);
assert(mac_len == ticket_mac.size());
@@ -4032,6 +3956,7 @@ enum ssl_ticket_aead_result_t ssl_process_ticket(
SSL_HANDSHAKE *hs, UniquePtr<SSL_SESSION> *out_session,
bool *out_renew_ticket, Span<const uint8_t> ticket,
Span<const uint8_t> session_id) {
+ SSL *const ssl = hs->ssl;
*out_renew_ticket = false;
out_session->reset();
@@ -4040,9 +3965,21 @@ enum ssl_ticket_aead_result_t ssl_process_ticket(
return ssl_ticket_aead_ignore_ticket;
}
+ // Tickets in TLS 1.3 are tied into pre-shared keys (PSKs), unlike in TLS 1.2
+ // where that concept doesn't exist. The |decrypted_psk| and |ignore_psk|
+ // hints only apply to PSKs. We check the version to determine which this is.
+ const bool is_psk = ssl_protocol_version(ssl) >= TLS1_3_VERSION;
+
Array<uint8_t> plaintext;
enum ssl_ticket_aead_result_t result;
- if (hs->ssl->session_ctx->ticket_aead_method != NULL) {
+ SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
+ if (is_psk && hints && !hs->hints_requested &&
+ !hints->decrypted_psk.empty()) {
+ result = plaintext.CopyFrom(hints->decrypted_psk) ? ssl_ticket_aead_success
+ : ssl_ticket_aead_error;
+ } else if (is_psk && hints && !hs->hints_requested && hints->ignore_psk) {
+ result = ssl_ticket_aead_ignore_ticket;
+ } else if (ssl->session_ctx->ticket_aead_method != NULL) {
result = ssl_decrypt_ticket_with_method(hs, &plaintext, out_renew_ticket,
ticket);
} else {
@@ -4051,9 +3988,8 @@ enum ssl_ticket_aead_result_t ssl_process_ticket(
// length should be well under the minimum size for the session material and
// HMAC.
if (ticket.size() < SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH) {
- return ssl_ticket_aead_ignore_ticket;
- }
- if (hs->ssl->session_ctx->ticket_key_cb != NULL) {
+ result = ssl_ticket_aead_ignore_ticket;
+ } else if (ssl->session_ctx->ticket_key_cb != NULL) {
result =
ssl_decrypt_ticket_with_cb(hs, &plaintext, out_renew_ticket, ticket);
} else {
@@ -4061,22 +3997,33 @@ enum ssl_ticket_aead_result_t ssl_process_ticket(
}
}
+ if (is_psk && hints && hs->hints_requested) {
+ if (result == ssl_ticket_aead_ignore_ticket) {
+ hints->ignore_psk = true;
+ } else if (result == ssl_ticket_aead_success &&
+ !hints->decrypted_psk.CopyFrom(plaintext)) {
+ return ssl_ticket_aead_error;
+ }
+ }
+
if (result != ssl_ticket_aead_success) {
return result;
}
// Decode the session.
UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(
- plaintext.data(), plaintext.size(), hs->ssl->ctx.get()));
+ plaintext.data(), plaintext.size(), ssl->ctx.get()));
if (!session) {
ERR_clear_error(); // Don't leave an error on the queue.
return ssl_ticket_aead_ignore_ticket;
}
- // Copy the client's session ID into the new session, to denote the ticket has
- // been accepted.
- OPENSSL_memcpy(session->session_id, session_id.data(), session_id.size());
- session->session_id_length = session_id.size();
+ // Envoy's tests expect the session to have a session ID that matches the
+ // placeholder used by the client. It's unclear whether this is a good idea,
+ // but we maintain it for now.
+ SHA256(ticket.data(), ticket.size(), session->session_id);
+ // Other consumers may expect a non-empty session ID to indicate resumption.
+ session->session_id_length = SHA256_DIGEST_LENGTH;
*out_session = std::move(session);
return ssl_ticket_aead_success;
@@ -4224,11 +4171,11 @@ bool tls1_verify_channel_id(SSL_HANDSHAKE *hs, const SSLMessage &msg) {
if (!sig_ok) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
- ssl->s3->channel_id_valid = false;
return false;
}
OPENSSL_memcpy(ssl->s3->channel_id, p, 64);
+ ssl->s3->channel_id_valid = true;
return true;
}
@@ -4339,23 +4286,6 @@ bool tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs) {
return true;
}
-bool ssl_do_channel_id_callback(SSL_HANDSHAKE *hs) {
- if (hs->config->channel_id_private != NULL ||
- hs->ssl->ctx->channel_id_cb == NULL) {
- return true;
- }
-
- EVP_PKEY *key = NULL;
- hs->ssl->ctx->channel_id_cb(hs->ssl, &key);
- if (key == NULL) {
- // The caller should try again later.
- return true;
- }
-
- UniquePtr<EVP_PKEY> free_key(key);
- return SSL_set1_tls_channel_id(hs->ssl, key);
-}
-
bool ssl_is_sct_list_valid(const CBS *contents) {
// Shallow parse the SCT list for sanity. By the RFC
// (https://tools.ietf.org/html/rfc6962#section-3.3) neither the list nor any
diff --git a/deps/boringssl/src/ssl/handoff.cc b/deps/boringssl/src/ssl/handoff.cc
index 16cbdf7..883f832 100644
--- a/deps/boringssl/src/ssl/handoff.cc
+++ b/deps/boringssl/src/ssl/handoff.cc
@@ -15,6 +15,7 @@
#include <openssl/ssl.h>
#include <openssl/bytestring.h>
+#include <openssl/err.h>
#include "internal.h"
@@ -93,7 +94,7 @@ bool SSL_serialize_handoff(const SSL *ssl, CBB *out,
!serialize_features(&seq) ||
!CBB_flush(out) ||
!ssl->method->get_message(ssl, &msg) ||
- !ssl_client_hello_init(ssl, out_hello, msg)) {
+ !ssl_client_hello_init(ssl, out_hello, msg.body)) {
return false;
}
@@ -231,7 +232,7 @@ static bool apply_remote_features(SSL *ssl, CBS *in) {
// disqualifies it for split handshakes.
static bool uses_disallowed_feature(const SSL *ssl) {
return ssl->method->is_dtls || (ssl->config->cert && ssl->config->cert->dc) ||
- ssl->config->quic_transport_params.size() > 0;
+ ssl->config->quic_transport_params.size() > 0 || ssl->ctx->ech_keys;
}
bool SSL_apply_handoff(SSL *ssl, Span<const uint8_t> handoff) {
@@ -337,6 +338,7 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
} else {
session = s3->session_reused ? ssl->session.get() : hs->new_session.get();
}
+ static const uint8_t kUnusedChannelID[64] = {0};
if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&seq, kHandbackVersion) ||
!CBB_add_asn1_uint64(&seq, type) ||
@@ -351,7 +353,7 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
!CBB_add_asn1_octet_string(&seq, read_iv, read_iv_len) ||
!CBB_add_asn1_octet_string(&seq, write_iv, write_iv_len) ||
!CBB_add_asn1_bool(&seq, s3->session_reused) ||
- !CBB_add_asn1_bool(&seq, s3->channel_id_valid) ||
+ !CBB_add_asn1_bool(&seq, hs->channel_id_negotiated) ||
!ssl_session_serialize(session, &seq) ||
!CBB_add_asn1_octet_string(&seq, s3->next_proto_negotiated.data(),
s3->next_proto_negotiated.size()) ||
@@ -360,10 +362,12 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
!CBB_add_asn1_octet_string(
&seq, reinterpret_cast<uint8_t *>(s3->hostname.get()),
hostname_len) ||
- !CBB_add_asn1_octet_string(&seq, s3->channel_id,
- sizeof(s3->channel_id)) ||
- !CBB_add_asn1_bool(&seq, ssl->s3->token_binding_negotiated) ||
- !CBB_add_asn1_uint64(&seq, ssl->s3->negotiated_token_binding_param) ||
+ !CBB_add_asn1_octet_string(&seq, kUnusedChannelID,
+ sizeof(kUnusedChannelID)) ||
+ // These two fields were historically |token_binding_negotiated| and
+ // |negotiated_token_binding_param|.
+ !CBB_add_asn1_bool(&seq, 0) ||
+ !CBB_add_asn1_uint64(&seq, 0) ||
!CBB_add_asn1_bool(&seq, s3->hs->next_proto_neg_seen) ||
!CBB_add_asn1_bool(&seq, s3->hs->cert_request) ||
!CBB_add_asn1_bool(&seq, s3->hs->extended_master_secret) ||
@@ -442,12 +446,13 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
}
SSL3_STATE *const s3 = ssl->s3;
- uint64_t handback_version, negotiated_token_binding_param, cipher, type_u64;
+ uint64_t handback_version, unused_token_binding_param, cipher, type_u64;
CBS seq, read_seq, write_seq, server_rand, client_rand, read_iv, write_iv,
- next_proto, alpn, hostname, channel_id, transcript, key_share;
- int session_reused, channel_id_valid, cert_request, extended_master_secret,
- ticket_expected, token_binding_negotiated, next_proto_neg_seen;
+ next_proto, alpn, hostname, unused_channel_id, transcript, key_share;
+ int session_reused, channel_id_negotiated, cert_request,
+ extended_master_secret, ticket_expected, unused_token_binding,
+ next_proto_neg_seen;
SSL_SESSION *session = nullptr;
CBS handback_cbs(handback);
@@ -475,7 +480,7 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
!CBS_get_asn1(&seq, &read_iv, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &write_iv, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1_bool(&seq, &session_reused) ||
- !CBS_get_asn1_bool(&seq, &channel_id_valid)) {
+ !CBS_get_asn1_bool(&seq, &channel_id_negotiated)) {
return false;
}
@@ -494,12 +499,9 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
if (!session || !CBS_get_asn1(&seq, &next_proto, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &alpn, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &hostname, CBS_ASN1_OCTETSTRING) ||
- !CBS_get_asn1(&seq, &channel_id, CBS_ASN1_OCTETSTRING) ||
- CBS_len(&channel_id) != sizeof(s3->channel_id) ||
- !CBS_copy_bytes(&channel_id, s3->channel_id,
- sizeof(s3->channel_id)) ||
- !CBS_get_asn1_bool(&seq, &token_binding_negotiated) ||
- !CBS_get_asn1_uint64(&seq, &negotiated_token_binding_param) ||
+ !CBS_get_asn1(&seq, &unused_channel_id, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_asn1_bool(&seq, &unused_token_binding) ||
+ !CBS_get_asn1_uint64(&seq, &unused_token_binding_param) ||
!CBS_get_asn1_bool(&seq, &next_proto_neg_seen) ||
!CBS_get_asn1_bool(&seq, &cert_request) ||
!CBS_get_asn1_bool(&seq, &extended_master_secret) ||
@@ -613,7 +615,7 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
return false;
}
s3->session_reused = session_reused;
- s3->channel_id_valid = channel_id_valid;
+ hs->channel_id_negotiated = channel_id_negotiated;
s3->next_proto_negotiated.CopyFrom(next_proto);
s3->alpn_selected.CopyFrom(alpn);
@@ -628,9 +630,6 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
s3->hostname.reset(hostname_str);
}
- s3->token_binding_negotiated = token_binding_negotiated;
- s3->negotiated_token_binding_param =
- static_cast<uint8_t>(negotiated_token_binding_param);
hs->next_proto_neg_seen = next_proto_neg_seen;
hs->wait = ssl_hs_flush;
hs->extended_master_secret = extended_master_secret;
@@ -708,3 +707,280 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
}
BSSL_NAMESPACE_END
+
+using namespace bssl;
+
+int SSL_serialize_capabilities(const SSL *ssl, CBB *out) {
+ CBB seq;
+ if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
+ !serialize_features(&seq) || //
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int SSL_request_handshake_hints(SSL *ssl, const uint8_t *client_hello,
+ size_t client_hello_len,
+ const uint8_t *capabilities,
+ size_t capabilities_len) {
+ if (SSL_is_dtls(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
+ CBS cbs, seq;
+ CBS_init(&cbs, capabilities, capabilities_len);
+ UniquePtr<SSL_HANDSHAKE_HINTS> hints = MakeUnique<SSL_HANDSHAKE_HINTS>();
+ if (hints == nullptr ||
+ !CBS_get_asn1(&cbs, &seq, CBS_ASN1_SEQUENCE) ||
+ !apply_remote_features(ssl, &seq)) {
+ return 0;
+ }
+
+ SSL3_STATE *const s3 = ssl->s3;
+ s3->v2_hello_done = true;
+ s3->has_message = true;
+
+ Array<uint8_t> client_hello_msg;
+ ScopedCBB client_hello_cbb;
+ CBB client_hello_body;
+ if (!ssl->method->init_message(ssl, client_hello_cbb.get(),
+ &client_hello_body, SSL3_MT_CLIENT_HELLO) ||
+ !CBB_add_bytes(&client_hello_body, client_hello, client_hello_len) ||
+ !ssl->method->finish_message(ssl, client_hello_cbb.get(),
+ &client_hello_msg)) {
+ return 0;
+ }
+
+ s3->hs_buf.reset(BUF_MEM_new());
+ if (!s3->hs_buf || !BUF_MEM_append(s3->hs_buf.get(), client_hello_msg.data(),
+ client_hello_msg.size())) {
+ return 0;
+ }
+
+ s3->hs->hints_requested = true;
+ s3->hs->hints = std::move(hints);
+ return 1;
+}
+
+// |SSL_HANDSHAKE_HINTS| is serialized as the following ASN.1 structure. We use
+// implicit tagging to make it a little more compact.
+//
+// HandshakeHints ::= SEQUENCE {
+// serverRandom [0] IMPLICIT OCTET STRING OPTIONAL,
+// keyShareHint [1] IMPLICIT KeyShareHint OPTIONAL,
+// signatureHint [2] IMPLICIT SignatureHint OPTIONAL,
+// -- At most one of decryptedPSKHint or ignorePSKHint may be present. It
+// -- corresponds to the first entry in pre_shared_keys. TLS 1.2 session
+// -- tickets will use a separate hint, to ensure the caller does not mix
+// -- them up.
+// decryptedPSKHint [3] IMPLICIT OCTET STRING OPTIONAL,
+// ignorePSKHint [4] IMPLICIT NULL OPTIONAL,
+// compressCertificateHint [5] IMPLICIT CompressCertificateHint OPTIONAL,
+// }
+//
+// KeyShareHint ::= SEQUENCE {
+// groupId INTEGER,
+// publicKey OCTET STRING,
+// secret OCTET STRING,
+// }
+//
+// SignatureHint ::= SEQUENCE {
+// algorithm INTEGER,
+// input OCTET STRING,
+// subjectPublicKeyInfo OCTET STRING,
+// signature OCTET STRING,
+// }
+//
+// CompressCertificateHint ::= SEQUENCE {
+// algorithm INTEGER,
+// input OCTET STRING,
+// compressed OCTET STRING,
+// }
+
+// HandshakeHints tags.
+static const unsigned kServerRandomTag = CBS_ASN1_CONTEXT_SPECIFIC | 0;
+static const unsigned kKeyShareHintTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
+static const unsigned kSignatureHintTag =
+ CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2;
+static const unsigned kDecryptedPSKTag = CBS_ASN1_CONTEXT_SPECIFIC | 3;
+static const unsigned kIgnorePSKTag = CBS_ASN1_CONTEXT_SPECIFIC | 4;
+static const unsigned kCompressCertificateTag = CBS_ASN1_CONTEXT_SPECIFIC | 5;
+
+int SSL_serialize_handshake_hints(const SSL *ssl, CBB *out) {
+ const SSL_HANDSHAKE *hs = ssl->s3->hs.get();
+ if (!ssl->server || !hs->hints_requested) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
+ const SSL_HANDSHAKE_HINTS *hints = hs->hints.get();
+ CBB seq, child;
+ if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE)) {
+ return 0;
+ }
+
+ if (!hints->server_random.empty()) {
+ if (!CBB_add_asn1(&seq, &child, kServerRandomTag) ||
+ !CBB_add_bytes(&child, hints->server_random.data(),
+ hints->server_random.size())) {
+ return 0;
+ }
+ }
+
+ if (hints->key_share_group_id != 0 && !hints->key_share_public_key.empty() &&
+ !hints->key_share_secret.empty()) {
+ if (!CBB_add_asn1(&seq, &child, kKeyShareHintTag) ||
+ !CBB_add_asn1_uint64(&child, hints->key_share_group_id) ||
+ !CBB_add_asn1_octet_string(&child, hints->key_share_public_key.data(),
+ hints->key_share_public_key.size()) ||
+ !CBB_add_asn1_octet_string(&child, hints->key_share_secret.data(),
+ hints->key_share_secret.size())) {
+ return 0;
+ }
+ }
+
+ if (hints->signature_algorithm != 0 && !hints->signature_input.empty() &&
+ !hints->signature.empty()) {
+ if (!CBB_add_asn1(&seq, &child, kSignatureHintTag) ||
+ !CBB_add_asn1_uint64(&child, hints->signature_algorithm) ||
+ !CBB_add_asn1_octet_string(&child, hints->signature_input.data(),
+ hints->signature_input.size()) ||
+ !CBB_add_asn1_octet_string(&child, hints->signature_spki.data(),
+ hints->signature_spki.size()) ||
+ !CBB_add_asn1_octet_string(&child, hints->signature.data(),
+ hints->signature.size())) {
+ return 0;
+ }
+ }
+
+ if (!hints->decrypted_psk.empty()) {
+ if (!CBB_add_asn1(&seq, &child, kDecryptedPSKTag) ||
+ !CBB_add_bytes(&child, hints->decrypted_psk.data(),
+ hints->decrypted_psk.size())) {
+ return 0;
+ }
+ }
+
+ if (hints->ignore_psk && //
+ !CBB_add_asn1(&seq, &child, kIgnorePSKTag)) {
+ return 0;
+ }
+
+ if (hints->cert_compression_alg_id != 0 &&
+ !hints->cert_compression_input.empty() &&
+ !hints->cert_compression_output.empty()) {
+ if (!CBB_add_asn1(&seq, &child, kCompressCertificateTag) ||
+ !CBB_add_asn1_uint64(&child, hints->cert_compression_alg_id) ||
+ !CBB_add_asn1_octet_string(&child, hints->cert_compression_input.data(),
+ hints->cert_compression_input.size()) ||
+ !CBB_add_asn1_octet_string(&child,
+ hints->cert_compression_output.data(),
+ hints->cert_compression_output.size())) {
+ return 0;
+ }
+ }
+
+ return CBB_flush(out);
+}
+
+int SSL_set_handshake_hints(SSL *ssl, const uint8_t *hints, size_t hints_len) {
+ if (SSL_is_dtls(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
+ UniquePtr<SSL_HANDSHAKE_HINTS> hints_obj = MakeUnique<SSL_HANDSHAKE_HINTS>();
+ if (hints_obj == nullptr) {
+ return 0;
+ }
+
+ CBS cbs, seq, server_random, key_share, signature_hint, ticket, ignore_psk,
+ cert_compression;
+ int has_server_random, has_key_share, has_signature_hint, has_ticket,
+ has_ignore_psk, has_cert_compression;
+ CBS_init(&cbs, hints, hints_len);
+ if (!CBS_get_asn1(&cbs, &seq, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_optional_asn1(&seq, &server_random, &has_server_random,
+ kServerRandomTag) ||
+ !CBS_get_optional_asn1(&seq, &key_share, &has_key_share,
+ kKeyShareHintTag) ||
+ !CBS_get_optional_asn1(&seq, &signature_hint, &has_signature_hint,
+ kSignatureHintTag) ||
+ !CBS_get_optional_asn1(&seq, &ticket, &has_ticket, kDecryptedPSKTag) ||
+ !CBS_get_optional_asn1(&seq, &ignore_psk, &has_ignore_psk,
+ kIgnorePSKTag) ||
+ !CBS_get_optional_asn1(&seq, &cert_compression, &has_cert_compression,
+ kCompressCertificateTag)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_COULD_NOT_PARSE_HINTS);
+ return 0;
+ }
+
+ if (has_server_random && !hints_obj->server_random.CopyFrom(server_random)) {
+ return 0;
+ }
+
+ if (has_key_share) {
+ uint64_t group_id;
+ CBS public_key, secret;
+ if (!CBS_get_asn1_uint64(&key_share, &group_id) || //
+ group_id == 0 || group_id > 0xffff ||
+ !CBS_get_asn1(&key_share, &public_key, CBS_ASN1_OCTETSTRING) ||
+ !hints_obj->key_share_public_key.CopyFrom(public_key) ||
+ !CBS_get_asn1(&key_share, &secret, CBS_ASN1_OCTETSTRING) ||
+ !hints_obj->key_share_secret.CopyFrom(secret)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_COULD_NOT_PARSE_HINTS);
+ return 0;
+ }
+ hints_obj->key_share_group_id = static_cast<uint16_t>(group_id);
+ }
+
+ if (has_signature_hint) {
+ uint64_t sig_alg;
+ CBS input, spki, signature;
+ if (!CBS_get_asn1_uint64(&signature_hint, &sig_alg) || //
+ sig_alg == 0 || sig_alg > 0xffff ||
+ !CBS_get_asn1(&signature_hint, &input, CBS_ASN1_OCTETSTRING) ||
+ !hints_obj->signature_input.CopyFrom(input) ||
+ !CBS_get_asn1(&signature_hint, &spki, CBS_ASN1_OCTETSTRING) ||
+ !hints_obj->signature_spki.CopyFrom(spki) ||
+ !CBS_get_asn1(&signature_hint, &signature, CBS_ASN1_OCTETSTRING) ||
+ !hints_obj->signature.CopyFrom(signature)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_COULD_NOT_PARSE_HINTS);
+ return 0;
+ }
+ hints_obj->signature_algorithm = static_cast<uint16_t>(sig_alg);
+ }
+
+ if (has_ticket && !hints_obj->decrypted_psk.CopyFrom(ticket)) {
+ return 0;
+ }
+
+ if (has_ignore_psk) {
+ if (CBS_len(&ignore_psk) != 0) {
+ return 0;
+ }
+ hints_obj->ignore_psk = true;
+ }
+
+ if (has_cert_compression) {
+ uint64_t alg;
+ CBS input, output;
+ if (!CBS_get_asn1_uint64(&cert_compression, &alg) || //
+ alg == 0 || alg > 0xffff ||
+ !CBS_get_asn1(&cert_compression, &input, CBS_ASN1_OCTETSTRING) ||
+ !hints_obj->cert_compression_input.CopyFrom(input) ||
+ !CBS_get_asn1(&cert_compression, &output, CBS_ASN1_OCTETSTRING) ||
+ !hints_obj->cert_compression_output.CopyFrom(output)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_COULD_NOT_PARSE_HINTS);
+ return 0;
+ }
+ hints_obj->cert_compression_alg_id = static_cast<uint16_t>(alg);
+ }
+
+ ssl->s3->hs->hints = std::move(hints_obj);
+ return 1;
+}
diff --git a/deps/boringssl/src/ssl/handshake.cc b/deps/boringssl/src/ssl/handshake.cc
index b38f96a..fc85e21 100644
--- a/deps/boringssl/src/ssl/handshake.cc
+++ b/deps/boringssl/src/ssl/handshake.cc
@@ -126,10 +126,9 @@ BSSL_NAMESPACE_BEGIN
SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg)
: ssl(ssl_arg),
- ech_present(false),
- ech_is_inner_present(false),
+ ech_is_inner(false),
+ ech_authenticated_reject(false),
scts_requested(false),
- needs_psk_binder(false),
handshake_finalized(false),
accept_psk_mode(false),
cert_request(false),
@@ -146,11 +145,19 @@ SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg)
ticket_expected(false),
extended_master_secret(false),
pending_private_key_op(false),
- grease_seeded(false),
handback(false),
+ hints_requested(false),
cert_compression_negotiated(false),
- apply_jdk11_workaround(false) {
+ apply_jdk11_workaround(false),
+ can_release_private_key(false),
+ channel_id_negotiated(false) {
assert(ssl);
+
+ // Draw entropy for all GREASE values at once. This avoids calling
+ // |RAND_bytes| repeatedly and makes the values consistent within a
+ // connection. The latter is so the second ClientHello matches after
+ // HelloRetryRequest and so supported_groups and key_shares are consistent.
+ RAND_bytes(grease_seed, sizeof(grease_seed));
}
SSL_HANDSHAKE::~SSL_HANDSHAKE() {
@@ -164,6 +171,28 @@ void SSL_HANDSHAKE::ResizeSecrets(size_t hash_len) {
hash_len_ = hash_len;
}
+bool SSL_HANDSHAKE::GetClientHello(SSLMessage *out_msg,
+ SSL_CLIENT_HELLO *out_client_hello) {
+ if (!ech_client_hello_buf.empty()) {
+ // If the backing buffer is non-empty, the ClientHelloInner has been set.
+ out_msg->is_v2_hello = false;
+ out_msg->type = SSL3_MT_CLIENT_HELLO;
+ out_msg->raw = CBS(ech_client_hello_buf);
+ out_msg->body = MakeConstSpan(ech_client_hello_buf).subspan(4);
+ } else if (!ssl->method->get_message(ssl, out_msg)) {
+ // The message has already been read, so this cannot fail.
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ if (!ssl_client_hello_init(ssl, out_client_hello, out_msg->body)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return false;
+ }
+ return true;
+}
+
UniquePtr<SSL_HANDSHAKE> ssl_handshake_new(SSL *ssl) {
UniquePtr<SSL_HANDSHAKE> hs = MakeUnique<SSL_HANDSHAKE>(ssl);
if (!hs || !hs->transcript.Init()) {
@@ -238,12 +267,15 @@ bool ssl_hash_message(SSL_HANDSHAKE *hs, const SSLMessage &msg) {
}
bool ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
- Span<const SSL_EXTENSION_TYPE> ext_types,
+ std::initializer_list<SSLExtension *> extensions,
bool ignore_unknown) {
// Reset everything.
- for (const SSL_EXTENSION_TYPE &ext_type : ext_types) {
- *ext_type.out_present = false;
- CBS_init(ext_type.out_data, nullptr, 0);
+ for (SSLExtension *ext : extensions) {
+ ext->present = false;
+ CBS_init(&ext->data, nullptr, 0);
+ if (!ext->allowed) {
+ assert(!ignore_unknown);
+ }
}
CBS copy = *cbs;
@@ -257,10 +289,10 @@ bool ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
return false;
}
- const SSL_EXTENSION_TYPE *found = nullptr;
- for (const SSL_EXTENSION_TYPE &ext_type : ext_types) {
- if (type == ext_type.type) {
- found = &ext_type;
+ SSLExtension *found = nullptr;
+ for (SSLExtension *ext : extensions) {
+ if (type == ext->type && ext->allowed) {
+ found = ext;
break;
}
}
@@ -275,14 +307,14 @@ bool ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
}
// Duplicate ext_types are forbidden.
- if (*found->out_present) {
+ if (found->present) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return false;
}
- *found->out_present = 1;
- *found->out_data = data;
+ found->present = true;
+ found->data = data;
}
return true;
@@ -410,17 +442,8 @@ enum ssl_verify_result_t ssl_reverify_peer_cert(SSL_HANDSHAKE *hs,
return ret;
}
-uint16_t ssl_get_grease_value(SSL_HANDSHAKE *hs,
- enum ssl_grease_index_t index) {
- // Draw entropy for all GREASE values at once. This avoids calling
- // |RAND_bytes| repeatedly and makes the values consistent within a
- // connection. The latter is so the second ClientHello matches after
- // HelloRetryRequest and so supported_groups and key_shares are consistent.
- if (!hs->grease_seeded) {
- RAND_bytes(hs->grease_seed, sizeof(hs->grease_seed));
- hs->grease_seeded = true;
- }
-
+static uint16_t grease_index_to_value(const SSL_HANDSHAKE *hs,
+ enum ssl_grease_index_t index) {
// This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16.
uint16_t ret = hs->grease_seed[index];
ret = (ret & 0xf0) | 0x0a;
@@ -428,6 +451,19 @@ uint16_t ssl_get_grease_value(SSL_HANDSHAKE *hs,
return ret;
}
+uint16_t ssl_get_grease_value(const SSL_HANDSHAKE *hs,
+ enum ssl_grease_index_t index) {
+ uint16_t ret = grease_index_to_value(hs, index);
+ if (index == ssl_grease_extension2 &&
+ ret == grease_index_to_value(hs, ssl_grease_extension1)) {
+ // The two fake extensions must not have the same value. GREASE values are
+ // of the form 0x1a1a, 0x2a2a, 0x3a3a, etc., so XOR to generate a different
+ // one.
+ ret ^= 0x1010;
+ }
+ return ret;
+}
+
enum ssl_hs_wait_t ssl_get_finished(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
SSLMessage msg;
@@ -552,7 +588,11 @@ const SSL_SESSION *ssl_handshake_session(const SSL_HANDSHAKE *hs) {
int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) {
SSL *const ssl = hs->ssl;
for (;;) {
- // Resolve the operation the handshake was waiting on.
+ // Resolve the operation the handshake was waiting on. Each condition may
+ // halt the handshake by returning, or continue executing if the handshake
+ // may immediately proceed. Cases which halt the handshake can clear
+ // |hs->wait| to re-enter the state machine on the next iteration, or leave
+ // it set to keep the condition sticky.
switch (hs->wait) {
case ssl_hs_error:
ERR_restore_state(hs->error.get());
@@ -570,13 +610,13 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) {
case ssl_hs_read_message:
case ssl_hs_read_change_cipher_spec: {
if (ssl->quic_method) {
+ // QUIC has no ChangeCipherSpec messages.
+ assert(hs->wait != ssl_hs_read_change_cipher_spec);
+ // The caller should call |SSL_provide_quic_data|. Clear |hs->wait| so
+ // the handshake can check if there is sufficient data next iteration.
+ ssl->s3->rwstate = SSL_ERROR_WANT_READ;
hs->wait = ssl_hs_ok;
- // The change cipher spec is omitted in QUIC.
- if (hs->wait != ssl_hs_read_change_cipher_spec) {
- ssl->s3->rwstate = SSL_ERROR_WANT_READ;
- return -1;
- }
- break;
+ return -1;
}
uint8_t alert = SSL_AD_DECODE_ERROR;
@@ -646,31 +686,26 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) {
return -1;
}
+ // The following cases are associated with callback APIs which expect to
+ // be called each time the state machine runs. Thus they set |hs->wait|
+ // to |ssl_hs_ok| so that, next time, we re-enter the state machine and
+ // call the callback again.
case ssl_hs_x509_lookup:
ssl->s3->rwstate = SSL_ERROR_WANT_X509_LOOKUP;
hs->wait = ssl_hs_ok;
return -1;
-
- case ssl_hs_channel_id_lookup:
- ssl->s3->rwstate = SSL_ERROR_WANT_CHANNEL_ID_LOOKUP;
- hs->wait = ssl_hs_ok;
- return -1;
-
case ssl_hs_private_key_operation:
ssl->s3->rwstate = SSL_ERROR_WANT_PRIVATE_KEY_OPERATION;
hs->wait = ssl_hs_ok;
return -1;
-
case ssl_hs_pending_session:
ssl->s3->rwstate = SSL_ERROR_PENDING_SESSION;
hs->wait = ssl_hs_ok;
return -1;
-
case ssl_hs_pending_ticket:
ssl->s3->rwstate = SSL_ERROR_PENDING_TICKET;
hs->wait = ssl_hs_ok;
return -1;
-
case ssl_hs_certificate_verify:
ssl->s3->rwstate = SSL_ERROR_WANT_CERTIFICATE_VERIFY;
hs->wait = ssl_hs_ok;
@@ -683,10 +718,18 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) {
return -1;
case ssl_hs_early_return:
+ if (!ssl->server) {
+ // On ECH reject, the handshake should never complete.
+ assert(ssl->s3->ech_status != ssl_ech_rejected);
+ }
*out_early_return = true;
hs->wait = ssl_hs_ok;
return 1;
+ case ssl_hs_hints_ready:
+ ssl->s3->rwstate = SSL_ERROR_HANDSHAKE_HINTS_READY;
+ return -1;
+
case ssl_hs_ok:
break;
}
@@ -698,6 +741,10 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) {
return -1;
}
if (hs->wait == ssl_hs_ok) {
+ if (!ssl->server) {
+ // On ECH reject, the handshake should never complete.
+ assert(ssl->s3->ech_status != ssl_ech_rejected);
+ }
// The handshake has completed.
*out_early_return = false;
return 1;
diff --git a/deps/boringssl/src/ssl/handshake_client.cc b/deps/boringssl/src/ssl/handshake_client.cc
index 59ef6ec..17b41e0 100644
--- a/deps/boringssl/src/ssl/handshake_client.cc
+++ b/deps/boringssl/src/ssl/handshake_client.cc
@@ -162,6 +162,7 @@
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#include <openssl/hpke.h>
#include <openssl/md5.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
@@ -201,7 +202,8 @@ enum ssl_client_hs_state_t {
// ssl_get_client_disabled sets |*out_mask_a| and |*out_mask_k| to masks of
// disabled algorithms.
-static void ssl_get_client_disabled(SSL_HANDSHAKE *hs, uint32_t *out_mask_a,
+static void ssl_get_client_disabled(const SSL_HANDSHAKE *hs,
+ uint32_t *out_mask_a,
uint32_t *out_mask_k) {
*out_mask_a = 0;
*out_mask_k = 0;
@@ -213,8 +215,9 @@ static void ssl_get_client_disabled(SSL_HANDSHAKE *hs, uint32_t *out_mask_a,
}
}
-static bool ssl_write_client_cipher_list(SSL_HANDSHAKE *hs, CBB *out) {
- SSL *const ssl = hs->ssl;
+static bool ssl_write_client_cipher_list(const SSL_HANDSHAKE *hs, CBB *out,
+ ssl_client_hello_type_t type) {
+ const SSL *const ssl = hs->ssl;
uint32_t mask_a, mask_k;
ssl_get_client_disabled(hs, &mask_a, &mask_k);
@@ -223,7 +226,7 @@ static bool ssl_write_client_cipher_list(SSL_HANDSHAKE *hs, CBB *out) {
return false;
}
- // Add a fake cipher suite. See draft-davidben-tls-grease-01.
+ // Add a fake cipher suite. See RFC 8701.
if (ssl->ctx->grease_enabled &&
!CBB_add_u16(&child, ssl_get_grease_value(hs, ssl_grease_cipher))) {
return false;
@@ -246,7 +249,7 @@ static bool ssl_write_client_cipher_list(SSL_HANDSHAKE *hs, CBB *out) {
}
}
- if (hs->min_version < TLS1_3_VERSION) {
+ if (hs->min_version < TLS1_3_VERSION && type != ssl_client_hello_inner) {
bool any_enabled = false;
for (const SSL_CIPHER *cipher : SSL_get_ciphers(ssl)) {
// Skip disabled ciphers
@@ -280,100 +283,161 @@ static bool ssl_write_client_cipher_list(SSL_HANDSHAKE *hs, CBB *out) {
return CBB_flush(out);
}
-bool ssl_write_client_hello(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- ScopedCBB cbb;
- CBB body;
- if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CLIENT_HELLO)) {
- return false;
- }
-
+bool ssl_write_client_hello_without_extensions(const SSL_HANDSHAKE *hs,
+ CBB *cbb,
+ ssl_client_hello_type_t type,
+ bool empty_session_id) {
+ const SSL *const ssl = hs->ssl;
CBB child;
- if (!CBB_add_u16(&body, hs->client_version) ||
- !CBB_add_bytes(&body, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
- !CBB_add_u8_length_prefixed(&body, &child)) {
+ if (!CBB_add_u16(cbb, hs->client_version) ||
+ !CBB_add_bytes(cbb,
+ type == ssl_client_hello_inner ? hs->inner_client_random
+ : ssl->s3->client_random,
+ SSL3_RANDOM_SIZE) ||
+ !CBB_add_u8_length_prefixed(cbb, &child)) {
return false;
}
// Do not send a session ID on renegotiation.
if (!ssl->s3->initial_handshake_complete &&
+ !empty_session_id &&
!CBB_add_bytes(&child, hs->session_id, hs->session_id_len)) {
return false;
}
if (SSL_is_dtls(ssl)) {
- if (!CBB_add_u8_length_prefixed(&body, &child) ||
+ if (!CBB_add_u8_length_prefixed(cbb, &child) ||
!CBB_add_bytes(&child, ssl->d1->cookie, ssl->d1->cookie_len)) {
return false;
}
}
- size_t header_len =
- SSL_is_dtls(ssl) ? DTLS1_HM_HEADER_LENGTH : SSL3_HM_HEADER_LENGTH;
- if (!ssl_write_client_cipher_list(hs, &body) ||
- !CBB_add_u8(&body, 1 /* one compression method */) ||
- !CBB_add_u8(&body, 0 /* null compression */) ||
- !ssl_add_clienthello_tlsext(hs, &body, header_len + CBB_len(&body))) {
+ if (!ssl_write_client_cipher_list(hs, cbb, type) ||
+ !CBB_add_u8(cbb, 1 /* one compression method */) ||
+ !CBB_add_u8(cbb, 0 /* null compression */)) {
return false;
}
+ return true;
+}
+bool ssl_add_client_hello(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+ ScopedCBB cbb;
+ CBB body;
+ ssl_client_hello_type_t type = hs->selected_ech_config
+ ? ssl_client_hello_outer
+ : ssl_client_hello_unencrypted;
+ bool needs_psk_binder;
Array<uint8_t> msg;
- if (!ssl->method->finish_message(ssl, cbb.get(), &msg)) {
+ if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CLIENT_HELLO) ||
+ !ssl_write_client_hello_without_extensions(hs, &body, type,
+ /*empty_session_id*/ false) ||
+ !ssl_add_clienthello_tlsext(hs, &body, /*out_encoded=*/nullptr,
+ &needs_psk_binder, type, CBB_len(&body)) ||
+ !ssl->method->finish_message(ssl, cbb.get(), &msg)) {
return false;
}
// Now that the length prefixes have been computed, fill in the placeholder
// PSK binder.
- if (hs->needs_psk_binder &&
- !tls13_write_psk_binder(hs, MakeSpan(msg))) {
- return false;
+ if (needs_psk_binder) {
+ // ClientHelloOuter cannot have a PSK binder. Otherwise the
+ // ClientHellOuterAAD computation would break.
+ assert(type != ssl_client_hello_outer);
+ if (!tls13_write_psk_binder(hs, hs->transcript, MakeSpan(msg),
+ /*out_binder_len=*/0)) {
+ return false;
+ }
}
return ssl->method->add_message(ssl, std::move(msg));
}
-static bool parse_supported_versions(SSL_HANDSHAKE *hs, uint16_t *version,
- const CBS *in) {
- // If the outer version is not TLS 1.2, or there is no extensions block, use
- // the outer version.
- if (*version != TLS1_2_VERSION || CBS_len(in) == 0) {
+static bool parse_server_version(const SSL_HANDSHAKE *hs, uint16_t *out_version,
+ uint8_t *out_alert,
+ const ParsedServerHello &server_hello) {
+ // If the outer version is not TLS 1.2, use it.
+ // TODO(davidben): This function doesn't quite match the RFC8446 formulation.
+ if (server_hello.legacy_version != TLS1_2_VERSION) {
+ *out_version = server_hello.legacy_version;
return true;
}
- SSL *const ssl = hs->ssl;
- CBS copy = *in, extensions;
- if (!CBS_get_u16_length_prefixed(&copy, &extensions) ||
- CBS_len(&copy) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ SSLExtension supported_versions(TLSEXT_TYPE_supported_versions);
+ CBS extensions = server_hello.extensions;
+ if (!ssl_parse_extensions(&extensions, out_alert, {&supported_versions},
+ /*ignore_unknown=*/true)) {
return false;
}
- bool have_supported_versions;
- CBS supported_versions;
- const SSL_EXTENSION_TYPE ext_types[] = {
- {TLSEXT_TYPE_supported_versions, &have_supported_versions,
- &supported_versions},
- };
-
- uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!ssl_parse_extensions(&extensions, &alert, ext_types,
- /*ignore_unknown=*/true)) {
- ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
- return false;
+ if (!supported_versions.present) {
+ *out_version = server_hello.legacy_version;
+ return true;
}
- // Override the outer version with the extension, if present.
- if (have_supported_versions &&
- (!CBS_get_u16(&supported_versions, version) ||
- CBS_len(&supported_versions) != 0)) {
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ if (!CBS_get_u16(&supported_versions.data, out_version) ||
+ CBS_len(&supported_versions.data) != 0) {
+ *out_alert = SSL_AD_DECODE_ERROR;
return false;
}
return true;
}
+// should_offer_early_data returns |ssl_early_data_accepted| if |hs| should
+// offer early data, and some other reason code otherwise.
+static ssl_early_data_reason_t should_offer_early_data(
+ const SSL_HANDSHAKE *hs) {
+ const SSL *const ssl = hs->ssl;
+ assert(!ssl->server);
+ if (!ssl->enable_early_data) {
+ return ssl_early_data_disabled;
+ }
+
+ if (hs->max_version < TLS1_3_VERSION) {
+ // We discard inapplicable sessions, so this is redundant with the session
+ // checks below, but reporting that TLS 1.3 was disabled is more useful.
+ return ssl_early_data_protocol_version;
+ }
+
+ if (ssl->session == nullptr) {
+ return ssl_early_data_no_session_offered;
+ }
+
+ if (ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION ||
+ ssl->session->ticket_max_early_data == 0) {
+ return ssl_early_data_unsupported_for_session;
+ }
+
+ if (!ssl->session->early_alpn.empty()) {
+ if (!ssl_is_alpn_protocol_allowed(hs, ssl->session->early_alpn)) {
+ // Avoid reporting a confusing value in |SSL_get0_alpn_selected|.
+ return ssl_early_data_alpn_mismatch;
+ }
+
+ // If the previous connection negotiated ALPS, only offer 0-RTT when the
+ // local are settings are consistent with what we'd offer for this
+ // connection.
+ if (ssl->session->has_application_settings) {
+ Span<const uint8_t> settings;
+ if (!ssl_get_local_application_settings(hs, &settings,
+ ssl->session->early_alpn) ||
+ settings != ssl->session->local_application_settings) {
+ return ssl_early_data_alps_mismatch;
+ }
+ }
+ }
+
+ // Early data has not yet been accepted, but we use it as a success code.
+ return ssl_early_data_accepted;
+}
+
+void ssl_done_writing_client_hello(SSL_HANDSHAKE *hs) {
+ hs->ech_client_outer.Reset();
+ hs->cookie.Reset();
+ hs->key_share_bytes.Reset();
+}
+
static enum ssl_hs_wait_t do_start_connect(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
@@ -386,6 +450,12 @@ static enum ssl_hs_wait_t do_start_connect(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
+ uint8_t ech_enc[EVP_HPKE_MAX_ENC_LENGTH];
+ size_t ech_enc_len;
+ if (!ssl_select_ech_config(hs, ech_enc, &ech_enc_len)) {
+ return ssl_hs_error;
+ }
+
// Always advertise the ClientHello version from the original maximum version,
// even on renegotiation. The static RSA key exchange uses this field, and
// some servers fail when it changes across handshakes.
@@ -397,34 +467,47 @@ static enum ssl_hs_wait_t do_start_connect(SSL_HANDSHAKE *hs) {
hs->max_version >= TLS1_2_VERSION ? TLS1_2_VERSION : hs->max_version;
}
- // If the configured session has expired or was created at a disabled
- // version, drop it.
- if (ssl->session != NULL) {
+ // If the configured session has expired or is not usable, drop it. We also do
+ // not offer sessions on renegotiation.
+ if (ssl->session != nullptr) {
if (ssl->session->is_server ||
!ssl_supports_version(hs, ssl->session->ssl_version) ||
- (ssl->session->session_id_length == 0 &&
- ssl->session->ticket.empty()) ||
- ssl->session->not_resumable ||
+ // Do not offer TLS 1.2 sessions with ECH. ClientHelloInner does not
+ // offer TLS 1.2, and the cleartext session ID may leak the server
+ // identity.
+ (hs->selected_ech_config &&
+ ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION) ||
+ !SSL_SESSION_is_resumable(ssl->session.get()) ||
!ssl_session_is_time_valid(ssl, ssl->session.get()) ||
- (ssl->quic_method != nullptr) != ssl->session->is_quic) {
- ssl_set_session(ssl, NULL);
+ (ssl->quic_method != nullptr) != ssl->session->is_quic ||
+ ssl->s3->initial_handshake_complete) {
+ ssl_set_session(ssl, nullptr);
}
}
if (!RAND_bytes(ssl->s3->client_random, sizeof(ssl->s3->client_random))) {
return ssl_hs_error;
}
+ if (hs->selected_ech_config &&
+ !RAND_bytes(hs->inner_client_random, sizeof(hs->inner_client_random))) {
+ return ssl_hs_error;
+ }
// Never send a session ID in QUIC. QUIC uses TLS 1.3 at a minimum and
// disables TLS 1.3 middlebox compatibility mode.
if (ssl->quic_method == nullptr) {
- if (ssl->session != nullptr && !ssl->s3->initial_handshake_complete &&
- ssl->session->session_id_length > 0) {
+ const bool has_id_session = ssl->session != nullptr &&
+ ssl->session->session_id_length > 0 &&
+ ssl->session->ticket.empty();
+ const bool has_ticket_session =
+ ssl->session != nullptr && !ssl->session->ticket.empty();
+ if (has_id_session) {
hs->session_id_len = ssl->session->session_id_length;
OPENSSL_memcpy(hs->session_id, ssl->session->session_id,
hs->session_id_len);
- } else if (hs->max_version >= TLS1_3_VERSION) {
- // Initialize a random session ID.
+ } else if (has_ticket_session || hs->max_version >= TLS1_3_VERSION) {
+ // Send a random session ID. TLS 1.3 always sends one, and TLS 1.2 session
+ // tickets require a placeholder value to signal resumption.
hs->session_id_len = sizeof(hs->session_id);
if (!RAND_bytes(hs->session_id, hs->session_id_len)) {
return ssl_hs_error;
@@ -432,7 +515,17 @@ static enum ssl_hs_wait_t do_start_connect(SSL_HANDSHAKE *hs) {
}
}
- if (!ssl_write_client_hello(hs)) {
+ ssl_early_data_reason_t reason = should_offer_early_data(hs);
+ if (reason != ssl_early_data_accepted) {
+ ssl->s3->early_data_reason = reason;
+ } else {
+ hs->early_data_offered = true;
+ }
+
+ if (!ssl_setup_key_shares(hs, /*override_group_id=*/0) ||
+ !ssl_setup_extension_permutation(hs) ||
+ !ssl_encrypt_client_hello(hs, MakeConstSpan(ech_enc, ech_enc_len)) ||
+ !ssl_add_client_hello(hs)) {
return ssl_hs_error;
}
@@ -458,9 +551,7 @@ static enum ssl_hs_wait_t do_enter_early_data(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- if (!tls13_init_early_key_schedule(
- hs,
- MakeConstSpan(ssl->session->secret, ssl->session->secret_length)) ||
+ if (!tls13_init_early_key_schedule(hs, ssl->session.get()) ||
!tls13_derive_early_secret(hs)) {
return ssl_hs_error;
}
@@ -511,6 +602,10 @@ static enum ssl_hs_wait_t do_read_hello_verify_request(SSL_HANDSHAKE *hs) {
assert(SSL_is_dtls(ssl));
+ // When implementing DTLS 1.3, we need to handle the interactions between
+ // HelloVerifyRequest, DTLS 1.3's HelloVerifyRequest removal, and ECH.
+ assert(hs->max_version < TLS1_3_VERSION);
+
SSLMessage msg;
if (!ssl->method->get_message(ssl, &msg)) {
return ssl_hs_read_message;
@@ -542,7 +637,7 @@ static enum ssl_hs_wait_t do_read_hello_verify_request(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- if (!ssl_write_client_hello(hs)) {
+ if (!ssl_add_client_hello(hs)) {
return ssl_hs_error;
}
@@ -550,6 +645,38 @@ static enum ssl_hs_wait_t do_read_hello_verify_request(SSL_HANDSHAKE *hs) {
return ssl_hs_flush;
}
+bool ssl_parse_server_hello(ParsedServerHello *out, uint8_t *out_alert,
+ const SSLMessage &msg) {
+ if (msg.type != SSL3_MT_SERVER_HELLO) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+ *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+ return false;
+ }
+ out->raw = msg.raw;
+ CBS body = msg.body;
+ if (!CBS_get_u16(&body, &out->legacy_version) ||
+ !CBS_get_bytes(&body, &out->random, SSL3_RANDOM_SIZE) ||
+ !CBS_get_u8_length_prefixed(&body, &out->session_id) ||
+ CBS_len(&out->session_id) > SSL3_SESSION_ID_SIZE ||
+ !CBS_get_u16(&body, &out->cipher_suite) ||
+ !CBS_get_u8(&body, &out->compression_method)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return false;
+ }
+ // In TLS 1.2 and below, empty extensions blocks may be omitted. In TLS 1.3,
+ // ServerHellos always have extensions, so this can be applied generically.
+ CBS_init(&out->extensions, nullptr, 0);
+ if ((CBS_len(&body) != 0 &&
+ !CBS_get_u16_length_prefixed(&body, &out->extensions)) ||
+ CBS_len(&body) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return false;
+ }
+ return true;
+}
+
static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
SSLMessage msg;
@@ -557,26 +684,12 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_read_server_hello;
}
- if (!ssl_check_message_type(ssl, msg, SSL3_MT_SERVER_HELLO)) {
- return ssl_hs_error;
- }
-
- CBS server_hello = msg.body, server_random, session_id;
- uint16_t server_version, cipher_suite;
- uint8_t compression_method;
- if (!CBS_get_u16(&server_hello, &server_version) ||
- !CBS_get_bytes(&server_hello, &server_random, SSL3_RANDOM_SIZE) ||
- !CBS_get_u8_length_prefixed(&server_hello, &session_id) ||
- CBS_len(&session_id) > SSL3_SESSION_ID_SIZE ||
- !CBS_get_u16(&server_hello, &cipher_suite) ||
- !CBS_get_u8(&server_hello, &compression_method)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
-
- // Use the supported_versions extension if applicable.
- if (!parse_supported_versions(hs, &server_version, &server_hello)) {
+ ParsedServerHello server_hello;
+ uint16_t server_version;
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ssl_parse_server_hello(&server_hello, &alert, msg) ||
+ !parse_server_version(hs, &server_version, &alert, server_hello)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
@@ -607,19 +720,30 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
// Clear some TLS 1.3 state that no longer needs to be retained.
hs->key_shares[0].reset();
hs->key_shares[1].reset();
- hs->key_share_bytes.Reset();
+ ssl_done_writing_client_hello(hs);
// A TLS 1.2 server would not know to skip the early data we offered. Report
// an error code sooner. The caller may use this error code to implement the
// fallback described in RFC 8446 appendix D.3.
if (hs->early_data_offered) {
+ // Disconnect early writes. This ensures subsequent |SSL_write| calls query
+ // the handshake which, in turn, will replay the error code rather than fail
+ // at the |write_shutdown| check. See https://crbug.com/1078515.
+ // TODO(davidben): Should all handshake errors do this? What about record
+ // decryption failures?
+ hs->can_early_write = false;
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_ON_EARLY_DATA);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
return ssl_hs_error;
}
+ // TLS 1.2 handshakes cannot accept ECH.
+ if (hs->selected_ech_config) {
+ ssl->s3->ech_status = ssl_ech_rejected;
+ }
+
// Copy over the server random.
- OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random),
+ OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_hello.random),
SSL3_RANDOM_SIZE);
// Enforce the TLS 1.3 anti-downgrade feature.
@@ -642,64 +766,44 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
}
}
- if (!ssl->s3->initial_handshake_complete && ssl->session != nullptr &&
- ssl->session->session_id_length != 0 &&
- CBS_mem_equal(&session_id, ssl->session->session_id,
- ssl->session->session_id_length)) {
- ssl->s3->session_reused = true;
- } else {
- // The server may also have echoed back the TLS 1.3 compatibility mode
- // session ID. As we know this is not a session the server knows about, any
- // server resuming it is in error. Reject the first connection
- // deterministicly, rather than installing an invalid session into the
- // session cache. https://crbug.com/796910
- if (hs->session_id_len != 0 &&
- CBS_mem_equal(&session_id, hs->session_id, hs->session_id_len)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_ECHOED_INVALID_SESSION_ID);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
-
- // The session wasn't resumed. Create a fresh SSL_SESSION to
- // fill out.
- ssl_set_session(ssl, NULL);
- if (!ssl_get_new_session(hs, 0 /* client */)) {
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return ssl_hs_error;
- }
- // Note: session_id could be empty.
- hs->new_session->session_id_length = CBS_len(&session_id);
- OPENSSL_memcpy(hs->new_session->session_id, CBS_data(&session_id),
- CBS_len(&session_id));
- }
-
- const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
- if (cipher == NULL) {
- // unknown cipher
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
-
// The cipher must be allowed in the selected version and enabled.
+ const SSL_CIPHER *cipher = SSL_get_cipher_by_value(server_hello.cipher_suite);
uint32_t mask_a, mask_k;
ssl_get_client_disabled(hs, &mask_a, &mask_k);
- if ((cipher->algorithm_mkey & mask_k) || (cipher->algorithm_auth & mask_a) ||
+ if (cipher == nullptr ||
+ (cipher->algorithm_mkey & mask_k) ||
+ (cipher->algorithm_auth & mask_a) ||
SSL_CIPHER_get_min_version(cipher) > ssl_protocol_version(ssl) ||
SSL_CIPHER_get_max_version(cipher) < ssl_protocol_version(ssl) ||
- !sk_SSL_CIPHER_find(SSL_get_ciphers(ssl), NULL, cipher)) {
+ !sk_SSL_CIPHER_find(SSL_get_ciphers(ssl), nullptr, cipher)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
- if (ssl->session != NULL) {
+ hs->new_cipher = cipher;
+
+ if (hs->session_id_len != 0 &&
+ CBS_mem_equal(&server_hello.session_id, hs->session_id,
+ hs->session_id_len)) {
+ // Echoing the ClientHello session ID in TLS 1.2, whether from the session
+ // or a synthetic one, indicates resumption. If there was no session (or if
+ // the session was only offered in ECH ClientHelloInner), this was the
+ // TLS 1.3 compatibility mode session ID. As we know this is not a session
+ // the server knows about, any server resuming it is in error. Reject the
+ // first connection deterministicly, rather than installing an invalid
+ // session into the session cache. https://crbug.com/796910
+ if (ssl->session == nullptr || ssl->s3->ech_status == ssl_ech_rejected) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_ECHOED_INVALID_SESSION_ID);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_hs_error;
+ }
if (ssl->session->ssl_version != ssl->version) {
OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
- if (ssl->session->cipher != cipher) {
+ if (ssl->session->cipher != hs->new_cipher) {
OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
@@ -711,10 +815,23 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
+ // We never offer sessions on renegotiation.
+ assert(!ssl->s3->initial_handshake_complete);
+ ssl->s3->session_reused = true;
} else {
- hs->new_session->cipher = cipher;
+ // The session wasn't resumed. Create a fresh SSL_SESSION to fill out.
+ ssl_set_session(ssl, NULL);
+ if (!ssl_get_new_session(hs)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ // Note: session_id could be empty.
+ hs->new_session->session_id_length = CBS_len(&server_hello.session_id);
+ OPENSSL_memcpy(hs->new_session->session_id,
+ CBS_data(&server_hello.session_id),
+ CBS_len(&server_hello.session_id));
+ hs->new_session->cipher = hs->new_cipher;
}
- hs->new_cipher = cipher;
// Now that the cipher is known, initialize the handshake hash and hash the
// ServerHello.
@@ -733,26 +850,17 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
}
// Only the NULL compression algorithm is supported.
- if (compression_method != 0) {
+ if (server_hello.compression_method != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
- // TLS extensions
- if (!ssl_parse_serverhello_tlsext(hs, &server_hello)) {
+ if (!ssl_parse_serverhello_tlsext(hs, &server_hello.extensions)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
return ssl_hs_error;
}
- // There should be nothing left over in the record.
- if (CBS_len(&server_hello) != 0) {
- // wrong packet length
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
-
if (ssl->session != NULL &&
hs->extended_master_secret != ssl->session->extended_master_secret) {
if (ssl->session->extended_master_secret) {
@@ -764,13 +872,6 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- if (ssl->s3->token_binding_negotiated &&
- (!hs->extended_master_secret || !ssl->s3->send_connection_binding)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_TB_WITHOUT_EMS_OR_RI);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return ssl_hs_error;
- }
-
ssl->method->next_message(ssl);
if (ssl->session != NULL) {
@@ -1219,8 +1320,12 @@ static enum ssl_hs_wait_t do_send_client_certificate(SSL_HANDSHAKE *hs) {
return ssl_hs_ok;
}
- // Call cert_cb to update the certificate.
- if (hs->config->cert->cert_cb != NULL) {
+ if (ssl->s3->ech_status == ssl_ech_rejected) {
+ // Do not send client certificates on ECH reject. We have not authenticated
+ // the server for the name that can learn the certificate.
+ SSL_certs_clear(ssl);
+ } else if (hs->config->cert->cert_cb != nullptr) {
+ // Call cert_cb to update the certificate.
int rv = hs->config->cert->cert_cb(ssl, hs->config->cert->cert_cb_arg);
if (rv == 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
@@ -1482,18 +1587,7 @@ static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_send_client_finished(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- // Resolve Channel ID first, before any non-idempotent operations.
- if (ssl->s3->channel_id_valid) {
- if (!ssl_do_channel_id_callback(hs)) {
- return ssl_hs_error;
- }
-
- if (hs->config->channel_id_private == NULL) {
- hs->state = state_send_client_finished;
- return ssl_hs_channel_id_lookup;
- }
- }
-
+ hs->can_release_private_key = true;
if (!ssl->method->add_change_cipher_spec(ssl) ||
!tls1_change_cipher_state(hs, evp_aead_seal)) {
return ssl_hs_error;
@@ -1518,7 +1612,7 @@ static enum ssl_hs_wait_t do_send_client_finished(SSL_HANDSHAKE *hs) {
}
}
- if (ssl->s3->channel_id_valid) {
+ if (hs->channel_id_negotiated) {
ScopedCBB cbb;
CBB body;
if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CHANNEL_ID) ||
@@ -1538,7 +1632,7 @@ static enum ssl_hs_wait_t do_send_client_finished(SSL_HANDSHAKE *hs) {
}
static bool can_false_start(const SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
+ const SSL *const ssl = hs->ssl;
// False Start bypasses the Finished check's downgrade protection. This can
// enable attacks where we send data under weaker settings than supported
@@ -1556,6 +1650,13 @@ static bool can_false_start(const SSL_HANDSHAKE *hs) {
return false;
}
+ // If ECH was rejected, disable False Start. We run the handshake to
+ // completion, including the Finished downgrade check, to authenticate the
+ // recovery flow.
+ if (ssl->s3->ech_status == ssl_ech_rejected) {
+ return false;
+ }
+
// Additionally require ALPN or NPN by default.
//
// TODO(davidben): Can this constraint be relaxed globally now that cipher
@@ -1635,40 +1736,30 @@ static enum ssl_hs_wait_t do_read_session_ticket(SSL_HANDSHAKE *hs) {
return ssl_hs_read_change_cipher_spec;
}
- SSL_SESSION *session = hs->new_session.get();
- UniquePtr<SSL_SESSION> renewed_session;
- if (ssl->session != NULL) {
+ if (ssl->session != nullptr) {
// The server is sending a new ticket for an existing session. Sessions are
// immutable once established, so duplicate all but the ticket of the
// existing session.
- renewed_session =
+ assert(!hs->new_session);
+ hs->new_session =
SSL_SESSION_dup(ssl->session.get(), SSL_SESSION_INCLUDE_NONAUTH);
- if (!renewed_session) {
- // This should never happen.
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ if (!hs->new_session) {
return ssl_hs_error;
}
- session = renewed_session.get();
}
// |ticket_lifetime_hint| is measured from when the ticket was issued.
- ssl_session_rebase_time(ssl, session);
+ ssl_session_rebase_time(ssl, hs->new_session.get());
- if (!session->ticket.CopyFrom(ticket)) {
+ if (!hs->new_session->ticket.CopyFrom(ticket)) {
return ssl_hs_error;
}
- session->ticket_lifetime_hint = ticket_lifetime_hint;
-
- // Generate a session ID for this session. Some callers expect all sessions to
- // have a session ID. Additionally, it acts as the session ID to signal
- // resumption.
- SHA256(CBS_data(&ticket), CBS_len(&ticket), session->session_id);
- session->session_id_length = SHA256_DIGEST_LENGTH;
+ hs->new_session->ticket_lifetime_hint = ticket_lifetime_hint;
- if (renewed_session) {
- session->not_resumable = false;
- ssl->session = std::move(renewed_session);
- }
+ // Historically, OpenSSL filled in fake session IDs for ticket-based sessions.
+ // TODO(davidben): Are external callers relying on this? Try removing this.
+ SHA256(CBS_data(&ticket), CBS_len(&ticket), hs->new_session->session_id);
+ hs->new_session->session_id_length = SHA256_DIGEST_LENGTH;
ssl->method->next_message(ssl);
hs->state = state_process_change_cipher_spec;
@@ -1702,15 +1793,25 @@ static enum ssl_hs_wait_t do_read_server_finished(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_finish_client_handshake(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+ if (ssl->s3->ech_status == ssl_ech_rejected) {
+ // Release the retry configs.
+ hs->ech_authenticated_reject = true;
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ECH_REQUIRED);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ECH_REJECTED);
+ return ssl_hs_error;
+ }
ssl->method->on_handshake_complete(ssl);
- if (ssl->session != NULL) {
- ssl->s3->established_session = UpRef(ssl->session);
- } else {
- // We make a copy of the session in order to maintain the immutability
- // of the new established_session due to False Start. The caller may
- // have taken a reference to the temporary session.
+ // Note TLS 1.2 resumptions with ticket renewal have both |ssl->session| (the
+ // resumed session) and |hs->new_session| (the session with the new ticket).
+ bool has_new_session = hs->new_session != nullptr;
+ if (has_new_session) {
+ // When False Start is enabled, the handshake reports completion early. The
+ // caller may then have passed the (then unresuable) |hs->new_session| to
+ // another thread via |SSL_get0_session| for resumption. To avoid potential
+ // race conditions in such callers, we duplicate the session before
+ // clearing |not_resumable|.
ssl->s3->established_session =
SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_DUP_ALL);
if (!ssl->s3->established_session) {
@@ -1722,11 +1823,16 @@ static enum ssl_hs_wait_t do_finish_client_handshake(SSL_HANDSHAKE *hs) {
}
hs->new_session.reset();
+ } else {
+ assert(ssl->session != nullptr);
+ ssl->s3->established_session = UpRef(ssl->session);
}
hs->handshake_finalized = true;
ssl->s3->initial_handshake_complete = true;
- ssl_update_cache(hs, SSL_SESS_CACHE_CLIENT);
+ if (has_new_session) {
+ ssl_update_cache(ssl);
+ }
hs->state = state_done;
return ssl_hs_ok;
diff --git a/deps/boringssl/src/ssl/handshake_server.cc b/deps/boringssl/src/ssl/handshake_server.cc
index bc0a0d1..fdf9511 100644
--- a/deps/boringssl/src/ssl/handshake_server.cc
+++ b/deps/boringssl/src/ssl/handshake_server.cc
@@ -154,6 +154,8 @@
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/cipher.h>
+#include <openssl/curve25519.h>
+#include <openssl/digest.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
@@ -502,6 +504,91 @@ static bool is_probably_jdk11_with_tls13(const SSL_CLIENT_HELLO *client_hello) {
return true;
}
+static bool decrypt_ech(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ const SSL_CLIENT_HELLO *client_hello) {
+ SSL *const ssl = hs->ssl;
+ CBS body;
+ if (!ssl_client_hello_get_extension(client_hello, &body,
+ TLSEXT_TYPE_encrypted_client_hello)) {
+ return true;
+ }
+ uint8_t type;
+ if (!CBS_get_u8(&body, &type)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return false;
+ }
+ if (type != ECH_CLIENT_OUTER) {
+ return true;
+ }
+ // This is a ClientHelloOuter ECH extension. Attempt to decrypt it.
+ uint8_t config_id;
+ uint16_t kdf_id, aead_id;
+ CBS enc, payload;
+ if (!CBS_get_u16(&body, &kdf_id) || //
+ !CBS_get_u16(&body, &aead_id) || //
+ !CBS_get_u8(&body, &config_id) ||
+ !CBS_get_u16_length_prefixed(&body, &enc) ||
+ !CBS_get_u16_length_prefixed(&body, &payload) || //
+ CBS_len(&body) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return false;
+ }
+
+ {
+ MutexReadLock lock(&ssl->ctx->lock);
+ hs->ech_keys = UpRef(ssl->ctx->ech_keys);
+ }
+
+ if (!hs->ech_keys) {
+ ssl->s3->ech_status = ssl_ech_rejected;
+ return true;
+ }
+
+ for (const auto &config : hs->ech_keys->configs) {
+ hs->ech_hpke_ctx.Reset();
+ if (config_id != config->ech_config().config_id ||
+ !config->SetupContext(hs->ech_hpke_ctx.get(), kdf_id, aead_id, enc)) {
+ // Ignore the error and try another ECHConfig.
+ ERR_clear_error();
+ continue;
+ }
+ Array<uint8_t> encoded_client_hello_inner;
+ bool is_decrypt_error;
+ if (!ssl_client_hello_decrypt(hs->ech_hpke_ctx.get(),
+ &encoded_client_hello_inner,
+ &is_decrypt_error, client_hello, payload)) {
+ if (is_decrypt_error) {
+ // Ignore the error and try another ECHConfig.
+ ERR_clear_error();
+ continue;
+ }
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
+ return false;
+ }
+
+ // Recover the ClientHelloInner from the EncodedClientHelloInner.
+ bssl::Array<uint8_t> client_hello_inner;
+ if (!ssl_decode_client_hello_inner(ssl, out_alert, &client_hello_inner,
+ encoded_client_hello_inner,
+ client_hello)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return false;
+ }
+ hs->ech_client_hello_buf = std::move(client_hello_inner);
+ hs->ech_config_id = config_id;
+ ssl->s3->ech_status = ssl_ech_accepted;
+ return true;
+ }
+
+ // If we did not accept ECH, proceed with the ClientHelloOuter. Note this
+ // could be key mismatch or ECH GREASE, so we must complete the handshake
+ // as usual, except EncryptedExtensions will contain retry configs.
+ ssl->s3->ech_status = ssl_ech_rejected;
+ return true;
+}
+
static bool extract_sni(SSL_HANDSHAKE *hs, uint8_t *out_alert,
const SSL_CLIENT_HELLO *client_hello) {
SSL *const ssl = hs->ssl;
@@ -563,7 +650,7 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
}
SSL_CLIENT_HELLO client_hello;
- if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
+ if (!ssl_client_hello_init(ssl, &client_hello, msg.body)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
@@ -582,11 +669,36 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
}
uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!decrypt_ech(hs, &alert, &client_hello)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
+ // ECH may have changed which ClientHello we process. Update |msg| and
+ // |client_hello| in case.
+ if (!hs->GetClientHello(&msg, &client_hello)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+
if (!extract_sni(hs, &alert, &client_hello)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
+ hs->state = state12_read_client_hello_after_ech;
+ return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_read_client_hello_after_ech(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
+
+ SSLMessage msg_unused;
+ SSL_CLIENT_HELLO client_hello;
+ if (!hs->GetClientHello(&msg_unused, &client_hello)) {
+ return ssl_hs_error;
+ }
+
// Run the early callback.
if (ssl->ctx->select_certificate_cb != NULL) {
switch (ssl->ctx->select_certificate_cb(&client_hello)) {
@@ -614,6 +726,7 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
hs->apply_jdk11_workaround = true;
}
+ uint8_t alert = SSL_AD_DECODE_ERROR;
if (!negotiate_version(hs, &alert, &client_hello)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
@@ -644,12 +757,6 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- if (hs->ech_present && hs->ech_is_inner_present) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
-
hs->state = state12_select_certificate;
return ssl_hs_ok;
}
@@ -657,11 +764,6 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- SSLMessage msg;
- if (!ssl->method->get_message(ssl, &msg)) {
- return ssl_hs_read_message;
- }
-
// Call |cert_cb| to update server certificates if required.
if (hs->config->cert->cert_cb != NULL) {
int rv = hs->config->cert->cert_cb(ssl, hs->config->cert->cert_cb_arg);
@@ -701,10 +803,22 @@ static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {
return ssl_hs_ok;
}
+ // It should not be possible to negotiate TLS 1.2 with ECH. The
+ // ClientHelloInner decoding function rejects ClientHellos which offer TLS 1.2
+ // or below.
+ assert(ssl->s3->ech_status != ssl_ech_accepted);
+
+ // TODO(davidben): Also compute hints for TLS 1.2. When doing so, update the
+ // check in bssl_shim.cc to test this.
+ if (hs->hints_requested) {
+ return ssl_hs_hints_ready;
+ }
+
ssl->s3->early_data_reason = ssl_early_data_protocol_version;
+ SSLMessage msg_unused;
SSL_CLIENT_HELLO client_hello;
- if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
+ if (!hs->GetClientHello(&msg_unused, &client_hello)) {
return ssl_hs_error;
}
@@ -743,10 +857,15 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
}
SSL_CLIENT_HELLO client_hello;
- if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
+ if (!ssl_client_hello_init(ssl, &client_hello, msg.body)) {
return ssl_hs_error;
}
+ hs->session_id_len = client_hello.session_id_len;
+ // This is checked in |ssl_client_hello_init|.
+ assert(hs->session_id_len <= sizeof(hs->session_id));
+ OPENSSL_memcpy(hs->session_id, client_hello.session_id, hs->session_id_len);
+
// Determine whether we are doing session resumption.
UniquePtr<SSL_SESSION> session;
bool tickets_supported = false, renew_ticket = false;
@@ -778,16 +897,20 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
hs->ticket_expected = renew_ticket;
ssl->session = std::move(session);
ssl->s3->session_reused = true;
+ hs->can_release_private_key = true;
} else {
hs->ticket_expected = tickets_supported;
- ssl_set_session(ssl, NULL);
- if (!ssl_get_new_session(hs, 1 /* server */)) {
+ ssl_set_session(ssl, nullptr);
+ if (!ssl_get_new_session(hs)) {
return ssl_hs_error;
}
- // Clear the session ID if we want the session to be single-use.
- if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
- hs->new_session->session_id_length = 0;
+ // Assign a session ID if not using session tickets.
+ if (!hs->ticket_expected &&
+ (ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
+ hs->new_session->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
+ RAND_bytes(hs->new_session->session_id,
+ hs->new_session->session_id_length);
}
}
@@ -806,7 +929,7 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
hs->cert_request = !!(hs->config->verify_mode & SSL_VERIFY_PEER);
// Only request a certificate if Channel ID isn't negotiated.
if ((hs->config->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) &&
- ssl->s3->channel_id_valid) {
+ hs->channel_id_negotiated) {
hs->cert_request = false;
}
// CertificateRequest may only be sent in certificate-based ciphers.
@@ -850,8 +973,7 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
}
static void copy_suffix(Span<uint8_t> out, Span<const uint8_t> in) {
- out = out.subspan(out.size() - in.size());
- assert(out.size() == in.size());
+ out = out.last(in.size());
OPENSSL_memcpy(out.data(), in.data(), in.size());
}
@@ -860,9 +982,9 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
// We only accept ChannelIDs on connections with ECDHE in order to avoid a
// known attack while we fix ChannelID itself.
- if (ssl->s3->channel_id_valid &&
+ if (hs->channel_id_negotiated &&
(hs->new_cipher->algorithm_mkey & SSL_kECDHE) == 0) {
- ssl->s3->channel_id_valid = false;
+ hs->channel_id_negotiated = false;
}
// If this is a resumption and the original handshake didn't support
@@ -870,7 +992,7 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
// session and so cannot resume with ChannelIDs.
if (ssl->session != NULL &&
ssl->session->original_handshake_hash_len == 0) {
- ssl->s3->channel_id_valid = false;
+ hs->channel_id_negotiated = false;
}
struct OPENSSL_timeval now;
@@ -901,19 +1023,22 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
}
}
- const SSL_SESSION *session = hs->new_session.get();
+ Span<const uint8_t> session_id;
if (ssl->session != nullptr) {
- session = ssl->session.get();
+ // Echo the session ID from the ClientHello to indicate resumption.
+ session_id = MakeConstSpan(hs->session_id, hs->session_id_len);
+ } else {
+ session_id = MakeConstSpan(hs->new_session->session_id,
+ hs->new_session->session_id_length);
}
ScopedCBB cbb;
- CBB body, session_id;
+ CBB body, session_id_bytes;
if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_SERVER_HELLO) ||
!CBB_add_u16(&body, ssl->version) ||
!CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) ||
- !CBB_add_u8_length_prefixed(&body, &session_id) ||
- !CBB_add_bytes(&session_id, session->session_id,
- session->session_id_length) ||
+ !CBB_add_u8_length_prefixed(&body, &session_id_bytes) ||
+ !CBB_add_bytes(&session_id_bytes, session_id.data(), session_id.size()) ||
!CBB_add_u16(&body, SSL_CIPHER_get_protocol_id(hs->new_cipher)) ||
!CBB_add_u8(&body, 0 /* no compression */) ||
!ssl_add_serverhello_tlsext(hs, &body) ||
@@ -1083,6 +1208,7 @@ static enum ssl_hs_wait_t do_send_server_key_exchange(SSL_HANDSHAKE *hs) {
}
}
+ hs->can_release_private_key = true;
if (!ssl_add_message_cbb(ssl, cbb.get())) {
return ssl_hs_error;
}
@@ -1415,6 +1541,7 @@ static enum ssl_hs_wait_t do_read_client_key_exchange(SSL_HANDSHAKE *hs) {
}
hs->new_session->extended_master_secret = hs->extended_master_secret;
CONSTTIME_DECLASSIFY(hs->new_session->secret, hs->new_session->secret_length);
+ hs->can_release_private_key = true;
ssl->method->next_message(ssl);
hs->state = state12_read_client_certificate_verify;
@@ -1556,7 +1683,7 @@ static enum ssl_hs_wait_t do_read_next_proto(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_read_channel_id(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- if (!ssl->s3->channel_id_valid) {
+ if (!hs->channel_id_negotiated) {
hs->state = state12_read_client_finished;
return ssl_hs_ok;
}
@@ -1666,16 +1793,21 @@ static enum ssl_hs_wait_t do_finish_server_handshake(SSL_HANDSHAKE *hs) {
ssl->ctx->x509_method->session_clear(hs->new_session.get());
}
- if (ssl->session != NULL) {
- ssl->s3->established_session = UpRef(ssl->session);
- } else {
+ bool has_new_session = hs->new_session != nullptr;
+ if (has_new_session) {
+ assert(ssl->session == nullptr);
ssl->s3->established_session = std::move(hs->new_session);
ssl->s3->established_session->not_resumable = false;
+ } else {
+ assert(ssl->session != nullptr);
+ ssl->s3->established_session = UpRef(ssl->session);
}
hs->handshake_finalized = true;
ssl->s3->initial_handshake_complete = true;
- ssl_update_cache(hs, SSL_SESS_CACHE_SERVER);
+ if (has_new_session) {
+ ssl_update_cache(ssl);
+ }
hs->state = state12_done;
return ssl_hs_ok;
@@ -1693,6 +1825,9 @@ enum ssl_hs_wait_t ssl_server_handshake(SSL_HANDSHAKE *hs) {
case state12_read_client_hello:
ret = do_read_client_hello(hs);
break;
+ case state12_read_client_hello_after_ech:
+ ret = do_read_client_hello_after_ech(hs);
+ break;
case state12_select_certificate:
ret = do_select_certificate(hs);
break;
@@ -1773,6 +1908,8 @@ const char *ssl_server_handshake_state(SSL_HANDSHAKE *hs) {
return "TLS server start_accept";
case state12_read_client_hello:
return "TLS server read_client_hello";
+ case state12_read_client_hello_after_ech:
+ return "TLS server read_client_hello_after_ech";
case state12_select_certificate:
return "TLS server select_certificate";
case state12_tls13:
diff --git a/deps/boringssl/src/ssl/internal.h b/deps/boringssl/src/ssl/internal.h
index b3b7540..ab23d29 100644
--- a/deps/boringssl/src/ssl/internal.h
+++ b/deps/boringssl/src/ssl/internal.h
@@ -146,13 +146,16 @@
#include <stdlib.h>
+#include <initializer_list>
#include <limits>
#include <new>
#include <type_traits>
#include <utility>
#include <openssl/aead.h>
+#include <openssl/curve25519.h>
#include <openssl/err.h>
+#include <openssl/hpke.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/span.h>
@@ -161,6 +164,7 @@
#include "../crypto/err/internal.h"
#include "../crypto/internal.h"
+#include "../crypto/lhash/internal.h"
#if defined(OPENSSL_WINDOWS)
@@ -276,9 +280,9 @@ class Array {
T &operator[](size_t i) { return data_[i]; }
T *begin() { return data_; }
- const T *cbegin() const { return data_; }
+ const T *begin() const { return data_; }
T *end() { return data_ + size_; }
- const T *cend() const { return data_ + size_; }
+ const T *end() const { return data_ + size_; }
void Reset() { Reset(nullptr, 0); }
@@ -378,6 +382,8 @@ class GrowableArray {
return *this;
}
+ const T *data() const { return array_.data(); }
+ T *data() { return array_.data(); }
size_t size() const { return size_; }
bool empty() const { return size_ == 0; }
@@ -385,9 +391,9 @@ class GrowableArray {
T &operator[](size_t i) { return array_[i]; }
T *begin() { return array_.data(); }
- const T *cbegin() const { return array_.data(); }
+ const T *begin() const { return array_.data(); }
T *end() { return array_.data() + size_; }
- const T *cend() const { return array_.data() + size_; }
+ const T *end() const { return array_.data() + size_; }
void clear() {
size_ = 0;
@@ -484,15 +490,17 @@ bool ssl_get_version_range(const SSL_HANDSHAKE *hs, uint16_t *out_min_version,
uint16_t *out_max_version);
// ssl_supports_version returns whether |hs| supports |version|.
-bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version);
+bool ssl_supports_version(const SSL_HANDSHAKE *hs, uint16_t version);
// ssl_method_supports_version returns whether |method| supports |version|.
bool ssl_method_supports_version(const SSL_PROTOCOL_METHOD *method,
uint16_t version);
// ssl_add_supported_versions writes the supported versions of |hs| to |cbb|, in
-// decreasing preference order.
-bool ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb);
+// decreasing preference order. The version list is filtered to those whose
+// protocol version is at least |extra_min_version|.
+bool ssl_add_supported_versions(const SSL_HANDSHAKE *hs, CBB *cbb,
+ uint16_t extra_min_version);
// ssl_negotiate_version negotiates a common version based on |hs|'s preferences
// and the peer preference list in |peer_versions|. On success, it returns true
@@ -675,6 +683,9 @@ class SSLTranscript {
SSLTranscript();
~SSLTranscript();
+ SSLTranscript(SSLTranscript &&other) = default;
+ SSLTranscript &operator=(SSLTranscript &&other) = default;
+
// Init initializes the handshake transcript. If called on an existing
// transcript, it resets the transcript and hash. It returns true on success
// and false on failure.
@@ -683,7 +694,8 @@ class SSLTranscript {
// InitHash initializes the handshake hash based on the PRF and contents of
// the handshake transcript. Subsequent calls to |Update| will update the
// rolling hash. It returns one on success and zero on failure. It is an error
- // to call this function after the handshake buffer is released.
+ // to call this function after the handshake buffer is released. This may be
+ // called multiple times to change the hash function.
bool InitHash(uint16_t version, const SSL_CIPHER *cipher);
// UpdateForHelloRetryRequest resets the rolling hash with the
@@ -696,9 +708,9 @@ class SSLTranscript {
// the transcript. It returns true on success and false on failure. If the
// handshake buffer is still present, |digest| may be any supported digest.
// Otherwise, |digest| must match the transcript hash.
- bool CopyToHashContext(EVP_MD_CTX *ctx, const EVP_MD *digest);
+ bool CopyToHashContext(EVP_MD_CTX *ctx, const EVP_MD *digest) const;
- Span<const uint8_t> buffer() {
+ Span<const uint8_t> buffer() const {
return MakeConstSpan(reinterpret_cast<const uint8_t *>(buffer_->data),
buffer_->length);
}
@@ -721,14 +733,14 @@ class SSLTranscript {
// GetHash writes the handshake hash to |out| which must have room for at
// least |DigestLen| bytes. On success, it returns true and sets |*out_len| to
// the number of bytes written. Otherwise, it returns false.
- bool GetHash(uint8_t *out, size_t *out_len);
+ bool GetHash(uint8_t *out, size_t *out_len) const;
// GetFinishedMAC computes the MAC for the Finished message into the bytes
// pointed by |out| and writes the number of bytes to |*out_len|. |out| must
// have room for |EVP_MAX_MD_SIZE| bytes. It returns true on success and false
// on failure.
bool GetFinishedMAC(uint8_t *out, size_t *out_len, const SSL_SESSION *session,
- bool from_server);
+ bool from_server) const;
private:
// buffer_, if non-null, contains the handshake transcript.
@@ -1066,6 +1078,10 @@ class SSLKeyShare {
// |Serialize|.
static UniquePtr<SSLKeyShare> Create(CBS *in);
+ // Serializes writes the group ID and private key, in a format that can be
+ // read by |Create|.
+ bool Serialize(CBB *out);
+
// GroupID returns the group ID.
virtual uint16_t GroupID() const PURE_VIRTUAL;
@@ -1090,13 +1106,13 @@ class SSLKeyShare {
virtual bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert,
Span<const uint8_t> peer_key) PURE_VIRTUAL;
- // Serialize writes the state of the key exchange to |out|, returning true if
- // successful and false otherwise.
- virtual bool Serialize(CBB *out) { return false; }
+ // SerializePrivateKey writes the private key to |out|, returning true if
+ // successful and false otherwise. It should be called after |Offer|.
+ virtual bool SerializePrivateKey(CBB *out) { return false; }
- // Deserialize initializes the state of the key exchange from |in|, returning
- // true if successful and false otherwise. It is called by |Create|.
- virtual bool Deserialize(CBS *in) { return false; }
+ // DeserializePrivateKey initializes the state of the key exchange from |in|,
+ // returning true if successful and false otherwise.
+ virtual bool DeserializePrivateKey(CBS *in) { return false; }
};
struct NamedGroup {
@@ -1352,9 +1368,10 @@ bool ssl_on_certificate_selected(SSL_HANDSHAKE *hs);
bool tls13_init_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> psk);
// tls13_init_early_key_schedule initializes the handshake hash and key
-// derivation state from the resumption secret and incorporates the PSK to
-// derive the early secrets. It returns one on success and zero on error.
-bool tls13_init_early_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> psk);
+// derivation state from |session| for use with 0-RTT. It returns one on success
+// and zero on error.
+bool tls13_init_early_key_schedule(SSL_HANDSHAKE *hs,
+ const SSL_SESSION *session);
// tls13_advance_key_schedule incorporates |in| into the key schedule with
// HKDF-Extract. It returns true on success and false on error.
@@ -1407,25 +1424,184 @@ bool tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len,
// on failure.
bool tls13_derive_session_psk(SSL_SESSION *session, Span<const uint8_t> nonce);
-// tls13_write_psk_binder calculates the PSK binder value and replaces the last
-// bytes of |msg| with the resulting value. It returns true on success, and
-// false on failure.
-bool tls13_write_psk_binder(SSL_HANDSHAKE *hs, Span<uint8_t> msg);
+// tls13_write_psk_binder calculates the PSK binder value over |transcript| and
+// |msg|, and replaces the last bytes of |msg| with the resulting value. It
+// returns true on success, and false on failure. If |out_binder_len| is
+// non-NULL, it sets |*out_binder_len| to the length of the value computed.
+bool tls13_write_psk_binder(const SSL_HANDSHAKE *hs,
+ const SSLTranscript &transcript, Span<uint8_t> msg,
+ size_t *out_binder_len);
// tls13_verify_psk_binder verifies that the handshake transcript, truncated up
// to the binders has a valid signature using the value of |session|'s
// resumption secret. It returns true on success, and false on failure.
-bool tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
- const SSLMessage &msg, CBS *binders);
+bool tls13_verify_psk_binder(const SSL_HANDSHAKE *hs,
+ const SSL_SESSION *session, const SSLMessage &msg,
+ CBS *binders);
+
+
+// Encrypted ClientHello.
+struct ECHConfig {
+ static constexpr bool kAllowUniquePtr = true;
+ // raw contains the serialized ECHConfig.
+ Array<uint8_t> raw;
+ // The following fields alias into |raw|.
+ Span<const uint8_t> public_key;
+ Span<const uint8_t> public_name;
+ Span<const uint8_t> cipher_suites;
+ uint16_t kem_id = 0;
+ uint8_t maximum_name_length = 0;
+ uint8_t config_id = 0;
+};
+
+class ECHServerConfig {
+ public:
+ static constexpr bool kAllowUniquePtr = true;
+ ECHServerConfig() = default;
+ ECHServerConfig(const ECHServerConfig &other) = delete;
+ ECHServerConfig &operator=(ECHServerConfig &&) = delete;
-// Encrypted Client Hello.
+ // Init parses |ech_config| as an ECHConfig and saves a copy of |key|.
+ // It returns true on success and false on error.
+ bool Init(Span<const uint8_t> ech_config, const EVP_HPKE_KEY *key,
+ bool is_retry_config);
-// tls13_ech_accept_confirmation computes the server's ECH acceptance signal,
-// writing it to |out|. It returns true on success, and false on failure.
-bool tls13_ech_accept_confirmation(
- SSL_HANDSHAKE *hs, bssl::Span<uint8_t> out,
- bssl::Span<const uint8_t> server_hello_ech_conf);
+ // SetupContext sets up |ctx| for a new connection, given the specified
+ // HPKE ciphersuite and encapsulated KEM key. It returns true on success and
+ // false on error. This function may only be called on an initialized object.
+ bool SetupContext(EVP_HPKE_CTX *ctx, uint16_t kdf_id, uint16_t aead_id,
+ Span<const uint8_t> enc) const;
+
+ const ECHConfig &ech_config() const { return ech_config_; }
+ bool is_retry_config() const { return is_retry_config_; }
+
+ private:
+ ECHConfig ech_config_;
+ ScopedEVP_HPKE_KEY key_;
+ bool is_retry_config_ = false;
+};
+
+enum ssl_client_hello_type_t {
+ ssl_client_hello_unencrypted,
+ ssl_client_hello_inner,
+ ssl_client_hello_outer,
+};
+
+// ECH_CLIENT_* are types for the ClientHello encrypted_client_hello extension.
+#define ECH_CLIENT_OUTER 0
+#define ECH_CLIENT_INNER 1
+
+// ssl_decode_client_hello_inner recovers the full ClientHelloInner from the
+// EncodedClientHelloInner |encoded_client_hello_inner| by replacing its
+// outer_extensions extension with the referenced extensions from the
+// ClientHelloOuter |client_hello_outer|. If successful, it writes the recovered
+// ClientHelloInner to |out_client_hello_inner|. It returns true on success and
+// false on failure.
+OPENSSL_EXPORT bool ssl_decode_client_hello_inner(
+ SSL *ssl, uint8_t *out_alert, Array<uint8_t> *out_client_hello_inner,
+ Span<const uint8_t> encoded_client_hello_inner,
+ const SSL_CLIENT_HELLO *client_hello_outer);
+
+// ssl_client_hello_decrypt attempts to decrypt the |payload| and writes the
+// result to |*out|. |payload| must point into |client_hello_outer|. It returns
+// true on success and false on error. On error, it sets |*out_is_decrypt_error|
+// to whether the failure was due to a bad ciphertext.
+bool ssl_client_hello_decrypt(EVP_HPKE_CTX *hpke_ctx, Array<uint8_t> *out,
+ bool *out_is_decrypt_error,
+ const SSL_CLIENT_HELLO *client_hello_outer,
+ Span<const uint8_t> payload);
+
+#define ECH_CONFIRMATION_SIGNAL_LEN 8
+
+// ssl_ech_confirmation_signal_hello_offset returns the offset of the ECH
+// confirmation signal in a ServerHello message, including the handshake header.
+size_t ssl_ech_confirmation_signal_hello_offset(const SSL *ssl);
+
+// ssl_ech_accept_confirmation computes the server's ECH acceptance signal,
+// writing it to |out|. The transcript portion is the concatenation of
+// |transcript| with |msg|. The |ECH_CONFIRMATION_SIGNAL_LEN| bytes from
+// |offset| in |msg| are replaced with zeros before hashing. This function
+// returns true on success, and false on failure.
+bool ssl_ech_accept_confirmation(const SSL_HANDSHAKE *hs, Span<uint8_t> out,
+ Span<const uint8_t> client_random,
+ const SSLTranscript &transcript, bool is_hrr,
+ Span<const uint8_t> msg, size_t offset);
+
+// ssl_is_valid_ech_public_name returns true if |public_name| is a valid ECH
+// public name and false otherwise. It is exported for testing.
+OPENSSL_EXPORT bool ssl_is_valid_ech_public_name(
+ Span<const uint8_t> public_name);
+
+// ssl_is_valid_ech_config_list returns true if |ech_config_list| is a valid
+// ECHConfigList structure and false otherwise.
+bool ssl_is_valid_ech_config_list(Span<const uint8_t> ech_config_list);
+
+// ssl_select_ech_config selects an ECHConfig and associated parameters to offer
+// on the client and updates |hs|. It returns true on success, whether an
+// ECHConfig was found or not, and false on internal error. On success, the
+// encapsulated key is written to |out_enc| and |*out_enc_len| is set to the
+// number of bytes written. If the function did not select an ECHConfig, the
+// encapsulated key is the empty string.
+bool ssl_select_ech_config(SSL_HANDSHAKE *hs, Span<uint8_t> out_enc,
+ size_t *out_enc_len);
+
+// ssl_ech_extension_body_length returns the length of the body of a ClientHello
+// ECH extension that encrypts |in_len| bytes with |aead| and an 'enc' value of
+// length |enc_len|. The result does not include the four-byte extension header.
+size_t ssl_ech_extension_body_length(const EVP_HPKE_AEAD *aead, size_t enc_len,
+ size_t in_len);
+
+// ssl_encrypt_client_hello constructs a new ClientHelloInner, adds it to the
+// inner transcript, and encrypts for inclusion in the ClientHelloOuter. |enc|
+// is the encapsulated key to include in the extension. It returns true on
+// success and false on error. If not offering ECH, |enc| is ignored and the
+// function will compute a GREASE ECH extension if necessary, and otherwise
+// return success while doing nothing.
+//
+// Encrypting the ClientHelloInner incorporates all extensions in the
+// ClientHelloOuter, so all other state necessary for |ssl_add_client_hello|
+// must already be computed.
+bool ssl_encrypt_client_hello(SSL_HANDSHAKE *hs, Span<const uint8_t> enc);
+
+
+// Delegated credentials.
+
+// This structure stores a delegated credential (DC) as defined by
+// draft-ietf-tls-subcerts-03.
+struct DC {
+ static constexpr bool kAllowUniquePtr = true;
+ ~DC();
+
+ // Dup returns a copy of this DC and takes references to |raw| and |pkey|.
+ UniquePtr<DC> Dup();
+
+ // Parse parses the delegated credential stored in |in|. If successful it
+ // returns the parsed structure, otherwise it returns |nullptr| and sets
+ // |*out_alert|.
+ static UniquePtr<DC> Parse(CRYPTO_BUFFER *in, uint8_t *out_alert);
+
+ // raw is the delegated credential encoded as specified in draft-ietf-tls-
+ // subcerts-03.
+ UniquePtr<CRYPTO_BUFFER> raw;
+
+ // expected_cert_verify_algorithm is the signature scheme of the DC public
+ // key.
+ uint16_t expected_cert_verify_algorithm = 0;
+
+ // pkey is the public key parsed from |public_key|.
+ UniquePtr<EVP_PKEY> pkey;
+
+ private:
+ friend DC* New<DC>();
+ DC();
+};
+
+// ssl_signing_with_dc returns true if the peer has indicated support for
+// delegated credentials and this host has sent a delegated credential in
+// response. If this is true then we've committed to using the DC in the
+// handshake.
+bool ssl_signing_with_dc(const SSL_HANDSHAKE *hs);
// Handshake functions.
@@ -1440,7 +1616,6 @@ enum ssl_hs_wait_t {
ssl_hs_handoff,
ssl_hs_handback,
ssl_hs_x509_lookup,
- ssl_hs_channel_id_lookup,
ssl_hs_private_key_operation,
ssl_hs_pending_session,
ssl_hs_pending_ticket,
@@ -1449,6 +1624,7 @@ enum ssl_hs_wait_t {
ssl_hs_read_end_of_early_data,
ssl_hs_read_change_cipher_spec,
ssl_hs_certificate_verify,
+ ssl_hs_hints_ready,
};
enum ssl_grease_index_t {
@@ -1458,12 +1634,14 @@ enum ssl_grease_index_t {
ssl_grease_extension2,
ssl_grease_version,
ssl_grease_ticket_extension,
- ssl_grease_last_index = ssl_grease_ticket_extension,
+ ssl_grease_ech_config_id,
+ ssl_grease_last_index = ssl_grease_ech_config_id,
};
enum tls12_server_hs_state_t {
state12_start_accept = 0,
state12_read_client_hello,
+ state12_read_client_hello_after_ech,
state12_select_certificate,
state12_tls13,
state12_select_parameters,
@@ -1515,46 +1693,30 @@ enum handback_t {
handback_max_value = handback_tls13,
};
-
-// Delegated credentials.
-
-// This structure stores a delegated credential (DC) as defined by
-// draft-ietf-tls-subcerts-03.
-struct DC {
+// SSL_HANDSHAKE_HINTS contains handshake hints for a connection. See
+// |SSL_request_handshake_hints| and related functions.
+struct SSL_HANDSHAKE_HINTS {
static constexpr bool kAllowUniquePtr = true;
- ~DC();
- // Dup returns a copy of this DC and takes references to |raw| and |pkey|.
- UniquePtr<DC> Dup();
+ Array<uint8_t> server_random;
- // Parse parses the delegated credential stored in |in|. If successful it
- // returns the parsed structure, otherwise it returns |nullptr| and sets
- // |*out_alert|.
- static UniquePtr<DC> Parse(CRYPTO_BUFFER *in, uint8_t *out_alert);
+ uint16_t key_share_group_id = 0;
+ Array<uint8_t> key_share_public_key;
+ Array<uint8_t> key_share_secret;
- // raw is the delegated credential encoded as specified in draft-ietf-tls-
- // subcerts-03.
- UniquePtr<CRYPTO_BUFFER> raw;
+ uint16_t signature_algorithm = 0;
+ Array<uint8_t> signature_input;
+ Array<uint8_t> signature_spki;
+ Array<uint8_t> signature;
- // expected_cert_verify_algorithm is the signature scheme of the DC public
- // key.
- uint16_t expected_cert_verify_algorithm = 0;
+ Array<uint8_t> decrypted_psk;
+ bool ignore_psk = false;
- // pkey is the public key parsed from |public_key|.
- UniquePtr<EVP_PKEY> pkey;
-
- private:
- friend DC* New<DC>();
- DC();
+ uint16_t cert_compression_alg_id = 0;
+ Array<uint8_t> cert_compression_input;
+ Array<uint8_t> cert_compression_output;
};
-// ssl_signing_with_dc returns true if the peer has indicated support for
-// delegated credentials and this host has sent a delegated credential in
-// response. If this is true then we've committed to using the DC in the
-// handshake.
-bool ssl_signing_with_dc(const SSL_HANDSHAKE *hs);
-
-
struct SSL_HANDSHAKE {
explicit SSL_HANDSHAKE(SSL *ssl);
~SSL_HANDSHAKE();
@@ -1599,7 +1761,21 @@ struct SSL_HANDSHAKE {
public:
void ResizeSecrets(size_t hash_len);
+ // GetClientHello, on the server, returns either the normal ClientHello
+ // message or the ClientHelloInner if it has been serialized to
+ // |ech_client_hello_buf|. This function should only be called when the
+ // current message is a ClientHello. It returns true on success and false on
+ // error.
+ //
+ // Note that fields of the returned |out_msg| and |out_client_hello| point
+ // into a handshake-owned buffer, so their lifetimes should not exceed this
+ // SSL_HANDSHAKE.
+ bool GetClientHello(SSLMessage *out_msg, SSL_CLIENT_HELLO *out_client_hello);
+
Span<uint8_t> secret() { return MakeSpan(secret_, hash_len_); }
+ Span<const uint8_t> secret() const {
+ return MakeConstSpan(secret_, hash_len_);
+ }
Span<uint8_t> early_traffic_secret() {
return MakeSpan(early_traffic_secret_, hash_len_);
}
@@ -1621,7 +1797,7 @@ struct SSL_HANDSHAKE {
union {
// sent is a bitset where the bits correspond to elements of kExtensions
- // in t1_lib.c. Each bit is set if that extension was sent in a
+ // in extensions.cc. Each bit is set if that extension was sent in a
// ClientHello. It's not used by servers.
uint32_t sent = 0;
// received is a bitset, like |sent|, but is used by servers to record
@@ -1629,9 +1805,9 @@ struct SSL_HANDSHAKE {
uint32_t received;
} extensions;
- // retry_group is the group ID selected by the server in HelloRetryRequest in
- // TLS 1.3.
- uint16_t retry_group = 0;
+ // inner_extensions_sent, on clients that offer ECH, is |extensions.sent| for
+ // the ClientHelloInner.
+ uint32_t inner_extensions_sent = 0;
// error, if |wait| is |ssl_hs_error|, is the error the handshake failed on.
UniquePtr<ERR_SAVE_STATE> error;
@@ -1644,15 +1820,31 @@ struct SSL_HANDSHAKE {
// transcript is the current handshake transcript.
SSLTranscript transcript;
+ // inner_transcript, on the client, is the handshake transcript for the
+ // ClientHelloInner handshake. It is moved to |transcript| if the server
+ // accepts ECH.
+ SSLTranscript inner_transcript;
+
+ // inner_client_random is the ClientHello random value used with
+ // ClientHelloInner.
+ uint8_t inner_client_random[SSL3_RANDOM_SIZE] = {0};
+
// cookie is the value of the cookie received from the server, if any.
Array<uint8_t> cookie;
- // ech_grease contains the bytes of the GREASE ECH extension that was sent in
- // the first ClientHello.
- Array<uint8_t> ech_grease;
+ // ech_client_outer contains the outer ECH extension to send in the
+ // ClientHello, excluding the header and type byte.
+ Array<uint8_t> ech_client_outer;
+
+ // ech_retry_configs, on the client, contains the retry configs from the
+ // server as a serialized ECHConfigList.
+ Array<uint8_t> ech_retry_configs;
+
+ // ech_client_hello_buf, on the server, contains the bytes of the
+ // reconstructed ClientHelloInner message.
+ Array<uint8_t> ech_client_hello_buf;
- // key_share_bytes is the value of the previously sent KeyShare extension by
- // the client in TLS 1.3.
+ // key_share_bytes is the key_share extension that the client should send.
Array<uint8_t> key_share_bytes;
// ecdh_public_key, for servers, is the key share to be sent to the client in
@@ -1676,17 +1868,21 @@ struct SSL_HANDSHAKE {
// peer_key is the peer's ECDH key for a TLS 1.2 client.
Array<uint8_t> peer_key;
- // negotiated_token_binding_version is used by a server to store the
- // on-the-wire encoding of the Token Binding protocol version to advertise in
- // the ServerHello/EncryptedExtensions if the Token Binding extension is to be
- // sent.
- uint16_t negotiated_token_binding_version;
+ // extension_permutation is the permutation to apply to ClientHello
+ // extensions. It maps indices into the |kExtensions| table into other
+ // indices.
+ Array<uint8_t> extension_permutation;
// cert_compression_alg_id, for a server, contains the negotiated certificate
// compression algorithm for this client. It is only valid if
// |cert_compression_negotiated| is true.
uint16_t cert_compression_alg_id;
+ // ech_hpke_ctx is the HPKE context used in ECH. On the server, it is
+ // initialized if |ech_status| is |ssl_ech_accepted|. On the client, it is
+ // initialized if |selected_ech_config| is not nullptr.
+ ScopedEVP_HPKE_CTX ech_hpke_ctx;
+
// server_params, in a TLS 1.2 server, stores the ServerKeyExchange
// parameters. It has client and server randoms prepended for signing
// convenience.
@@ -1723,27 +1919,40 @@ struct SSL_HANDSHAKE {
// the client if |in_early_data| is true.
UniquePtr<SSL_SESSION> early_session;
+ // ssl_ech_keys, for servers, is the set of ECH keys to use with this
+ // handshake. This is copied from |SSL_CTX| to ensure consistent behavior as
+ // |SSL_CTX| rotates keys.
+ UniquePtr<SSL_ECH_KEYS> ech_keys;
+
+ // selected_ech_config, for clients, is the ECHConfig the client uses to offer
+ // ECH, or nullptr if ECH is not being offered. If non-NULL, |ech_hpke_ctx|
+ // will be initialized.
+ UniquePtr<ECHConfig> selected_ech_config;
+
// new_cipher is the cipher being negotiated in this handshake.
const SSL_CIPHER *new_cipher = nullptr;
// key_block is the record-layer key block for TLS 1.2 and earlier.
Array<uint8_t> key_block;
- // ech_present, on the server, indicates whether the ClientHello contained an
- // encrypted_client_hello extension.
- bool ech_present : 1;
+ // hints contains the handshake hints for this connection. If
+ // |hints_requested| is true, this field is non-null and contains the pending
+ // hints to filled as the predicted handshake progresses. Otherwise, this
+ // field, if non-null, contains hints configured by the caller and will
+ // influence the handshake on match.
+ UniquePtr<SSL_HANDSHAKE_HINTS> hints;
- // ech_is_inner_present, on the server, indicates whether the ClientHello
- // contained an ech_is_inner extension.
- bool ech_is_inner_present : 1;
+ // ech_is_inner, on the server, indicates whether the ClientHello contained an
+ // inner ECH extension.
+ bool ech_is_inner : 1;
+
+ // ech_authenticated_reject, on the client, indicates whether an ECH rejection
+ // handshake has been authenticated.
+ bool ech_authenticated_reject : 1;
// scts_requested is true if the SCT extension is in the ClientHello.
bool scts_requested : 1;
- // needs_psk_binder is true if the ClientHello has a placeholder PSK binder to
- // be filled in.
- bool needs_psk_binder : 1;
-
// handshake_finalized is true once the handshake has completed, at which
// point accessors should use the established state.
bool handshake_finalized : 1;
@@ -1805,15 +2014,17 @@ struct SSL_HANDSHAKE {
// in progress.
bool pending_private_key_op : 1;
- // grease_seeded is true if |grease_seed| has been initialized.
- bool grease_seeded : 1;
-
// handback indicates that a server should pause the handshake after
// finishing operations that require private key material, in such a way that
// |SSL_get_error| returns |SSL_ERROR_HANDBACK|. It is set by
// |SSL_apply_handoff|.
bool handback : 1;
+ // hints_requested indicates the caller has requested handshake hints. Only
+ // the first round-trip of the handshake will complete, after which the
+ // |hints| structure can be serialized.
+ bool hints_requested : 1;
+
// cert_compression_negotiated is true iff |cert_compression_alg_id| is valid.
bool cert_compression_negotiated : 1;
@@ -1821,6 +2032,14 @@ struct SSL_HANDSHAKE {
// which implemented TLS 1.3 incorrectly.
bool apply_jdk11_workaround : 1;
+ // can_release_private_key is true if the private key will no longer be used
+ // in this handshake.
+ bool can_release_private_key : 1;
+
+ // channel_id_negotiated is true if Channel ID should be used in this
+ // handshake.
+ bool channel_id_negotiated : 1;
+
// client_version is the value sent or received in the ClientHello version.
uint16_t client_version = 0;
@@ -1832,12 +2051,14 @@ struct SSL_HANDSHAKE {
// record layer.
uint16_t early_data_written = 0;
+ // ech_config_id is the ECH config sent by the client.
+ uint8_t ech_config_id = 0;
+
// session_id is the session ID in the ClientHello.
uint8_t session_id[SSL_MAX_SSL_SESSION_ID_LENGTH] = {0};
uint8_t session_id_len = 0;
- // grease_seed is the entropy for GREASE values. It is valid if
- // |grease_seeded| is true.
+ // grease_seed is the entropy for GREASE values.
uint8_t grease_seed[ssl_grease_last_index + 1] = {0};
};
@@ -1897,14 +2118,24 @@ bool tls13_process_new_session_ticket(SSL *ssl, const SSLMessage &msg);
bssl::UniquePtr<SSL_SESSION> tls13_create_session_with_ticket(SSL *ssl,
CBS *body);
+// ssl_setup_extension_permutation computes a ClientHello extension permutation
+// for |hs|, if applicable. It returns true on success and false on error.
+bool ssl_setup_extension_permutation(SSL_HANDSHAKE *hs);
+
+// ssl_setup_key_shares computes client key shares and saves them in |hs|. It
+// returns true on success and false on failure. If |override_group_id| is zero,
+// it offers the default groups, including GREASE. If it is non-zero, it offers
+// a single key share of the specified group.
+bool ssl_setup_key_shares(SSL_HANDSHAKE *hs, uint16_t override_group_id);
+
bool ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs,
Array<uint8_t> *out_secret,
uint8_t *out_alert, CBS *contents);
bool ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, bool *out_found,
- Array<uint8_t> *out_secret,
- uint8_t *out_alert, CBS *contents);
-bool ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out,
- bool dry_run);
+ Span<const uint8_t> *out_peer_key,
+ uint8_t *out_alert,
+ const SSL_CLIENT_HELLO *client_hello);
+bool ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out);
bool ssl_ext_pre_shared_key_parse_serverhello(SSL_HANDSHAKE *hs,
uint8_t *out_alert,
@@ -1919,7 +2150,33 @@ bool ssl_ext_pre_shared_key_add_serverhello(SSL_HANDSHAKE *hs, CBB *out);
// returns whether it's valid.
bool ssl_is_sct_list_valid(const CBS *contents);
-bool ssl_write_client_hello(SSL_HANDSHAKE *hs);
+// ssl_write_client_hello_without_extensions writes a ClientHello to |out|,
+// up to the extensions field. |type| determines the type of ClientHello to
+// write. If |omit_session_id| is true, the session ID is empty.
+bool ssl_write_client_hello_without_extensions(const SSL_HANDSHAKE *hs,
+ CBB *cbb,
+ ssl_client_hello_type_t type,
+ bool empty_session_id);
+
+// ssl_add_client_hello constructs a ClientHello and adds it to the outgoing
+// flight. It returns true on success and false on error.
+bool ssl_add_client_hello(SSL_HANDSHAKE *hs);
+
+struct ParsedServerHello {
+ CBS raw;
+ uint16_t legacy_version = 0;
+ CBS random;
+ CBS session_id;
+ uint16_t cipher_suite = 0;
+ uint8_t compression_method = 0;
+ CBS extensions;
+};
+
+// ssl_parse_server_hello parses |msg| as a ServerHello. On success, it writes
+// the result to |*out| and returns true. Otherwise, it returns false and sets
+// |*out_alert| to an alert to send to the peer.
+bool ssl_parse_server_hello(ParsedServerHello *out, uint8_t *out_alert,
+ const SSLMessage &msg);
enum ssl_cert_verify_context_t {
ssl_cert_verify_server,
@@ -1935,6 +2192,9 @@ bool tls13_get_cert_verify_signature_input(
SSL_HANDSHAKE *hs, Array<uint8_t> *out,
enum ssl_cert_verify_context_t cert_verify_context);
+// ssl_is_valid_alpn_list returns whether |in| is a valid ALPN protocol list.
+bool ssl_is_valid_alpn_list(Span<const uint8_t> in);
+
// ssl_is_alpn_protocol_allowed returns whether |protocol| is a valid server
// selection for |hs->ssl|'s client preferences.
bool ssl_is_alpn_protocol_allowed(const SSL_HANDSHAKE *hs,
@@ -1946,25 +2206,38 @@ bool ssl_is_alpn_protocol_allowed(const SSL_HANDSHAKE *hs,
bool ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert,
const SSL_CLIENT_HELLO *client_hello);
+// ssl_get_local_application_settings looks up the configured ALPS value for
+// |protocol|. If found, it sets |*out_settings| to the value and returns true.
+// Otherwise, it returns false.
+bool ssl_get_local_application_settings(const SSL_HANDSHAKE *hs,
+ Span<const uint8_t> *out_settings,
+ Span<const uint8_t> protocol);
+
// ssl_negotiate_alps negotiates the ALPS extension, if applicable. It returns
// true on successful negotiation or if nothing was negotiated. It returns false
// and sets |*out_alert| to an alert on error.
bool ssl_negotiate_alps(SSL_HANDSHAKE *hs, uint8_t *out_alert,
const SSL_CLIENT_HELLO *client_hello);
-struct SSL_EXTENSION_TYPE {
+struct SSLExtension {
+ SSLExtension(uint16_t type_arg, bool allowed_arg = true)
+ : type(type_arg), allowed(allowed_arg), present(false) {
+ CBS_init(&data, nullptr, 0);
+ }
+
uint16_t type;
- bool *out_present;
- CBS *out_data;
+ bool allowed;
+ bool present;
+ CBS data;
};
// ssl_parse_extensions parses a TLS extensions block out of |cbs| and advances
-// it. It writes the parsed extensions to pointers denoted by |ext_types|. On
-// success, it fills in the |out_present| and |out_data| fields and returns
-// true. Otherwise, it sets |*out_alert| to an alert to send and returns false.
-// Unknown extensions are rejected unless |ignore_unknown| is true.
+// it. It writes the parsed extensions to pointers in |extensions|. On success,
+// it fills in the |present| and |data| fields and returns true. Otherwise, it
+// sets |*out_alert| to an alert to send and returns false. Unknown extensions
+// are rejected unless |ignore_unknown| is true.
bool ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
- Span<const SSL_EXTENSION_TYPE> ext_types,
+ std::initializer_list<SSLExtension *> extensions,
bool ignore_unknown);
// ssl_verify_peer_cert verifies the peer certificate for |hs|.
@@ -1982,6 +2255,10 @@ bool ssl_output_cert_chain(SSL_HANDSHAKE *hs);
// handshake. Note, in TLS 1.2 resumptions, this session is immutable.
const SSL_SESSION *ssl_handshake_session(const SSL_HANDSHAKE *hs);
+// ssl_done_writing_client_hello is called after the last ClientHello is written
+// by |hs|. It releases some memory that is no longer needed.
+void ssl_done_writing_client_hello(SSL_HANDSHAKE *hs);
+
// SSLKEYLOGFILE functions.
@@ -1993,8 +2270,14 @@ bool ssl_log_secret(const SSL *ssl, const char *label,
// ClientHello functions.
-bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out,
- const SSLMessage &msg);
+// ssl_client_hello_init parses |body| as a ClientHello message, excluding the
+// message header, and writes the result to |*out|. It returns true on success
+// and false on error. This function is exported for testing.
+OPENSSL_EXPORT bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out,
+ Span<const uint8_t> body);
+
+bool ssl_parse_client_hello_with_trailing_data(const SSL *ssl, CBS *cbs,
+ SSL_CLIENT_HELLO *out);
bool ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello,
CBS *out, uint16_t extension_type);
@@ -2009,7 +2292,8 @@ bool ssl_client_cipher_list_contains_cipher(
// connection, the values for each index will be deterministic. This allows the
// same ClientHello be sent twice for a HelloRetryRequest or the same group be
// advertised in both supported_groups and key_shares.
-uint16_t ssl_get_grease_value(SSL_HANDSHAKE *hs, enum ssl_grease_index_t index);
+uint16_t ssl_get_grease_value(const SSL_HANDSHAKE *hs,
+ enum ssl_grease_index_t index);
// Signature algorithms.
@@ -2055,7 +2339,7 @@ bool tls12_check_peer_sigalg(const SSL_HANDSHAKE *hs, uint8_t *out_alert,
#define TLSEXT_CHANNEL_ID_SIZE 128
-// From RFC4492, used in encoding the curve type in ECParameters
+// From RFC 4492, used in encoding the curve type in ECParameters
#define NAMED_CURVE_TYPE 3
struct CERT {
@@ -2169,10 +2453,11 @@ struct SSL_PROTOCOL_METHOD {
// init_message begins a new handshake message of type |type|. |cbb| is the
// root CBB to be passed into |finish_message|. |*body| is set to a child CBB
// the caller should write to. It returns true on success and false on error.
- bool (*init_message)(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
+ bool (*init_message)(const SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
// finish_message finishes a handshake message. It sets |*out_msg| to the
// serialized message. It returns true on success and false on error.
- bool (*finish_message)(SSL *ssl, CBB *cbb, bssl::Array<uint8_t> *out_msg);
+ bool (*finish_message)(const SSL *ssl, CBB *cbb,
+ bssl::Array<uint8_t> *out_msg);
// add_message adds a handshake message to the pending flight. It returns
// true on success and false on error.
bool (*add_message)(SSL *ssl, bssl::Array<uint8_t> msg);
@@ -2321,6 +2606,16 @@ enum ssl_shutdown_t {
ssl_shutdown_error = 2,
};
+enum ssl_ech_status_t {
+ // ssl_ech_none indicates ECH was not offered, or we have not gotten far
+ // enough in the handshake to determine the status.
+ ssl_ech_none,
+ // ssl_ech_accepted indicates the server accepted ECH.
+ ssl_ech_accepted,
+ // ssl_ech_rejected indicates the server was offered ECH but rejected it.
+ ssl_ech_rejected,
+};
+
struct SSL3_STATE {
static constexpr bool kAllowUniquePtr = true;
@@ -2383,9 +2678,8 @@ struct SSL3_STATE {
// key_update_count is the number of consecutive KeyUpdates received.
uint8_t key_update_count = 0;
- // The negotiated Token Binding key parameter. Only valid if
- // |token_binding_negotiated| is set.
- uint8_t negotiated_token_binding_param = 0;
+ // ech_status indicates whether ECH was accepted by the server.
+ ssl_ech_status_t ech_status = ssl_ech_none;
// skip_early_data instructs the record layer to skip unexpected early data
// messages when 0RTT is rejected.
@@ -2420,9 +2714,8 @@ struct SSL3_STATE {
bool send_connection_binding : 1;
- // In a client, this means that the server supported Channel ID and that a
- // Channel ID was sent. In a server it means that we echoed support for
- // Channel IDs and that |channel_id| will be valid after the handshake.
+ // channel_id_valid is true if, on the server, the client has negotiated a
+ // Channel ID and the |channel_id| field is filled in.
bool channel_id_valid : 1;
// key_update_pending is true if we have a KeyUpdate acknowledgment
@@ -2435,9 +2728,6 @@ struct SSL3_STATE {
// early_data_accepted is true if early data was accepted by the server.
bool early_data_accepted : 1;
- // token_binding_negotiated is set if Token Binding was negotiated.
- bool token_binding_negotiated : 1;
-
// alert_dispatch is true there is an alert in |send_alert| to be sent.
bool alert_dispatch : 1;
@@ -2720,7 +3010,8 @@ struct SSL_CONFIG {
Array<uint16_t> supported_group_list; // our list
- // The client's Channel ID private key.
+ // channel_id_private is the client's Channel ID private key, or null if
+ // Channel ID should not be offered on this connection.
UniquePtr<EVP_PKEY> channel_id_private;
// For a client, this contains the list of supported protocols in wire
@@ -2731,9 +3022,6 @@ struct SSL_CONFIG {
// along with their corresponding ALPS values.
GrowableArray<ALPSConfig> alps_configs;
- // Contains a list of supported Token Binding key parameters.
- Array<uint8_t> token_binding_params;
-
// Contains the QUIC transport params that this endpoint will send.
Array<uint8_t> quic_transport_params;
@@ -2748,6 +3036,10 @@ struct SSL_CONFIG {
// DTLS-SRTP.
UniquePtr<STACK_OF(SRTP_PROTECTION_PROFILE)> srtp_profiles;
+ // client_ech_config_list, if not empty, is a serialized ECHConfigList
+ // structure for the client to use when negotiating ECH.
+ Array<uint8_t> client_ech_config_list;
+
// verify_mode is a bitmask of |SSL_VERIFY_*| values.
uint8_t verify_mode = SSL_VERIFY_NONE;
@@ -2762,9 +3054,8 @@ struct SSL_CONFIG {
// whether OCSP stapling will be requested.
bool ocsp_stapling_enabled : 1;
- // channel_id_enabled is copied from the |SSL_CTX|. For a server, means that
- // we'll accept Channel IDs from clients. For a client, means that we'll
- // advertise support.
+ // channel_id_enabled is copied from the |SSL_CTX|. For a server, it means
+ // that we'll accept Channel IDs from clients. It is ignored on the client.
bool channel_id_enabled : 1;
// If enforce_rsa_key_usage is true, the handshake will fail if the
@@ -2794,6 +3085,9 @@ struct SSL_CONFIG {
// QUIC drafts up to and including 32 used a different TLS extension
// codepoint to convey QUIC's transport parameters.
bool quic_use_legacy_codepoint : 1;
+
+ // permute_extensions is whether to permute extensions when sending messages.
+ bool permute_extensions : 1;
};
// From RFC 8446, used in determining PSK modes.
@@ -2814,7 +3108,7 @@ bool ssl_is_key_type_supported(int key_type);
bool ssl_compare_public_and_private_key(const EVP_PKEY *pubkey,
const EVP_PKEY *privkey);
bool ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey);
-int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server);
+bool ssl_get_new_session(SSL_HANDSHAKE *hs);
int ssl_encrypt_ticket(SSL_HANDSHAKE *hs, CBB *out, const SSL_SESSION *session);
int ssl_ctx_rotate_ticket_encryption_key(SSL_CTX *ctx);
@@ -2895,7 +3189,7 @@ void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session);
void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
uint32_t timeout);
-void ssl_update_cache(SSL_HANDSHAKE *hs, int mode);
+void ssl_update_cache(SSL *ssl);
void ssl_send_alert(SSL *ssl, int level, int desc);
int ssl_send_alert_impl(SSL *ssl, int level, int desc);
@@ -2917,14 +3211,14 @@ int tls_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *buf,
bool tls_new(SSL *ssl);
void tls_free(SSL *ssl);
-bool tls_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-bool tls_finish_message(SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg);
+bool tls_init_message(const SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
+bool tls_finish_message(const SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg);
bool tls_add_message(SSL *ssl, Array<uint8_t> msg);
bool tls_add_change_cipher_spec(SSL *ssl);
int tls_flush_flight(SSL *ssl);
-bool dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-bool dtls1_finish_message(SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg);
+bool dtls1_init_message(const SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
+bool dtls1_finish_message(const SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg);
bool dtls1_add_message(SSL *ssl, Array<uint8_t> msg);
bool dtls1_add_change_cipher_spec(SSL *ssl);
int dtls1_flush_flight(SSL *ssl);
@@ -3009,16 +3303,28 @@ bool tls1_set_curves(Array<uint16_t> *out_group_ids, Span<const int> curves);
// false.
bool tls1_set_curves_list(Array<uint16_t> *out_group_ids, const char *curves);
-// ssl_add_clienthello_tlsext writes ClientHello extensions to |out|. It returns
-// true on success and false on failure. The |header_len| argument is the length
-// of the ClientHello written so far and is used to compute the padding length.
-// (It does not include the record header.)
-bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len);
+// ssl_add_clienthello_tlsext writes ClientHello extensions to |out| for |type|.
+// It returns true on success and false on failure. The |header_len| argument is
+// the length of the ClientHello written so far and is used to compute the
+// padding length. (It does not include the record header or handshake headers.)
+//
+// If |type| is |ssl_client_hello_inner|, this function also writes the
+// compressed extensions to |out_encoded|. Otherwise, |out_encoded| should be
+// nullptr.
+//
+// On success, the function sets |*out_needs_psk_binder| to whether the last
+// ClientHello extension was the pre_shared_key extension and needs a PSK binder
+// filled in. The caller should then update |out| and, if applicable,
+// |out_encoded| with the binder after completing the whole message.
+bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, CBB *out_encoded,
+ bool *out_needs_psk_binder,
+ ssl_client_hello_type_t type,
+ size_t header_len);
bool ssl_add_serverhello_tlsext(SSL_HANDSHAKE *hs, CBB *out);
bool ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs,
const SSL_CLIENT_HELLO *client_hello);
-bool ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs);
+bool ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, const CBS *extensions);
#define tlsext_tick_md EVP_sha256
@@ -3056,12 +3362,6 @@ bool tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len);
// data.
bool tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs);
-// ssl_do_channel_id_callback checks runs |hs->ssl->ctx->channel_id_cb| if
-// necessary. It returns true on success and false on fatal error. Note that, on
-// success, |hs->ssl->channel_id_private| may be unset, in which case the
-// operation should be retried later.
-bool ssl_do_channel_id_callback(SSL_HANDSHAKE *hs);
-
// ssl_can_write returns whether |ssl| is allowed to write.
bool ssl_can_write(const SSL *ssl);
@@ -3185,9 +3485,6 @@ struct ssl_ctx_st {
int (*client_cert_cb)(SSL *ssl, X509 **out_x509,
EVP_PKEY **out_pkey) = nullptr;
- // get channel id callback
- void (*channel_id_cb)(SSL *ssl, EVP_PKEY **out_pkey) = nullptr;
-
CRYPTO_EX_DATA ex_data;
// Default values used when no per-SSL value is defined follow
@@ -3315,9 +3612,15 @@ struct ssl_ctx_st {
// Supported group values inherited by SSL structure
bssl::Array<uint16_t> supported_group_list;
- // The client's Channel ID private key.
+ // channel_id_private is the client's Channel ID private key, or null if
+ // Channel ID should not be offered on this connection.
bssl::UniquePtr<EVP_PKEY> channel_id_private;
+ // ech_keys contains the server's list of ECHConfig values and associated
+ // private keys. This list may be swapped out at any time, so all access must
+ // be synchronized through |lock|.
+ bssl::UniquePtr<SSL_ECH_KEYS> ech_keys;
+
// keylog_callback, if not NULL, is the key logging callback. See
// |SSL_CTX_set_keylog_callback|.
void (*keylog_callback)(const SSL *ssl, const char *line) = nullptr;
@@ -3365,9 +3668,12 @@ struct ssl_ctx_st {
// advertise support.
bool channel_id_enabled : 1;
- // grease_enabled is whether draft-davidben-tls-grease-01 is enabled.
+ // grease_enabled is whether GREASE (RFC 8701) is enabled.
bool grease_enabled : 1;
+ // permute_extensions is whether to permute extensions when sending messages.
+ bool permute_extensions : 1;
+
// allow_unknown_alpn_protos is whether the client allows unsolicited ALPN
// protocols from the peer.
bool allow_unknown_alpn_protos : 1;
@@ -3631,5 +3937,17 @@ struct ssl_session_st {
friend void SSL_SESSION_free(SSL_SESSION *);
};
+struct ssl_ech_keys_st {
+ ssl_ech_keys_st() = default;
+ ssl_ech_keys_st(const ssl_ech_keys_st &) = delete;
+ ssl_ech_keys_st &operator=(const ssl_ech_keys_st &) = delete;
+
+ bssl::GrowableArray<bssl::UniquePtr<bssl::ECHServerConfig>> configs;
+ CRYPTO_refcount_t references = 1;
+
+ private:
+ ~ssl_ech_keys_st() = default;
+ friend void SSL_ECH_KEYS_free(SSL_ECH_KEYS *);
+};
#endif // OPENSSL_HEADER_SSL_INTERNAL_H
diff --git a/deps/boringssl/src/ssl/s3_both.cc b/deps/boringssl/src/ssl/s3_both.cc
index 4415bd7..cddeb3f 100644
--- a/deps/boringssl/src/ssl/s3_both.cc
+++ b/deps/boringssl/src/ssl/s3_both.cc
@@ -168,7 +168,7 @@ static bool add_record_to_flight(SSL *ssl, uint8_t type,
return true;
}
-bool tls_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
+bool tls_init_message(const SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
// Pick a modest size hint to save most of the |realloc| calls.
if (!CBB_init(cbb, 64) ||
!CBB_add_u8(cbb, type) ||
@@ -181,7 +181,7 @@ bool tls_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
return true;
}
-bool tls_finish_message(SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg) {
+bool tls_finish_message(const SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg) {
return CBBFinishArray(cbb, out_msg);
}
@@ -251,7 +251,8 @@ bool tls_flush_pending_hs_data(SSL *ssl) {
MakeConstSpan(reinterpret_cast<const uint8_t *>(pending_hs_data->data),
pending_hs_data->length);
if (ssl->quic_method) {
- if (!ssl->quic_method->add_handshake_data(ssl, ssl->s3->write_level,
+ if ((ssl->s3->hs == nullptr || !ssl->s3->hs->hints_requested) &&
+ !ssl->quic_method->add_handshake_data(ssl, ssl->s3->write_level,
data.data(), data.size())) {
OPENSSL_PUT_ERROR(SSL, SSL_R_QUIC_INTERNAL_ERROR);
return false;
@@ -322,6 +323,11 @@ int tls_flush_flight(SSL *ssl) {
}
}
+ if (ssl->wbio == nullptr) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
+ return -1;
+ }
+
// Write the pending flight.
while (ssl->s3->pending_flight_offset < ssl->s3->pending_flight->length) {
int ret = BIO_write(
diff --git a/deps/boringssl/src/ssl/s3_lib.cc b/deps/boringssl/src/ssl/s3_lib.cc
index 3e12492..fa73d34 100644
--- a/deps/boringssl/src/ssl/s3_lib.cc
+++ b/deps/boringssl/src/ssl/s3_lib.cc
@@ -177,7 +177,6 @@ SSL3_STATE::SSL3_STATE()
key_update_pending(false),
wpend_pending(false),
early_data_accepted(false),
- token_binding_negotiated(false),
alert_dispatch(false),
renegotiate_pending(false),
used_hello_retry_request(false) {}
diff --git a/deps/boringssl/src/ssl/s3_pkt.cc b/deps/boringssl/src/ssl/s3_pkt.cc
index 457696d..450f7dc 100644
--- a/deps/boringssl/src/ssl/s3_pkt.cc
+++ b/deps/boringssl/src/ssl/s3_pkt.cc
@@ -112,6 +112,8 @@
#include <limits.h>
#include <string.h>
+#include <algorithm>
+
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
@@ -138,10 +140,9 @@ int tls_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *in,
return -1;
}
- unsigned tot, n, nw;
-
+ // TODO(davidben): Switch this logic to |size_t| and |bssl::Span|.
assert(ssl->s3->wnum <= INT_MAX);
- tot = ssl->s3->wnum;
+ unsigned tot = ssl->s3->wnum;
ssl->s3->wnum = 0;
// Ensure that if we end up with a smaller value of data to write out than
@@ -159,29 +160,23 @@ int tls_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *in,
const int is_early_data_write =
!ssl->server && SSL_in_early_data(ssl) && ssl->s3->hs->can_early_write;
- n = len - tot;
+ unsigned n = len - tot;
for (;;) {
- // max contains the maximum number of bytes that we can put into a record.
- unsigned max = ssl->max_send_fragment;
- if (is_early_data_write &&
- max > ssl->session->ticket_max_early_data -
- ssl->s3->hs->early_data_written) {
- max =
- ssl->session->ticket_max_early_data - ssl->s3->hs->early_data_written;
- if (max == 0) {
+ size_t max_send_fragment = ssl->max_send_fragment;
+ if (is_early_data_write) {
+ SSL_HANDSHAKE *hs = ssl->s3->hs.get();
+ if (hs->early_data_written >= hs->early_session->ticket_max_early_data) {
ssl->s3->wnum = tot;
- ssl->s3->hs->can_early_write = false;
+ hs->can_early_write = false;
*out_needs_handshake = true;
return -1;
}
+ max_send_fragment = std::min(
+ max_send_fragment, size_t{hs->early_session->ticket_max_early_data -
+ hs->early_data_written});
}
- if (n > max) {
- nw = max;
- } else {
- nw = n;
- }
-
+ const size_t nw = std::min(max_send_fragment, size_t{n});
int ret = do_tls_write(ssl, SSL3_RT_APPLICATION_DATA, &in[tot], nw);
if (ret <= 0) {
ssl->s3->wnum = tot;
diff --git a/deps/boringssl/src/ssl/ssl_cert.cc b/deps/boringssl/src/ssl/ssl_cert.cc
index c64303a..68e010a 100644
--- a/deps/boringssl/src/ssl/ssl_cert.cc
+++ b/deps/boringssl/src/ssl/ssl_cert.cc
@@ -548,13 +548,11 @@ bool ssl_cert_check_key_usage(const CBS *in, enum ssl_key_usage_t bit) {
// subjectPublicKeyInfo
!CBS_get_asn1(&tbs_cert, NULL, CBS_ASN1_SEQUENCE) ||
// issuerUniqueID
- !CBS_get_optional_asn1(
- &tbs_cert, NULL, NULL,
- CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1) ||
+ !CBS_get_optional_asn1(&tbs_cert, NULL, NULL,
+ CBS_ASN1_CONTEXT_SPECIFIC | 1) ||
// subjectUniqueID
- !CBS_get_optional_asn1(
- &tbs_cert, NULL, NULL,
- CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2) ||
+ !CBS_get_optional_asn1(&tbs_cert, NULL, NULL,
+ CBS_ASN1_CONTEXT_SPECIFIC | 2) ||
!CBS_get_optional_asn1(
&tbs_cert, &outer_extensions, &has_extensions,
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3)) {
diff --git a/deps/boringssl/src/ssl/ssl_cipher.cc b/deps/boringssl/src/ssl/ssl_cipher.cc
index 4f5049c..60b3e2c 100644
--- a/deps/boringssl/src/ssl/ssl_cipher.cc
+++ b/deps/boringssl/src/ssl/ssl_cipher.cc
@@ -234,7 +234,7 @@ static constexpr SSL_CIPHER kCiphers[] = {
SSL_HANDSHAKE_MAC_DEFAULT,
},
- // GCM ciphersuites from RFC5288
+ // GCM ciphersuites from RFC 5288
// Cipher 9C
{
@@ -346,7 +346,7 @@ static constexpr SSL_CIPHER kCiphers[] = {
SSL_HANDSHAKE_MAC_DEFAULT,
},
- // GCM based TLS v1.2 ciphersuites from RFC5289
+ // GCM based TLS v1.2 ciphersuites from RFC 5289
// Cipher C02B
{
diff --git a/deps/boringssl/src/ssl/ssl_key_share.cc b/deps/boringssl/src/ssl/ssl_key_share.cc
index 6cac3cf..c847a0a 100644
--- a/deps/boringssl/src/ssl/ssl_key_share.cc
+++ b/deps/boringssl/src/ssl/ssl_key_share.cc
@@ -124,29 +124,17 @@ class ECKeyShare : public SSLKeyShare {
return true;
}
- bool Serialize(CBB *out) override {
+ bool SerializePrivateKey(CBB *out) override {
assert(private_key_);
- CBB cbb;
UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_));
// Padding is added to avoid leaking the length.
size_t len = BN_num_bytes(EC_GROUP_get0_order(group.get()));
- if (!CBB_add_asn1_uint64(out, group_id_) ||
- !CBB_add_asn1(out, &cbb, CBS_ASN1_OCTETSTRING) ||
- !BN_bn2cbb_padded(&cbb, len, private_key_.get()) ||
- !CBB_flush(out)) {
- return false;
- }
- return true;
+ return BN_bn2cbb_padded(out, len, private_key_.get());
}
- bool Deserialize(CBS *in) override {
+ bool DeserializePrivateKey(CBS *in) override {
assert(!private_key_);
- CBS private_key;
- if (!CBS_get_asn1(in, &private_key, CBS_ASN1_OCTETSTRING)) {
- return false;
- }
- private_key_.reset(BN_bin2bn(CBS_data(&private_key),
- CBS_len(&private_key), nullptr));
+ private_key_.reset(BN_bin2bn(CBS_data(in), CBS_len(in), nullptr));
return private_key_ != nullptr;
}
@@ -189,16 +177,13 @@ class X25519KeyShare : public SSLKeyShare {
return true;
}
- bool Serialize(CBB *out) override {
- return (CBB_add_asn1_uint64(out, GroupID()) &&
- CBB_add_asn1_octet_string(out, private_key_, sizeof(private_key_)));
+ bool SerializePrivateKey(CBB *out) override {
+ return CBB_add_bytes(out, private_key_, sizeof(private_key_));
}
- bool Deserialize(CBS *in) override {
- CBS key;
- if (!CBS_get_asn1(in, &key, CBS_ASN1_OCTETSTRING) ||
- CBS_len(&key) != sizeof(private_key_) ||
- !CBS_copy_bytes(&key, private_key_, sizeof(private_key_))) {
+ bool DeserializePrivateKey(CBS *in) override {
+ if (CBS_len(in) != sizeof(private_key_) ||
+ !CBS_copy_bytes(in, private_key_, sizeof(private_key_))) {
return false;
}
return true;
@@ -221,7 +206,10 @@ class CECPQ2KeyShare : public SSLKeyShare {
uint8_t hrss_entropy[HRSS_GENERATE_KEY_BYTES];
HRSS_public_key hrss_public_key;
RAND_bytes(hrss_entropy, sizeof(hrss_entropy));
- HRSS_generate_key(&hrss_public_key, &hrss_private_key_, hrss_entropy);
+ if (!HRSS_generate_key(&hrss_public_key, &hrss_private_key_,
+ hrss_entropy)) {
+ return false;
+ }
uint8_t hrss_public_key_bytes[HRSS_PUBLIC_KEY_BYTES];
HRSS_marshal_public_key(hrss_public_key_bytes, &hrss_public_key);
@@ -258,9 +246,10 @@ class CECPQ2KeyShare : public SSLKeyShare {
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES];
uint8_t entropy[HRSS_ENCAP_BYTES];
RAND_bytes(entropy, sizeof(entropy));
- HRSS_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy);
- if (!CBB_add_bytes(out_public_key, x25519_public_key,
+ if (!HRSS_encap(ciphertext, secret.data() + 32, &peer_public_key,
+ entropy) ||
+ !CBB_add_bytes(out_public_key, x25519_public_key,
sizeof(x25519_public_key)) ||
!CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) {
return false;
@@ -287,8 +276,10 @@ class CECPQ2KeyShare : public SSLKeyShare {
return false;
}
- HRSS_decap(secret.data() + 32, &hrss_private_key_, peer_key.data() + 32,
- peer_key.size() - 32);
+ if (!HRSS_decap(secret.data() + 32, &hrss_private_key_,
+ peer_key.data() + 32, peer_key.size() - 32)) {
+ return false;
+ }
*out_secret = std::move(secret);
return true;
@@ -339,16 +330,28 @@ UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) {
UniquePtr<SSLKeyShare> SSLKeyShare::Create(CBS *in) {
uint64_t group;
- if (!CBS_get_asn1_uint64(in, &group) || group > 0xffff) {
+ CBS private_key;
+ if (!CBS_get_asn1_uint64(in, &group) || group > 0xffff ||
+ !CBS_get_asn1(in, &private_key, CBS_ASN1_OCTETSTRING)) {
return nullptr;
}
UniquePtr<SSLKeyShare> key_share = Create(static_cast<uint16_t>(group));
- if (!key_share || !key_share->Deserialize(in)) {
+ if (!key_share || !key_share->DeserializePrivateKey(&private_key)) {
return nullptr;
}
return key_share;
}
+bool SSLKeyShare::Serialize(CBB *out) {
+ CBB private_key;
+ if (!CBB_add_asn1_uint64(out, GroupID()) ||
+ !CBB_add_asn1(out, &private_key, CBS_ASN1_OCTETSTRING) ||
+ !SerializePrivateKey(&private_key) || //
+ !CBB_flush(out)) {
+ return false;
+ }
+ return true;
+}
bool SSLKeyShare::Accept(CBB *out_public_key, Array<uint8_t> *out_secret,
uint8_t *out_alert, Span<const uint8_t> peer_key) {
diff --git a/deps/boringssl/src/ssl/ssl_lib.cc b/deps/boringssl/src/ssl/ssl_lib.cc
index 7c7bbbf..03864e1 100644
--- a/deps/boringssl/src/ssl/ssl_lib.cc
+++ b/deps/boringssl/src/ssl/ssl_lib.cc
@@ -272,57 +272,6 @@ ssl_open_record_t ssl_open_app_data(SSL *ssl, Span<uint8_t> *out,
return ret;
}
-void ssl_update_cache(SSL_HANDSHAKE *hs, int mode) {
- SSL *const ssl = hs->ssl;
- SSL_CTX *ctx = ssl->session_ctx.get();
- // Never cache sessions with empty session IDs.
- if (ssl->s3->established_session->session_id_length == 0 ||
- ssl->s3->established_session->not_resumable ||
- (ctx->session_cache_mode & mode) != mode) {
- return;
- }
-
- // Clients never use the internal session cache.
- int use_internal_cache = ssl->server && !(ctx->session_cache_mode &
- SSL_SESS_CACHE_NO_INTERNAL_STORE);
-
- // A client may see new sessions on abbreviated handshakes if the server
- // decides to renew the ticket. Once the handshake is completed, it should be
- // inserted into the cache.
- if (ssl->s3->established_session.get() != ssl->session.get() ||
- (!ssl->server && hs->ticket_expected)) {
- if (use_internal_cache) {
- SSL_CTX_add_session(ctx, ssl->s3->established_session.get());
- }
- if (ctx->new_session_cb != NULL) {
- UniquePtr<SSL_SESSION> ref = UpRef(ssl->s3->established_session);
- if (ctx->new_session_cb(ssl, ref.get())) {
- // |new_session_cb|'s return value signals whether it took ownership.
- ref.release();
- }
- }
- }
-
- if (use_internal_cache &&
- !(ctx->session_cache_mode & SSL_SESS_CACHE_NO_AUTO_CLEAR)) {
- // Automatically flush the internal session cache every 255 connections.
- int flush_cache = 0;
- CRYPTO_MUTEX_lock_write(&ctx->lock);
- ctx->handshakes_since_cache_flush++;
- if (ctx->handshakes_since_cache_flush >= 255) {
- flush_cache = 1;
- ctx->handshakes_since_cache_flush = 0;
- }
- CRYPTO_MUTEX_unlock_write(&ctx->lock);
-
- if (flush_cache) {
- struct OPENSSL_timeval now;
- ssl_get_current_time(ssl, &now);
- SSL_CTX_flush_sessions(ctx, now.tv_sec);
- }
- }
-}
-
static bool cbb_add_hex(CBB *cbb, Span<const uint8_t> in) {
static const char hextable[] = "0123456789abcdef";
uint8_t *out;
@@ -463,7 +412,8 @@ static bool ssl_can_renegotiate(const SSL *ssl) {
return false;
}
- if (ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
+ if (ssl->s3->have_version &&
+ ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
return false;
}
@@ -563,6 +513,7 @@ ssl_ctx_st::ssl_ctx_st(const SSL_METHOD *ssl_method)
signed_cert_timestamps_enabled(false),
channel_id_enabled(false),
grease_enabled(false),
+ permute_extensions(false),
allow_unknown_alpn_protos(false),
false_start_allowed_without_alpn(false),
handoff(false),
@@ -685,6 +636,7 @@ SSL *SSL_new(SSL_CTX *ctx) {
ssl->config->custom_verify_callback = ctx->custom_verify_callback;
ssl->config->retain_only_sha256_of_client_certs =
ctx->retain_only_sha256_of_client_certs;
+ ssl->config->permute_extensions = ctx->permute_extensions;
if (!ssl->config->supported_group_list.CopyFrom(ctx->supported_group_list) ||
!ssl->config->alpn_client_proto_list.CopyFrom(
@@ -731,7 +683,8 @@ SSL_CONFIG::SSL_CONFIG(SSL *ssl_arg)
handoff(false),
shed_handshake_config(false),
jdk11_workaround(false),
- quic_use_legacy_codepoint(true) {
+ quic_use_legacy_codepoint(false),
+ permute_extensions(false) {
assert(ssl);
}
@@ -1070,7 +1023,7 @@ int SSL_read(SSL *ssl, void *buf, int num) {
int SSL_peek(SSL *ssl, void *buf, int num) {
if (ssl->quic_method != nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
+ return -1;
}
int ret = ssl_read_impl(ssl);
@@ -1091,7 +1044,7 @@ int SSL_write(SSL *ssl, const void *buf, int num) {
if (ssl->quic_method != nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
+ return -1;
}
if (ssl->do_handshake == NULL) {
@@ -1099,11 +1052,6 @@ int SSL_write(SSL *ssl, const void *buf, int num) {
return -1;
}
- if (ssl->s3->write_shutdown != ssl_shutdown_none) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN);
- return -1;
- }
-
int ret = 0;
bool needs_handshake = false;
do {
@@ -1317,8 +1265,6 @@ const char *SSL_early_data_reason_string(enum ssl_early_data_reason_t reason) {
return "alpn_mismatch";
case ssl_early_data_channel_id:
return "channel_id";
- case ssl_early_data_token_binding:
- return "token_binding";
case ssl_early_data_ticket_age_skew:
return "ticket_age_skew";
case ssl_early_data_quic_parameter_mismatch:
@@ -1372,12 +1318,12 @@ int SSL_get_error(const SSL *ssl, int ret_code) {
case SSL_ERROR_HANDOFF:
case SSL_ERROR_HANDBACK:
case SSL_ERROR_WANT_X509_LOOKUP:
- case SSL_ERROR_WANT_CHANNEL_ID_LOOKUP:
case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION:
case SSL_ERROR_PENDING_TICKET:
case SSL_ERROR_EARLY_DATA_REJECTED:
case SSL_ERROR_WANT_CERTIFICATE_VERIFY:
case SSL_ERROR_WANT_RENEGOTIATE:
+ case SSL_ERROR_HANDSHAKE_HINTS_READY:
return ssl->s3->rwstate;
case SSL_ERROR_WANT_READ: {
@@ -1445,8 +1391,6 @@ const char *SSL_error_description(int err) {
return "WANT_CONNECT";
case SSL_ERROR_WANT_ACCEPT:
return "WANT_ACCEPT";
- case SSL_ERROR_WANT_CHANNEL_ID_LOOKUP:
- return "WANT_CHANNEL_ID_LOOKUP";
case SSL_ERROR_PENDING_SESSION:
return "PENDING_SESSION";
case SSL_ERROR_PENDING_CERTIFICATE:
@@ -1463,18 +1407,15 @@ const char *SSL_error_description(int err) {
return "HANDOFF";
case SSL_ERROR_HANDBACK:
return "HANDBACK";
+ case SSL_ERROR_WANT_RENEGOTIATE:
+ return "WANT_RENEGOTIATE";
+ case SSL_ERROR_HANDSHAKE_HINTS_READY:
+ return "HANDSHAKE_HINTS_READY";
default:
return nullptr;
}
}
-void SSL_set_enable_ech_grease(SSL *ssl, int enable) {
- if (!ssl->config) {
- return;
- }
- ssl->config->ech_grease_enabled = !!enable;
-}
-
uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) {
ctx->options |= options;
return ctx->options;
@@ -1785,6 +1726,9 @@ int SSL_renegotiate(SSL *ssl) {
return 0;
}
+ // We should not have told the caller to release the private key.
+ assert(!SSL_can_release_private_key(ssl));
+
// Renegotiation is only supported at quiescent points in the application
// protocol, namely in HTTPS, just before reading the HTTP response.
// Require the record-layer be idle and avoid complexities of sending a
@@ -2243,21 +2187,26 @@ void SSL_CTX_set_next_proto_select_cb(
int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const uint8_t *protos,
unsigned protos_len) {
- // Note this function's calling convention is backwards.
- return ctx->alpn_client_proto_list.CopyFrom(MakeConstSpan(protos, protos_len))
- ? 0
- : 1;
+ // Note this function's return value is backwards.
+ auto span = MakeConstSpan(protos, protos_len);
+ if (!span.empty() && !ssl_is_valid_alpn_list(span)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL_LIST);
+ return 1;
+ }
+ return ctx->alpn_client_proto_list.CopyFrom(span) ? 0 : 1;
}
int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos, unsigned protos_len) {
- // Note this function's calling convention is backwards.
+ // Note this function's return value is backwards.
if (!ssl->config) {
return 1;
}
- return ssl->config->alpn_client_proto_list.CopyFrom(
- MakeConstSpan(protos, protos_len))
- ? 0
- : 1;
+ auto span = MakeConstSpan(protos, protos_len);
+ if (!span.empty() && !ssl_is_valid_alpn_list(span)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL_LIST);
+ return 1;
+ }
+ return ssl->config->alpn_client_proto_list.CopyFrom(span) ? 0 : 1;
}
void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
@@ -2367,8 +2316,6 @@ int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, EVP_PKEY *private_key) {
}
ctx->channel_id_private = UpRef(private_key);
- ctx->channel_id_enabled = true;
-
return 1;
}
@@ -2382,8 +2329,6 @@ int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key) {
}
ssl->config->channel_id_private = UpRef(private_key);
- ssl->config->channel_id_enabled = true;
-
return 1;
}
@@ -2395,25 +2340,6 @@ size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, size_t max_out) {
return 64;
}
-int SSL_set_token_binding_params(SSL *ssl, const uint8_t *params, size_t len) {
- if (!ssl->config) {
- return 0;
- }
- if (len > 256) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
- return 0;
- }
- return ssl->config->token_binding_params.CopyFrom(MakeConstSpan(params, len));
-}
-
-int SSL_is_token_binding_negotiated(const SSL *ssl) {
- return ssl->s3->token_binding_negotiated;
-}
-
-uint8_t SSL_get_negotiated_token_binding_param(const SSL *ssl) {
- return ssl->s3->negotiated_token_binding_param;
-}
-
size_t SSL_get0_certificate_types(const SSL *ssl, const uint8_t **out_types) {
Span<const uint8_t> types;
if (!ssl->server && ssl->s3->hs != nullptr) {
@@ -2775,6 +2701,17 @@ void SSL_CTX_set_current_time_cb(SSL_CTX *ctx,
ctx->current_time_cb = cb;
}
+int SSL_can_release_private_key(const SSL *ssl) {
+ if (ssl_can_renegotiate(ssl)) {
+ // If the connection can renegotiate (client only), the private key may be
+ // used in a future handshake.
+ return 0;
+ }
+
+ // Otherwise, this is determined by the current handshake.
+ return !ssl->s3->hs || ssl->s3->hs->can_release_private_key;
+}
+
int SSL_is_init_finished(const SSL *ssl) {
return !SSL_in_init(ssl);
}
@@ -2927,6 +2864,17 @@ void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled) {
ctx->grease_enabled = !!enabled;
}
+void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled) {
+ ctx->permute_extensions = !!enabled;
+}
+
+void SSL_set_permute_extensions(SSL *ssl, int enabled) {
+ if (!ssl->config) {
+ return;
+ }
+ ssl->config->permute_extensions = !!enabled;
+}
+
int32_t SSL_get_ticket_age_skew(const SSL *ssl) {
return ssl->s3->ticket_age_skew;
}
@@ -2935,16 +2883,10 @@ void SSL_CTX_set_false_start_allowed_without_alpn(SSL_CTX *ctx, int allowed) {
ctx->false_start_allowed_without_alpn = !!allowed;
}
-int SSL_is_tls13_downgrade(const SSL *ssl) { return 0; }
-
int SSL_used_hello_retry_request(const SSL *ssl) {
return ssl->s3->used_hello_retry_request;
}
-void SSL_CTX_set_ignore_tls13_downgrade(SSL_CTX *ctx, int ignore) {}
-
-void SSL_set_ignore_tls13_downgrade(SSL *ssl, int ignore) {}
-
void SSL_set_shed_handshake_config(SSL *ssl, int enable) {
if (!ssl->config) {
return;
diff --git a/deps/boringssl/src/ssl/ssl_privkey.cc b/deps/boringssl/src/ssl/ssl_privkey.cc
index e800136..8462ebf 100644
--- a/deps/boringssl/src/ssl/ssl_privkey.cc
+++ b/deps/boringssl/src/ssl/ssl_privkey.cc
@@ -203,6 +203,7 @@ enum ssl_private_key_result_t ssl_private_key_sign(
SSL *const ssl = hs->ssl;
const SSL_PRIVATE_KEY_METHOD *key_method = hs->config->cert->key_method;
EVP_PKEY *privatekey = hs->config->cert->privatekey.get();
+ assert(!hs->can_release_private_key);
if (ssl_signing_with_dc(hs)) {
key_method = hs->config->cert->dc_key_method;
privatekey = hs->config->cert->dc_privatekey.get();
@@ -254,6 +255,7 @@ enum ssl_private_key_result_t ssl_private_key_decrypt(SSL_HANDSHAKE *hs,
size_t max_out,
Span<const uint8_t> in) {
SSL *const ssl = hs->ssl;
+ assert(!hs->can_release_private_key);
if (hs->config->cert->key_method != NULL) {
enum ssl_private_key_result_t ret;
if (hs->pending_private_key_op) {
diff --git a/deps/boringssl/src/ssl/ssl_session.cc b/deps/boringssl/src/ssl/ssl_session.cc
index 91b2fff..76e6dc4 100644
--- a/deps/boringssl/src/ssl/ssl_session.cc
+++ b/deps/boringssl/src/ssl/ssl_session.cc
@@ -163,7 +163,6 @@ static CRYPTO_EX_DATA_CLASS g_ex_data_class =
static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session);
static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session);
-static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock);
UniquePtr<SSL_SESSION> ssl_session_new(const SSL_X509_METHOD *x509_method) {
return MakeUnique<SSL_SESSION>(x509_method);
@@ -350,19 +349,19 @@ const EVP_MD *ssl_session_get_digest(const SSL_SESSION *session) {
session->cipher);
}
-int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) {
+bool ssl_get_new_session(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
if (ssl->mode & SSL_MODE_NO_SESSION_CREATION) {
OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_MAY_NOT_BE_CREATED);
- return 0;
+ return false;
}
UniquePtr<SSL_SESSION> session = ssl_session_new(ssl->ctx->x509_method);
if (session == NULL) {
- return 0;
+ return false;
}
- session->is_server = is_server;
+ session->is_server = ssl->server;
session->ssl_version = ssl->version;
session->is_quic = ssl->quic_method != nullptr;
@@ -384,24 +383,9 @@ int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) {
session->auth_timeout = ssl->session_ctx->session_timeout;
}
- if (is_server) {
- if (hs->ticket_expected || version >= TLS1_3_VERSION) {
- // Don't set session IDs for sessions resumed with tickets. This will keep
- // them out of the session cache.
- session->session_id_length = 0;
- } else {
- session->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
- if (!RAND_bytes(session->session_id, session->session_id_length)) {
- return 0;
- }
- }
- } else {
- session->session_id_length = 0;
- }
-
if (hs->config->cert->sid_ctx_length > sizeof(session->sid_ctx)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
+ return false;
}
OPENSSL_memcpy(session->sid_ctx, hs->config->cert->sid_ctx,
hs->config->cert->sid_ctx_length);
@@ -413,7 +397,7 @@ int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) {
hs->new_session = std::move(session);
ssl_set_session(ssl, NULL);
- return 1;
+ return true;
}
int ssl_ctx_rotate_ticket_encryption_key(SSL_CTX *ctx) {
@@ -769,34 +753,36 @@ enum ssl_hs_wait_t ssl_get_prev_session(SSL_HANDSHAKE *hs,
return ssl_hs_ok;
}
-static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock) {
- int ret = 0;
+static bool remove_session(SSL_CTX *ctx, SSL_SESSION *session, bool lock) {
+ if (session == nullptr || session->session_id_length == 0) {
+ return false;
+ }
- if (session != NULL && session->session_id_length != 0) {
- if (lock) {
- CRYPTO_MUTEX_lock_write(&ctx->lock);
- }
- SSL_SESSION *found_session = lh_SSL_SESSION_retrieve(ctx->sessions,
- session);
- if (found_session == session) {
- ret = 1;
- found_session = lh_SSL_SESSION_delete(ctx->sessions, session);
- SSL_SESSION_list_remove(ctx, session);
- }
+ if (lock) {
+ CRYPTO_MUTEX_lock_write(&ctx->lock);
+ }
- if (lock) {
- CRYPTO_MUTEX_unlock_write(&ctx->lock);
- }
+ SSL_SESSION *found_session = lh_SSL_SESSION_retrieve(ctx->sessions, session);
+ bool found = found_session == session;
+ if (found) {
+ found_session = lh_SSL_SESSION_delete(ctx->sessions, session);
+ SSL_SESSION_list_remove(ctx, session);
+ }
- if (ret) {
- if (ctx->remove_session_cb != NULL) {
- ctx->remove_session_cb(ctx, found_session);
- }
- SSL_SESSION_free(found_session);
+ if (lock) {
+ CRYPTO_MUTEX_unlock_write(&ctx->lock);
+ }
+
+ if (found) {
+ // TODO(https://crbug.com/boringssl/251): Callbacks should not be called
+ // under a lock.
+ if (ctx->remove_session_cb != nullptr) {
+ ctx->remove_session_cb(ctx, found_session);
}
+ SSL_SESSION_free(found_session);
}
- return ret;
+ return found;
}
void ssl_set_session(SSL *ssl, SSL_SESSION *session) {
@@ -854,6 +840,98 @@ static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session) {
}
}
+static bool add_session_locked(SSL_CTX *ctx, UniquePtr<SSL_SESSION> session) {
+ SSL_SESSION *new_session = session.get();
+ SSL_SESSION *old_session;
+ if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, new_session)) {
+ return false;
+ }
+ // |ctx->sessions| took ownership of |new_session| and gave us back a
+ // reference to |old_session|. (|old_session| may be the same as
+ // |new_session|, in which case we traded identical references with
+ // |ctx->sessions|.)
+ session.release();
+ session.reset(old_session);
+
+ if (old_session != nullptr) {
+ if (old_session == new_session) {
+ // |session| was already in the cache. There are no linked list pointers
+ // to update.
+ return false;
+ }
+
+ // There was a session ID collision. |old_session| was replaced with
+ // |session| in the hash table, so |old_session| must be removed from the
+ // linked list to match.
+ SSL_SESSION_list_remove(ctx, old_session);
+ }
+
+ // This does not increment the reference count. Although |session| is inserted
+ // into two structures (a doubly-linked list and the hash table), |ctx| only
+ // takes one reference.
+ SSL_SESSION_list_add(ctx, new_session);
+
+ // Enforce any cache size limits.
+ if (SSL_CTX_sess_get_cache_size(ctx) > 0) {
+ while (lh_SSL_SESSION_num_items(ctx->sessions) >
+ SSL_CTX_sess_get_cache_size(ctx)) {
+ if (!remove_session(ctx, ctx->session_cache_tail,
+ /*lock=*/false)) {
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+void ssl_update_cache(SSL *ssl) {
+ SSL_CTX *ctx = ssl->session_ctx.get();
+ SSL_SESSION *session = ssl->s3->established_session.get();
+ int mode = SSL_is_server(ssl) ? SSL_SESS_CACHE_SERVER : SSL_SESS_CACHE_CLIENT;
+ if (!SSL_SESSION_is_resumable(session) ||
+ (ctx->session_cache_mode & mode) != mode) {
+ return;
+ }
+
+ // Clients never use the internal session cache.
+ if (ssl->server &&
+ !(ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
+ UniquePtr<SSL_SESSION> ref = UpRef(session);
+ bool remove_expired_sessions = false;
+ {
+ MutexWriteLock lock(&ctx->lock);
+ add_session_locked(ctx, std::move(ref));
+
+ if (!(ctx->session_cache_mode & SSL_SESS_CACHE_NO_AUTO_CLEAR)) {
+ // Automatically flush the internal session cache every 255 connections.
+ ctx->handshakes_since_cache_flush++;
+ if (ctx->handshakes_since_cache_flush >= 255) {
+ remove_expired_sessions = true;
+ ctx->handshakes_since_cache_flush = 0;
+ }
+ }
+ }
+
+ if (remove_expired_sessions) {
+ // |SSL_CTX_flush_sessions| takes the lock we just released. We could
+ // merge the critical sections, but we'd then call user code under a
+ // lock, or compute |now| earlier, even when not flushing.
+ OPENSSL_timeval now;
+ ssl_get_current_time(ssl, &now);
+ SSL_CTX_flush_sessions(ctx, now.tv_sec);
+ }
+ }
+
+ if (ctx->new_session_cb != nullptr) {
+ UniquePtr<SSL_SESSION> ref = UpRef(session);
+ if (ctx->new_session_cb(ssl, ref.get())) {
+ // |new_session_cb|'s return value signals whether it took ownership.
+ ref.release();
+ }
+ }
+}
+
BSSL_NAMESPACE_END
using namespace bssl;
@@ -1019,7 +1097,8 @@ int SSL_SESSION_should_be_single_use(const SSL_SESSION *session) {
}
int SSL_SESSION_is_resumable(const SSL_SESSION *session) {
- return !session->not_resumable;
+ return !session->not_resumable &&
+ (session->session_id_length != 0 || !session->ticket.empty());
}
int SSL_SESSION_has_ticket(const SSL_SESSION *session) {
@@ -1135,51 +1214,13 @@ void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) {
}
int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session) {
- // Although |session| is inserted into two structures (a doubly-linked list
- // and the hash table), |ctx| only takes one reference.
UniquePtr<SSL_SESSION> owned_session = UpRef(session);
-
- SSL_SESSION *old_session;
MutexWriteLock lock(&ctx->lock);
- if (!lh_SSL_SESSION_insert(ctx->sessions, &old_session, session)) {
- return 0;
- }
- // |ctx->sessions| took ownership of |session| and gave us back a reference to
- // |old_session|. (|old_session| may be the same as |session|, in which case
- // we traded identical references with |ctx->sessions|.)
- owned_session.release();
- owned_session.reset(old_session);
-
- if (old_session != NULL) {
- if (old_session == session) {
- // |session| was already in the cache. There are no linked list pointers
- // to update.
- return 0;
- }
-
- // There was a session ID collision. |old_session| was replaced with
- // |session| in the hash table, so |old_session| must be removed from the
- // linked list to match.
- SSL_SESSION_list_remove(ctx, old_session);
- }
-
- SSL_SESSION_list_add(ctx, session);
-
- // Enforce any cache size limits.
- if (SSL_CTX_sess_get_cache_size(ctx) > 0) {
- while (lh_SSL_SESSION_num_items(ctx->sessions) >
- SSL_CTX_sess_get_cache_size(ctx)) {
- if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) {
- break;
- }
- }
- }
-
- return 1;
+ return add_session_locked(ctx, std::move(owned_session));
}
int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *session) {
- return remove_session_lock(ctx, session, 1);
+ return remove_session(ctx, session, /*lock=*/true);
}
int SSL_set_session(SSL *ssl, SSL_SESSION *session) {
@@ -1233,10 +1274,11 @@ static void timeout_doall_arg(SSL_SESSION *session, void *void_param) {
if (param->time == 0 ||
session->time + session->timeout < session->time ||
param->time > (session->time + session->timeout)) {
- // The reason we don't call SSL_CTX_remove_session() is to
- // save on locking overhead
+ // TODO(davidben): This can probably just call |remove_session|.
(void) lh_SSL_SESSION_delete(param->cache, session);
SSL_SESSION_list_remove(param->ctx, session);
+ // TODO(https://crbug.com/boringssl/251): Callbacks should not be called
+ // under a lock.
if (param->ctx->remove_session_cb != NULL) {
param->ctx->remove_session_cb(param->ctx, session);
}
@@ -1298,12 +1340,3 @@ void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl, int type,
int value) {
return ctx->info_callback;
}
-
-void SSL_CTX_set_channel_id_cb(SSL_CTX *ctx,
- void (*cb)(SSL *ssl, EVP_PKEY **pkey)) {
- ctx->channel_id_cb = cb;
-}
-
-void (*SSL_CTX_get_channel_id_cb(SSL_CTX *ctx))(SSL *ssl, EVP_PKEY **pkey) {
- return ctx->channel_id_cb;
-}
diff --git a/deps/boringssl/src/ssl/ssl_stat.cc b/deps/boringssl/src/ssl/ssl_stat.cc
index 5770aac..f7e1675 100644
--- a/deps/boringssl/src/ssl/ssl_stat.cc
+++ b/deps/boringssl/src/ssl/ssl_stat.cc
@@ -224,6 +224,9 @@ const char *SSL_alert_desc_string_long(int value) {
case TLS1_AD_NO_APPLICATION_PROTOCOL:
return "no application protocol";
+ case TLS1_AD_ECH_REQUIRED:
+ return "ECH required";
+
default:
return "unknown";
}
diff --git a/deps/boringssl/src/ssl/ssl_test.cc b/deps/boringssl/src/ssl/ssl_test.cc
index 637f4d5..60d820b 100644
--- a/deps/boringssl/src/ssl/ssl_test.cc
+++ b/deps/boringssl/src/ssl/ssl_test.cc
@@ -26,11 +26,14 @@
#include <openssl/aead.h>
#include <openssl/base64.h>
+#include <openssl/bytestring.h>
#include <openssl/bio.h>
#include <openssl/cipher.h>
#include <openssl/crypto.h>
+#include <openssl/curve25519.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
+#include <openssl/hpke.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/ssl.h>
@@ -1192,6 +1195,24 @@ TEST(SSLTest, Padding) {
}
}
+static bssl::UniquePtr<X509> CertFromPEM(const char *pem) {
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
+ if (!bio) {
+ return nullptr;
+ }
+ return bssl::UniquePtr<X509>(
+ PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+}
+
+static bssl::UniquePtr<EVP_PKEY> KeyFromPEM(const char *pem) {
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
+ if (!bio) {
+ return nullptr;
+ }
+ return bssl::UniquePtr<EVP_PKEY>(
+ PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+}
+
static bssl::UniquePtr<X509> GetTestCertificate() {
static const char kCertPEM[] =
"-----BEGIN CERTIFICATE-----\n"
@@ -1209,9 +1230,7 @@ static bssl::UniquePtr<X509> GetTestCertificate() {
"T5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4f\n"
"j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==\n"
"-----END CERTIFICATE-----\n";
- bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kCertPEM, strlen(kCertPEM)));
- return bssl::UniquePtr<X509>(
- PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+ return CertFromPEM(kCertPEM);
}
static bssl::UniquePtr<EVP_PKEY> GetTestKey() {
@@ -1231,9 +1250,20 @@ static bssl::UniquePtr<EVP_PKEY> GetTestKey() {
"tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n"
"moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n"
"-----END RSA PRIVATE KEY-----\n";
- bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kKeyPEM, strlen(kKeyPEM)));
- return bssl::UniquePtr<EVP_PKEY>(
- PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+ return KeyFromPEM(kKeyPEM);
+}
+
+static bssl::UniquePtr<SSL_CTX> CreateContextWithTestCertificate(
+ const SSL_METHOD *method) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ if (!ctx || !cert || !key ||
+ !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(ctx.get(), key.get())) {
+ return nullptr;
+ }
+ return ctx;
}
static bssl::UniquePtr<X509> GetECDSATestCertificate() {
@@ -1250,8 +1280,7 @@ static bssl::UniquePtr<X509> GetECDSATestCertificate() {
"BgcqhkjOPQQBA0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13E\n"
"BwIgfB55FGohg/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=\n"
"-----END CERTIFICATE-----\n";
- bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kCertPEM, strlen(kCertPEM)));
- return bssl::UniquePtr<X509>(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+ return CertFromPEM(kCertPEM);
}
static bssl::UniquePtr<EVP_PKEY> GetECDSATestKey() {
@@ -1261,9 +1290,7 @@ static bssl::UniquePtr<EVP_PKEY> GetECDSATestKey() {
"TYlodwi1b8ldMHcO6NHJzgqLtGqhRANCAATmK2niv2Wfl74vHg2UikzVl2u3qR4N\n"
"Rvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYaHPUdfvGULUvPciLB\n"
"-----END PRIVATE KEY-----\n";
- bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kKeyPEM, strlen(kKeyPEM)));
- return bssl::UniquePtr<EVP_PKEY>(
- PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+ return KeyFromPEM(kKeyPEM);
}
static bssl::UniquePtr<CRYPTO_BUFFER> BufferFromPEM(const char *pem) {
@@ -1377,9 +1404,165 @@ static bssl::UniquePtr<EVP_PKEY> GetChainTestKey() {
"buB7ERSdaNbO21zXt9FEA3+z0RfMd/Zv2vlIWOSB5nzl/7UKti3sribK6s9ZVLfi\n"
"SxpiPQ8d/hmSGwn4ksrWUsJD\n"
"-----END PRIVATE KEY-----\n";
- bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kKeyPEM, strlen(kKeyPEM)));
- return bssl::UniquePtr<EVP_PKEY>(
- PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+ return KeyFromPEM(kKeyPEM);
+}
+
+static bool CompleteHandshakes(SSL *client, SSL *server) {
+ // Drive both their handshakes to completion.
+ for (;;) {
+ int client_ret = SSL_do_handshake(client);
+ int client_err = SSL_get_error(client, client_ret);
+ if (client_err != SSL_ERROR_NONE &&
+ client_err != SSL_ERROR_WANT_READ &&
+ client_err != SSL_ERROR_WANT_WRITE &&
+ client_err != SSL_ERROR_PENDING_TICKET) {
+ fprintf(stderr, "Client error: %s\n", SSL_error_description(client_err));
+ return false;
+ }
+
+ int server_ret = SSL_do_handshake(server);
+ int server_err = SSL_get_error(server, server_ret);
+ if (server_err != SSL_ERROR_NONE &&
+ server_err != SSL_ERROR_WANT_READ &&
+ server_err != SSL_ERROR_WANT_WRITE &&
+ server_err != SSL_ERROR_PENDING_TICKET) {
+ fprintf(stderr, "Server error: %s\n", SSL_error_description(server_err));
+ return false;
+ }
+
+ if (client_ret == 1 && server_ret == 1) {
+ break;
+ }
+ }
+
+ return true;
+}
+
+static bool FlushNewSessionTickets(SSL *client, SSL *server) {
+ // NewSessionTickets are deferred on the server to |SSL_write|, and clients do
+ // not pick them up until |SSL_read|.
+ for (;;) {
+ int server_ret = SSL_write(server, nullptr, 0);
+ int server_err = SSL_get_error(server, server_ret);
+ // The server may either succeed (|server_ret| is zero) or block on write
+ // (|server_ret| is -1 and |server_err| is |SSL_ERROR_WANT_WRITE|).
+ if (server_ret > 0 ||
+ (server_ret < 0 && server_err != SSL_ERROR_WANT_WRITE)) {
+ fprintf(stderr, "Unexpected server result: %d %d\n", server_ret,
+ server_err);
+ return false;
+ }
+
+ int client_ret = SSL_read(client, nullptr, 0);
+ int client_err = SSL_get_error(client, client_ret);
+ // The client must always block on read.
+ if (client_ret != -1 || client_err != SSL_ERROR_WANT_READ) {
+ fprintf(stderr, "Unexpected client result: %d %d\n", client_ret,
+ client_err);
+ return false;
+ }
+
+ // The server flushed everything it had to write.
+ if (server_ret == 0) {
+ return true;
+ }
+ }
+}
+
+// CreateClientAndServer creates a client and server |SSL| objects whose |BIO|s
+// are paired with each other. It does not run the handshake. The caller is
+// expected to configure the objects and drive the handshake as needed.
+static bool CreateClientAndServer(bssl::UniquePtr<SSL> *out_client,
+ bssl::UniquePtr<SSL> *out_server,
+ SSL_CTX *client_ctx, SSL_CTX *server_ctx) {
+ bssl::UniquePtr<SSL> client(SSL_new(client_ctx)), server(SSL_new(server_ctx));
+ if (!client || !server) {
+ return false;
+ }
+ SSL_set_connect_state(client.get());
+ SSL_set_accept_state(server.get());
+
+ BIO *bio1, *bio2;
+ if (!BIO_new_bio_pair(&bio1, 0, &bio2, 0)) {
+ return false;
+ }
+ // SSL_set_bio takes ownership.
+ SSL_set_bio(client.get(), bio1, bio1);
+ SSL_set_bio(server.get(), bio2, bio2);
+
+ *out_client = std::move(client);
+ *out_server = std::move(server);
+ return true;
+}
+
+struct ClientConfig {
+ SSL_SESSION *session = nullptr;
+ std::string servername;
+ bool early_data = false;
+};
+
+static bool ConnectClientAndServer(bssl::UniquePtr<SSL> *out_client,
+ bssl::UniquePtr<SSL> *out_server,
+ SSL_CTX *client_ctx, SSL_CTX *server_ctx,
+ const ClientConfig &config = ClientConfig(),
+ bool shed_handshake_config = true) {
+ bssl::UniquePtr<SSL> client, server;
+ if (!CreateClientAndServer(&client, &server, client_ctx, server_ctx)) {
+ return false;
+ }
+ if (config.early_data) {
+ SSL_set_early_data_enabled(client.get(), 1);
+ }
+ if (config.session) {
+ SSL_set_session(client.get(), config.session);
+ }
+ if (!config.servername.empty() &&
+ !SSL_set_tlsext_host_name(client.get(), config.servername.c_str())) {
+ return false;
+ }
+
+ SSL_set_shed_handshake_config(client.get(), shed_handshake_config);
+ SSL_set_shed_handshake_config(server.get(), shed_handshake_config);
+
+ if (!CompleteHandshakes(client.get(), server.get())) {
+ return false;
+ }
+
+ *out_client = std::move(client);
+ *out_server = std::move(server);
+ return true;
+}
+
+static bssl::UniquePtr<SSL_SESSION> g_last_session;
+
+static int SaveLastSession(SSL *ssl, SSL_SESSION *session) {
+ // Save the most recent session.
+ g_last_session.reset(session);
+ return 1;
+}
+
+static bssl::UniquePtr<SSL_SESSION> CreateClientSession(
+ SSL_CTX *client_ctx, SSL_CTX *server_ctx,
+ const ClientConfig &config = ClientConfig()) {
+ g_last_session = nullptr;
+ SSL_CTX_sess_set_new_cb(client_ctx, SaveLastSession);
+
+ // Connect client and server to get a session.
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx, server_ctx,
+ config) ||
+ !FlushNewSessionTickets(client.get(), server.get())) {
+ fprintf(stderr, "Failed to connect client and server.\n");
+ return nullptr;
+ }
+
+ SSL_CTX_sess_set_new_cb(client_ctx, nullptr);
+
+ if (!g_last_session) {
+ fprintf(stderr, "Client did not receive a session.\n");
+ return nullptr;
+ }
+ return std::move(g_last_session);
}
// Test that |SSL_get_client_CA_list| echoes back the configured parameter even
@@ -1440,6 +1623,746 @@ TEST(SSLTest, AddClientCA) {
EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(list, 2), name1));
}
+struct ECHConfigParams {
+ uint16_t version = TLSEXT_TYPE_encrypted_client_hello;
+ uint16_t config_id = 1;
+ std::string public_name = "example.com";
+ const EVP_HPKE_KEY *key = nullptr;
+ // kem_id, if zero, takes its value from |key|.
+ uint16_t kem_id = 0;
+ // public_key, if empty takes its value from |key|.
+ std::vector<uint8_t> public_key;
+ size_t max_name_len = 16;
+ // cipher_suites is a list of code points which should contain pairs of KDF
+ // and AEAD IDs.
+ std::vector<uint16_t> cipher_suites = {EVP_HPKE_HKDF_SHA256,
+ EVP_HPKE_AES_128_GCM};
+ std::vector<uint8_t> extensions;
+};
+
+// MakeECHConfig serializes an ECHConfig from |params| and writes it to
+// |*out|.
+bool MakeECHConfig(std::vector<uint8_t> *out,
+ const ECHConfigParams &params) {
+ uint16_t kem_id = params.kem_id == 0
+ ? EVP_HPKE_KEM_id(EVP_HPKE_KEY_kem(params.key))
+ : params.kem_id;
+ std::vector<uint8_t> public_key = params.public_key;
+ if (public_key.empty()) {
+ public_key.resize(EVP_HPKE_MAX_PUBLIC_KEY_LENGTH);
+ size_t len;
+ if (!EVP_HPKE_KEY_public_key(params.key, public_key.data(), &len,
+ public_key.size())) {
+ return false;
+ }
+ public_key.resize(len);
+ }
+
+ bssl::ScopedCBB cbb;
+ CBB contents, child;
+ if (!CBB_init(cbb.get(), 64) ||
+ !CBB_add_u16(cbb.get(), params.version) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &contents) ||
+ !CBB_add_u8(&contents, params.config_id) ||
+ !CBB_add_u16(&contents, kem_id) ||
+ !CBB_add_u16_length_prefixed(&contents, &child) ||
+ !CBB_add_bytes(&child, public_key.data(), public_key.size()) ||
+ !CBB_add_u16_length_prefixed(&contents, &child)) {
+ return false;
+ }
+ for (uint16_t cipher_suite : params.cipher_suites) {
+ if (!CBB_add_u16(&child, cipher_suite)) {
+ return false;
+ }
+ }
+ if (!CBB_add_u8(&contents, params.max_name_len) ||
+ !CBB_add_u8_length_prefixed(&contents, &child) ||
+ !CBB_add_bytes(
+ &child, reinterpret_cast<const uint8_t *>(params.public_name.data()),
+ params.public_name.size()) ||
+ !CBB_add_u16_length_prefixed(&contents, &child) ||
+ !CBB_add_bytes(&child, params.extensions.data(),
+ params.extensions.size()) ||
+ !CBB_flush(cbb.get())) {
+ return false;
+ }
+
+ out->assign(CBB_data(cbb.get()), CBB_data(cbb.get()) + CBB_len(cbb.get()));
+ return true;
+}
+
+static bssl::UniquePtr<SSL_ECH_KEYS> MakeTestECHKeys(uint8_t config_id = 1) {
+ bssl::ScopedEVP_HPKE_KEY key;
+ uint8_t *ech_config;
+ size_t ech_config_len;
+ if (!EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()) ||
+ !SSL_marshal_ech_config(&ech_config, &ech_config_len, config_id,
+ key.get(), "public.example", 16)) {
+ return nullptr;
+ }
+ bssl::UniquePtr<uint8_t> free_ech_config(ech_config);
+
+ // Install a non-retry config.
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ if (!keys || !SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1, ech_config,
+ ech_config_len, key.get())) {
+ return nullptr;
+ }
+ return keys;
+}
+
+static bool InstallECHConfigList(SSL *client, const SSL_ECH_KEYS *keys) {
+ uint8_t *ech_config_list;
+ size_t ech_config_list_len;
+ if (!SSL_ECH_KEYS_marshal_retry_configs(keys, &ech_config_list,
+ &ech_config_list_len)) {
+ return false;
+ }
+ bssl::UniquePtr<uint8_t> free_ech_config_list(ech_config_list);
+ return SSL_set1_ech_config_list(client, ech_config_list, ech_config_list_len);
+}
+
+// Test that |SSL_marshal_ech_config| and |SSL_ECH_KEYS_marshal_retry_configs|
+// output values as expected.
+TEST(SSLTest, MarshalECHConfig) {
+ static const uint8_t kPrivateKey[X25519_PRIVATE_KEY_LEN] = {
+ 0xbc, 0xb5, 0x51, 0x29, 0x31, 0x10, 0x30, 0xc9, 0xed, 0x26, 0xde,
+ 0xd4, 0xb3, 0xdf, 0x3a, 0xce, 0x06, 0x8a, 0xee, 0x17, 0xab, 0xce,
+ 0xd7, 0xdb, 0xf3, 0x11, 0xe5, 0xa8, 0xf3, 0xb1, 0x8e, 0x24};
+ bssl::ScopedEVP_HPKE_KEY key;
+ ASSERT_TRUE(EVP_HPKE_KEY_init(key.get(), EVP_hpke_x25519_hkdf_sha256(),
+ kPrivateKey, sizeof(kPrivateKey)));
+
+ static const uint8_t kECHConfig[] = {
+ // version
+ 0xfe, 0x0d,
+ // length
+ 0x00, 0x41,
+ // contents.config_id
+ 0x01,
+ // contents.kem_id
+ 0x00, 0x20,
+ // contents.public_key
+ 0x00, 0x20, 0xa6, 0x9a, 0x41, 0x48, 0x5d, 0x32, 0x96, 0xa4, 0xe0, 0xc3,
+ 0x6a, 0xee, 0xf6, 0x63, 0x0f, 0x59, 0x32, 0x6f, 0xdc, 0xff, 0x81, 0x29,
+ 0x59, 0xa5, 0x85, 0xd3, 0x9b, 0x3b, 0xde, 0x98, 0x55, 0x5c,
+ // contents.cipher_suites
+ 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03,
+ // contents.maximum_name_length
+ 0x10,
+ // contents.public_name
+ 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2e, 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65,
+ // contents.extensions
+ 0x00, 0x00};
+ uint8_t *ech_config;
+ size_t ech_config_len;
+ ASSERT_TRUE(SSL_marshal_ech_config(&ech_config, &ech_config_len,
+ /*config_id=*/1, key.get(),
+ "public.example", 16));
+ bssl::UniquePtr<uint8_t> free_ech_config(ech_config);
+ EXPECT_EQ(Bytes(kECHConfig), Bytes(ech_config, ech_config_len));
+
+ // Generate a second ECHConfig.
+ bssl::ScopedEVP_HPKE_KEY key2;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key2.get(), EVP_hpke_x25519_hkdf_sha256()));
+ uint8_t *ech_config2;
+ size_t ech_config2_len;
+ ASSERT_TRUE(SSL_marshal_ech_config(&ech_config2, &ech_config2_len,
+ /*config_id=*/2, key2.get(),
+ "public.example", 16));
+ bssl::UniquePtr<uint8_t> free_ech_config2(ech_config2);
+
+ // Install both ECHConfigs in an |SSL_ECH_KEYS|.
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ ASSERT_TRUE(keys);
+ ASSERT_TRUE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1, ech_config,
+ ech_config_len, key.get()));
+ ASSERT_TRUE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1, ech_config2,
+ ech_config2_len, key2.get()));
+
+ // The ECHConfigList should be correctly serialized.
+ uint8_t *ech_config_list;
+ size_t ech_config_list_len;
+ ASSERT_TRUE(SSL_ECH_KEYS_marshal_retry_configs(keys.get(), &ech_config_list,
+ &ech_config_list_len));
+ bssl::UniquePtr<uint8_t> free_ech_config_list(ech_config_list);
+
+ // ECHConfigList is just the concatenation with a length prefix.
+ size_t len = ech_config_len + ech_config2_len;
+ std::vector<uint8_t> expected = {uint8_t(len >> 8), uint8_t(len)};
+ expected.insert(expected.end(), ech_config, ech_config + ech_config_len);
+ expected.insert(expected.end(), ech_config2, ech_config2 + ech_config2_len);
+ EXPECT_EQ(Bytes(expected), Bytes(ech_config_list, ech_config_list_len));
+}
+
+TEST(SSLTest, ECHHasDuplicateConfigID) {
+ const struct {
+ std::vector<uint8_t> ids;
+ bool has_duplicate;
+ } kTests[] = {
+ {{}, false},
+ {{1}, false},
+ {{1, 2, 3, 255}, false},
+ {{1, 2, 3, 1}, true},
+ };
+ for (const auto &test : kTests) {
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ ASSERT_TRUE(keys);
+ for (const uint8_t id : test.ids) {
+ bssl::ScopedEVP_HPKE_KEY key;
+ ASSERT_TRUE(
+ EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()));
+ uint8_t *ech_config;
+ size_t ech_config_len;
+ ASSERT_TRUE(SSL_marshal_ech_config(&ech_config, &ech_config_len, id,
+ key.get(), "public.example", 16));
+ bssl::UniquePtr<uint8_t> free_ech_config(ech_config);
+ ASSERT_TRUE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config, ech_config_len, key.get()));
+ }
+
+ EXPECT_EQ(test.has_duplicate ? 1 : 0,
+ SSL_ECH_KEYS_has_duplicate_config_id(keys.get()));
+ }
+}
+
+// Test that |SSL_ECH_KEYS_add| checks consistency between the public and
+// private key.
+TEST(SSLTest, ECHKeyConsistency) {
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ ASSERT_TRUE(keys);
+ bssl::ScopedEVP_HPKE_KEY key;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()));
+ uint8_t public_key[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH];
+ size_t public_key_len;
+ ASSERT_TRUE(EVP_HPKE_KEY_public_key(key.get(), public_key, &public_key_len,
+ sizeof(public_key)));
+
+ // Adding an ECHConfig with the matching public key succeeds.
+ ECHConfigParams params;
+ params.key = key.get();
+ std::vector<uint8_t> ech_config;
+ ASSERT_TRUE(MakeECHConfig(&ech_config, params));
+ EXPECT_TRUE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config.data(), ech_config.size(),
+ key.get()));
+
+ // Adding an ECHConfig with the wrong public key is an error.
+ bssl::ScopedEVP_HPKE_KEY wrong_key;
+ ASSERT_TRUE(
+ EVP_HPKE_KEY_generate(wrong_key.get(), EVP_hpke_x25519_hkdf_sha256()));
+ EXPECT_FALSE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config.data(), ech_config.size(),
+ wrong_key.get()));
+
+ // Adding an ECHConfig with a truncated public key is an error.
+ ECHConfigParams truncated;
+ truncated.key = key.get();
+ truncated.public_key.assign(public_key, public_key + public_key_len - 1);
+ ASSERT_TRUE(MakeECHConfig(&ech_config, truncated));
+ EXPECT_FALSE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config.data(), ech_config.size(), key.get()));
+
+ // Adding an ECHConfig with the right public key, but wrong KEM ID, is an
+ // error.
+ ECHConfigParams wrong_kem;
+ wrong_kem.key = key.get();
+ wrong_kem.kem_id = 0x0010; // DHKEM(P-256, HKDF-SHA256)
+ ASSERT_TRUE(MakeECHConfig(&ech_config, wrong_kem));
+ EXPECT_FALSE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config.data(), ech_config.size(),
+ key.get()));
+}
+
+// Test that |SSL_CTX_set1_ech_keys| fails when the config list
+// has no retry configs.
+TEST(SSLTest, ECHServerConfigsWithoutRetryConfigs) {
+ bssl::ScopedEVP_HPKE_KEY key;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()));
+ uint8_t *ech_config;
+ size_t ech_config_len;
+ ASSERT_TRUE(SSL_marshal_ech_config(&ech_config, &ech_config_len,
+ /*config_id=*/1, key.get(),
+ "public.example", 16));
+ bssl::UniquePtr<uint8_t> free_ech_config(ech_config);
+
+ // Install a non-retry config.
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ ASSERT_TRUE(keys);
+ ASSERT_TRUE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/0, ech_config,
+ ech_config_len, key.get()));
+
+ // |keys| has no retry configs.
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+ EXPECT_FALSE(SSL_CTX_set1_ech_keys(ctx.get(), keys.get()));
+
+ // Add the same ECHConfig to the list, but this time mark it as a retry
+ // config.
+ ASSERT_TRUE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1, ech_config,
+ ech_config_len, key.get()));
+ EXPECT_TRUE(SSL_CTX_set1_ech_keys(ctx.get(), keys.get()));
+}
+
+// Test that the server APIs reject ECHConfigs with unsupported features.
+TEST(SSLTest, UnsupportedECHConfig) {
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ ASSERT_TRUE(keys);
+ bssl::ScopedEVP_HPKE_KEY key;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()));
+
+ // Unsupported versions are rejected.
+ ECHConfigParams unsupported_version;
+ unsupported_version.version = 0xffff;
+ unsupported_version.key = key.get();
+ std::vector<uint8_t> ech_config;
+ ASSERT_TRUE(MakeECHConfig(&ech_config, unsupported_version));
+ EXPECT_FALSE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config.data(), ech_config.size(),
+ key.get()));
+
+ // Unsupported cipher suites are rejected. (We only support HKDF-SHA256.)
+ ECHConfigParams unsupported_kdf;
+ unsupported_kdf.key = key.get();
+ unsupported_kdf.cipher_suites = {0x002 /* HKDF-SHA384 */,
+ EVP_HPKE_AES_128_GCM};
+ ASSERT_TRUE(MakeECHConfig(&ech_config, unsupported_kdf));
+ EXPECT_FALSE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config.data(), ech_config.size(),
+ key.get()));
+ ECHConfigParams unsupported_aead;
+ unsupported_aead.key = key.get();
+ unsupported_aead.cipher_suites = {EVP_HPKE_HKDF_SHA256, 0xffff};
+ ASSERT_TRUE(MakeECHConfig(&ech_config, unsupported_aead));
+ EXPECT_FALSE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config.data(), ech_config.size(),
+ key.get()));
+
+
+ // Unsupported extensions are rejected.
+ ECHConfigParams extensions;
+ extensions.key = key.get();
+ extensions.extensions = {0x00, 0x01, 0x00, 0x00};
+ ASSERT_TRUE(MakeECHConfig(&ech_config, extensions));
+ EXPECT_FALSE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config.data(), ech_config.size(),
+ key.get()));
+
+ // Invalid public names are rejected.
+ ECHConfigParams invalid_public_name;
+ invalid_public_name.key = key.get();
+ invalid_public_name.public_name = "dns_names_have_no_underscores.example";
+ ASSERT_TRUE(MakeECHConfig(&ech_config, invalid_public_name));
+ EXPECT_FALSE(SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1,
+ ech_config.data(), ech_config.size(),
+ key.get()));
+}
+
+// Test that |SSL_get_client_random| reports the correct value on both client
+// and server in ECH. The client sends two different random values. When ECH is
+// accepted, we should report the inner one.
+TEST(SSLTest, ECHClientRandomsMatch) {
+ bssl::UniquePtr<SSL_CTX> server_ctx =
+ CreateContextWithTestCertificate(TLS_method());
+ bssl::UniquePtr<SSL_ECH_KEYS> keys = MakeTestECHKeys();
+ ASSERT_TRUE(keys);
+ ASSERT_TRUE(SSL_CTX_set1_ech_keys(server_ctx.get(), keys.get()));
+
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(client_ctx);
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ ASSERT_TRUE(InstallECHConfigList(client.get(), keys.get()));
+ ASSERT_TRUE(CompleteHandshakes(client.get(), server.get()));
+
+ EXPECT_TRUE(SSL_ech_accepted(client.get()));
+ EXPECT_TRUE(SSL_ech_accepted(server.get()));
+
+ // An ECH server will fairly naturally record the inner ClientHello random,
+ // but an ECH client may forget to update the random once ClientHelloInner is
+ // selected.
+ uint8_t client_random1[SSL3_RANDOM_SIZE];
+ uint8_t client_random2[SSL3_RANDOM_SIZE];
+ ASSERT_EQ(sizeof(client_random1),
+ SSL_get_client_random(client.get(), client_random1,
+ sizeof(client_random1)));
+ ASSERT_EQ(sizeof(client_random2),
+ SSL_get_client_random(server.get(), client_random2,
+ sizeof(client_random2)));
+ EXPECT_EQ(Bytes(client_random1), Bytes(client_random2));
+}
+
+// GetECHLength sets |*out_client_hello_len| and |*out_ech_len| to the lengths
+// of the ClientHello and ECH extension, respectively, when a client created
+// from |ctx| constructs a ClientHello with name |name| and an ECHConfig with
+// maximum name length |max_name_len|.
+static bool GetECHLength(SSL_CTX *ctx, size_t *out_client_hello_len,
+ size_t *out_ech_len, size_t max_name_len,
+ const char *name) {
+ bssl::ScopedEVP_HPKE_KEY key;
+ uint8_t *ech_config;
+ size_t ech_config_len;
+ if (!EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()) ||
+ !SSL_marshal_ech_config(&ech_config, &ech_config_len,
+ /*config_id=*/1, key.get(), "public.example",
+ max_name_len)) {
+ return false;
+ }
+ bssl::UniquePtr<uint8_t> free_ech_config(ech_config);
+
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ if (!keys || !SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/1, ech_config,
+ ech_config_len, key.get())) {
+ return false;
+ }
+
+ bssl::UniquePtr<SSL> ssl(SSL_new(ctx));
+ if (!ssl || !InstallECHConfigList(ssl.get(), keys.get()) ||
+ (name != nullptr && !SSL_set_tlsext_host_name(ssl.get(), name))) {
+ return false;
+ }
+ SSL_set_connect_state(ssl.get());
+
+ std::vector<uint8_t> client_hello;
+ SSL_CLIENT_HELLO parsed;
+ const uint8_t *unused;
+ if (!GetClientHello(ssl.get(), &client_hello) ||
+ !ssl_client_hello_init(
+ ssl.get(), &parsed,
+ // Skip record and handshake headers. This assumes the ClientHello
+ // fits in one record.
+ MakeConstSpan(client_hello)
+ .subspan(SSL3_RT_HEADER_LENGTH + SSL3_HM_HEADER_LENGTH)) ||
+ !SSL_early_callback_ctx_extension_get(
+ &parsed, TLSEXT_TYPE_encrypted_client_hello, &unused, out_ech_len)) {
+ return false;
+ }
+ *out_client_hello_len = client_hello.size();
+ return true;
+}
+
+TEST(SSLTest, ECHPadding) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+
+ // Sample lengths with max_name_len = 128 as baseline.
+ size_t client_hello_len_baseline, ech_len_baseline;
+ ASSERT_TRUE(GetECHLength(ctx.get(), &client_hello_len_baseline,
+ &ech_len_baseline, 128, "example.com"));
+
+ // Check that all name lengths under the server's maximum look the same.
+ for (size_t name_len : {1, 2, 32, 64, 127, 128}) {
+ SCOPED_TRACE(name_len);
+ size_t client_hello_len, ech_len;
+ ASSERT_TRUE(GetECHLength(ctx.get(), &client_hello_len, &ech_len, 128,
+ std::string(name_len, 'a').c_str()));
+ EXPECT_EQ(client_hello_len, client_hello_len_baseline);
+ EXPECT_EQ(ech_len, ech_len_baseline);
+ }
+
+ // When sending no SNI, we must still pad as if we are sending one.
+ size_t client_hello_len, ech_len;
+ ASSERT_TRUE(
+ GetECHLength(ctx.get(), &client_hello_len, &ech_len, 128, nullptr));
+ EXPECT_EQ(client_hello_len, client_hello_len_baseline);
+ EXPECT_EQ(ech_len, ech_len_baseline);
+
+ // Name lengths above the maximum do not get named-based padding, but the
+ // overall input is padded to a multiple of 32.
+ size_t client_hello_len_baseline2, ech_len_baseline2;
+ ASSERT_TRUE(GetECHLength(ctx.get(), &client_hello_len_baseline2,
+ &ech_len_baseline2, 128,
+ std::string(128 + 32, 'a').c_str()));
+ EXPECT_EQ(ech_len_baseline2, ech_len_baseline + 32);
+ // The ClientHello lengths may match if we are still under the threshold for
+ // padding extension.
+ EXPECT_GE(client_hello_len_baseline2, client_hello_len_baseline);
+
+ for (size_t name_len = 128 + 1; name_len < 128 + 32; name_len++) {
+ SCOPED_TRACE(name_len);
+ ASSERT_TRUE(GetECHLength(ctx.get(), &client_hello_len, &ech_len, 128,
+ std::string(name_len, 'a').c_str()));
+ EXPECT_TRUE(ech_len == ech_len_baseline || ech_len == ech_len_baseline2)
+ << ech_len;
+ EXPECT_TRUE(client_hello_len == client_hello_len_baseline ||
+ client_hello_len == client_hello_len_baseline2)
+ << client_hello_len;
+ }
+}
+
+TEST(SSLTest, ECHPublicName) {
+ auto str_to_span = [](const char *str) -> Span<const uint8_t> {
+ return MakeConstSpan(reinterpret_cast<const uint8_t *>(str), strlen(str));
+ };
+
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("example.com")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span(".example.com")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("example.com.")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("example..com")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("www.-example.com")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("www.example-.com")));
+ EXPECT_FALSE(
+ ssl_is_valid_ech_public_name(str_to_span("no_underscores.example")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(
+ str_to_span("invalid_chars.\x01.example")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(
+ str_to_span("invalid_chars.\xff.example")));
+ static const uint8_t kWithNUL[] = {'t', 'e', 's', 't', 0};
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(kWithNUL));
+
+ // Test an LDH label with every character and the maximum length.
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span(
+ "abcdefhijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span(
+ "abcdefhijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-01234567899")));
+
+ // Inputs that parse as IPv4 addresses are rejected.
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("127.0.0.1")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("0177.0.0.01")));
+ EXPECT_FALSE(
+ ssl_is_valid_ech_public_name(str_to_span("0x7f.0x.0x.0x00000001")));
+ EXPECT_FALSE(
+ ssl_is_valid_ech_public_name(str_to_span("0XAB.0XCD.0XEF.0X01")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("0.0.0.0")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("255.255.255.255")));
+ // Out-of-bounds or overflowing components are not IP addresses.
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("256.255.255.255")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("255.0x100.255.255")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("255.255.255.0400")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(
+ str_to_span("255.255.255.0x100000000")));
+ // Invalid characters for the base are not IP addresses.
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("12a.0.0.1")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("0xg.0.0.1")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("08.0.0.1")));
+ // Trailing components can be merged into a single component.
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("127.0.1")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("127.1")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("2130706433")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("0x7f000001")));
+ // Merged components must respect their limits.
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("0.0.0.0xff")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("0.0.0xffff")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("0.0xffffff")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("0xffffffff")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("0.0.0.0x100")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("0.0.0x10000")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("0.0x1000000")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("0x100000000")));
+ // Correctly handle overflow in decimal and octal.
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("037777777777")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("040000000000")));
+ EXPECT_FALSE(ssl_is_valid_ech_public_name(str_to_span("4294967295")));
+ EXPECT_TRUE(ssl_is_valid_ech_public_name(str_to_span("4294967296")));
+}
+
+// When using the built-in verifier, test that |SSL_get0_ech_name_override| is
+// applied automatically.
+TEST(SSLTest, ECHBuiltinVerifier) {
+ // These test certificates generated with the following Go program.
+ /* clang-format off
+func main() {
+ notBefore := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
+ notAfter := time.Date(2099, time.January, 1, 0, 0, 0, 0, time.UTC)
+ rootKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ rootTemplate := &x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{CommonName: "Test CA"},
+ NotBefore: notBefore,
+ NotAfter: notAfter,
+ BasicConstraintsValid: true,
+ IsCA: true,
+ }
+ rootDER, _ := x509.CreateCertificate(rand.Reader, rootTemplate, rootTemplate, &rootKey.PublicKey, rootKey)
+ root, _ := x509.ParseCertificate(rootDER)
+ pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: rootDER})
+ leafKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ leafKeyDER, _ := x509.MarshalPKCS8PrivateKey(leafKey)
+ pem.Encode(os.Stdout, &pem.Block{Type: "PRIVATE KEY", Bytes: leafKeyDER})
+ for i, name := range []string{"public.example", "secret.example"} {
+ leafTemplate := &x509.Certificate{
+ SerialNumber: big.NewInt(int64(i) + 2),
+ Subject: pkix.Name{CommonName: name},
+ NotBefore: notBefore,
+ NotAfter: notAfter,
+ BasicConstraintsValid: true,
+ DNSNames: []string{name},
+ }
+ leafDER, _ := x509.CreateCertificate(rand.Reader, leafTemplate, root, &leafKey.PublicKey, rootKey)
+ pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: leafDER})
+ }
+}
+clang-format on */
+ bssl::UniquePtr<X509> root = CertFromPEM(R"(
+-----BEGIN CERTIFICATE-----
+MIIBRzCB7aADAgECAgEBMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMTB1Rlc3QgQ0Ew
+IBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMBIxEDAOBgNVBAMTB1Rl
+c3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT5JUjrI1DAxSpEl88UkmJw
+tAJqxo/YrSFo9V3MkcNkfTixi5p6MUtO8DazhEgekBcd2+tBAWtl7dy0qpvTqx92
+ozIwMDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTw6ftkexAI6o4r5FntJIfL
+GU5F4zAKBggqhkjOPQQDAgNJADBGAiEAiiNowddQeHZaZFIygwe6RW5/WG4sUXWC
+dkyl9CQzRaYCIQCFS1EvwZbZtMny27fYm1eeYciY0TkJTEi34H1KwyzzIA==
+-----END CERTIFICATE-----
+)");
+ ASSERT_TRUE(root);
+ bssl::UniquePtr<EVP_PKEY> leaf_key = KeyFromPEM(R"(
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgj5WKHwHnziiyPauf
+7QukxTwtTyGZkk8qNdms4puJfxqhRANCAARNrkhxabALDlJrHtvkuDwvCWUF/oVC
+hr6PDITHi1lDlJzvVT4aXBH87sH2n2UV5zpx13NHkq1bIC8eRT8eOIe0
+-----END PRIVATE KEY-----
+)");
+ ASSERT_TRUE(leaf_key);
+ bssl::UniquePtr<X509> leaf_public = CertFromPEM(R"(
+-----BEGIN CERTIFICATE-----
+MIIBaDCCAQ6gAwIBAgIBAjAKBggqhkjOPQQDAjASMRAwDgYDVQQDEwdUZXN0IENB
+MCAXDTAwMDEwMTAwMDAwMFoYDzIwOTkwMTAxMDAwMDAwWjAZMRcwFQYDVQQDEw5w
+dWJsaWMuZXhhbXBsZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE2uSHFpsAsO
+Umse2+S4PC8JZQX+hUKGvo8MhMeLWUOUnO9VPhpcEfzuwfafZRXnOnHXc0eSrVsg
+Lx5FPx44h7SjTDBKMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU8On7ZHsQCOqO
+K+RZ7SSHyxlOReMwGQYDVR0RBBIwEIIOcHVibGljLmV4YW1wbGUwCgYIKoZIzj0E
+AwIDSAAwRQIhANqZRhDR/+QL05hsWXMYEwaiHifd9iakKoFEhKFchcF3AiBRAeXw
+wRGGT6+iPmTYM6N5/IDyAb5B9Ke38O6lLEsUwA==
+-----END CERTIFICATE-----
+)");
+ ASSERT_TRUE(leaf_public);
+ bssl::UniquePtr<X509> leaf_secret = CertFromPEM(R"(
+-----BEGIN CERTIFICATE-----
+MIIBaTCCAQ6gAwIBAgIBAzAKBggqhkjOPQQDAjASMRAwDgYDVQQDEwdUZXN0IENB
+MCAXDTAwMDEwMTAwMDAwMFoYDzIwOTkwMTAxMDAwMDAwWjAZMRcwFQYDVQQDEw5z
+ZWNyZXQuZXhhbXBsZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE2uSHFpsAsO
+Umse2+S4PC8JZQX+hUKGvo8MhMeLWUOUnO9VPhpcEfzuwfafZRXnOnHXc0eSrVsg
+Lx5FPx44h7SjTDBKMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU8On7ZHsQCOqO
+K+RZ7SSHyxlOReMwGQYDVR0RBBIwEIIOc2VjcmV0LmV4YW1wbGUwCgYIKoZIzj0E
+AwIDSQAwRgIhAPQdIz1xCFkc9WuSkxOxJDpywZiEp9SnKcxJ9nwrlRp3AiEA+O3+
+XRqE7XFhHL+7TNC2a9OOAjQsEF137YPWo+rhgko=
+-----END CERTIFICATE-----
+)");
+ ASSERT_TRUE(leaf_secret);
+
+ // Use different config IDs so that fuzzer mode, which breaks trial
+ // decryption, will observe the key mismatch.
+ bssl::UniquePtr<SSL_ECH_KEYS> keys = MakeTestECHKeys(/*config_id=*/1);
+ ASSERT_TRUE(keys);
+ bssl::UniquePtr<SSL_ECH_KEYS> wrong_keys = MakeTestECHKeys(/*config_id=*/2);
+ ASSERT_TRUE(wrong_keys);
+ bssl::UniquePtr<SSL_CTX> server_ctx =
+ CreateContextWithTestCertificate(TLS_method());
+ ASSERT_TRUE(server_ctx);
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(client_ctx);
+
+ // Configure the client to verify certificates and expect the secret name.
+ // This is the name the client is trying to connect to. If ECH is rejected,
+ // BoringSSL will internally override this setting with the public name.
+ bssl::UniquePtr<X509_STORE> store(X509_STORE_new());
+ ASSERT_TRUE(store);
+ ASSERT_TRUE(X509_STORE_add_cert(store.get(), root.get()));
+ SSL_CTX_set_cert_store(client_ctx.get(), store.release());
+ SSL_CTX_set_verify(client_ctx.get(), SSL_VERIFY_PEER, nullptr);
+ static const char kSecretName[] = "secret.example";
+ ASSERT_TRUE(X509_VERIFY_PARAM_set1_host(SSL_CTX_get0_param(client_ctx.get()),
+ kSecretName, strlen(kSecretName)));
+
+ // For simplicity, we only run through a pair of representative scenarios here
+ // and rely on runner.go to verify that |SSL_get0_ech_name_override| behaves
+ // correctly.
+ for (bool accept_ech : {false, true}) {
+ SCOPED_TRACE(accept_ech);
+ for (bool use_leaf_secret : {false, true}) {
+ SCOPED_TRACE(use_leaf_secret);
+
+ // The server will reject ECH when configured with the wrong keys.
+ ASSERT_TRUE(SSL_CTX_set1_ech_keys(
+ server_ctx.get(), accept_ech ? keys.get() : wrong_keys.get()));
+
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ ASSERT_TRUE(InstallECHConfigList(client.get(), keys.get()));
+
+ // Configure the server with the selected certificate.
+ ASSERT_TRUE(SSL_use_certificate(server.get(), use_leaf_secret
+ ? leaf_secret.get()
+ : leaf_public.get()));
+ ASSERT_TRUE(SSL_use_PrivateKey(server.get(), leaf_key.get()));
+
+ // The handshake may fail due to name mismatch or ECH reject. We check
+ // |SSL_get_verify_result| to confirm the handshake got far enough.
+ CompleteHandshakes(client.get(), server.get());
+ EXPECT_EQ(accept_ech == use_leaf_secret ? X509_V_OK
+ : X509_V_ERR_HOSTNAME_MISMATCH,
+ SSL_get_verify_result(client.get()));
+ }
+ }
+}
+
+#if defined(OPENSSL_THREADS)
+// Test that the server ECH config can be swapped out while the |SSL_CTX| is
+// in use on other threads. This test is intended to be run with TSan.
+TEST(SSLTest, ECHThreads) {
+ // Generate a pair of ECHConfigs.
+ bssl::ScopedEVP_HPKE_KEY key1;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key1.get(), EVP_hpke_x25519_hkdf_sha256()));
+ uint8_t *ech_config1;
+ size_t ech_config1_len;
+ ASSERT_TRUE(SSL_marshal_ech_config(&ech_config1, &ech_config1_len,
+ /*config_id=*/1, key1.get(),
+ "public.example", 16));
+ bssl::UniquePtr<uint8_t> free_ech_config1(ech_config1);
+ bssl::ScopedEVP_HPKE_KEY key2;
+ ASSERT_TRUE(EVP_HPKE_KEY_generate(key2.get(), EVP_hpke_x25519_hkdf_sha256()));
+ uint8_t *ech_config2;
+ size_t ech_config2_len;
+ ASSERT_TRUE(SSL_marshal_ech_config(&ech_config2, &ech_config2_len,
+ /*config_id=*/2, key2.get(),
+ "public.example", 16));
+ bssl::UniquePtr<uint8_t> free_ech_config2(ech_config2);
+
+ // |keys1| contains the first config. |keys12| contains both.
+ bssl::UniquePtr<SSL_ECH_KEYS> keys1(SSL_ECH_KEYS_new());
+ ASSERT_TRUE(keys1);
+ ASSERT_TRUE(SSL_ECH_KEYS_add(keys1.get(), /*is_retry_config=*/1, ech_config1,
+ ech_config1_len, key1.get()));
+ bssl::UniquePtr<SSL_ECH_KEYS> keys12(SSL_ECH_KEYS_new());
+ ASSERT_TRUE(keys12);
+ ASSERT_TRUE(SSL_ECH_KEYS_add(keys12.get(), /*is_retry_config=*/1, ech_config2,
+ ech_config2_len, key2.get()));
+ ASSERT_TRUE(SSL_ECH_KEYS_add(keys12.get(), /*is_retry_config=*/0, ech_config1,
+ ech_config1_len, key1.get()));
+
+ bssl::UniquePtr<SSL_CTX> server_ctx =
+ CreateContextWithTestCertificate(TLS_method());
+ ASSERT_TRUE(SSL_CTX_set1_ech_keys(server_ctx.get(), keys1.get()));
+
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(client_ctx);
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ ASSERT_TRUE(InstallECHConfigList(client.get(), keys1.get()));
+
+ // In parallel, complete the connection and reconfigure the ECHConfig. Note
+ // |keys12| supports all the keys in |keys1|, so the handshake should complete
+ // the same whichever the server uses.
+ std::vector<std::thread> threads;
+ threads.emplace_back([&] {
+ ASSERT_TRUE(CompleteHandshakes(client.get(), server.get()));
+ EXPECT_TRUE(SSL_ech_accepted(client.get()));
+ EXPECT_TRUE(SSL_ech_accepted(server.get()));
+ });
+ threads.emplace_back([&] {
+ EXPECT_TRUE(SSL_CTX_set1_ech_keys(server_ctx.get(), keys12.get()));
+ });
+ for (auto &thread : threads) {
+ thread.join();
+ }
+}
+#endif // OPENSSL_THREADS
+
static void AppendSession(SSL_SESSION *session, void *arg) {
std::vector<SSL_SESSION*> *out =
reinterpret_cast<std::vector<SSL_SESSION*>*>(arg);
@@ -1565,118 +2488,6 @@ static const uint8_t kTestName[] = {
0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
};
-static bool CompleteHandshakes(SSL *client, SSL *server) {
- // Drive both their handshakes to completion.
- for (;;) {
- int client_ret = SSL_do_handshake(client);
- int client_err = SSL_get_error(client, client_ret);
- if (client_err != SSL_ERROR_NONE &&
- client_err != SSL_ERROR_WANT_READ &&
- client_err != SSL_ERROR_WANT_WRITE &&
- client_err != SSL_ERROR_PENDING_TICKET) {
- fprintf(stderr, "Client error: %s\n", SSL_error_description(client_err));
- return false;
- }
-
- int server_ret = SSL_do_handshake(server);
- int server_err = SSL_get_error(server, server_ret);
- if (server_err != SSL_ERROR_NONE &&
- server_err != SSL_ERROR_WANT_READ &&
- server_err != SSL_ERROR_WANT_WRITE &&
- server_err != SSL_ERROR_PENDING_TICKET) {
- fprintf(stderr, "Server error: %s\n", SSL_error_description(server_err));
- return false;
- }
-
- if (client_ret == 1 && server_ret == 1) {
- break;
- }
- }
-
- return true;
-}
-
-static bool FlushNewSessionTickets(SSL *client, SSL *server) {
- // NewSessionTickets are deferred on the server to |SSL_write|, and clients do
- // not pick them up until |SSL_read|.
- for (;;) {
- int server_ret = SSL_write(server, nullptr, 0);
- int server_err = SSL_get_error(server, server_ret);
- // The server may either succeed (|server_ret| is zero) or block on write
- // (|server_ret| is -1 and |server_err| is |SSL_ERROR_WANT_WRITE|).
- if (server_ret > 0 ||
- (server_ret < 0 && server_err != SSL_ERROR_WANT_WRITE)) {
- fprintf(stderr, "Unexpected server result: %d %d\n", server_ret,
- server_err);
- return false;
- }
-
- int client_ret = SSL_read(client, nullptr, 0);
- int client_err = SSL_get_error(client, client_ret);
- // The client must always block on read.
- if (client_ret != -1 || client_err != SSL_ERROR_WANT_READ) {
- fprintf(stderr, "Unexpected client result: %d %d\n", client_ret,
- client_err);
- return false;
- }
-
- // The server flushed everything it had to write.
- if (server_ret == 0) {
- return true;
- }
- }
-}
-
-struct ClientConfig {
- SSL_SESSION *session = nullptr;
- std::string servername;
- bool early_data = false;
-};
-
-static bool ConnectClientAndServer(bssl::UniquePtr<SSL> *out_client,
- bssl::UniquePtr<SSL> *out_server,
- SSL_CTX *client_ctx, SSL_CTX *server_ctx,
- const ClientConfig &config = ClientConfig(),
- bool do_handshake = true,
- bool shed_handshake_config = true) {
- bssl::UniquePtr<SSL> client(SSL_new(client_ctx)), server(SSL_new(server_ctx));
- if (!client || !server) {
- return false;
- }
- if (config.early_data) {
- SSL_set_early_data_enabled(client.get(), 1);
- }
- SSL_set_connect_state(client.get());
- SSL_set_accept_state(server.get());
-
- if (config.session) {
- SSL_set_session(client.get(), config.session);
- }
- if (!config.servername.empty() &&
- !SSL_set_tlsext_host_name(client.get(), config.servername.c_str())) {
- return false;
- }
-
- BIO *bio1, *bio2;
- if (!BIO_new_bio_pair(&bio1, 0, &bio2, 0)) {
- return false;
- }
- // SSL_set_bio takes ownership.
- SSL_set_bio(client.get(), bio1, bio1);
- SSL_set_bio(server.get(), bio2, bio2);
-
- SSL_set_shed_handshake_config(client.get(), shed_handshake_config);
- SSL_set_shed_handshake_config(server.get(), shed_handshake_config);
-
- if (do_handshake && !CompleteHandshakes(client.get(), server.get())) {
- return false;
- }
-
- *out_client = std::move(client);
- *out_server = std::move(server);
- return true;
-}
-
// SSLVersionTest executes its test cases under all available protocol versions.
// Test cases call |Connect| to create a connection using context objects with
// the protocol version fixed to the current version under test.
@@ -1714,7 +2525,7 @@ class SSLVersionTest : public ::testing::TestWithParam<VersionParam> {
bool Connect(const ClientConfig &config = ClientConfig()) {
return ConnectClientAndServer(&client_, &server_, client_ctx_.get(),
- server_ctx_.get(), config, true,
+ server_ctx_.get(), config,
shed_handshake_config_);
}
@@ -1783,7 +2594,7 @@ TEST_P(SSLVersionTest, OneSidedShutdown) {
}
ASSERT_TRUE(Connect());
- // Shut down half the connection. SSL_shutdown will return 0 to signal only
+ // Shut down half the connection. |SSL_shutdown| will return 0 to signal only
// one side has shut down.
ASSERT_EQ(SSL_shutdown(client_.get()), 0);
@@ -1804,18 +2615,223 @@ TEST_P(SSLVersionTest, OneSidedShutdown) {
EXPECT_EQ(SSL_shutdown(client_.get()), 1);
}
-TEST(SSLTest, SessionDuplication) {
+// Test that, after calling |SSL_shutdown|, |SSL_write| fails.
+TEST_P(SSLVersionTest, WriteAfterShutdown) {
+ ASSERT_TRUE(Connect());
+
+ for (SSL *ssl : {client_.get(), server_.get()}) {
+ SCOPED_TRACE(SSL_is_server(ssl) ? "server" : "client");
+
+ bssl::UniquePtr<BIO> mem(BIO_new(BIO_s_mem()));
+ ASSERT_TRUE(mem);
+ SSL_set0_wbio(ssl, bssl::UpRef(mem).release());
+
+ // Shut down half the connection. |SSL_shutdown| will return 0 to signal
+ // only one side has shut down.
+ ASSERT_EQ(SSL_shutdown(ssl), 0);
+
+ // |ssl| should have written an alert to the transport.
+ const uint8_t *unused;
+ size_t len;
+ ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
+ EXPECT_NE(0u, len);
+ EXPECT_TRUE(BIO_reset(mem.get()));
+
+ // Writing should fail.
+ EXPECT_EQ(-1, SSL_write(ssl, "a", 1));
+
+ // Nothing should be written to the transport.
+ ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
+ EXPECT_EQ(0u, len);
+ }
+}
+
+// Test that, after sending a fatal alert in a failed |SSL_read|, |SSL_write|
+// fails.
+TEST_P(SSLVersionTest, WriteAfterReadSentFatalAlert) {
+ // Decryption failures are not fatal in DTLS.
+ if (is_dtls()) {
+ return;
+ }
+
+ ASSERT_TRUE(Connect());
+
+ // Save the write |BIO|s as the test will overwrite them.
+ bssl::UniquePtr<BIO> client_wbio = bssl::UpRef(SSL_get_wbio(client_.get()));
+ bssl::UniquePtr<BIO> server_wbio = bssl::UpRef(SSL_get_wbio(server_.get()));
+
+ for (bool test_server : {false, true}) {
+ SCOPED_TRACE(test_server ? "server" : "client");
+ SSL *ssl = test_server ? server_.get() : client_.get();
+ BIO *other_wbio = test_server ? client_wbio.get() : server_wbio.get();
+
+ bssl::UniquePtr<BIO> mem(BIO_new(BIO_s_mem()));
+ ASSERT_TRUE(mem);
+ SSL_set0_wbio(ssl, bssl::UpRef(mem).release());
+
+ // Read an invalid record from the peer.
+ static const uint8_t kInvalidRecord[] = "invalid record";
+ EXPECT_EQ(int{sizeof(kInvalidRecord)},
+ BIO_write(other_wbio, kInvalidRecord, sizeof(kInvalidRecord)));
+ char buf[256];
+ EXPECT_EQ(-1, SSL_read(ssl, buf, sizeof(buf)));
+
+ // |ssl| should have written an alert to the transport.
+ const uint8_t *unused;
+ size_t len;
+ ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
+ EXPECT_NE(0u, len);
+ EXPECT_TRUE(BIO_reset(mem.get()));
+
+ // Writing should fail.
+ EXPECT_EQ(-1, SSL_write(ssl, "a", 1));
+
+ // Nothing should be written to the transport.
+ ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
+ EXPECT_EQ(0u, len);
+ }
+}
+
+// Test that, after sending a fatal alert from the handshake, |SSL_write| fails.
+TEST_P(SSLVersionTest, WriteAfterHandshakeSentFatalAlert) {
+ for (bool test_server : {false, true}) {
+ SCOPED_TRACE(test_server ? "server" : "client");
+
+ bssl::UniquePtr<SSL> ssl(
+ SSL_new(test_server ? server_ctx_.get() : client_ctx_.get()));
+ ASSERT_TRUE(ssl);
+ if (test_server) {
+ SSL_set_accept_state(ssl.get());
+ } else {
+ SSL_set_connect_state(ssl.get());
+ }
+
+ std::vector<uint8_t> invalid;
+ if (is_dtls()) {
+ // In DTLS, invalid records are discarded. To cause the handshake to fail,
+ // use a valid handshake record with invalid contents.
+ invalid.push_back(SSL3_RT_HANDSHAKE);
+ invalid.push_back(DTLS1_VERSION >> 8);
+ invalid.push_back(DTLS1_VERSION & 0xff);
+ // epoch and sequence_number
+ for (int i = 0; i < 8; i++) {
+ invalid.push_back(0);
+ }
+ // A one-byte fragment is invalid.
+ invalid.push_back(0);
+ invalid.push_back(1);
+ // Arbitrary contents.
+ invalid.push_back(0);
+ } else {
+ invalid = {'i', 'n', 'v', 'a', 'l', 'i', 'd'};
+ }
+ bssl::UniquePtr<BIO> rbio(
+ BIO_new_mem_buf(invalid.data(), invalid.size()));
+ ASSERT_TRUE(rbio);
+ SSL_set0_rbio(ssl.get(), rbio.release());
+
+ bssl::UniquePtr<BIO> mem(BIO_new(BIO_s_mem()));
+ ASSERT_TRUE(mem);
+ SSL_set0_wbio(ssl.get(), bssl::UpRef(mem).release());
+
+ // The handshake should fail.
+ EXPECT_EQ(-1, SSL_do_handshake(ssl.get()));
+ EXPECT_EQ(SSL_ERROR_SSL, SSL_get_error(ssl.get(), -1));
+ uint32_t err = ERR_get_error();
+
+ // |ssl| should have written an alert (and, in the client's case, a
+ // ClientHello) to the transport.
+ const uint8_t *unused;
+ size_t len;
+ ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
+ EXPECT_NE(0u, len);
+ EXPECT_TRUE(BIO_reset(mem.get()));
+
+ // Writing should fail, with the same error as the handshake.
+ EXPECT_EQ(-1, SSL_write(ssl.get(), "a", 1));
+ EXPECT_EQ(SSL_ERROR_SSL, SSL_get_error(ssl.get(), -1));
+ EXPECT_EQ(err, ERR_get_error());
+
+ // Nothing should be written to the transport.
+ ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
+ EXPECT_EQ(0u, len);
+ }
+}
+
+// Test that, after seeing TLS 1.2 in response to early data, |SSL_write|
+// continues to report |SSL_R_WRONG_VERSION_ON_EARLY_DATA|. See
+// https://crbug.com/1078515.
+TEST(SSLTest, WriteAfterWrongVersionOnEarlyData) {
+ // Set up some 0-RTT-enabled contexts.
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx =
+ CreateContextWithTestCertificate(TLS_method());
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
+ SSL_CTX_set_early_data_enabled(client_ctx.get(), 1);
+ SSL_CTX_set_early_data_enabled(server_ctx.get(), 1);
+ SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
+ // Get an early-data-capable session.
+ bssl::UniquePtr<SSL_SESSION> session =
+ CreateClientSession(client_ctx.get(), server_ctx.get());
+ ASSERT_TRUE(session);
+ EXPECT_TRUE(SSL_SESSION_early_data_capable(session.get()));
+
+ // Offer the session to the server, but now the server speaks TLS 1.2.
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ SSL_set_session(client.get(), session.get());
+ EXPECT_TRUE(SSL_set_max_proto_version(server.get(), TLS1_2_VERSION));
+
+ // The client handshake initially succeeds in the early data state.
+ EXPECT_EQ(1, SSL_do_handshake(client.get()));
+ EXPECT_TRUE(SSL_in_early_data(client.get()));
+
+ // The server processes the ClientHello and negotiates TLS 1.2.
+ EXPECT_EQ(-1, SSL_do_handshake(server.get()));
+ EXPECT_EQ(SSL_ERROR_WANT_READ, SSL_get_error(server.get(), -1));
+ EXPECT_EQ(TLS1_2_VERSION, SSL_version(server.get()));
+
+ // Capture the client's output.
+ bssl::UniquePtr<BIO> mem(BIO_new(BIO_s_mem()));
+ ASSERT_TRUE(mem);
+ SSL_set0_wbio(client.get(), bssl::UpRef(mem).release());
+
+ // The client processes the ServerHello and fails.
+ EXPECT_EQ(-1, SSL_do_handshake(client.get()));
+ EXPECT_EQ(SSL_ERROR_SSL, SSL_get_error(client.get(), -1));
+ uint32_t err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_SSL, ERR_GET_LIB(err));
+ EXPECT_EQ(SSL_R_WRONG_VERSION_ON_EARLY_DATA, ERR_GET_REASON(err));
+
+ // The client should have written an alert to the transport.
+ const uint8_t *unused;
+ size_t len;
+ ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
+ EXPECT_NE(0u, len);
+ EXPECT_TRUE(BIO_reset(mem.get()));
+
+ // Writing should fail, with the same error as the handshake.
+ EXPECT_EQ(-1, SSL_write(client.get(), "a", 1));
+ EXPECT_EQ(SSL_ERROR_SSL, SSL_get_error(client.get(), -1));
+ err = ERR_get_error();
+ EXPECT_EQ(ERR_LIB_SSL, ERR_GET_LIB(err));
+ EXPECT_EQ(SSL_R_WRONG_VERSION_ON_EARLY_DATA, ERR_GET_REASON(err));
+
+ // Nothing should be written to the transport.
+ ASSERT_TRUE(BIO_mem_contents(mem.get(), &unused, &len));
+ EXPECT_EQ(0u, len);
+}
+
+TEST(SSLTest, SessionDuplication) {
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx =
+ CreateContextWithTestCertificate(TLS_method());
+ ASSERT_TRUE(client_ctx);
+ ASSERT_TRUE(server_ctx);
bssl::UniquePtr<SSL> client, server;
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
@@ -2147,38 +3163,6 @@ TEST(SSLTest, ClientHello) {
}
}
-static bssl::UniquePtr<SSL_SESSION> g_last_session;
-
-static int SaveLastSession(SSL *ssl, SSL_SESSION *session) {
- // Save the most recent session.
- g_last_session.reset(session);
- return 1;
-}
-
-static bssl::UniquePtr<SSL_SESSION> CreateClientSession(
- SSL_CTX *client_ctx, SSL_CTX *server_ctx,
- const ClientConfig &config = ClientConfig()) {
- g_last_session = nullptr;
- SSL_CTX_sess_set_new_cb(client_ctx, SaveLastSession);
-
- // Connect client and server to get a session.
- bssl::UniquePtr<SSL> client, server;
- if (!ConnectClientAndServer(&client, &server, client_ctx, server_ctx,
- config) ||
- !FlushNewSessionTickets(client.get(), server.get())) {
- fprintf(stderr, "Failed to connect client and server.\n");
- return nullptr;
- }
-
- SSL_CTX_sess_set_new_cb(client_ctx, nullptr);
-
- if (!g_last_session) {
- fprintf(stderr, "Client did not receive a session.\n");
- return nullptr;
- }
- return std::move(g_last_session);
-}
-
static void ExpectSessionReused(SSL_CTX *client_ctx, SSL_CTX *server_ctx,
SSL_SESSION *session, bool want_reused) {
bssl::UniquePtr<SSL> client, server;
@@ -2644,16 +3628,11 @@ TEST_P(SSLVersionTest, SNICallback) {
// Test that the early callback can swap the maximum version.
TEST(SSLTest, EarlyCallbackVersionSwitch) {
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx =
+ CreateContextWithTestCertificate(TLS_method());
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
ASSERT_TRUE(server_ctx);
ASSERT_TRUE(client_ctx);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
@@ -3624,12 +4603,8 @@ class TicketAEADMethodTest
: public ::testing::TestWithParam<TicketAEADMethodParam> {};
TEST_P(TicketAEADMethodTest, Resume) {
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- ASSERT_TRUE(cert);
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(key);
-
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx =
+ CreateContextWithTestCertificate(TLS_method());
ASSERT_TRUE(server_ctx);
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
ASSERT_TRUE(client_ctx);
@@ -3639,8 +4614,6 @@ TEST_P(TicketAEADMethodTest, Resume) {
const ssl_test_ticket_aead_failure_mode failure_mode =
testing::get<2>(GetParam());
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), version));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), version));
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), version));
@@ -3784,17 +4757,10 @@ TEST(SSLTest, SelectNextProto) {
TEST(SSLTest, SealRecord) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLSv1_2_method())),
- server_ctx(SSL_CTX_new(TLSv1_2_method()));
+ server_ctx(CreateContextWithTestCertificate(TLSv1_2_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
-
bssl::UniquePtr<SSL> client, server;
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
server_ctx.get()));
@@ -3827,17 +4793,10 @@ TEST(SSLTest, SealRecord) {
TEST(SSLTest, SealRecordInPlace) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLSv1_2_method())),
- server_ctx(SSL_CTX_new(TLSv1_2_method()));
+ server_ctx(CreateContextWithTestCertificate(TLSv1_2_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
-
bssl::UniquePtr<SSL> client, server;
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
server_ctx.get()));
@@ -3865,17 +4824,10 @@ TEST(SSLTest, SealRecordInPlace) {
TEST(SSLTest, SealRecordTrailingData) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLSv1_2_method())),
- server_ctx(SSL_CTX_new(TLSv1_2_method()));
+ server_ctx(CreateContextWithTestCertificate(TLSv1_2_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
-
bssl::UniquePtr<SSL> client, server;
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
server_ctx.get()));
@@ -3904,17 +4856,10 @@ TEST(SSLTest, SealRecordTrailingData) {
TEST(SSLTest, SealRecordInvalidSpanSize) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLSv1_2_method())),
- server_ctx(SSL_CTX_new(TLSv1_2_method()));
+ server_ctx(CreateContextWithTestCertificate(TLSv1_2_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
-
bssl::UniquePtr<SSL> client, server;
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
server_ctx.get()));
@@ -4038,18 +4983,11 @@ TEST_P(SSLVersionTest, SSLPending) {
// Test that post-handshake tickets consumed by |SSL_shutdown| are ignored.
TEST(SSLTest, ShutdownIgnoresTickets) {
- bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> ctx(CreateContextWithTestCertificate(TLS_method()));
ASSERT_TRUE(ctx);
ASSERT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_3_VERSION));
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(ctx.get(), key.get()));
-
SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_BOTH);
bssl::UniquePtr<SSL> client, server;
@@ -4131,17 +5069,11 @@ static int XORDecompressFunc(SSL *ssl, CRYPTO_BUFFER **out,
TEST(SSLTest, CertCompression) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
-
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_add_cert_compression_alg(
@@ -4173,7 +5105,8 @@ void MoveBIOs(SSL *dest, SSL *src) {
TEST(SSLTest, Handoff) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> handshaker_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> handshaker_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
ASSERT_TRUE(handshaker_ctx);
@@ -4185,36 +5118,28 @@ TEST(SSLTest, Handoff) {
SSL_CTX_get_tlsext_ticket_keys(server_ctx.get(), &keys, sizeof(keys));
SSL_CTX_set_tlsext_ticket_keys(handshaker_ctx.get(), &keys, sizeof(keys));
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(handshaker_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(handshaker_ctx.get(), key.get()));
-
for (bool early_data : {false, true}) {
SCOPED_TRACE(early_data);
for (bool is_resume : {false, true}) {
SCOPED_TRACE(is_resume);
bssl::UniquePtr<SSL> client, server;
- auto config = ClientConfig();
- config.early_data = early_data;
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ SSL_set_early_data_enabled(client.get(), early_data);
if (is_resume) {
ASSERT_TRUE(g_last_session);
- config.session = g_last_session.get();
- }
- if (is_resume && config.early_data) {
- EXPECT_GT(g_last_session->ticket_max_early_data, 0u);
+ SSL_set_session(client.get(), g_last_session.get());
+ if (early_data) {
+ EXPECT_GT(g_last_session->ticket_max_early_data, 0u);
+ }
}
- ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
- server_ctx.get(), config,
- false /* don't handshake */));
+
int client_ret = SSL_do_handshake(client.get());
int client_err = SSL_get_error(client.get(), client_ret);
uint8_t byte_written;
- if (config.early_data && is_resume) {
+ if (early_data && is_resume) {
ASSERT_EQ(client_err, 0);
EXPECT_TRUE(SSL_in_early_data(client.get()));
// Attempt to write early data.
@@ -4267,7 +5192,7 @@ TEST(SSLTest, Handoff) {
ASSERT_TRUE(CompleteHandshakes(client.get(), server2.get()));
EXPECT_EQ(is_resume, SSL_session_reused(client.get()));
- if (config.early_data && is_resume) {
+ if (early_data && is_resume) {
// In this case, one byte of early data has already been written above.
EXPECT_TRUE(SSL_early_data_accepted(client.get()));
} else {
@@ -4288,24 +5213,17 @@ TEST(SSLTest, Handoff) {
TEST(SSLTest, HandoffDeclined) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
SSL_CTX_set_handoff_mode(server_ctx.get(), 1);
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_2_VERSION));
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
-
bssl::UniquePtr<SSL> client, server;
- ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
- server_ctx.get(), ClientConfig(),
- false /* don't handshake */));
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
int client_ret = SSL_do_handshake(client.get());
int client_err = SSL_get_error(client.get(), client_ret);
@@ -4551,15 +5469,10 @@ TEST(SSLTest, ApplyHandoffRemovesUnsupportedCurves) {
TEST(SSLTest, ZeroSizedWiteFlushesHandshakeMessages) {
// If there are pending handshake mesages, an |SSL_write| of zero bytes should
// flush them.
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
EXPECT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
EXPECT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), TLS1_3_VERSION));
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
EXPECT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
@@ -4660,7 +5573,8 @@ TEST_P(SSLVersionTest, SessionCacheThreads) {
}
}
- // Hit the maximum session cache size across multiple threads
+ // Hit the maximum session cache size across multiple threads, to test the
+ // size enforcement logic.
size_t limit = SSL_CTX_sess_number(server_ctx_.get()) + 2;
SSL_CTX_sess_set_cache_size(server_ctx_.get(), limit);
{
@@ -4676,6 +5590,59 @@ TEST_P(SSLVersionTest, SessionCacheThreads) {
}
EXPECT_EQ(SSL_CTX_sess_number(server_ctx_.get()), limit);
}
+
+ // Reset the session cache, this time with a mock clock.
+ ASSERT_NO_FATAL_FAILURE(ResetContexts());
+ SSL_CTX_set_options(server_ctx_.get(), SSL_OP_NO_TICKET);
+ SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_session_cache_mode(server_ctx_.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_current_time_cb(server_ctx_.get(), CurrentTimeCallback);
+
+ // Make some sessions at an arbitrary start time. Then expire them.
+ g_current_time.tv_sec = 1000;
+ bssl::UniquePtr<SSL_SESSION> expired_session1 =
+ CreateClientSession(client_ctx_.get(), server_ctx_.get());
+ ASSERT_TRUE(expired_session1);
+ bssl::UniquePtr<SSL_SESSION> expired_session2 =
+ CreateClientSession(client_ctx_.get(), server_ctx_.get());
+ ASSERT_TRUE(expired_session2);
+ g_current_time.tv_sec += 100 * SSL_DEFAULT_SESSION_TIMEOUT;
+
+ session1 = CreateClientSession(client_ctx_.get(), server_ctx_.get());
+ ASSERT_TRUE(session1);
+
+ // Every 256 connections, we flush stale sessions from the session cache. Test
+ // this logic is correctly synchronized with other connection attempts.
+ static const int kNumConnections = 256;
+ {
+ std::vector<std::thread> threads;
+ threads.emplace_back([&] {
+ for (int i = 0; i < kNumConnections; i++) {
+ connect_with_session(nullptr);
+ }
+ });
+ threads.emplace_back([&] {
+ for (int i = 0; i < kNumConnections; i++) {
+ connect_with_session(nullptr);
+ }
+ });
+ threads.emplace_back([&] {
+ // Never connect with |expired_session2|. The session cache eagerly
+ // removes expired sessions when it sees them. Leaving |expired_session2|
+ // untouched ensures it is instead cleared by periodic flushing.
+ for (int i = 0; i < kNumConnections; i++) {
+ connect_with_session(expired_session1.get());
+ }
+ });
+ threads.emplace_back([&] {
+ for (int i = 0; i < kNumConnections; i++) {
+ connect_with_session(session1.get());
+ }
+ });
+ for (auto &thread : threads) {
+ thread.join();
+ }
+ }
}
TEST_P(SSLVersionTest, SessionTicketThreads) {
@@ -5055,17 +6022,10 @@ class QUICMethodTest : public testing::Test {
protected:
void SetUp() override {
client_ctx_.reset(SSL_CTX_new(TLS_method()));
- server_ctx_.reset(SSL_CTX_new(TLS_method()));
+ server_ctx_ = CreateContextWithTestCertificate(TLS_method());
ASSERT_TRUE(client_ctx_);
ASSERT_TRUE(server_ctx_);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx_.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx_.get(), key.get()));
-
SSL_CTX_set_min_proto_version(server_ctx_.get(), TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(server_ctx_.get(), TLS1_3_VERSION);
SSL_CTX_set_min_proto_version(client_ctx_.get(), TLS1_3_VERSION);
@@ -6377,26 +7337,47 @@ TEST_P(SSLVersionTest, UnrelatedServerNoResume) {
EXPECT_FALSE(SSL_session_reused(server.get()));
}
+Span<const uint8_t> SessionIDOf(const SSL* ssl) {
+ const SSL_SESSION *session = SSL_get_session(ssl);
+ unsigned len;
+ const uint8_t *data = SSL_SESSION_get_id(session, &len);
+ return MakeConstSpan(data, len);
+}
+
+TEST_P(SSLVersionTest, TicketSessionIDsMatch) {
+ // This checks that the session IDs at client and server match after a ticket
+ // resumption. It's unclear whether this should be true, but Envoy depends
+ // on it in their tests so this will give an early signal if we break it.
+ SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_session_cache_mode(server_ctx_.get(), SSL_SESS_CACHE_BOTH);
+
+ bssl::UniquePtr<SSL_SESSION> session =
+ CreateClientSession(client_ctx_.get(), server_ctx_.get());
+
+ bssl::UniquePtr<SSL> client, server;
+ ClientConfig config;
+ config.session = session.get();
+ EXPECT_TRUE(ConnectClientAndServer(&client, &server, client_ctx_.get(),
+ server_ctx_.get(), config));
+ EXPECT_TRUE(SSL_session_reused(client.get()));
+ EXPECT_TRUE(SSL_session_reused(server.get()));
+
+ EXPECT_EQ(Bytes(SessionIDOf(client.get())), Bytes(SessionIDOf(server.get())));
+}
+
TEST(SSLTest, WriteWhileExplicitRenegotiate) {
- bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> ctx(CreateContextWithTestCertificate(TLS_method()));
ASSERT_TRUE(ctx);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> pkey = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(pkey);
- ASSERT_TRUE(SSL_CTX_use_certificate(ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(ctx.get(), pkey.get()));
ASSERT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), TLS1_2_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_2_VERSION));
ASSERT_TRUE(SSL_CTX_set_strict_cipher_list(
ctx.get(), "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"));
bssl::UniquePtr<SSL> client, server;
- ASSERT_TRUE(ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
- ClientConfig(), true /* do_handshake */,
- false /* don't shed handshake config */));
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, ctx.get(), ctx.get()));
SSL_set_renegotiate_mode(client.get(), ssl_renegotiate_explicit);
+ ASSERT_TRUE(CompleteHandshakes(client.get(), server.get()));
static const uint8_t kInput[] = {'h', 'e', 'l', 'l', 'o'};
@@ -6514,17 +7495,11 @@ TEST(SSLTest, WriteWhileExplicitRenegotiate) {
TEST(SSLTest, CopyWithoutEarlyData) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
-
SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
SSL_CTX_set_early_data_enabled(client_ctx.get(), 1);
@@ -6535,13 +7510,11 @@ TEST(SSLTest, CopyWithoutEarlyData) {
ASSERT_TRUE(session);
// The client should attempt early data with |session|.
- auto config = ClientConfig();
- config.early_data = true;
- config.session = session.get();
bssl::UniquePtr<SSL> client, server;
- ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
- server_ctx.get(), config,
- /*do_handshake=*/false));
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ SSL_set_session(client.get(), session.get());
+ SSL_set_early_data_enabled(client.get(), 1);
ASSERT_EQ(1, SSL_do_handshake(client.get()));
EXPECT_TRUE(SSL_in_early_data(client.get()));
@@ -6551,9 +7524,11 @@ TEST(SSLTest, CopyWithoutEarlyData) {
SSL_SESSION_copy_without_early_data(session.get()));
ASSERT_TRUE(session2);
EXPECT_NE(session.get(), session2.get());
- config.session = session2.get();
- ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
- server_ctx.get(), config));
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ SSL_set_session(client.get(), session2.get());
+ SSL_set_early_data_enabled(client.get(), 1);
+ EXPECT_TRUE(CompleteHandshakes(client.get(), server.get()));
EXPECT_TRUE(SSL_session_reused(client.get()));
EXPECT_EQ(ssl_early_data_unsupported_for_session,
SSL_get_early_data_reason(client.get()));
@@ -6567,18 +7542,15 @@ TEST(SSLTest, CopyWithoutEarlyData) {
TEST(SSLTest, ProcessTLS13NewSessionTicket) {
// Configure client and server to negotiate TLS 1.3 only.
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), TLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), TLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
bssl::UniquePtr<SSL> client, server;
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
@@ -6632,17 +7604,11 @@ TEST(SSLTest, ProcessTLS13NewSessionTicket) {
TEST(SSLTest, BIO) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- ASSERT_TRUE(cert);
- ASSERT_TRUE(key);
- ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
- ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
-
for (bool take_ownership : {true, false}) {
// For simplicity, get the handshake out of the way first.
bssl::UniquePtr<SSL> client, server;
@@ -6689,5 +7655,328 @@ TEST(SSLTest, BIO) {
}
}
+TEST(SSLTest, ALPNConfig) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ ASSERT_TRUE(cert);
+ ASSERT_TRUE(key);
+ ASSERT_TRUE(SSL_CTX_use_certificate(ctx.get(), cert.get()));
+ ASSERT_TRUE(SSL_CTX_use_PrivateKey(ctx.get(), key.get()));
+
+ // Set up some machinery to check the configured ALPN against what is actually
+ // sent over the wire. Note that the ALPN callback is only called when the
+ // client offers ALPN.
+ std::vector<uint8_t> observed_alpn;
+ SSL_CTX_set_alpn_select_cb(
+ ctx.get(),
+ [](SSL *ssl, const uint8_t **out, uint8_t *out_len, const uint8_t *in,
+ unsigned in_len, void *arg) -> int {
+ std::vector<uint8_t> *observed_alpn_ptr =
+ static_cast<std::vector<uint8_t> *>(arg);
+ observed_alpn_ptr->assign(in, in + in_len);
+ return SSL_TLSEXT_ERR_NOACK;
+ },
+ &observed_alpn);
+ auto check_alpn_proto = [&](Span<const uint8_t> expected) {
+ observed_alpn.clear();
+ bssl::UniquePtr<SSL> client, server;
+ EXPECT_TRUE(ConnectClientAndServer(&client, &server, ctx.get(), ctx.get()));
+ EXPECT_EQ(Bytes(expected), Bytes(observed_alpn));
+ };
+
+ // Note that |SSL_CTX_set_alpn_protos|'s return value is reversed.
+ static const uint8_t kValidList[] = {0x03, 'f', 'o', 'o',
+ 0x03, 'b', 'a', 'r'};
+ EXPECT_EQ(0,
+ SSL_CTX_set_alpn_protos(ctx.get(), kValidList, sizeof(kValidList)));
+ check_alpn_proto(kValidList);
+
+ // Invalid lists are rejected.
+ static const uint8_t kInvalidList[] = {0x04, 'f', 'o', 'o'};
+ EXPECT_EQ(1, SSL_CTX_set_alpn_protos(ctx.get(), kInvalidList,
+ sizeof(kInvalidList)));
+
+ // Empty lists are valid and are interpreted as disabling ALPN.
+ EXPECT_EQ(0, SSL_CTX_set_alpn_protos(ctx.get(), nullptr, 0));
+ check_alpn_proto({});
+}
+
+// Test that the key usage checker can correctly handle issuerUID and
+// subjectUID. See https://crbug.com/1199744.
+TEST(SSLTest, KeyUsageWithUIDs) {
+ static const char kGoodKeyUsage[] = R"(
+-----BEGIN CERTIFICATE-----
+MIIB7DCCAZOgAwIBAgIJANlMBNpJfb/rMAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT
+AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
+aXRzIFB0eSBMdGQwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjBFMQsw
+CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu
+ZXQgV2lkZ2l0cyBQdHkgTHRkMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5itp
+4r9ln5e+Lx4NlIpM1Zdrt6keDUb73ampHp3culoB59aXqAoY+cPEox5W4nyDSNsW
+Ghz1HX7xlC1Lz3IiwYEEABI0VoIEABI0VqNgMF4wHQYDVR0OBBYEFKuE0qyrlfCC
+ThZ4B1VXX+QmjYLRMB8GA1UdIwQYMBaAFKuE0qyrlfCCThZ4B1VXX+QmjYLRMA4G
+A1UdDwEB/wQEAwIHgDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIEWJ
+34EcqW5MHwLIA1hZ2Tj/jV2QjN02KLxis9mFsqDKAiAMlMTkzsM51vVs9Ohqa+Rc
+4Z7qDhjIhiF4dM0uEDYRVA==
+-----END CERTIFICATE-----
+)";
+ static const char kBadKeyUsage[] = R"(
+-----BEGIN CERTIFICATE-----
+MIIB7jCCAZOgAwIBAgIJANlMBNpJfb/rMAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT
+AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn
+aXRzIFB0eSBMdGQwHhcNMTQwNDIzMjMyMTU3WhcNMTQwNTIzMjMyMTU3WjBFMQsw
+CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu
+ZXQgV2lkZ2l0cyBQdHkgTHRkMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5itp
+4r9ln5e+Lx4NlIpM1Zdrt6keDUb73ampHp3culoB59aXqAoY+cPEox5W4nyDSNsW
+Ghz1HX7xlC1Lz3IiwYEEABI0VoIEABI0VqNgMF4wHQYDVR0OBBYEFKuE0qyrlfCC
+ThZ4B1VXX+QmjYLRMB8GA1UdIwQYMBaAFKuE0qyrlfCCThZ4B1VXX+QmjYLRMA4G
+A1UdDwEB/wQEAwIDCDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQC6
+taYBUDu2gcZC6EMk79FBHArYI0ucF+kzvETegZCbBAIhANtObFec5gtso/47moPD
+RHrQbWsFUakETXL9QMlegh5t
+-----END CERTIFICATE-----
+)";
+
+ bssl::UniquePtr<X509> good = CertFromPEM(kGoodKeyUsage);
+ ASSERT_TRUE(good);
+ bssl::UniquePtr<X509> bad = CertFromPEM(kBadKeyUsage);
+ ASSERT_TRUE(bad);
+
+ // We check key usage when configuring EC certificates to distinguish ECDSA
+ // and ECDH.
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+ EXPECT_TRUE(SSL_CTX_use_certificate(ctx.get(), good.get()));
+ EXPECT_FALSE(SSL_CTX_use_certificate(ctx.get(), bad.get()));
+}
+
+// Test that |SSL_can_release_private_key| reports true as early as expected.
+// The internal asserts in the library check we do not report true too early.
+TEST(SSLTest, CanReleasePrivateKey) {
+ bssl::UniquePtr<SSL_CTX> client_ctx =
+ CreateContextWithTestCertificate(TLS_method());
+ ASSERT_TRUE(client_ctx);
+ SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
+
+ // Note this assumes the transport buffer is large enough to fit the client
+ // and server first flights. We check this with |SSL_ERROR_WANT_READ|. If the
+ // transport buffer was too small it would return |SSL_ERROR_WANT_WRITE|.
+ auto check_first_server_round_trip = [&](SSL *client, SSL *server) {
+ // Write the ClientHello.
+ ASSERT_EQ(-1, SSL_do_handshake(client));
+ ASSERT_EQ(SSL_ERROR_WANT_READ, SSL_get_error(client, -1));
+
+ // Consume the ClientHello and write the server flight.
+ ASSERT_EQ(-1, SSL_do_handshake(server));
+ ASSERT_EQ(SSL_ERROR_WANT_READ, SSL_get_error(server, -1));
+
+ EXPECT_TRUE(SSL_can_release_private_key(server));
+ };
+
+ {
+ SCOPED_TRACE("TLS 1.2 ECDHE");
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
+ ASSERT_TRUE(server_ctx);
+ ASSERT_TRUE(
+ SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_2_VERSION));
+ ASSERT_TRUE(SSL_CTX_set_strict_cipher_list(
+ server_ctx.get(), "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"));
+ // Configure the server to request client certificates, so we can also test
+ // the client half.
+ SSL_CTX_set_custom_verify(
+ server_ctx.get(), SSL_VERIFY_PEER,
+ [](SSL *ssl, uint8_t *out_alert) { return ssl_verify_ok; });
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ check_first_server_round_trip(client.get(), server.get());
+
+ // Consume the server flight and write the client response. The client still
+ // has a Finished message to consume but can also release its key early.
+ ASSERT_EQ(-1, SSL_do_handshake(client.get()));
+ ASSERT_EQ(SSL_ERROR_WANT_READ, SSL_get_error(client.get(), -1));
+ EXPECT_TRUE(SSL_can_release_private_key(client.get()));
+
+ // However, a client that has not disabled renegotiation can never release
+ // the key.
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ SSL_set_renegotiate_mode(client.get(), ssl_renegotiate_freely);
+ check_first_server_round_trip(client.get(), server.get());
+ ASSERT_EQ(-1, SSL_do_handshake(client.get()));
+ ASSERT_EQ(SSL_ERROR_WANT_READ, SSL_get_error(client.get(), -1));
+ EXPECT_FALSE(SSL_can_release_private_key(client.get()));
+ }
+
+ {
+ SCOPED_TRACE("TLS 1.2 resumption");
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
+ ASSERT_TRUE(server_ctx);
+ ASSERT_TRUE(
+ SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_2_VERSION));
+ bssl::UniquePtr<SSL_SESSION> session =
+ CreateClientSession(client_ctx.get(), server_ctx.get());
+ ASSERT_TRUE(session);
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ SSL_set_session(client.get(), session.get());
+ check_first_server_round_trip(client.get(), server.get());
+ }
+
+ {
+ SCOPED_TRACE("TLS 1.3 1-RTT");
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
+ ASSERT_TRUE(server_ctx);
+ ASSERT_TRUE(
+ SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ check_first_server_round_trip(client.get(), server.get());
+ }
+
+ {
+ SCOPED_TRACE("TLS 1.3 resumption");
+ bssl::UniquePtr<SSL_CTX> server_ctx(
+ CreateContextWithTestCertificate(TLS_method()));
+ ASSERT_TRUE(server_ctx);
+ ASSERT_TRUE(
+ SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
+ bssl::UniquePtr<SSL_SESSION> session =
+ CreateClientSession(client_ctx.get(), server_ctx.get());
+ ASSERT_TRUE(session);
+ bssl::UniquePtr<SSL> client, server;
+ ASSERT_TRUE(CreateClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get()));
+ SSL_set_session(client.get(), session.get());
+ check_first_server_round_trip(client.get(), server.get());
+ }
+}
+
+// GetExtensionOrder sets |*out| to the list of extensions a client attached to
+// |ctx| will send in the ClientHello. If |ech_keys| is non-null, the client
+// will offer ECH with the public component. If |decrypt_ech| is true, |*out|
+// will be set to the ClientHelloInner's extensions, rather than
+// ClientHelloOuter.
+static bool GetExtensionOrder(SSL_CTX *client_ctx, std::vector<uint16_t> *out,
+ SSL_ECH_KEYS *ech_keys, bool decrypt_ech) {
+ struct AppData {
+ std::vector<uint16_t> *out;
+ bool decrypt_ech;
+ bool callback_done = false;
+ };
+ AppData app_data;
+ app_data.out = out;
+ app_data.decrypt_ech = decrypt_ech;
+
+ bssl::UniquePtr<SSL_CTX> server_ctx =
+ CreateContextWithTestCertificate(TLS_method());
+ if (!server_ctx || //
+ !SSL_CTX_set_app_data(server_ctx.get(), &app_data) ||
+ (decrypt_ech && !SSL_CTX_set1_ech_keys(server_ctx.get(), ech_keys))) {
+ return false;
+ }
+
+ // Configure the server to record the ClientHello extension order. We use a
+ // server rather than |GetClientHello| so it can decrypt ClientHelloInner.
+ SSL_CTX_set_select_certificate_cb(
+ server_ctx.get(),
+ [](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
+ AppData *app_data_ptr = static_cast<AppData *>(
+ SSL_CTX_get_app_data(SSL_get_SSL_CTX(client_hello->ssl)));
+ EXPECT_EQ(app_data_ptr->decrypt_ech ? 1 : 0,
+ SSL_ech_accepted(client_hello->ssl));
+
+ app_data_ptr->out->clear();
+ CBS extensions;
+ CBS_init(&extensions, client_hello->extensions,
+ client_hello->extensions_len);
+ while (CBS_len(&extensions)) {
+ uint16_t type;
+ CBS body;
+ if (!CBS_get_u16(&extensions, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions, &body)) {
+ return ssl_select_cert_error;
+ }
+ app_data_ptr->out->push_back(type);
+ }
+
+ // Don't bother completing the handshake.
+ app_data_ptr->callback_done = true;
+ return ssl_select_cert_error;
+ });
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!CreateClientAndServer(&client, &server, client_ctx, server_ctx.get()) ||
+ (ech_keys != nullptr && !InstallECHConfigList(client.get(), ech_keys))) {
+ return false;
+ }
+
+ // Run the handshake far enough to process the ClientHello.
+ SSL_do_handshake(client.get());
+ SSL_do_handshake(server.get());
+ return app_data.callback_done;
+}
+
+// Test that, when extension permutation is enabled, the ClientHello extension
+// order changes, both with and without ECH, and in both ClientHelloInner and
+// ClientHelloOuter.
+TEST(SSLTest, PermuteExtensions) {
+ bssl::UniquePtr<SSL_ECH_KEYS> keys = MakeTestECHKeys();
+ ASSERT_TRUE(keys);
+ for (bool offer_ech : {false, true}) {
+ SCOPED_TRACE(offer_ech);
+ SSL_ECH_KEYS *maybe_keys = offer_ech ? keys.get() : nullptr;
+ for (bool decrypt_ech : {false, true}) {
+ SCOPED_TRACE(decrypt_ech);
+ if (!offer_ech && decrypt_ech) {
+ continue;
+ }
+
+ // When extension permutation is disabled, the order should be consistent.
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+ std::vector<uint16_t> order1, order2;
+ ASSERT_TRUE(
+ GetExtensionOrder(ctx.get(), &order1, maybe_keys, decrypt_ech));
+ ASSERT_TRUE(
+ GetExtensionOrder(ctx.get(), &order2, maybe_keys, decrypt_ech));
+ EXPECT_EQ(order1, order2);
+
+ ctx.reset(SSL_CTX_new(TLS_method()));
+ ASSERT_TRUE(ctx);
+ SSL_CTX_set_permute_extensions(ctx.get(), 1);
+
+ // When extension permutation is enabled, each ClientHello should have a
+ // different order.
+ //
+ // This test is inherently flaky, so we run it multiple times. We send at
+ // least five extensions by default from TLS 1.3: supported_versions,
+ // key_share, supported_groups, psk_key_exchange_modes, and
+ // signature_algorithms. That means the probability of a false negative is
+ // at most 1/120. Repeating the test 14 times lowers false negative rate
+ // to under 2^-96.
+ ASSERT_TRUE(
+ GetExtensionOrder(ctx.get(), &order1, maybe_keys, decrypt_ech));
+ EXPECT_GE(order1.size(), 5u);
+ static const int kNumIterations = 14;
+ bool passed = false;
+ for (int i = 0; i < kNumIterations; i++) {
+ ASSERT_TRUE(
+ GetExtensionOrder(ctx.get(), &order2, maybe_keys, decrypt_ech));
+ if (order1 != order2) {
+ passed = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(passed) << "Extensions were not permuted";
+ }
+ }
+}
+
} // namespace
BSSL_NAMESPACE_END
diff --git a/deps/boringssl/src/ssl/ssl_transcript.cc b/deps/boringssl/src/ssl/ssl_transcript.cc
index 0bc13b9..58fd21e 100644
--- a/deps/boringssl/src/ssl/ssl_transcript.cc
+++ b/deps/boringssl/src/ssl/ssl_transcript.cc
@@ -158,20 +158,14 @@ bool SSLTranscript::Init() {
return true;
}
-// InitDigestWithData calls |EVP_DigestInit_ex| on |ctx| with |md| and then
-// writes the data in |buf| to it.
-static bool InitDigestWithData(EVP_MD_CTX *ctx, const EVP_MD *md,
- const BUF_MEM *buf) {
- if (!EVP_DigestInit_ex(ctx, md, NULL)) {
- return false;
- }
- EVP_DigestUpdate(ctx, buf->data, buf->length);
- return true;
-}
-
bool SSLTranscript::InitHash(uint16_t version, const SSL_CIPHER *cipher) {
const EVP_MD *md = ssl_get_handshake_digest(version, cipher);
- return InitDigestWithData(hash_.get(), md, buffer_.get());
+ if (Digest() == md) {
+ // No need to re-hash the buffer.
+ return true;
+ }
+ return EVP_DigestInit_ex(hash_.get(), md, nullptr) &&
+ EVP_DigestUpdate(hash_.get(), buffer_->data, buffer_->length);
}
void SSLTranscript::FreeBuffer() {
@@ -206,7 +200,8 @@ bool SSLTranscript::UpdateForHelloRetryRequest() {
return true;
}
-bool SSLTranscript::CopyToHashContext(EVP_MD_CTX *ctx, const EVP_MD *digest) {
+bool SSLTranscript::CopyToHashContext(EVP_MD_CTX *ctx,
+ const EVP_MD *digest) const {
const EVP_MD *transcript_digest = Digest();
if (transcript_digest != nullptr &&
EVP_MD_type(transcript_digest) == EVP_MD_type(digest)) {
@@ -237,7 +232,7 @@ bool SSLTranscript::Update(Span<const uint8_t> in) {
return true;
}
-bool SSLTranscript::GetHash(uint8_t *out, size_t *out_len) {
+bool SSLTranscript::GetHash(uint8_t *out, size_t *out_len) const {
ScopedEVP_MD_CTX ctx;
unsigned len;
if (!EVP_MD_CTX_copy_ex(ctx.get(), hash_.get()) ||
@@ -250,7 +245,7 @@ bool SSLTranscript::GetHash(uint8_t *out, size_t *out_len) {
bool SSLTranscript::GetFinishedMAC(uint8_t *out, size_t *out_len,
const SSL_SESSION *session,
- bool from_server) {
+ bool from_server) const {
static const char kClientLabel[] = "client finished";
static const char kServerLabel[] = "server finished";
auto label = from_server
diff --git a/deps/boringssl/src/ssl/ssl_versions.cc b/deps/boringssl/src/ssl/ssl_versions.cc
index 3bbb4e3..df499c7 100644
--- a/deps/boringssl/src/ssl/ssl_versions.cc
+++ b/deps/boringssl/src/ssl/ssl_versions.cc
@@ -260,8 +260,8 @@ uint16_t ssl_protocol_version(const SSL *ssl) {
return version;
}
-bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) {
- SSL *const ssl = hs->ssl;
+bool ssl_supports_version(const SSL_HANDSHAKE *hs, uint16_t version) {
+ const SSL *const ssl = hs->ssl;
uint16_t protocol_version;
if (!ssl_method_supports_version(ssl->method, version) ||
!ssl_protocol_version_from_wire(&protocol_version, version) ||
@@ -273,9 +273,13 @@ bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) {
return true;
}
-bool ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb) {
+bool ssl_add_supported_versions(const SSL_HANDSHAKE *hs, CBB *cbb,
+ uint16_t extra_min_version) {
for (uint16_t version : get_method_versions(hs->ssl->method)) {
+ uint16_t protocol_version;
if (ssl_supports_version(hs, version) &&
+ ssl_protocol_version_from_wire(&protocol_version, version) &&
+ protocol_version >= extra_min_version && //
!CBB_add_u16(cbb, version)) {
return false;
}
diff --git a/deps/boringssl/src/ssl/ssl_x509.cc b/deps/boringssl/src/ssl/ssl_x509.cc
index cda7611..680f253 100644
--- a/deps/boringssl/src/ssl/ssl_x509.cc
+++ b/deps/boringssl/src/ssl/ssl_x509.cc
@@ -368,25 +368,34 @@ static bool ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session,
return false;
}
- SSL_CTX *ssl_ctx = hs->ssl->ctx.get();
+ SSL *const ssl = hs->ssl;
+ SSL_CTX *ssl_ctx = ssl->ctx.get();
X509_STORE *verify_store = ssl_ctx->cert_store;
if (hs->config->cert->verify_store != nullptr) {
verify_store = hs->config->cert->verify_store;
}
X509 *leaf = sk_X509_value(cert_chain, 0);
- ScopedX509_STORE_CTX ctx;
- if (!X509_STORE_CTX_init(ctx.get(), verify_store, leaf, cert_chain) ||
- !X509_STORE_CTX_set_ex_data(
- ctx.get(), SSL_get_ex_data_X509_STORE_CTX_idx(), hs->ssl) ||
+ const char *name;
+ size_t name_len;
+ SSL_get0_ech_name_override(ssl, &name, &name_len);
+ UniquePtr<X509_STORE_CTX> ctx(X509_STORE_CTX_new());
+ if (!ctx ||
+ !X509_STORE_CTX_init(ctx.get(), verify_store, leaf, cert_chain) ||
+ !X509_STORE_CTX_set_ex_data(ctx.get(),
+ SSL_get_ex_data_X509_STORE_CTX_idx(), ssl) ||
// We need to inherit the verify parameters. These can be determined by
// the context: if its a server it will verify SSL client certificates or
// vice versa.
- !X509_STORE_CTX_set_default(
- ctx.get(), hs->ssl->server ? "ssl_client" : "ssl_server") ||
+ !X509_STORE_CTX_set_default(ctx.get(),
+ ssl->server ? "ssl_client" : "ssl_server") ||
// Anything non-default in "param" should overwrite anything in the ctx.
!X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(ctx.get()),
- hs->config->param)) {
+ hs->config->param) ||
+ // ClientHelloOuter connections use a different name.
+ (name_len != 0 &&
+ !X509_VERIFY_PARAM_set1_host(X509_STORE_CTX_get0_param(ctx.get()), name,
+ name_len))) {
OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
return false;
}
@@ -403,11 +412,11 @@ static bool ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session,
verify_ret = X509_verify_cert(ctx.get());
}
- session->verify_result = ctx->error;
+ session->verify_result = X509_STORE_CTX_get_error(ctx.get());
// If |SSL_VERIFY_NONE|, the error is non-fatal, but we keep the result.
if (verify_ret <= 0 && hs->config->verify_mode != SSL_VERIFY_NONE) {
- *out_alert = SSL_alert_from_verify_result(ctx->error);
+ *out_alert = SSL_alert_from_verify_result(session->verify_result);
return false;
}
@@ -456,9 +465,9 @@ static bool ssl_crypto_x509_ssl_auto_chain_if_needed(SSL_HANDSHAKE *hs) {
return false;
}
- ScopedX509_STORE_CTX ctx;
- if (!X509_STORE_CTX_init(ctx.get(), hs->ssl->ctx->cert_store, leaf.get(),
- NULL)) {
+ UniquePtr<X509_STORE_CTX> ctx(X509_STORE_CTX_new());
+ if (!ctx || !X509_STORE_CTX_init(ctx.get(), hs->ssl->ctx->cert_store,
+ leaf.get(), nullptr)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
return false;
}
@@ -468,9 +477,13 @@ static bool ssl_crypto_x509_ssl_auto_chain_if_needed(SSL_HANDSHAKE *hs) {
ERR_clear_error();
// Remove the leaf from the generated chain.
- X509_free(sk_X509_shift(ctx->chain));
+ UniquePtr<STACK_OF(X509)> chain(X509_STORE_CTX_get1_chain(ctx.get()));
+ if (!chain) {
+ return false;
+ }
+ X509_free(sk_X509_shift(chain.get()));
- if (!ssl_cert_set_chain(hs->config->cert.get(), ctx->chain)) {
+ if (!ssl_cert_set_chain(hs->config->cert.get(), chain.get())) {
return false;
}
@@ -698,13 +711,6 @@ int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *ca_file,
return X509_STORE_load_locations(ctx->cert_store, ca_file, ca_dir);
}
-void SSL_set_verify_result(SSL *ssl, long result) {
- check_ssl_x509_method(ssl);
- if (result != X509_V_OK) {
- abort();
- }
-}
-
long SSL_get_verify_result(const SSL *ssl) {
check_ssl_x509_method(ssl);
SSL_SESSION *session = SSL_get_session(ssl);
diff --git a/deps/boringssl/src/ssl/test/bssl_shim.cc b/deps/boringssl/src/ssl/test/bssl_shim.cc
index 31c0a01..f4e7fff 100644
--- a/deps/boringssl/src/ssl/test/bssl_shim.cc
+++ b/deps/boringssl/src/ssl/test/bssl_shim.cc
@@ -66,10 +66,6 @@ OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
#include "test_config.h"
#include "test_state.h"
-#if defined(OPENSSL_LINUX) && !defined(OPENSSL_ANDROID)
-#define HANDSHAKER_SUPPORTED
-#endif
-
#if !defined(OPENSSL_WINDOWS)
static int closesocket(int sock) {
@@ -550,18 +546,6 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume,
}
}
- if (config->expect_token_binding_param != -1) {
- if (!SSL_is_token_binding_negotiated(ssl)) {
- fprintf(stderr, "no Token Binding negotiated\n");
- return false;
- }
- if (SSL_get_negotiated_token_binding_param(ssl) !=
- static_cast<uint8_t>(config->expect_token_binding_param)) {
- fprintf(stderr, "Token Binding param mismatch\n");
- return false;
- }
- }
-
if (config->expect_extended_master_secret && !SSL_get_extms_support(ssl)) {
fprintf(stderr, "No EMS for connection when expected\n");
return false;
@@ -675,6 +659,33 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume,
SSL_used_hello_retry_request(ssl) ? "" : "no ");
return false;
}
+
+ if (config->expect_ech_accept != !!SSL_ech_accepted(ssl)) {
+ fprintf(stderr, "ECH was %saccepted, but wanted opposite.\n",
+ SSL_ech_accepted(ssl) ? "" : "not ");
+ return false;
+ }
+
+ // Test that handshake hints correctly skipped the expected operations.
+ //
+ // TODO(davidben): Add support for TLS 1.2 hints and remove the version check.
+ // Also add a check for the session cache lookup.
+ if (config->handshake_hints && !config->allow_hint_mismatch &&
+ SSL_version(ssl) == TLS1_3_VERSION) {
+ const TestState *state = GetTestState(ssl);
+ if (!SSL_used_hello_retry_request(ssl) && state->used_private_key) {
+ fprintf(
+ stderr,
+ "Performed private key operation, but hint should have skipped it\n");
+ return false;
+ }
+
+ if (state->ticket_decrypt_done) {
+ fprintf(stderr,
+ "Performed ticket decryption, but hint should have skipped it\n");
+ return false;
+ }
+ }
return true;
}
@@ -692,7 +703,7 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
const TestConfig *retry_config, bool is_resume,
SSL_SESSION *session, SettingsWriter *writer) {
bssl::UniquePtr<SSL> ssl = config->NewSSL(
- ssl_ctx, session, is_resume, std::unique_ptr<TestState>(new TestState));
+ ssl_ctx, session, std::unique_ptr<TestState>(new TestState));
if (!ssl) {
return false;
}
@@ -701,6 +712,17 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
} else {
SSL_set_connect_state(ssl.get());
}
+ if (config->handshake_hints) {
+#if defined(HANDSHAKER_SUPPORTED)
+ GetTestState(ssl.get())->get_handshake_hints_cb =
+ [&](const SSL_CLIENT_HELLO *client_hello) {
+ return GetHandshakeHint(ssl.get(), writer, is_resume, client_hello);
+ };
+#else
+ fprintf(stderr, "The external handshaker can only be used on Linux\n");
+ return false;
+#endif
+ }
int sock = Connect(config->port);
if (sock == -1) {
@@ -787,9 +809,44 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
}
assert(!config->handoff);
+ config = retry_config;
ret = DoExchange(out_session, &ssl, retry_config, is_resume, true, writer);
}
+ // An ECH rejection appears as a failed connection. Note |ssl| may use a
+ // different config on ECH rejection.
+ if (config->expect_no_ech_retry_configs ||
+ !config->expect_ech_retry_configs.empty()) {
+ bssl::Span<const uint8_t> expected =
+ config->expect_no_ech_retry_configs
+ ? bssl::Span<const uint8_t>()
+ : bssl::MakeConstSpan(reinterpret_cast<const uint8_t *>(
+ config->expect_ech_retry_configs.data()),
+ config->expect_ech_retry_configs.size());
+ if (ret) {
+ fprintf(stderr, "Expected ECH rejection, but connection succeeded.\n");
+ return false;
+ }
+ uint32_t err = ERR_peek_error();
+ if (SSL_get_error(ssl.get(), -1) != SSL_ERROR_SSL ||
+ ERR_GET_LIB(err) != ERR_LIB_SSL ||
+ ERR_GET_REASON(err) != SSL_R_ECH_REJECTED) {
+ fprintf(stderr, "Expected ECH rejection, but connection succeeded.\n");
+ return false;
+ }
+ const uint8_t *retry_configs;
+ size_t retry_configs_len;
+ SSL_get0_ech_retry_configs(ssl.get(), &retry_configs, &retry_configs_len);
+ if (bssl::MakeConstSpan(retry_configs, retry_configs_len) != expected) {
+ fprintf(stderr, "ECH retry configs did not match expectations.\n");
+ // Clear the error queue. Otherwise |SSL_R_ECH_REJECTED| will be printed
+ // to stderr and the test framework will think the test had the expected
+ // expectations.
+ ERR_clear_error();
+ return false;
+ }
+ }
+
if (!ret) {
// Print the |SSL_get_error| code. Otherwise, some failures are silent and
// hard to debug.
@@ -823,6 +880,7 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
int ret;
SSL *ssl = ssl_uniqueptr->get();
SSL_CTX *session_ctx = SSL_get_SSL_CTX(ssl);
+ TestState *test_state = GetTestState(ssl);
if (!config->implicit_handshake) {
if (config->handoff) {
@@ -831,6 +889,7 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
return false;
}
ssl = ssl_uniqueptr->get();
+ test_state = GetTestState(ssl);
#else
fprintf(stderr, "The external handshaker can only be used on Linux\n");
return false;
@@ -875,9 +934,44 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
return false;
}
+ if (config->early_write_after_message != 0) {
+ if (!SSL_in_early_data(ssl) || config->is_server) {
+ fprintf(stderr,
+ "-early-write-after-message only works for 0-RTT connections "
+ "on servers.\n");
+ return false;
+ }
+ if (!config->shim_writes_first || !config->async) {
+ fprintf(stderr,
+ "-early-write-after-message requires -shim-writes-first and "
+ "-async.\n");
+ return false;
+ }
+ // Run the handshake until the specified message. Note that, if a
+ // handshake record contains multiple messages, |SSL_do_handshake| usually
+ // processes both atomically. The test must ensure there is a record
+ // boundary after the desired message. Checking |last_message_received|
+ // confirms this.
+ do {
+ ret = SSL_do_handshake(ssl);
+ } while (test_state->last_message_received !=
+ config->early_write_after_message &&
+ RetryAsync(ssl, ret));
+ if (ret == 1) {
+ fprintf(stderr, "Handshake unexpectedly succeeded.\n");
+ return false;
+ }
+ if (test_state->last_message_received !=
+ config->early_write_after_message) {
+ // The handshake failed before we saw the target message. The generic
+ // error-handling logic in the caller will print the error.
+ return false;
+ }
+ }
+
// Reset the state to assert later that the callback isn't called in
// renegotations.
- GetTestState(ssl)->got_new_session = false;
+ test_state->got_new_session = false;
}
if (config->export_keying_material > 0) {
@@ -977,7 +1071,7 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
}
// Let only one byte of the record through.
- AsyncBioAllowWrite(GetTestState(ssl)->async_bio, 1);
+ AsyncBioAllowWrite(test_state->async_bio, 1);
int write_ret =
SSL_write(ssl, kInitialWrite, strlen(kInitialWrite));
if (SSL_get_error(ssl, write_ret) != SSL_ERROR_WANT_WRITE) {
@@ -1032,7 +1126,7 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
// After a successful read, with or without False Start, the handshake
// must be complete unless we are doing early data.
- if (!GetTestState(ssl)->handshake_done &&
+ if (!test_state->handshake_done &&
!SSL_early_data_accepted(ssl)) {
fprintf(stderr, "handshake was not completed after SSL_read\n");
return false;
@@ -1066,7 +1160,7 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
!config->implicit_handshake &&
// Session tickets are sent post-handshake in TLS 1.3.
GetProtocolVersion(ssl) < TLS1_3_VERSION &&
- GetTestState(ssl)->got_new_session) {
+ test_state->got_new_session) {
fprintf(stderr, "new session was established after the handshake\n");
return false;
}
@@ -1074,16 +1168,16 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
if (GetProtocolVersion(ssl) >= TLS1_3_VERSION && !config->is_server) {
bool expect_new_session =
!config->expect_no_session && !config->shim_shuts_down;
- if (expect_new_session != GetTestState(ssl)->got_new_session) {
+ if (expect_new_session != test_state->got_new_session) {
fprintf(stderr,
"new session was%s cached, but we expected the opposite\n",
- GetTestState(ssl)->got_new_session ? "" : " not");
+ test_state->got_new_session ? "" : " not");
return false;
}
if (expect_new_session) {
bool got_early_data =
- GetTestState(ssl)->new_session->ticket_max_early_data != 0;
+ test_state->new_session->ticket_max_early_data != 0;
if (config->expect_ticket_supports_early_data != got_early_data) {
fprintf(stderr,
"new session did%s support early data, but we expected the "
@@ -1095,7 +1189,7 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
}
if (out_session) {
- *out_session = std::move(GetTestState(ssl)->new_session);
+ *out_session = std::move(test_state->new_session);
}
ret = DoShutdown(ssl);
@@ -1144,10 +1238,10 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
if (config->renegotiate_explicit &&
SSL_total_renegotiations(ssl) !=
- GetTestState(ssl)->explicit_renegotiates) {
+ test_state->explicit_renegotiates) {
fprintf(stderr, "Performed %d renegotiations, but triggered %d of them\n",
SSL_total_renegotiations(ssl),
- GetTestState(ssl)->explicit_renegotiates);
+ test_state->explicit_renegotiates);
return false;
}
@@ -1184,8 +1278,8 @@ int main(int argc, char **argv) {
CRYPTO_library_init();
TestConfig initial_config, resume_config, retry_config;
- if (!ParseConfig(argc - 1, argv + 1, &initial_config, &resume_config,
- &retry_config)) {
+ if (!ParseConfig(argc - 1, argv + 1, /*is_shim=*/true, &initial_config,
+ &resume_config, &retry_config)) {
return Usage(argv[0]);
}
diff --git a/deps/boringssl/src/ssl/test/fuzzer.h b/deps/boringssl/src/ssl/test/fuzzer.h
index f10c4a0..509cfdb 100644
--- a/deps/boringssl/src/ssl/test/fuzzer.h
+++ b/deps/boringssl/src/ssl/test/fuzzer.h
@@ -20,17 +20,19 @@
#include <string.h>
#include <algorithm>
+#include <vector>
#include <openssl/bio.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#include <openssl/hpke.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
-#include "../internal.h"
+#include "../../crypto/internal.h"
#include "./fuzzer_tags.h"
namespace {
@@ -229,6 +231,22 @@ const uint8_t kALPNProtocols[] = {
0x01, 'a', 0x02, 'a', 'a', 0x03, 'a', 'a', 'a',
};
+const uint8_t kECHConfig[] = {
+ 0xfe, 0x0a, 0x00, 0x47, 0x2a, 0x00, 0x20, 0x00, 0x20, 0x6c, 0x55,
+ 0x96, 0x41, 0x3d, 0x12, 0x4e, 0x63, 0x3d, 0x39, 0x7a, 0xe9, 0xbc,
+ 0xec, 0xb2, 0x55, 0xd0, 0xe6, 0xaa, 0xbd, 0xa9, 0x79, 0xb8, 0x86,
+ 0x9a, 0x13, 0x61, 0xc6, 0x69, 0xac, 0xb4, 0x21, 0x00, 0x0c, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03,
+ 0x00, 0x10, 0x00, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2e,
+ 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x00, 0x00,
+};
+
+const uint8_t kECHKey[] = {
+ 0x35, 0x6d, 0x45, 0x06, 0xb3, 0x88, 0x89, 0x2e, 0xd6, 0x87, 0x84,
+ 0xd2, 0x2d, 0x6f, 0x83, 0x48, 0xad, 0xf2, 0xfd, 0x08, 0x51, 0x73,
+ 0x10, 0xa0, 0xb8, 0xdd, 0xe9, 0x96, 0x6a, 0xde, 0xbc, 0x82,
+};
+
int ALPNSelectCallback(SSL *ssl, const uint8_t **out, uint8_t *out_len,
const uint8_t *in, unsigned in_len, void *arg) {
static const uint8_t kProtocol[] = {'a', 'a'};
@@ -324,7 +342,7 @@ class TLSFuzzer {
MoveBIOs(ssl_handoff.get(), ssl.get());
// Ordinarily we would call SSL_serialize_handoff(ssl.get(). But for
// fuzzing, use the serialized handoff that's getting fuzzed.
- if (!SSL_apply_handoff(ssl_handoff.get(), handoff_)) {
+ if (!bssl::SSL_apply_handoff(ssl_handoff.get(), handoff_)) {
if (debug_) {
fprintf(stderr, "Handoff failed.\n");
}
@@ -334,7 +352,7 @@ class TLSFuzzer {
} else if (ret < 0 &&
SSL_get_error(ssl_handshake, ret) == SSL_ERROR_HANDBACK) {
MoveBIOs(ssl_handback.get(), ssl_handoff.get());
- if (!SSL_apply_handback(ssl_handback.get(), handback_)) {
+ if (!bssl::SSL_apply_handback(ssl_handback.get(), handback_)) {
if (debug_) {
fprintf(stderr, "Handback failed.\n");
}
@@ -437,6 +455,19 @@ class TLSFuzzer {
}
SSL_CTX_set_tls_channel_id_enabled(ctx_.get(), 1);
+ if (role_ == kServer) {
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ bssl::ScopedEVP_HPKE_KEY key;
+ if (!keys ||
+ !EVP_HPKE_KEY_init(key.get(), EVP_hpke_x25519_hkdf_sha256(), kECHKey,
+ sizeof(kECHKey)) ||
+ !SSL_ECH_KEYS_add(keys.get(), /*is_retry_config=*/true, kECHConfig,
+ sizeof(kECHConfig), key.get()) ||
+ !SSL_CTX_set1_ech_keys(ctx_.get(), keys.get())) {
+ return false;
+ }
+ }
+
return true;
}
@@ -497,7 +528,8 @@ class TLSFuzzer {
if (!CBS_get_u24_length_prefixed(cbs, &handoff)) {
return nullptr;
}
- handoff_.CopyFrom(handoff);
+ handoff_.assign(CBS_data(&handoff),
+ CBS_data(&handoff) + CBS_len(&handoff));
bssl::SSL_set_handoff_mode(ssl.get(), 1);
break;
}
@@ -507,11 +539,21 @@ class TLSFuzzer {
if (!CBS_get_u24_length_prefixed(cbs, &handback)) {
return nullptr;
}
- handback_.CopyFrom(handback);
+ handback_.assign(CBS_data(&handback),
+ CBS_data(&handback) + CBS_len(&handback));
bssl::SSL_set_handoff_mode(ssl.get(), 1);
break;
}
+ case kHintsTag: {
+ CBS hints;
+ if (!CBS_get_u24_length_prefixed(cbs, &hints)) {
+ return nullptr;
+ }
+ SSL_set_handshake_hints(ssl.get(), CBS_data(&hints), CBS_len(&hints));
+ break;
+ }
+
default:
return nullptr;
}
@@ -567,7 +609,7 @@ class TLSFuzzer {
Protocol protocol_;
Role role_;
bssl::UniquePtr<SSL_CTX> ctx_;
- bssl::Array<uint8_t> handoff_, handback_;
+ std::vector<uint8_t> handoff_, handback_;
};
const BIO_METHOD TLSFuzzer::kBIOMethod = {
diff --git a/deps/boringssl/src/ssl/test/fuzzer_tags.h b/deps/boringssl/src/ssl/test/fuzzer_tags.h
index eb9991d..b612222 100644
--- a/deps/boringssl/src/ssl/test/fuzzer_tags.h
+++ b/deps/boringssl/src/ssl/test/fuzzer_tags.h
@@ -23,7 +23,7 @@
// The TLS client and server fuzzers coordinate with bssl_shim on a common
// format to encode configuration parameters in a fuzzer file. To add a new
// configuration, define a tag, update |SetupTest| in fuzzer.h to parse it, and
-// update |WriteSettings| in bssl_shim to serialize it. Finally, record
+// update |SettingsWriter| in bssl_shim to serialize it. Finally, record
// transcripts from a test run, and use the BORINGSSL_FUZZER_DEBUG environment
// variable to confirm the transcripts are compatible.
@@ -45,4 +45,7 @@ static const uint16_t kHandoffTag = 3;
// kHandbackTag is followed by te output of |SSL_serialize_handback|.
static const uint16_t kHandbackTag = 4;
+// kHintsTag is followed by the output of |SSL_serialize_handshake_hints|.
+static const uint16_t kHintsTag = 5;
+
#endif // HEADER_SSL_TEST_FUZZER_TAGS
diff --git a/deps/boringssl/src/ssl/test/handshake_util.cc b/deps/boringssl/src/ssl/test/handshake_util.cc
index f3f725d..b999831 100644
--- a/deps/boringssl/src/ssl/test/handshake_util.cc
+++ b/deps/boringssl/src/ssl/test/handshake_util.cc
@@ -15,7 +15,7 @@
#include "handshake_util.h"
#include <assert.h>
-#if defined(OPENSSL_LINUX) && !defined(OPENSSL_ANDROID)
+#if defined(HANDSHAKER_SUPPORTED)
#include <errno.h>
#include <fcntl.h>
#include <spawn.h>
@@ -27,12 +27,15 @@
#endif
#include <functional>
+#include <map>
+#include <vector>
#include "async_bio.h"
#include "packeted_bio.h"
#include "test_config.h"
#include "test_state.h"
+#include <openssl/bytestring.h>
#include <openssl/ssl.h>
using namespace bssl;
@@ -83,14 +86,6 @@ bool RetryAsync(SSL *ssl, int ret) {
case SSL_ERROR_WANT_WRITE:
AsyncBioAllowWrite(test_state->async_bio, 1);
return true;
- case SSL_ERROR_WANT_CHANNEL_ID_LOOKUP: {
- UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(config->send_channel_id);
- if (!pkey) {
- return false;
- }
- test_state->channel_id = std::move(pkey);
- return true;
- }
case SSL_ERROR_WANT_X509_LOOKUP:
test_state->cert_ready = true;
return true;
@@ -135,7 +130,7 @@ int CheckIdempotentError(const char *name, SSL *ssl,
return ret;
}
-#if defined(OPENSSL_LINUX) && !defined(OPENSSL_ANDROID)
+#if defined(HANDSHAKER_SUPPORTED)
// MoveBIOs moves the |BIO|s of |src| to |dst|. It is used for handoff.
static void MoveBIOs(SSL *dest, SSL *src) {
@@ -231,7 +226,7 @@ static bool Proxy(BIO *socket, bool async, int control, int rfd, int wfd) {
return false;
}
switch (msg) {
- case kControlMsgHandback:
+ case kControlMsgDone:
return true;
case kControlMsgError:
return false;
@@ -303,17 +298,90 @@ static bool Proxy(BIO *socket, bool async, int control, int rfd, int wfd) {
class ScopedFD {
public:
- explicit ScopedFD(int fd): fd_(fd) {}
- ~ScopedFD() { close(fd_); }
+ ScopedFD() : fd_(-1) {}
+ explicit ScopedFD(int fd) : fd_(fd) {}
+ ~ScopedFD() { Reset(); }
+
+ ScopedFD(ScopedFD &&other) { *this = std::move(other); }
+ ScopedFD &operator=(ScopedFD &&other) {
+ Reset(other.fd_);
+ other.fd_ = -1;
+ return *this;
+ }
+
+ int fd() const { return fd_; }
+
+ void Reset(int fd = -1) {
+ if (fd_ >= 0) {
+ close(fd_);
+ }
+ fd_ = fd;
+ }
+
private:
- const int fd_;
+ int fd_;
};
-// RunHandshaker forks and execs the handshaker binary, handing off |input|,
-// and, after proxying some amount of handshake traffic, handing back |out|.
-static bool RunHandshaker(BIO *bio, const TestConfig *config, bool is_resume,
- const Array<uint8_t> &input,
- Array<uint8_t> *out) {
+class ScopedProcess {
+ public:
+ ScopedProcess() : pid_(-1) {}
+ ~ScopedProcess() { Reset(); }
+
+ ScopedProcess(ScopedProcess &&other) { *this = std::move(other); }
+ ScopedProcess &operator=(ScopedProcess &&other) {
+ Reset(other.pid_);
+ other.pid_ = -1;
+ return *this;
+ }
+
+ pid_t pid() const { return pid_; }
+
+ void Reset(pid_t pid = -1) {
+ if (pid_ >= 0) {
+ kill(pid_, SIGTERM);
+ int unused;
+ Wait(&unused);
+ }
+ pid_ = pid;
+ }
+
+ bool Wait(int *out_status) {
+ if (pid_ < 0) {
+ return false;
+ }
+ if (waitpid_eintr(pid_, out_status, 0) != pid_) {
+ return false;
+ }
+ pid_ = -1;
+ return true;
+ }
+
+ private:
+ pid_t pid_;
+};
+
+class FileActionsDestroyer {
+ public:
+ explicit FileActionsDestroyer(posix_spawn_file_actions_t *actions)
+ : actions_(actions) {}
+ ~FileActionsDestroyer() { posix_spawn_file_actions_destroy(actions_); }
+ FileActionsDestroyer(const FileActionsDestroyer &) = delete;
+ FileActionsDestroyer &operator=(const FileActionsDestroyer &) = delete;
+
+ private:
+ posix_spawn_file_actions_t *actions_;
+};
+
+// StartHandshaker starts the handshaker process and, on success, returns a
+// handle to the process in |*out|. It sets |*out_control| to a control pipe to
+// the process. |map_fds| maps from desired fd number in the child process to
+// the source fd in the calling process. |close_fds| is the list of additional
+// fds to close, which may overlap with |map_fds|. Other than stdin, stdout, and
+// stderr, the status of fds not listed in either set is undefined.
+static bool StartHandshaker(ScopedProcess *out, ScopedFD *out_control,
+ const TestConfig *config, bool is_resume,
+ std::map<int, int> map_fds,
+ std::vector<int> close_fds) {
if (config->handshaker_path.empty()) {
fprintf(stderr, "no -handshaker-path specified\n");
return false;
@@ -324,12 +392,97 @@ static bool RunHandshaker(BIO *bio, const TestConfig *config, bool is_resume,
return false;
}
+ std::vector<const char *> args;
+ args.push_back(config->handshaker_path.c_str());
+ static const char kResumeFlag[] = "-handshaker-resume";
+ if (is_resume) {
+ args.push_back(kResumeFlag);
+ }
+ // config->argv omits argv[0].
+ for (int j = 0; j < config->argc; ++j) {
+ args.push_back(config->argv[j]);
+ }
+ args.push_back(nullptr);
+
// A datagram socket guarantees that writes are all-or-nothing.
int control[2];
if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, control) != 0) {
perror("socketpair");
return false;
}
+ ScopedFD scoped_control0(control[0]), scoped_control1(control[1]);
+ close_fds.push_back(control[0]);
+ map_fds[kFdControl] = control[1];
+
+ posix_spawn_file_actions_t actions;
+ if (posix_spawn_file_actions_init(&actions) != 0) {
+ return false;
+ }
+ FileActionsDestroyer actions_destroyer(&actions);
+ for (int fd : close_fds) {
+ if (posix_spawn_file_actions_addclose(&actions, fd) != 0) {
+ return false;
+ }
+ }
+ if (!map_fds.empty()) {
+ int max_fd = STDERR_FILENO;
+ for (const auto &pair : map_fds) {
+ max_fd = std::max(max_fd, pair.first);
+ max_fd = std::max(max_fd, pair.second);
+ }
+ // |map_fds| may contain cycles, so make a copy of all the source fds.
+ // |posix_spawn| can only use |dup2|, not |dup|, so we assume |max_fd| is
+ // the last fd we care about inheriting. |temp_fds| maps from fd number in
+ // the parent process to a temporary fd number in the child process.
+ std::map<int, int> temp_fds;
+ int next_fd = max_fd + 1;
+ for (const auto &pair : map_fds) {
+ if (temp_fds.count(pair.second)) {
+ continue;
+ }
+ temp_fds[pair.second] = next_fd;
+ if (posix_spawn_file_actions_adddup2(&actions, pair.second, next_fd) !=
+ 0 ||
+ posix_spawn_file_actions_addclose(&actions, pair.second) != 0) {
+ return false;
+ }
+ next_fd++;
+ }
+ for (const auto &pair : map_fds) {
+ if (posix_spawn_file_actions_adddup2(&actions, temp_fds[pair.second],
+ pair.first) != 0) {
+ return false;
+ }
+ }
+ // Clean up temporary fds.
+ for (int fd = max_fd + 1; fd < next_fd; fd++) {
+ if (posix_spawn_file_actions_addclose(&actions, fd) != 0) {
+ return false;
+ }
+ }
+ }
+
+ fflush(stdout);
+ fflush(stderr);
+
+ // MSan doesn't know that |posix_spawn| initializes its output, so initialize
+ // it to -1.
+ pid_t pid = -1;
+ if (posix_spawn(&pid, args[0], &actions, nullptr,
+ const_cast<char *const *>(args.data()), environ) != 0) {
+ return false;
+ }
+
+ out->Reset(pid);
+ *out_control = std::move(scoped_control0);
+ return true;
+}
+
+// RunHandshaker forks and execs the handshaker binary, handing off |input|,
+// and, after proxying some amount of handshake traffic, handing back |out|.
+static bool RunHandshaker(BIO *bio, const TestConfig *config, bool is_resume,
+ Span<const uint8_t> input,
+ std::vector<uint8_t> *out) {
int rfd[2], wfd[2];
// We use pipes, rather than some other mechanism, for their buffers. During
// the handshake, this process acts as a dumb proxy until receiving the
@@ -341,77 +494,37 @@ static bool RunHandshaker(BIO *bio, const TestConfig *config, bool is_resume,
// handshaker has not explicitly requested as a result of hitting
// |SSL_ERROR_WANT_READ|. Pipes allow the data to sit in a buffer while the
// two processes synchronize over the |control| channel.
- if (pipe(rfd) != 0 || pipe(wfd) != 0) {
- perror("pipe2");
+ if (pipe(rfd) != 0) {
+ perror("pipe");
return false;
}
+ ScopedFD rfd0_closer(rfd[0]), rfd1_closer(rfd[1]);
- fflush(stdout);
- fflush(stderr);
-
- std::vector<char *> args;
- bssl::UniquePtr<char> handshaker_path(
- OPENSSL_strdup(config->handshaker_path.c_str()));
- args.push_back(handshaker_path.get());
- char resume[] = "-handshaker-resume";
- if (is_resume) {
- args.push_back(resume);
- }
- // config->argv omits argv[0].
- for (int j = 0; j < config->argc; ++j) {
- args.push_back(config->argv[j]);
- }
- args.push_back(nullptr);
-
- posix_spawn_file_actions_t actions;
- if (posix_spawn_file_actions_init(&actions) != 0 ||
- posix_spawn_file_actions_addclose(&actions, control[0]) ||
- posix_spawn_file_actions_addclose(&actions, rfd[1]) ||
- posix_spawn_file_actions_addclose(&actions, wfd[0])) {
- return false;
- }
- assert(kFdControl != rfd[0]);
- assert(kFdControl != wfd[1]);
- if (control[1] != kFdControl &&
- posix_spawn_file_actions_adddup2(&actions, control[1], kFdControl) != 0) {
+ if (pipe(wfd) != 0) {
+ perror("pipe");
return false;
}
- assert(kFdProxyToHandshaker != wfd[1]);
- if (rfd[0] != kFdProxyToHandshaker &&
- posix_spawn_file_actions_adddup2(&actions, rfd[0],
- kFdProxyToHandshaker) != 0) {
+ ScopedFD wfd0_closer(wfd[0]), wfd1_closer(wfd[1]);
+
+ ScopedProcess handshaker;
+ ScopedFD control;
+ if (!StartHandshaker(
+ &handshaker, &control, config, is_resume,
+ {{kFdProxyToHandshaker, rfd[0]}, {kFdHandshakerToProxy, wfd[1]}},
+ {rfd[1], wfd[0]})) {
return false;
}
- if (wfd[1] != kFdHandshakerToProxy &&
- posix_spawn_file_actions_adddup2(&actions, wfd[1],
- kFdHandshakerToProxy) != 0) {
- return false;
- }
- // MSan doesn't know that |posix_spawn| initializes its output, so initialize
- // it to -1.
- pid_t handshaker_pid = -1;
- int ret = posix_spawn(&handshaker_pid, args[0], &actions, nullptr,
- args.data(), environ);
- if (posix_spawn_file_actions_destroy(&actions) != 0 ||
- ret != 0) {
- return false;
- }
+ rfd0_closer.Reset();
+ wfd1_closer.Reset();
- close(control[1]);
- close(rfd[0]);
- close(wfd[1]);
- ScopedFD rfd_closer(rfd[1]);
- ScopedFD wfd_closer(wfd[0]);
- ScopedFD control_closer(control[0]);
-
- if (write_eintr(control[0], input.data(), input.size()) == -1) {
+ if (write_eintr(control.fd(), input.data(), input.size()) == -1) {
perror("write");
return false;
}
- bool ok = Proxy(bio, config->async, control[0], rfd[1], wfd[0]);
+ bool ok = Proxy(bio, config->async, control.fd(), rfd[1], wfd[0]);
int wstatus;
- if (waitpid_eintr(handshaker_pid, &wstatus, 0) != handshaker_pid) {
+ if (!handshaker.Wait(&wstatus)) {
perror("waitpid");
return false;
}
@@ -424,13 +537,69 @@ static bool RunHandshaker(BIO *bio, const TestConfig *config, bool is_resume,
}
constexpr size_t kBufSize = 1024 * 1024;
- bssl::UniquePtr<uint8_t> buf((uint8_t *) OPENSSL_malloc(kBufSize));
- int len = read_eintr(control[0], buf.get(), kBufSize);
+ std::vector<uint8_t> buf(kBufSize);
+ ssize_t len = read_eintr(control.fd(), buf.data(), buf.size());
if (len == -1) {
perror("read");
return false;
}
- out->CopyFrom({buf.get(), (size_t)len});
+ buf.resize(len);
+ *out = std::move(buf);
+ return true;
+}
+
+static bool RequestHandshakeHint(const TestConfig *config, bool is_resume,
+ Span<const uint8_t> input, bool *out_has_hints,
+ std::vector<uint8_t> *out_hints) {
+ ScopedProcess handshaker;
+ ScopedFD control;
+ if (!StartHandshaker(&handshaker, &control, config, is_resume, {}, {})) {
+ return false;
+ }
+
+ if (write_eintr(control.fd(), input.data(), input.size()) == -1) {
+ perror("write");
+ return false;
+ }
+
+ char msg;
+ if (read_eintr(control.fd(), &msg, 1) != 1) {
+ perror("read");
+ return false;
+ }
+
+ switch (msg) {
+ case kControlMsgDone: {
+ constexpr size_t kBufSize = 1024 * 1024;
+ out_hints->resize(kBufSize);
+ ssize_t len =
+ read_eintr(control.fd(), out_hints->data(), out_hints->size());
+ if (len == -1) {
+ perror("read");
+ return false;
+ }
+ out_hints->resize(len);
+ *out_has_hints = true;
+ break;
+ }
+ case kControlMsgError:
+ *out_has_hints = false;
+ break;
+ default:
+ fprintf(stderr, "Unknown control message from handshaker: %c\n", msg);
+ return false;
+ }
+
+ int wstatus;
+ if (!handshaker.Wait(&wstatus)) {
+ perror("waitpid");
+ return false;
+ }
+ if (wstatus) {
+ fprintf(stderr, "handshaker exited irregularly\n");
+ return false;
+ }
+
return true;
}
@@ -438,7 +607,7 @@ static bool RunHandshaker(BIO *bio, const TestConfig *config, bool is_resume,
// be passed to the handshaker. The serialized state includes both the SSL
// handoff, as well test-related state.
static bool PrepareHandoff(SSL *ssl, SettingsWriter *writer,
- Array<uint8_t> *out_handoff) {
+ std::vector<uint8_t> *out_handoff) {
SSL_set_handoff_mode(ssl, 1);
const TestConfig *config = GetTestConfig(ssl);
@@ -460,12 +629,14 @@ static bool PrepareHandoff(SSL *ssl, SettingsWriter *writer,
if (!CBB_init(cbb.get(), 512) ||
!SSL_serialize_handoff(ssl, cbb.get(), &hello) ||
!writer->WriteHandoff({CBB_data(cbb.get()), CBB_len(cbb.get())}) ||
- !SerializeContextState(ssl->ctx.get(), cbb.get()) ||
+ !SerializeContextState(SSL_get_SSL_CTX(ssl), cbb.get()) ||
!GetTestState(ssl)->Serialize(cbb.get())) {
fprintf(stderr, "Handoff serialisation failed.\n");
return false;
}
- return CBBFinishArray(cbb.get(), out_handoff);
+ out_handoff->assign(CBB_data(cbb.get()),
+ CBB_data(cbb.get()) + CBB_len(cbb.get()));
+ return true;
}
// DoSplitHandshake delegates the SSL handshake to a separate process, called
@@ -476,11 +647,11 @@ static bool PrepareHandoff(SSL *ssl, SettingsWriter *writer,
bool DoSplitHandshake(UniquePtr<SSL> *ssl, SettingsWriter *writer,
bool is_resume) {
assert(SSL_get_rbio(ssl->get()) == SSL_get_wbio(ssl->get()));
- Array<uint8_t> handshaker_input;
+ std::vector<uint8_t> handshaker_input;
const TestConfig *config = GetTestConfig(ssl->get());
// out is the response from the handshaker, which includes a serialized
// handback message, but also serialized updates to the |TestState|.
- Array<uint8_t> out;
+ std::vector<uint8_t> out;
if (!PrepareHandoff(ssl->get(), writer, &handshaker_input) ||
!RunHandshaker(SSL_get_rbio(ssl->get()), config, is_resume,
handshaker_input, &out)) {
@@ -488,19 +659,17 @@ bool DoSplitHandshake(UniquePtr<SSL> *ssl, SettingsWriter *writer,
return false;
}
- UniquePtr<SSL> ssl_handback =
- config->NewSSL((*ssl)->ctx.get(), nullptr, false, nullptr);
+ SSL_CTX *ctx = SSL_get_SSL_CTX(ssl->get());
+ UniquePtr<SSL> ssl_handback = config->NewSSL(ctx, nullptr, nullptr);
if (!ssl_handback) {
return false;
}
CBS output, handback;
CBS_init(&output, out.data(), out.size());
if (!CBS_get_u24_length_prefixed(&output, &handback) ||
- !DeserializeContextState(&output, ssl_handback->ctx.get()) ||
- !SetTestState(ssl_handback.get(), TestState::Deserialize(
- &output, ssl_handback->ctx.get())) ||
- !GetTestState(ssl_handback.get()) ||
- !writer->WriteHandback(handback) ||
+ !DeserializeContextState(&output, ctx) ||
+ !SetTestState(ssl_handback.get(), TestState::Deserialize(&output, ctx)) ||
+ !GetTestState(ssl_handback.get()) || !writer->WriteHandback(handback) ||
!SSL_apply_handback(ssl_handback.get(), handback)) {
fprintf(stderr, "Handback failed.\n");
return false;
@@ -514,4 +683,35 @@ bool DoSplitHandshake(UniquePtr<SSL> *ssl, SettingsWriter *writer,
return true;
}
-#endif // defined(OPENSSL_LINUX) && !defined(OPENSSL_ANDROID)
+bool GetHandshakeHint(SSL *ssl, SettingsWriter *writer, bool is_resume,
+ const SSL_CLIENT_HELLO *client_hello) {
+ ScopedCBB input;
+ CBB child;
+ if (!CBB_init(input.get(), client_hello->client_hello_len + 256) ||
+ !CBB_add_u24_length_prefixed(input.get(), &child) ||
+ !CBB_add_bytes(&child, client_hello->client_hello,
+ client_hello->client_hello_len) ||
+ !CBB_add_u24_length_prefixed(input.get(), &child) ||
+ !SSL_serialize_capabilities(ssl, &child) || //
+ !CBB_flush(input.get())) {
+ return false;
+ }
+
+ bool has_hints;
+ std::vector<uint8_t> hints;
+ if (!RequestHandshakeHint(
+ GetTestConfig(ssl), is_resume,
+ MakeConstSpan(CBB_data(input.get()), CBB_len(input.get())),
+ &has_hints, &hints)) {
+ return false;
+ }
+ if (has_hints &&
+ (!writer->WriteHints(hints) ||
+ !SSL_set_handshake_hints(ssl, hints.data(), hints.size()))) {
+ return false;
+ }
+
+ return true;
+}
+
+#endif // defined(HANDSHAKER_SUPPORTED)
diff --git a/deps/boringssl/src/ssl/test/handshake_util.h b/deps/boringssl/src/ssl/test/handshake_util.h
index 4fb46db..dda9206 100644
--- a/deps/boringssl/src/ssl/test/handshake_util.h
+++ b/deps/boringssl/src/ssl/test/handshake_util.h
@@ -21,6 +21,11 @@
#include "settings_writer.h"
+
+#if defined(OPENSSL_LINUX) && !defined(OPENSSL_ANDROID)
+#define HANDSHAKER_SUPPORTED
+#endif
+
// RetryAsync is called after a failed operation on |ssl| with return code
// |ret|. If the operation should be retried, it simulates one asynchronous
// event and returns true. Otherwise it returns false.
@@ -30,6 +35,7 @@ bool RetryAsync(SSL *ssl, int ret);
// errors are idempotent.
int CheckIdempotentError(const char *name, SSL *ssl, std::function<int()> func);
+#if defined(HANDSHAKER_SUPPORTED)
// DoSplitHandshake delegates the SSL handshake to a separate process, called
// the handshaker. This process proxies I/O between the handshaker and the
// client, using the |BIO| from |ssl|. After a successful handshake, |ssl| is
@@ -38,16 +44,24 @@ int CheckIdempotentError(const char *name, SSL *ssl, std::function<int()> func);
bool DoSplitHandshake(bssl::UniquePtr<SSL> *ssl, SettingsWriter *writer,
bool is_resume);
+// GetHandshakeHint requests a handshake hint from the handshaker process and
+// configures the result on |ssl|. It returns true on success and false on
+// error.
+bool GetHandshakeHint(SSL *ssl, SettingsWriter *writer, bool is_resume,
+ const SSL_CLIENT_HELLO *client_hello);
+
// The protocol between the proxy and the handshaker is defined by these
-// single-character prefixes.
+// single-character prefixes. |kControlMsgDone| uses 'H' for compatibility with
+// older binaries.
constexpr char kControlMsgWantRead = 'R'; // Handshaker wants data
constexpr char kControlMsgWriteCompleted = 'W'; // Proxy has sent data
-constexpr char kControlMsgHandback = 'H'; // Proxy should resume control
+constexpr char kControlMsgDone = 'H'; // Proxy should resume control
constexpr char kControlMsgError = 'E'; // Handshaker hit an error
// The protocol between the proxy and handshaker uses these file descriptors.
-constexpr int kFdControl = 3; // Bi-directional dgram socket.
-constexpr int kFdProxyToHandshaker = 4; // Uni-directional pipe.
-constexpr int kFdHandshakerToProxy = 5; // Uni-directional pipe.
+constexpr int kFdControl = 3; // Bi-directional dgram socket.
+constexpr int kFdProxyToHandshaker = 4; // Uni-directional pipe.
+constexpr int kFdHandshakerToProxy = 5; // Uni-directional pipe.
+#endif // HANDSHAKER_SUPPORTED
#endif // HEADER_TEST_HANDSHAKE
diff --git a/deps/boringssl/src/ssl/test/handshaker.cc b/deps/boringssl/src/ssl/test/handshaker.cc
index 72d6b2f..ac89063 100644
--- a/deps/boringssl/src/ssl/test/handshaker.cc
+++ b/deps/boringssl/src/ssl/test/handshaker.cc
@@ -12,16 +12,18 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
+#include <memory>
+
#include <openssl/bytestring.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
-#include "../internal.h"
#include "handshake_util.h"
#include "test_config.h"
#include "test_state.h"
@@ -30,6 +32,22 @@ using namespace bssl;
namespace {
+ssize_t read_eintr(int fd, void *out, size_t len) {
+ ssize_t ret;
+ do {
+ ret = read(fd, out, len);
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+ssize_t write_eintr(int fd, const void *in, size_t len) {
+ ssize_t ret;
+ do {
+ ret = write(fd, in, len);
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
bool HandbackReady(SSL *ssl, int ret) {
return ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_HANDBACK;
}
@@ -40,7 +58,11 @@ bool Handshaker(const TestConfig *config, int rfd, int wfd,
if (!ctx) {
return false;
}
- UniquePtr<SSL> ssl = config->NewSSL(ctx.get(), nullptr, false, nullptr);
+ UniquePtr<SSL> ssl =
+ config->NewSSL(ctx.get(), /*session=*/nullptr, /*test_state=*/nullptr);
+ if (!ssl) {
+ return false;
+ }
// Set |O_NONBLOCK| in order to break out of the loop when we hit
// |SSL_ERROR_WANT_READ|, so that we can send |kControlMsgWantRead| to the
@@ -72,8 +94,8 @@ bool Handshaker(const TestConfig *config, int rfd, int wfd,
// Synchronize with the proxy, i.e. don't let the handshake continue until
// the proxy has sent more data.
char msg = kControlMsgWantRead;
- if (write(control, &msg, 1) != 1 ||
- read(control, &msg, 1) != 1 ||
+ if (write_eintr(control, &msg, 1) != 1 ||
+ read_eintr(control, &msg, 1) != 1 ||
msg != kControlMsgWriteCompleted) {
fprintf(stderr, "read via proxy failed\n");
return false;
@@ -85,46 +107,109 @@ bool Handshaker(const TestConfig *config, int rfd, int wfd,
}
}
if (!HandbackReady(ssl.get(), ret)) {
+ fprintf(stderr, "Handshaker: %s\n",
+ SSL_error_description(SSL_get_error(ssl.get(), ret)));
ERR_print_errors_fp(stderr);
return false;
}
ScopedCBB output;
CBB handback;
- Array<uint8_t> bytes;
if (!CBB_init(output.get(), 1024) ||
!CBB_add_u24_length_prefixed(output.get(), &handback) ||
!SSL_serialize_handback(ssl.get(), &handback) ||
- !SerializeContextState(ssl->ctx.get(), output.get()) ||
- !GetTestState(ssl.get())->Serialize(output.get()) ||
- !CBBFinishArray(output.get(), &bytes)) {
+ !SerializeContextState(ctx.get(), output.get()) ||
+ !GetTestState(ssl.get())->Serialize(output.get())) {
fprintf(stderr, "Handback serialisation failed.\n");
return false;
}
- char msg = kControlMsgHandback;
- if (write(control, &msg, 1) == -1 ||
- write(control, bytes.data(), bytes.size()) == -1) {
+ char msg = kControlMsgDone;
+ if (write_eintr(control, &msg, 1) == -1 ||
+ write_eintr(control, CBB_data(output.get()), CBB_len(output.get())) ==
+ -1) {
perror("write");
return false;
}
return true;
}
-ssize_t read_eintr(int fd, void *out, size_t len) {
- ssize_t ret;
- do {
- ret = read(fd, out, len);
- } while (ret < 0 && errno == EINTR);
- return ret;
-}
+bool GenerateHandshakeHint(const TestConfig *config,
+ bssl::Span<const uint8_t> request, int control) {
+ // The handshake hint contains the ClientHello and the capabilities string.
+ CBS cbs = request;
+ CBS client_hello, capabilities;
+ if (!CBS_get_u24_length_prefixed(&cbs, &client_hello) ||
+ !CBS_get_u24_length_prefixed(&cbs, &capabilities) || //
+ CBS_len(&cbs) != 0) {
+ fprintf(stderr, "Handshaker: Could not parse hint request\n");
+ return false;
+ }
-ssize_t write_eintr(int fd, const void *in, size_t len) {
- ssize_t ret;
+ UniquePtr<SSL_CTX> ctx = config->SetupCtx(/*old_ctx=*/nullptr);
+ if (!ctx) {
+ return false;
+ }
+
+ UniquePtr<SSL> ssl =
+ config->NewSSL(ctx.get(), /*session=*/nullptr,
+ std::unique_ptr<TestState>(new TestState));
+ if (!ssl) {
+ return false;
+ }
+
+ // TODO(davidben): When split handshakes is replaced, move this into |NewSSL|.
+ assert(config->is_server);
+ SSL_set_accept_state(ssl.get());
+
+ if (!SSL_request_handshake_hints(
+ ssl.get(), CBS_data(&client_hello), CBS_len(&client_hello),
+ CBS_data(&capabilities), CBS_len(&capabilities))) {
+ fprintf(stderr, "Handshaker: SSL_request_handshake_hints failed\n");
+ return false;
+ }
+
+ int ret = 0;
do {
- ret = write(fd, in, len);
- } while (ret < 0 && errno == EINTR);
- return ret;
+ ret = CheckIdempotentError("SSL_do_handshake", ssl.get(),
+ [&] { return SSL_do_handshake(ssl.get()); });
+ } while (RetryAsync(ssl.get(), ret));
+
+ if (ret > 0) {
+ fprintf(stderr, "Handshaker: handshake unexpectedly succeeded.\n");
+ return false;
+ }
+
+ if (SSL_get_error(ssl.get(), ret) != SSL_ERROR_HANDSHAKE_HINTS_READY) {
+ // Errors here may be expected if the test is testing a failing case. The
+ // shim should continue executing without a hint, so we report an error
+ // "successfully". This allows the shim to distinguish this from the other
+ // unexpected error cases.
+ //
+ // We intentionally avoid printing the error in this case, to avoid mixing
+ // up test expectations with errors from the shim.
+ char msg = kControlMsgError;
+ if (write_eintr(control, &msg, 1) == -1) {
+ return false;
+ }
+ return true;
+ }
+
+ bssl::ScopedCBB hints;
+ if (!CBB_init(hints.get(), 256) ||
+ !SSL_serialize_handshake_hints(ssl.get(), hints.get())) {
+ fprintf(stderr, "Handshaker: failed to serialize handshake hints\n");
+ return false;
+ }
+
+ char msg = kControlMsgDone;
+ if (write_eintr(control, &msg, 1) == -1 ||
+ write_eintr(control, CBB_data(hints.get()), CBB_len(hints.get())) == -1) {
+ perror("write");
+ return false;
+ }
+
+ return true;
}
int SignalError() {
@@ -139,12 +224,12 @@ int SignalError() {
int main(int argc, char **argv) {
TestConfig initial_config, resume_config, retry_config;
- if (!ParseConfig(argc - 1, argv + 1, &initial_config, &resume_config,
- &retry_config)) {
+ if (!ParseConfig(argc - 1, argv + 1, /*is_shim=*/false, &initial_config,
+ &resume_config, &retry_config)) {
return SignalError();
}
- const TestConfig *config = initial_config.handshaker_resume
- ? &resume_config : &initial_config;
+ const TestConfig *config =
+ initial_config.handshaker_resume ? &resume_config : &initial_config;
#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
if (initial_config.handshaker_resume) {
// If the PRNG returns exactly the same values when trying to resume then a
@@ -159,16 +244,23 @@ int main(int argc, char **argv) {
// read() will return the entire message in one go, because it's a datagram
// socket.
constexpr size_t kBufSize = 1024 * 1024;
- bssl::UniquePtr<uint8_t> buf((uint8_t *) OPENSSL_malloc(kBufSize));
- ssize_t len = read_eintr(kFdControl, buf.get(), kBufSize);
+ std::vector<uint8_t> request(kBufSize);
+ ssize_t len = read_eintr(kFdControl, request.data(), request.size());
if (len == -1) {
perror("read");
return 2;
}
- Span<uint8_t> handoff(buf.get(), len);
- if (!Handshaker(config, kFdProxyToHandshaker, kFdHandshakerToProxy, handoff,
- kFdControl)) {
- return SignalError();
+ request.resize(static_cast<size_t>(len));
+
+ if (config->handshake_hints) {
+ if (!GenerateHandshakeHint(config, request, kFdControl)) {
+ return SignalError();
+ }
+ } else {
+ if (!Handshaker(config, kFdProxyToHandshaker, kFdHandshakerToProxy,
+ request, kFdControl)) {
+ return SignalError();
+ }
}
return 0;
}
diff --git a/deps/boringssl/src/ssl/test/mock_quic_transport.cc b/deps/boringssl/src/ssl/test/mock_quic_transport.cc
index 4b8bc30..310b779 100644
--- a/deps/boringssl/src/ssl/test/mock_quic_transport.cc
+++ b/deps/boringssl/src/ssl/test/mock_quic_transport.cc
@@ -271,7 +271,7 @@ bool MockQuicTransport::WriteApplicationData(const uint8_t *in, size_t len) {
return WriteRecord(level, SSL3_RT_APPLICATION_DATA, in, len);
}
-bool MockQuicTransport::Flush() { return BIO_flush(bio_.get()); }
+bool MockQuicTransport::Flush() { return BIO_flush(bio_.get()) > 0; }
bool MockQuicTransport::SendAlert(enum ssl_encryption_level_t level,
uint8_t alert) {
diff --git a/deps/boringssl/src/ssl/test/settings_writer.cc b/deps/boringssl/src/ssl/test/settings_writer.cc
index fe8d42e..8605222 100644
--- a/deps/boringssl/src/ssl/test/settings_writer.cc
+++ b/deps/boringssl/src/ssl/test/settings_writer.cc
@@ -85,29 +85,26 @@ bool SettingsWriter::Commit() {
}
bool SettingsWriter::WriteHandoff(bssl::Span<const uint8_t> handoff) {
- if (path_.empty()) {
- return true;
- }
-
- CBB child;
- if (!CBB_add_u16(cbb_.get(), kHandoffTag) ||
- !CBB_add_u24_length_prefixed(cbb_.get(), &child) ||
- !CBB_add_bytes(&child, handoff.data(), handoff.size()) ||
- !CBB_flush(cbb_.get())) {
- return false;
- }
- return true;
+ return WriteData(kHandoffTag, handoff);
}
bool SettingsWriter::WriteHandback(bssl::Span<const uint8_t> handback) {
+ return WriteData(kHandbackTag, handback);
+}
+
+bool SettingsWriter::WriteHints(bssl::Span<const uint8_t> hints) {
+ return WriteData(kHintsTag, hints);
+}
+
+bool SettingsWriter::WriteData(uint16_t tag, bssl::Span<const uint8_t> data) {
if (path_.empty()) {
return true;
}
CBB child;
- if (!CBB_add_u16(cbb_.get(), kHandbackTag) ||
+ if (!CBB_add_u16(cbb_.get(), tag) ||
!CBB_add_u24_length_prefixed(cbb_.get(), &child) ||
- !CBB_add_bytes(&child, handback.data(), handback.size()) ||
+ !CBB_add_bytes(&child, data.data(), data.size()) ||
!CBB_flush(cbb_.get())) {
return false;
}
diff --git a/deps/boringssl/src/ssl/test/settings_writer.h b/deps/boringssl/src/ssl/test/settings_writer.h
index 322850d..e1ffdc1 100644
--- a/deps/boringssl/src/ssl/test/settings_writer.h
+++ b/deps/boringssl/src/ssl/test/settings_writer.h
@@ -20,7 +20,6 @@
#include <openssl/bytestring.h>
#include <openssl/ssl.h>
-#include "../internal.h"
#include "test_config.h"
struct SettingsWriter {
@@ -35,10 +34,12 @@ struct SettingsWriter {
bool Commit();
bool WriteHandoff(bssl::Span<const uint8_t> handoff);
-
bool WriteHandback(bssl::Span<const uint8_t> handback);
+ bool WriteHints(bssl::Span<const uint8_t> hints);
private:
+ bool WriteData(uint16_t tag, bssl::Span<const uint8_t> data);
+
std::string path_;
bssl::ScopedCBB cbb_;
};
diff --git a/deps/boringssl/src/ssl/test/test_config.cc b/deps/boringssl/src/ssl/test/test_config.cc
index c1d215b..7d1cefa 100644
--- a/deps/boringssl/src/ssl/test/test_config.cc
+++ b/deps/boringssl/src/ssl/test/test_config.cc
@@ -22,11 +22,14 @@
#include <memory>
#include <openssl/base64.h>
+#include <openssl/hpke.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include "../../crypto/internal.h"
#include "../internal.h"
+#include "handshake_util.h"
+#include "mock_quic_transport.h"
#include "test_state.h"
namespace {
@@ -56,6 +59,9 @@ const Flag<bool> kBoolFlags[] = {
{"-quic", &TestConfig::is_quic},
{"-fallback-scsv", &TestConfig::fallback_scsv},
{"-enable-ech-grease", &TestConfig::enable_ech_grease},
+ {"-expect-ech-accept", &TestConfig::expect_ech_accept},
+ {"-expect-no-ech-name-override", &TestConfig::expect_no_ech_name_override},
+ {"-expect-no-ech-retry-configs", &TestConfig::expect_no_ech_retry_configs},
{"-require-any-client-certificate",
&TestConfig::require_any_client_certificate},
{"-false-start", &TestConfig::false_start},
@@ -73,6 +79,7 @@ const Flag<bool> kBoolFlags[] = {
{"-shim-writes-first", &TestConfig::shim_writes_first},
{"-expect-session-miss", &TestConfig::expect_session_miss},
{"-decline-alpn", &TestConfig::decline_alpn},
+ {"-reject-alpn", &TestConfig::reject_alpn},
{"-select-empty-alpn", &TestConfig::select_empty_alpn},
{"-defer-alps", &TestConfig::defer_alps},
{"-expect-extended-master-secret",
@@ -108,12 +115,12 @@ const Flag<bool> kBoolFlags[] = {
{"-renegotiate-explicit", &TestConfig::renegotiate_explicit},
{"-forbid-renegotiation-after-handshake",
&TestConfig::forbid_renegotiation_after_handshake},
- {"-enable-all-curves", &TestConfig::enable_all_curves},
{"-use-old-client-cert-callback",
&TestConfig::use_old_client_cert_callback},
{"-send-alert", &TestConfig::send_alert},
{"-peek-then-read", &TestConfig::peek_then_read},
{"-enable-grease", &TestConfig::enable_grease},
+ {"-permute-extensions", &TestConfig::permute_extensions},
{"-use-exporter-between-reads", &TestConfig::use_exporter_between_reads},
{"-retain-only-sha256-client-cert",
&TestConfig::retain_only_sha256_client_cert},
@@ -134,6 +141,8 @@ const Flag<bool> kBoolFlags[] = {
{"-allow-false-start-without-alpn",
&TestConfig::allow_false_start_without_alpn},
{"-handoff", &TestConfig::handoff},
+ {"-handshake-hints", &TestConfig::handshake_hints},
+ {"-allow-hint-mismatch", &TestConfig::allow_hint_mismatch},
{"-use-ocsp-callback", &TestConfig::use_ocsp_callback},
{"-set-ocsp-in-callback", &TestConfig::set_ocsp_in_callback},
{"-decline-ocsp-callback", &TestConfig::decline_ocsp_callback},
@@ -160,6 +169,7 @@ const Flag<std::string> kStringFlags[] = {
{"-key-file", &TestConfig::key_file},
{"-cert-file", &TestConfig::cert_file},
{"-expect-server-name", &TestConfig::expect_server_name},
+ {"-expect-ech-name-override", &TestConfig::expect_ech_name_override},
{"-advertise-npn", &TestConfig::advertise_npn},
{"-expect-next-proto", &TestConfig::expect_next_proto},
{"-select-next-proto", &TestConfig::select_next_proto},
@@ -194,9 +204,10 @@ const Flag<std::unique_ptr<std::string>> kOptionalStringFlags[] = {
};
const Flag<std::string> kBase64Flags[] = {
+ {"-expect-ech-retry-configs", &TestConfig::expect_ech_retry_configs},
+ {"-ech-config-list", &TestConfig::ech_config_list},
{"-expect-certificate-types", &TestConfig::expect_certificate_types},
{"-expect-channel-id", &TestConfig::expect_channel_id},
- {"-token-binding-params", &TestConfig::send_token_binding_params},
{"-expect-ocsp-response", &TestConfig::expect_ocsp_response},
{"-expect-signed-cert-timestamps",
&TestConfig::expect_signed_cert_timestamps},
@@ -211,7 +222,6 @@ const Flag<std::string> kBase64Flags[] = {
const Flag<int> kIntFlags[] = {
{"-port", &TestConfig::port},
{"-resume-count", &TestConfig::resume_count},
- {"-expect-token-binding-param", &TestConfig::expect_token_binding_param},
{"-min-version", &TestConfig::min_version},
{"-max-version", &TestConfig::max_version},
{"-expect-version", &TestConfig::expect_version},
@@ -231,6 +241,9 @@ const Flag<int> kIntFlags[] = {
{"-read-size", &TestConfig::read_size},
{"-expect-ticket-age-skew", &TestConfig::expect_ticket_age_skew},
{"-quic-use-legacy-codepoint", &TestConfig::quic_use_legacy_codepoint},
+ {"-install-one-cert-compression-alg",
+ &TestConfig::install_one_cert_compression_alg},
+ {"-early-write-after-message", &TestConfig::early_write_after_message},
};
const Flag<std::vector<int>> kIntVectorFlags[] = {
@@ -238,6 +251,12 @@ const Flag<std::vector<int>> kIntVectorFlags[] = {
{"-verify-prefs", &TestConfig::verify_prefs},
{"-expect-peer-verify-pref", &TestConfig::expect_peer_verify_prefs},
{"-curves", &TestConfig::curves},
+ {"-ech-is-retry-config", &TestConfig::ech_is_retry_config},
+};
+
+const Flag<std::vector<std::string>> kBase64VectorFlags[] = {
+ {"-ech-server-config", &TestConfig::ech_server_configs},
+ {"-ech-server-key", &TestConfig::ech_server_keys},
};
const Flag<std::vector<std::pair<std::string, std::string>>>
@@ -245,7 +264,24 @@ const Flag<std::vector<std::pair<std::string, std::string>>>
{"-application-settings", &TestConfig::application_settings},
};
-bool ParseFlag(char *flag, int argc, char **argv, int *i,
+bool DecodeBase64(std::string *out, const std::string &in) {
+ size_t len;
+ if (!EVP_DecodedLength(&len, in.size())) {
+ fprintf(stderr, "Invalid base64: %s.\n", in.c_str());
+ return false;
+ }
+ std::vector<uint8_t> buf(len);
+ if (!EVP_DecodeBase64(buf.data(), &len, buf.size(),
+ reinterpret_cast<const uint8_t *>(in.data()),
+ in.size())) {
+ fprintf(stderr, "Invalid base64: %s.\n", in.c_str());
+ return false;
+ }
+ out->assign(reinterpret_cast<const char *>(buf.data()), len);
+ return true;
+}
+
+bool ParseFlag(const char *flag, int argc, char **argv, int *i,
bool skip, TestConfig *out_config) {
bool *bool_field = FindField(out_config, kBoolFlags, flag);
if (bool_field != NULL) {
@@ -289,21 +325,12 @@ bool ParseFlag(char *flag, int argc, char **argv, int *i,
fprintf(stderr, "Missing parameter.\n");
return false;
}
- size_t len;
- if (!EVP_DecodedLength(&len, strlen(argv[*i]))) {
- fprintf(stderr, "Invalid base64: %s.\n", argv[*i]);
- return false;
- }
- std::unique_ptr<uint8_t[]> decoded(new uint8_t[len]);
- if (!EVP_DecodeBase64(decoded.get(), &len, len,
- reinterpret_cast<const uint8_t *>(argv[*i]),
- strlen(argv[*i]))) {
- fprintf(stderr, "Invalid base64: %s.\n", argv[*i]);
+ std::string value;
+ if (!DecodeBase64(&value, argv[*i])) {
return false;
}
if (!skip) {
- base64_field->assign(reinterpret_cast<const char *>(decoded.get()),
- len);
+ *base64_field = std::move(value);
}
return true;
}
@@ -337,6 +364,25 @@ bool ParseFlag(char *flag, int argc, char **argv, int *i,
return true;
}
+ std::vector<std::string> *base64_vector_field =
+ FindField(out_config, kBase64VectorFlags, flag);
+ if (base64_vector_field) {
+ *i = *i + 1;
+ if (*i >= argc) {
+ fprintf(stderr, "Missing parameter.\n");
+ return false;
+ }
+ std::string value;
+ if (!DecodeBase64(&value, argv[*i])) {
+ return false;
+ }
+ // Each instance of the flag adds to the list.
+ if (!skip) {
+ base64_vector_field->push_back(std::move(value));
+ }
+ return true;
+ }
+
std::vector<std::pair<std::string, std::string>> *string_pair_vector_field =
FindField(out_config, kStringPairVectorFlags, flag);
if (string_pair_vector_field) {
@@ -347,8 +393,10 @@ bool ParseFlag(char *flag, int argc, char **argv, int *i,
}
const char *comma = strchr(argv[*i], ',');
if (!comma) {
- fprintf(stderr,
- "Parameter should be a pair of comma-separated strings.\n");
+ fprintf(
+ stderr,
+ "Parameter should be a comma-separated triple composed of two base64 "
+ "strings followed by \"true\" or \"false\".\n");
return false;
}
// Each instance of the flag adds to the list.
@@ -363,13 +411,21 @@ bool ParseFlag(char *flag, int argc, char **argv, int *i,
return false;
}
-const char kInit[] = "-on-initial";
-const char kResume[] = "-on-resume";
-const char kRetry[] = "-on-retry";
+// RemovePrefix checks if |*str| begins with |prefix| + "-". If so, it advances
+// |*str| past |prefix| (but not past the "-") and returns true. Otherwise, it
+// returns false and leaves |*str| unmodified.
+bool RemovePrefix(const char **str, const char *prefix) {
+ size_t prefix_len = strlen(prefix);
+ if (strncmp(*str, prefix, strlen(prefix)) == 0 && (*str)[prefix_len] == '-') {
+ *str += strlen(prefix);
+ return true;
+ }
+ return false;
+}
} // namespace
-bool ParseConfig(int argc, char **argv,
+bool ParseConfig(int argc, char **argv, bool is_shim,
TestConfig *out_initial,
TestConfig *out_resume,
TestConfig *out_retry) {
@@ -377,21 +433,36 @@ bool ParseConfig(int argc, char **argv,
out_initial->argv = out_resume->argv = out_retry->argv = argv;
for (int i = 0; i < argc; i++) {
bool skip = false;
- char *flag = argv[i];
- if (strncmp(flag, kInit, strlen(kInit)) == 0) {
- if (!ParseFlag(flag + strlen(kInit), argc, argv, &i, skip, out_initial)) {
+ const char *flag = argv[i];
+
+ // -on-shim and -on-handshaker prefixes enable flags only on the shim or
+ // handshaker.
+ if (RemovePrefix(&flag, "-on-shim")) {
+ if (!is_shim) {
+ skip = true;
+ }
+ } else if (RemovePrefix(&flag, "-on-handshaker")) {
+ if (is_shim) {
+ skip = true;
+ }
+ }
+
+ // The following prefixes allow different configurations for each of the
+ // initial, resumption, and 0-RTT retry handshakes.
+ if (RemovePrefix(&flag, "-on-initial")) {
+ if (!ParseFlag(flag, argc, argv, &i, skip, out_initial)) {
return false;
}
- } else if (strncmp(flag, kResume, strlen(kResume)) == 0) {
- if (!ParseFlag(flag + strlen(kResume), argc, argv, &i, skip,
- out_resume)) {
+ } else if (RemovePrefix(&flag, "-on-resume")) {
+ if (!ParseFlag(flag, argc, argv, &i, skip, out_resume)) {
return false;
}
- } else if (strncmp(flag, kRetry, strlen(kRetry)) == 0) {
- if (!ParseFlag(flag + strlen(kRetry), argc, argv, &i, skip, out_retry)) {
+ } else if (RemovePrefix(&flag, "-on-retry")) {
+ if (!ParseFlag(flag, argc, argv, &i, skip, out_retry)) {
return false;
}
} else {
+ // Unprefixed flags apply to all three.
int i_init = i;
int i_resume = i;
if (!ParseFlag(flag, argc, argv, &i_init, skip, out_initial) ||
@@ -537,6 +608,9 @@ static void MessageCallback(int is_write, int version, int content_type,
char text[16];
snprintf(text, sizeof(text), "hs %d\n", type);
state->msg_callback_text += text;
+ if (!is_write) {
+ state->last_message_received = type;
+ }
return;
}
@@ -628,17 +702,9 @@ static void InfoCallback(const SSL *ssl, int type, int val) {
abort();
}
GetTestState(ssl)->handshake_done = true;
-
- // Callbacks may be called again on a new handshake.
- GetTestState(ssl)->ticket_decrypt_done = false;
- GetTestState(ssl)->alpn_select_done = false;
}
}
-static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) {
- *out_pkey = GetTestState(ssl)->channel_id.release();
-}
-
static SSL_SESSION *GetSessionCallback(SSL *ssl, const uint8_t *data, int len,
int *copy) {
TestState *async_state = GetTestState(ssl);
@@ -669,6 +735,9 @@ static int AlpnSelectCallback(SSL *ssl, const uint8_t **out, uint8_t *outlen,
if (config->decline_alpn) {
return SSL_TLSEXT_ERR_NOACK;
}
+ if (config->reject_alpn) {
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
if (!config->expect_advertised_alpn.empty() &&
(config->expect_advertised_alpn.size() != inlen ||
@@ -709,6 +778,20 @@ static bool CheckVerifyCallback(SSL *ssl) {
}
}
+ const char *name_override;
+ size_t name_override_len;
+ SSL_get0_ech_name_override(ssl, &name_override, &name_override_len);
+ if (config->expect_no_ech_name_override && name_override_len != 0) {
+ fprintf(stderr, "Unexpected ECH name override.\n");
+ return false;
+ }
+ if (!config->expect_ech_name_override.empty() &&
+ config->expect_ech_name_override !=
+ std::string(name_override, name_override_len)) {
+ fprintf(stderr, "ECH name did not match expected value.\n");
+ return false;
+ }
+
if (GetTestState(ssl)->cert_verified) {
fprintf(stderr, "Certificate verified twice.\n");
return false;
@@ -727,7 +810,7 @@ static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) {
GetTestState(ssl)->cert_verified = true;
if (config->verify_fail) {
- store_ctx->error = X509_V_ERR_APPLICATION_VERIFICATION;
+ X509_STORE_CTX_set_error(store_ctx, X509_V_ERR_APPLICATION_VERIFICATION);
return 0;
}
@@ -1018,10 +1101,15 @@ static int ClientCertCallback(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) {
return 1;
}
+static ssl_private_key_result_t AsyncPrivateKeyComplete(SSL *ssl, uint8_t *out,
+ size_t *out_len,
+ size_t max_out);
+
static ssl_private_key_result_t AsyncPrivateKeySign(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
uint16_t signature_algorithm, const uint8_t *in, size_t in_len) {
TestState *test_state = GetTestState(ssl);
+ test_state->used_private_key = true;
if (!test_state->private_key_result.empty()) {
fprintf(stderr, "AsyncPrivateKeySign called with operation pending.\n");
abort();
@@ -1062,8 +1150,7 @@ static ssl_private_key_result_t AsyncPrivateKeySign(
}
test_state->private_key_result.resize(len);
- // The signature will be released asynchronously in |AsyncPrivateKeyComplete|.
- return ssl_private_key_retry;
+ return AsyncPrivateKeyComplete(ssl, out, out_len, max_out);
}
static ssl_private_key_result_t AsyncPrivateKeyDecrypt(SSL *ssl, uint8_t *out,
@@ -1072,6 +1159,7 @@ static ssl_private_key_result_t AsyncPrivateKeyDecrypt(SSL *ssl, uint8_t *out,
const uint8_t *in,
size_t in_len) {
TestState *test_state = GetTestState(ssl);
+ test_state->used_private_key = true;
if (!test_state->private_key_result.empty()) {
fprintf(stderr, "AsyncPrivateKeyDecrypt called with operation pending.\n");
abort();
@@ -1090,8 +1178,7 @@ static ssl_private_key_result_t AsyncPrivateKeyDecrypt(SSL *ssl, uint8_t *out,
test_state->private_key_result.resize(*out_len);
- // The decryption will be released asynchronously in |AsyncPrivateComplete|.
- return ssl_private_key_retry;
+ return AsyncPrivateKeyComplete(ssl, out, out_len, max_out);
}
static ssl_private_key_result_t AsyncPrivateKeyComplete(SSL *ssl, uint8_t *out,
@@ -1104,9 +1191,9 @@ static ssl_private_key_result_t AsyncPrivateKeyComplete(SSL *ssl, uint8_t *out,
abort();
}
- if (test_state->private_key_retries < 2) {
+ if (GetTestConfig(ssl)->async && test_state->private_key_retries < 2) {
// Only return the decryption on the second attempt, to test both incomplete
- // |decrypt| and |decrypt_complete|.
+ // |sign|/|decrypt| and |complete|.
return ssl_private_key_retry;
}
@@ -1140,7 +1227,10 @@ static bool InstallCertificate(SSL *ssl) {
if (pkey) {
TestState *test_state = GetTestState(ssl);
const TestConfig *config = GetTestConfig(ssl);
- if (config->async) {
+ if (config->async || config->handshake_hints) {
+ // Install a custom private key if testing asynchronous callbacks, or if
+ // testing handshake hints. In the handshake hints case, we wish to check
+ // that hints only mismatch when allowed.
test_state->private_key = std::move(pkey);
SSL_set_private_key_method(ssl, &g_async_private_key_method);
} else if (!SSL_use_PrivateKey(ssl, pkey.get())) {
@@ -1161,12 +1251,14 @@ static bool InstallCertificate(SSL *ssl) {
static enum ssl_select_cert_result_t SelectCertificateCallback(
const SSL_CLIENT_HELLO *client_hello) {
- const TestConfig *config = GetTestConfig(client_hello->ssl);
- GetTestState(client_hello->ssl)->early_callback_called = true;
+ SSL *ssl = client_hello->ssl;
+ const TestConfig *config = GetTestConfig(ssl);
+ TestState *test_state = GetTestState(ssl);
+ test_state->early_callback_called = true;
if (!config->expect_server_name.empty()) {
const char *server_name =
- SSL_get_servername(client_hello->ssl, TLSEXT_NAMETYPE_host_name);
+ SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (server_name == nullptr ||
std::string(server_name) != config->expect_server_name) {
fprintf(stderr,
@@ -1180,48 +1272,73 @@ static enum ssl_select_cert_result_t SelectCertificateCallback(
return ssl_select_cert_error;
}
- // Install the certificate in the early callback.
- if (config->use_early_callback) {
- bool early_callback_ready =
- GetTestState(client_hello->ssl)->early_callback_ready;
- if (config->async && !early_callback_ready) {
- // Install the certificate asynchronously.
- return ssl_select_cert_retry;
- }
- if (!InstallCertificate(client_hello->ssl)) {
- return ssl_select_cert_error;
- }
+ // Simulate some asynchronous work in the early callback.
+ if ((config->use_early_callback || test_state->get_handshake_hints_cb) &&
+ config->async && !test_state->early_callback_ready) {
+ return ssl_select_cert_retry;
+ }
+
+ if (test_state->get_handshake_hints_cb &&
+ !test_state->get_handshake_hints_cb(client_hello)) {
+ return ssl_select_cert_error;
+ }
+
+ if (config->use_early_callback && !InstallCertificate(ssl)) {
+ return ssl_select_cert_error;
}
+
return ssl_select_cert_success;
}
static int SetQuicReadSecret(SSL *ssl, enum ssl_encryption_level_t level,
const SSL_CIPHER *cipher, const uint8_t *secret,
size_t secret_len) {
- return GetTestState(ssl)->quic_transport->SetReadSecret(level, cipher, secret,
- secret_len);
+ MockQuicTransport *quic_transport = GetTestState(ssl)->quic_transport.get();
+ if (quic_transport == nullptr) {
+ fprintf(stderr, "No QUIC transport.\n");
+ return 0;
+ }
+ return quic_transport->SetReadSecret(level, cipher, secret, secret_len);
}
static int SetQuicWriteSecret(SSL *ssl, enum ssl_encryption_level_t level,
const SSL_CIPHER *cipher, const uint8_t *secret,
size_t secret_len) {
- return GetTestState(ssl)->quic_transport->SetWriteSecret(level, cipher,
- secret, secret_len);
+ MockQuicTransport *quic_transport = GetTestState(ssl)->quic_transport.get();
+ if (quic_transport == nullptr) {
+ fprintf(stderr, "No QUIC transport.\n");
+ return 0;
+ }
+ return quic_transport->SetWriteSecret(level, cipher, secret, secret_len);
}
static int AddQuicHandshakeData(SSL *ssl, enum ssl_encryption_level_t level,
const uint8_t *data, size_t len) {
- return GetTestState(ssl)->quic_transport->WriteHandshakeData(level, data,
- len);
+ MockQuicTransport *quic_transport = GetTestState(ssl)->quic_transport.get();
+ if (quic_transport == nullptr) {
+ fprintf(stderr, "No QUIC transport.\n");
+ return 0;
+ }
+ return quic_transport->WriteHandshakeData(level, data, len);
}
static int FlushQuicFlight(SSL *ssl) {
- return GetTestState(ssl)->quic_transport->Flush();
+ MockQuicTransport *quic_transport = GetTestState(ssl)->quic_transport.get();
+ if (quic_transport == nullptr) {
+ fprintf(stderr, "No QUIC transport.\n");
+ return 0;
+ }
+ return quic_transport->Flush();
}
static int SendQuicAlert(SSL *ssl, enum ssl_encryption_level_t level,
uint8_t alert) {
- return GetTestState(ssl)->quic_transport->SendAlert(level, alert);
+ MockQuicTransport *quic_transport = GetTestState(ssl)->quic_transport.get();
+ if (quic_transport == nullptr) {
+ fprintf(stderr, "No QUIC transport.\n");
+ return 0;
+ }
+ return quic_transport->SendAlert(level, alert);
}
static const SSL_QUIC_METHOD g_quic_method = {
@@ -1232,6 +1349,17 @@ static const SSL_QUIC_METHOD g_quic_method = {
SendQuicAlert,
};
+static bool MaybeInstallCertCompressionAlg(
+ const TestConfig *config, SSL_CTX *ssl_ctx, uint16_t alg,
+ ssl_cert_compression_func_t compress,
+ ssl_cert_decompression_func_t decompress) {
+ if (!config->install_cert_compression_algs &&
+ config->install_one_cert_compression_alg != alg) {
+ return true;
+ }
+ return SSL_CTX_add_cert_compression_alg(ssl_ctx, alg, compress, decompress);
+}
+
bssl::UniquePtr<SSL_CTX> TestConfig::SetupCtx(SSL_CTX *old_ctx) const {
bssl::UniquePtr<SSL_CTX> ssl_ctx(
SSL_CTX_new(is_dtls ? DTLS_method() : TLS_method()));
@@ -1274,18 +1402,20 @@ bssl::UniquePtr<SSL_CTX> TestConfig::SetupCtx(SSL_CTX *old_ctx) const {
NULL);
}
- if (!select_alpn.empty() || decline_alpn || select_empty_alpn) {
+ if (!select_alpn.empty() || decline_alpn || reject_alpn ||
+ select_empty_alpn) {
SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL);
}
- SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback);
-
SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback);
SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
- if (use_ticket_callback) {
+ if (use_ticket_callback || handshake_hints) {
+ // If using handshake hints, always enable the ticket callback, so we can
+ // check that hints only mismatch when allowed. The ticket callback also
+ // uses a constant key, which simplifies the test.
SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx.get(), TicketKeyCallback);
}
@@ -1317,6 +1447,10 @@ bssl::UniquePtr<SSL_CTX> TestConfig::SetupCtx(SSL_CTX *old_ctx) const {
SSL_CTX_set_grease_enabled(ssl_ctx.get(), 1);
}
+ if (permute_extensions) {
+ SSL_CTX_set_permute_extensions(ssl_ctx.get(), 1);
+ }
+
if (!expect_server_name.empty()) {
SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(), ServerNameCallback);
}
@@ -1360,48 +1494,65 @@ bssl::UniquePtr<SSL_CTX> TestConfig::SetupCtx(SSL_CTX *old_ctx) const {
return nullptr;
}
- if (install_cert_compression_algs &&
- (!SSL_CTX_add_cert_compression_alg(
- ssl_ctx.get(), 0xff02,
- [](SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) -> int {
- if (!CBB_add_u8(out, 1) || !CBB_add_u8(out, 2) ||
- !CBB_add_u8(out, 3) || !CBB_add_u8(out, 4) ||
- !CBB_add_bytes(out, in, in_len)) {
- return 0;
- }
- return 1;
- },
- [](SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len,
- const uint8_t *in, size_t in_len) -> int {
- if (in_len < 4 || in[0] != 1 || in[1] != 2 || in[2] != 3 ||
- in[3] != 4 || uncompressed_len != in_len - 4) {
- return 0;
- }
- const bssl::Span<const uint8_t> uncompressed(in + 4, in_len - 4);
- *out = CRYPTO_BUFFER_new(uncompressed.data(), uncompressed.size(),
- nullptr);
- return 1;
- }) ||
- !SSL_CTX_add_cert_compression_alg(
- ssl_ctx.get(), 0xff01,
- [](SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) -> int {
- if (in_len < 2 || in[0] != 0 || in[1] != 0) {
- return 0;
- }
- return CBB_add_bytes(out, in + 2, in_len - 2);
- },
- [](SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len,
- const uint8_t *in, size_t in_len) -> int {
- if (uncompressed_len != 2 + in_len) {
- return 0;
- }
- std::unique_ptr<uint8_t[]> buf(new uint8_t[2 + in_len]);
- buf[0] = 0;
- buf[1] = 0;
- OPENSSL_memcpy(&buf[2], in, in_len);
- *out = CRYPTO_BUFFER_new(buf.get(), 2 + in_len, nullptr);
- return 1;
- }))) {
+ // These mock compression algorithms match the corresponding ones in
+ // |addCertCompressionTests|.
+ if (!MaybeInstallCertCompressionAlg(
+ this, ssl_ctx.get(), 0xff02,
+ [](SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) -> int {
+ if (!CBB_add_u8(out, 1) || !CBB_add_u8(out, 2) ||
+ !CBB_add_u8(out, 3) || !CBB_add_u8(out, 4) ||
+ !CBB_add_bytes(out, in, in_len)) {
+ return 0;
+ }
+ return 1;
+ },
+ [](SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len,
+ const uint8_t *in, size_t in_len) -> int {
+ if (in_len < 4 || in[0] != 1 || in[1] != 2 || in[2] != 3 ||
+ in[3] != 4 || uncompressed_len != in_len - 4) {
+ return 0;
+ }
+ const bssl::Span<const uint8_t> uncompressed(in + 4, in_len - 4);
+ *out = CRYPTO_BUFFER_new(uncompressed.data(), uncompressed.size(),
+ nullptr);
+ return *out != nullptr;
+ }) ||
+ !MaybeInstallCertCompressionAlg(
+ this, ssl_ctx.get(), 0xff01,
+ [](SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) -> int {
+ if (in_len < 2 || in[0] != 0 || in[1] != 0) {
+ return 0;
+ }
+ return CBB_add_bytes(out, in + 2, in_len - 2);
+ },
+ [](SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len,
+ const uint8_t *in, size_t in_len) -> int {
+ if (uncompressed_len != 2 + in_len) {
+ return 0;
+ }
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[2 + in_len]);
+ buf[0] = 0;
+ buf[1] = 0;
+ OPENSSL_memcpy(&buf[2], in, in_len);
+ *out = CRYPTO_BUFFER_new(buf.get(), 2 + in_len, nullptr);
+ return *out != nullptr;
+ }) ||
+ !MaybeInstallCertCompressionAlg(
+ this, ssl_ctx.get(), 0xff03,
+ [](SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) -> int {
+ uint8_t byte;
+ return RAND_bytes(&byte, 1) && //
+ CBB_add_u8(out, byte) && //
+ CBB_add_bytes(out, in, in_len);
+ },
+ [](SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len,
+ const uint8_t *in, size_t in_len) -> int {
+ if (uncompressed_len + 1 != in_len) {
+ return 0;
+ }
+ *out = CRYPTO_BUFFER_new(in + 1, in_len - 1, nullptr);
+ return *out != nullptr;
+ })) {
fprintf(stderr, "SSL_CTX_add_cert_compression_alg failed.\n");
abort();
}
@@ -1514,7 +1665,7 @@ static int CertCallback(SSL *ssl, void *arg) {
}
bssl::UniquePtr<SSL> TestConfig::NewSSL(
- SSL_CTX *ssl_ctx, SSL_SESSION *session, bool is_resume,
+ SSL_CTX *ssl_ctx, SSL_SESSION *session,
std::unique_ptr<TestState> test_state) const {
bssl::UniquePtr<SSL> ssl(SSL_new(ssl_ctx));
if (!ssl) {
@@ -1528,7 +1679,6 @@ bssl::UniquePtr<SSL> TestConfig::NewSSL(
if (!SetTestState(ssl.get(), std::move(test_state))) {
return nullptr;
}
- GetTestState(ssl.get())->is_resume = is_resume;
}
if (fallback_scsv && !SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) {
@@ -1596,21 +1746,49 @@ bssl::UniquePtr<SSL> TestConfig::NewSSL(
if (enable_ech_grease) {
SSL_set_enable_ech_grease(ssl.get(), 1);
}
- if (!send_channel_id.empty()) {
- SSL_set_tls_channel_id_enabled(ssl.get(), 1);
- if (!async) {
- // The async case will be supplied by |ChannelIdCallback|.
- bssl::UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(send_channel_id);
- if (!pkey || !SSL_set1_tls_channel_id(ssl.get(), pkey.get())) {
+ if (!ech_config_list.empty() &&
+ !SSL_set1_ech_config_list(
+ ssl.get(), reinterpret_cast<const uint8_t *>(ech_config_list.data()),
+ ech_config_list.size())) {
+ return nullptr;
+ }
+ if (ech_server_configs.size() != ech_server_keys.size() ||
+ ech_server_configs.size() != ech_is_retry_config.size()) {
+ fprintf(stderr,
+ "-ech-server-config, -ech-server-key, and -ech-is-retry-config "
+ "flags must match.\n");
+ return nullptr;
+ }
+ if (!ech_server_configs.empty()) {
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ if (!keys) {
+ return nullptr;
+ }
+ for (size_t i = 0; i < ech_server_configs.size(); i++) {
+ const std::string &ech_config = ech_server_configs[i];
+ const std::string &ech_private_key = ech_server_keys[i];
+ const int is_retry_config = ech_is_retry_config[i];
+ bssl::ScopedEVP_HPKE_KEY key;
+ if (!EVP_HPKE_KEY_init(
+ key.get(), EVP_hpke_x25519_hkdf_sha256(),
+ reinterpret_cast<const uint8_t *>(ech_private_key.data()),
+ ech_private_key.size()) ||
+ !SSL_ECH_KEYS_add(
+ keys.get(), is_retry_config,
+ reinterpret_cast<const uint8_t *>(ech_config.data()),
+ ech_config.size(), key.get())) {
return nullptr;
}
}
+ if (!SSL_CTX_set1_ech_keys(ssl_ctx, keys.get())) {
+ return nullptr;
+ }
}
- if (!send_token_binding_params.empty()) {
- SSL_set_token_binding_params(
- ssl.get(),
- reinterpret_cast<const uint8_t *>(send_token_binding_params.data()),
- send_token_binding_params.length());
+ if (!send_channel_id.empty()) {
+ bssl::UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(send_channel_id);
+ if (!pkey || !SSL_set1_tls_channel_id(ssl.get(), pkey.get())) {
+ return nullptr;
+ }
}
if (!host_name.empty() &&
!SSL_set_tlsext_host_name(ssl.get(), host_name.c_str())) {
@@ -1716,16 +1894,6 @@ bssl::UniquePtr<SSL> TestConfig::NewSSL(
}
}
}
- if (enable_all_curves) {
- static const int kAllCurves[] = {
- NID_secp224r1, NID_X9_62_prime256v1, NID_secp384r1,
- NID_secp521r1, NID_X25519, NID_CECPQ2,
- };
- if (!SSL_set1_curves(ssl.get(), kAllCurves,
- OPENSSL_ARRAY_SIZE(kAllCurves))) {
- return nullptr;
- }
- }
if (initial_timeout_duration_ms > 0) {
DTLSv1_set_initial_timeout_duration(ssl.get(), initial_timeout_duration_ms);
}
diff --git a/deps/boringssl/src/ssl/test/test_config.h b/deps/boringssl/src/ssl/test/test_config.h
index 7d77994..c9f2a25 100644
--- a/deps/boringssl/src/ssl/test/test_config.h
+++ b/deps/boringssl/src/ssl/test/test_config.h
@@ -40,6 +40,15 @@ struct TestConfig {
std::string cert_file;
std::string expect_server_name;
bool enable_ech_grease = false;
+ std::vector<std::string> ech_server_configs;
+ std::vector<std::string> ech_server_keys;
+ std::vector<int> ech_is_retry_config;
+ bool expect_ech_accept = false;
+ std::string expect_ech_name_override;
+ bool expect_no_ech_name_override = false;
+ std::string expect_ech_retry_configs;
+ bool expect_no_ech_retry_configs = false;
+ std::string ech_config_list;
std::string expect_certificate_types;
bool require_any_client_certificate = false;
std::string advertise_npn;
@@ -58,8 +67,6 @@ struct TestConfig {
std::string expect_channel_id;
bool enable_channel_id = false;
std::string send_channel_id;
- int expect_token_binding_param = -1;
- std::string send_token_binding_params;
bool shim_writes_first = false;
std::string host_name;
std::string advertise_alpn;
@@ -68,6 +75,7 @@ struct TestConfig {
std::string expect_advertised_alpn;
std::string select_alpn;
bool decline_alpn = false;
+ bool reject_alpn = false;
bool select_empty_alpn = false;
bool defer_alps = false;
std::vector<std::pair<std::string, std::string>> application_settings;
@@ -130,7 +138,6 @@ struct TestConfig {
bool renegotiate_explicit = false;
bool forbid_renegotiation_after_handshake = false;
int expect_peer_signature_algorithm = 0;
- bool enable_all_curves = false;
int expect_curve_id = 0;
bool use_old_client_cert_callback = false;
int initial_timeout_duration_ms = 0;
@@ -139,6 +146,7 @@ struct TestConfig {
bool send_alert = false;
bool peek_then_read = false;
bool enable_grease = false;
+ bool permute_extensions = false;
int max_cert_list = 0;
std::string ticket_key;
bool use_exporter_between_reads = false;
@@ -164,11 +172,14 @@ struct TestConfig {
std::string expect_msg_callback;
bool allow_false_start_without_alpn = false;
bool handoff = false;
+ bool handshake_hints = false;
+ bool allow_hint_mismatch = false;
bool use_ocsp_callback = false;
bool set_ocsp_in_callback = false;
bool decline_ocsp_callback = false;
bool fail_ocsp_callback = false;
bool install_cert_compression_algs = false;
+ int install_one_cert_compression_alg = 0;
bool reverify_on_resume = false;
bool enforce_rsa_key_usage = false;
bool is_handshaker_supported = false;
@@ -185,6 +196,7 @@ struct TestConfig {
bool expect_no_hrr = false;
bool wait_for_debugger = false;
std::string quic_early_data_context;
+ int early_write_after_message = 0;
int argc;
char **argv;
@@ -192,11 +204,10 @@ struct TestConfig {
bssl::UniquePtr<SSL_CTX> SetupCtx(SSL_CTX *old_ctx) const;
bssl::UniquePtr<SSL> NewSSL(SSL_CTX *ssl_ctx, SSL_SESSION *session,
- bool is_resume,
std::unique_ptr<TestState> test_state) const;
};
-bool ParseConfig(int argc, char **argv, TestConfig *out_initial,
+bool ParseConfig(int argc, char **argv, bool is_shim, TestConfig *out_initial,
TestConfig *out_resume, TestConfig *out_retry);
bool SetTestConfig(SSL *ssl, const TestConfig *config);
diff --git a/deps/boringssl/src/ssl/test/test_state.h b/deps/boringssl/src/ssl/test/test_state.h
index 745c4c4..4199d4a 100644
--- a/deps/boringssl/src/ssl/test/test_state.h
+++ b/deps/boringssl/src/ssl/test/test_state.h
@@ -17,6 +17,7 @@
#include <openssl/base.h>
+#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -40,7 +41,6 @@ struct TestState {
// packeted_bio is the packeted BIO which simulates read timeouts.
BIO *packeted_bio = nullptr;
std::unique_ptr<MockQuicTransport> quic_transport;
- bssl::UniquePtr<EVP_PKEY> channel_id;
bool cert_ready = false;
bssl::UniquePtr<SSL_SESSION> session;
bssl::UniquePtr<SSL_SESSION> pending_session;
@@ -48,6 +48,8 @@ struct TestState {
bool handshake_done = false;
// private_key is the underlying private key used when testing custom keys.
bssl::UniquePtr<EVP_PKEY> private_key;
+ // When private key methods are used, whether the private key was used.
+ bool used_private_key = false;
std::vector<uint8_t> private_key_result;
// private_key_retries is the number of times an asynchronous private key
// operation has been retried.
@@ -56,7 +58,6 @@ struct TestState {
bssl::UniquePtr<SSL_SESSION> new_session;
bool ticket_decrypt_done = false;
bool alpn_select_done = false;
- bool is_resume = false;
bool early_callback_ready = false;
bool custom_verify_ready = false;
std::string msg_callback_text;
@@ -65,6 +66,8 @@ struct TestState {
// completion. This tests that the callback is not called again after this.
bool cert_verified = false;
int explicit_renegotiates = 0;
+ std::function<bool(const SSL_CLIENT_HELLO*)> get_handshake_hints_cb;
+ int last_message_received = -1;
};
bool SetTestState(SSL *ssl, std::unique_ptr<TestState> state);
diff --git a/deps/boringssl/src/ssl/tls13_both.cc b/deps/boringssl/src/ssl/tls13_both.cc
index c6bc2b1..226c67b 100644
--- a/deps/boringssl/src/ssl/tls13_both.cc
+++ b/deps/boringssl/src/ssl/tls13_both.cc
@@ -235,15 +235,14 @@ bool tls13_process_certificate(SSL_HANDSHAKE *hs, const SSLMessage &msg,
}
// Parse out the extensions.
- bool have_status_request = false, have_sct = false;
- CBS status_request, sct;
- const SSL_EXTENSION_TYPE ext_types[] = {
- {TLSEXT_TYPE_status_request, &have_status_request, &status_request},
- {TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct},
- };
-
+ SSLExtension status_request(
+ TLSEXT_TYPE_status_request,
+ !ssl->server && hs->config->ocsp_stapling_enabled);
+ SSLExtension sct(
+ TLSEXT_TYPE_certificate_timestamp,
+ !ssl->server && hs->config->signed_cert_timestamps_enabled);
uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ if (!ssl_parse_extensions(&extensions, &alert, {&status_request, &sct},
/*ignore_unknown=*/false)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return false;
@@ -251,20 +250,14 @@ bool tls13_process_certificate(SSL_HANDSHAKE *hs, const SSLMessage &msg,
// All Certificate extensions are parsed, but only the leaf extensions are
// stored.
- if (have_status_request) {
- if (ssl->server || !hs->config->ocsp_stapling_enabled) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return false;
- }
-
+ if (status_request.present) {
uint8_t status_type;
CBS ocsp_response;
- if (!CBS_get_u8(&status_request, &status_type) ||
+ if (!CBS_get_u8(&status_request.data, &status_type) ||
status_type != TLSEXT_STATUSTYPE_ocsp ||
- !CBS_get_u24_length_prefixed(&status_request, &ocsp_response) ||
+ !CBS_get_u24_length_prefixed(&status_request.data, &ocsp_response) ||
CBS_len(&ocsp_response) == 0 ||
- CBS_len(&status_request) != 0) {
+ CBS_len(&status_request.data) != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return false;
}
@@ -279,14 +272,8 @@ bool tls13_process_certificate(SSL_HANDSHAKE *hs, const SSLMessage &msg,
}
}
- if (have_sct) {
- if (ssl->server || !hs->config->signed_cert_timestamps_enabled) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return false;
- }
-
- if (!ssl_is_sct_list_valid(&sct)) {
+ if (sct.present) {
+ if (!ssl_is_sct_list_valid(&sct.data)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return false;
@@ -294,7 +281,7 @@ bool tls13_process_certificate(SSL_HANDSHAKE *hs, const SSLMessage &msg,
if (sk_CRYPTO_BUFFER_num(certs.get()) == 1) {
hs->new_session->signed_cert_timestamp_list.reset(
- CRYPTO_BUFFER_new_from_CBS(&sct, ssl->ctx->pool));
+ CRYPTO_BUFFER_new_from_CBS(&sct.data, ssl->ctx->pool));
if (hs->new_session->signed_cert_timestamp_list == nullptr) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return false;
@@ -534,9 +521,37 @@ bool tls13_add_certificate(SSL_HANDSHAKE *hs) {
SSL3_MT_COMPRESSED_CERTIFICATE) ||
!CBB_add_u16(body, hs->cert_compression_alg_id) ||
!CBB_add_u24(body, msg.size()) ||
- !CBB_add_u24_length_prefixed(body, &compressed) ||
- !alg->compress(ssl, &compressed, msg.data(), msg.size()) ||
- !ssl_add_message_cbb(ssl, cbb.get())) {
+ !CBB_add_u24_length_prefixed(body, &compressed)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
+ if (hints && !hs->hints_requested &&
+ hints->cert_compression_alg_id == hs->cert_compression_alg_id &&
+ hints->cert_compression_input == MakeConstSpan(msg) &&
+ !hints->cert_compression_output.empty()) {
+ if (!CBB_add_bytes(&compressed, hints->cert_compression_output.data(),
+ hints->cert_compression_output.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+ } else {
+ if (!alg->compress(ssl, &compressed, msg.data(), msg.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+ if (hints && hs->hints_requested) {
+ hints->cert_compression_alg_id = hs->cert_compression_alg_id;
+ if (!hints->cert_compression_input.CopyFrom(msg) ||
+ !hints->cert_compression_output.CopyFrom(
+ MakeConstSpan(CBB_data(&compressed), CBB_len(&compressed)))) {
+ return false;
+ }
+ }
+ }
+
+ if (!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
@@ -580,10 +595,40 @@ enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs) {
return ssl_private_key_failure;
}
- enum ssl_private_key_result_t sign_result = ssl_private_key_sign(
- hs, sig, &sig_len, max_sig_len, signature_algorithm, msg);
- if (sign_result != ssl_private_key_success) {
- return sign_result;
+ SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
+ Array<uint8_t> spki;
+ if (hints) {
+ ScopedCBB spki_cbb;
+ if (!CBB_init(spki_cbb.get(), 64) ||
+ !EVP_marshal_public_key(spki_cbb.get(), hs->local_pubkey.get()) ||
+ !CBBFinishArray(spki_cbb.get(), &spki)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_private_key_failure;
+ }
+ }
+
+ if (hints && !hs->hints_requested &&
+ signature_algorithm == hints->signature_algorithm &&
+ MakeConstSpan(msg) == hints->signature_input &&
+ MakeConstSpan(spki) == hints->signature_spki &&
+ !hints->signature.empty() && hints->signature.size() <= max_sig_len) {
+ // Signature algorithm and input both match. Reuse the signature from hints.
+ sig_len = hints->signature.size();
+ OPENSSL_memcpy(sig, hints->signature.data(), sig_len);
+ } else {
+ enum ssl_private_key_result_t sign_result = ssl_private_key_sign(
+ hs, sig, &sig_len, max_sig_len, signature_algorithm, msg);
+ if (sign_result != ssl_private_key_success) {
+ return sign_result;
+ }
+ if (hints && hs->hints_requested) {
+ hints->signature_algorithm = signature_algorithm;
+ hints->signature_input = std::move(msg);
+ hints->signature_spki = std::move(spki);
+ if (!hints->signature.CopyFrom(MakeSpan(sig, sig_len))) {
+ return ssl_private_key_failure;
+ }
+ }
}
if (!CBB_did_write(&child, sig_len) ||
diff --git a/deps/boringssl/src/ssl/tls13_client.cc b/deps/boringssl/src/ssl/tls13_client.cc
index 496ae01..af2120c 100644
--- a/deps/boringssl/src/ssl/tls13_client.cc
+++ b/deps/boringssl/src/ssl/tls13_client.cc
@@ -101,6 +101,73 @@ static bool close_early_data(SSL_HANDSHAKE *hs, ssl_encryption_level_t level) {
return true;
}
+static bool parse_server_hello_tls13(const SSL_HANDSHAKE *hs,
+ ParsedServerHello *out, uint8_t *out_alert,
+ const SSLMessage &msg) {
+ if (!ssl_parse_server_hello(out, out_alert, msg)) {
+ return false;
+ }
+ // The RFC8446 version of the structure fixes some legacy values.
+ // Additionally, the session ID must echo the original one.
+ if (out->legacy_version != TLS1_2_VERSION ||
+ out->compression_method != 0 ||
+ !CBS_mem_equal(&out->session_id, hs->session_id, hs->session_id_len) ||
+ CBS_len(&out->extensions) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return false;
+ }
+ return true;
+}
+
+static bool is_hello_retry_request(const ParsedServerHello &server_hello) {
+ return Span<const uint8_t>(server_hello.random) == kHelloRetryRequest;
+}
+
+static bool check_ech_confirmation(const SSL_HANDSHAKE *hs, bool *out_accepted,
+ uint8_t *out_alert,
+ const ParsedServerHello &server_hello) {
+ const bool is_hrr = is_hello_retry_request(server_hello);
+ size_t offset;
+ if (is_hrr) {
+ // We check for an unsolicited extension when parsing all of them.
+ SSLExtension ech(TLSEXT_TYPE_encrypted_client_hello);
+ if (!ssl_parse_extensions(&server_hello.extensions, out_alert, {&ech},
+ /*ignore_unknown=*/true)) {
+ return false;
+ }
+ if (!ech.present) {
+ *out_accepted = false;
+ return true;
+ }
+ if (CBS_len(&ech.data) != ECH_CONFIRMATION_SIGNAL_LEN) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return false;
+ }
+ offset = CBS_data(&ech.data) - CBS_data(&server_hello.raw);
+ } else {
+ offset = ssl_ech_confirmation_signal_hello_offset(hs->ssl);
+ }
+
+ if (!hs->selected_ech_config) {
+ *out_accepted = false;
+ return true;
+ }
+
+ uint8_t expected[ECH_CONFIRMATION_SIGNAL_LEN];
+ if (!ssl_ech_accept_confirmation(hs, expected, hs->inner_client_random,
+ hs->inner_transcript, is_hrr,
+ server_hello.raw, offset)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return false;
+ }
+
+ *out_accepted = CRYPTO_memcmp(CBS_data(&server_hello.raw) + offset, expected,
+ sizeof(expected)) == 0;
+ return true;
+}
+
static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
assert(ssl->s3->have_version);
@@ -117,36 +184,17 @@ static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- if (!ssl_check_message_type(ssl, msg, SSL3_MT_SERVER_HELLO)) {
- return ssl_hs_error;
- }
-
- CBS body = msg.body, extensions, server_random, session_id;
- uint16_t server_version, cipher_suite;
- uint8_t compression_method;
- if (!CBS_get_u16(&body, &server_version) ||
- !CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) ||
- !CBS_get_u8_length_prefixed(&body, &session_id) ||
- !CBS_mem_equal(&session_id, hs->session_id, hs->session_id_len) ||
- !CBS_get_u16(&body, &cipher_suite) ||
- !CBS_get_u8(&body, &compression_method) ||
- compression_method != 0 ||
- !CBS_get_u16_length_prefixed(&body, &extensions) ||
- CBS_len(&extensions) == 0 ||
- CBS_len(&body) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ ParsedServerHello server_hello;
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!parse_server_hello_tls13(hs, &server_hello, &alert, msg)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
- if (!CBS_mem_equal(&server_random, kHelloRetryRequest, SSL3_RANDOM_SIZE)) {
- hs->tls13_state = state_read_server_hello;
- return ssl_hs_ok;
- }
-
- const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
- // Check if the cipher is a TLS 1.3 cipher.
- if (cipher == NULL ||
+ // The cipher suite must be one we offered. We currently offer all supported
+ // TLS 1.3 ciphers, so check the version.
+ const SSL_CIPHER *cipher = SSL_get_cipher_by_value(server_hello.cipher_suite);
+ if (cipher == nullptr ||
SSL_CIPHER_get_min_version(cipher) > ssl_protocol_version(ssl) ||
SSL_CIPHER_get_max_version(cipher) < ssl_protocol_version(ssl)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
@@ -156,38 +204,60 @@ static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) {
hs->new_cipher = cipher;
+ const bool is_hrr = is_hello_retry_request(server_hello);
if (!hs->transcript.InitHash(ssl_protocol_version(ssl), hs->new_cipher) ||
- !hs->transcript.UpdateForHelloRetryRequest()) {
+ (is_hrr && !hs->transcript.UpdateForHelloRetryRequest())) {
return ssl_hs_error;
}
+ if (hs->selected_ech_config) {
+ if (!hs->inner_transcript.InitHash(ssl_protocol_version(ssl),
+ hs->new_cipher) ||
+ (is_hrr && !hs->inner_transcript.UpdateForHelloRetryRequest())) {
+ return ssl_hs_error;
+ }
+ }
+ // Determine which ClientHello the server is responding to. Run
+ // |check_ech_confirmation| unconditionally, so we validate the extension
+ // contents.
+ bool ech_accepted;
+ if (!check_ech_confirmation(hs, &ech_accepted, &alert, server_hello)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+ if (hs->selected_ech_config) {
+ ssl->s3->ech_status = ech_accepted ? ssl_ech_accepted : ssl_ech_rejected;
+ }
- bool have_cookie, have_key_share, have_supported_versions;
- CBS cookie, key_share, supported_versions;
- SSL_EXTENSION_TYPE ext_types[] = {
- {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
- {TLSEXT_TYPE_cookie, &have_cookie, &cookie},
- {TLSEXT_TYPE_supported_versions, &have_supported_versions,
- &supported_versions},
- };
+ if (!is_hrr) {
+ hs->tls13_state = state_read_server_hello;
+ return ssl_hs_ok;
+ }
- uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!ssl_parse_extensions(&extensions, &alert, ext_types,
- /*ignore_unknown=*/false)) {
+ // The ECH extension, if present, was already parsed by
+ // |check_ech_confirmation|.
+ SSLExtension cookie(TLSEXT_TYPE_cookie), key_share(TLSEXT_TYPE_key_share),
+ supported_versions(TLSEXT_TYPE_supported_versions),
+ ech_unused(TLSEXT_TYPE_encrypted_client_hello,
+ hs->selected_ech_config || hs->config->ech_grease_enabled);
+ if (!ssl_parse_extensions(
+ &server_hello.extensions, &alert,
+ {&cookie, &key_share, &supported_versions, &ech_unused},
+ /*ignore_unknown=*/false)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
- if (!have_cookie && !have_key_share) {
+ if (!cookie.present && !key_share.present) {
OPENSSL_PUT_ERROR(SSL, SSL_R_EMPTY_HELLO_RETRY_REQUEST);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
- if (have_cookie) {
+ if (cookie.present) {
CBS cookie_value;
- if (!CBS_get_u16_length_prefixed(&cookie, &cookie_value) ||
+ if (!CBS_get_u16_length_prefixed(&cookie.data, &cookie_value) ||
CBS_len(&cookie_value) == 0 ||
- CBS_len(&cookie) != 0) {
+ CBS_len(&cookie.data) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
@@ -198,9 +268,10 @@ static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) {
}
}
- if (have_key_share) {
+ if (key_share.present) {
uint16_t group_id;
- if (!CBS_get_u16(&key_share, &group_id) || CBS_len(&key_share) != 0) {
+ if (!CBS_get_u16(&key_share.data, &group_id) ||
+ CBS_len(&key_share.data) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
@@ -222,14 +293,22 @@ static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- hs->key_shares[0].reset();
- hs->key_shares[1].reset();
- hs->retry_group = group_id;
+ if (!ssl_setup_key_shares(hs, group_id)) {
+ return ssl_hs_error;
+ }
}
+ // Although we now know whether ClientHelloInner was used, we currently
+ // maintain both transcripts up to ServerHello. We could swap transcripts
+ // early, but then ClientHello construction and |check_ech_confirmation|
+ // become more complex.
if (!ssl_hash_message(hs, msg)) {
return ssl_hs_error;
}
+ if (ssl->s3->ech_status == ssl_ech_accepted &&
+ !hs->inner_transcript.Update(msg.raw)) {
+ return ssl_hs_error;
+ }
// HelloRetryRequest should be the end of the flight.
if (ssl->method->has_unprocessed_handshake_data(ssl)) {
@@ -256,10 +335,18 @@ static enum ssl_hs_wait_t do_send_second_client_hello(SSL_HANDSHAKE *hs) {
// Any 0-RTT keys must have been discarded.
assert(hs->ssl->s3->write_level == ssl_encryption_initial);
- if (!ssl_write_client_hello(hs)) {
+ // Build the second ClientHelloInner, if applicable. The second ClientHello
+ // uses an empty string for |enc|.
+ if (hs->ssl->s3->ech_status == ssl_ech_accepted &&
+ !ssl_encrypt_client_hello(hs, {})) {
+ return ssl_hs_error;
+ }
+
+ if (!ssl_add_client_hello(hs)) {
return ssl_hs_error;
}
+ ssl_done_writing_client_hello(hs);
hs->tls13_state = state_read_server_hello;
return ssl_hs_flush;
}
@@ -270,83 +357,70 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
if (!ssl->method->get_message(ssl, &msg)) {
return ssl_hs_read_message;
}
- if (!ssl_check_message_type(ssl, msg, SSL3_MT_SERVER_HELLO)) {
- return ssl_hs_error;
- }
-
- CBS body = msg.body, server_random, session_id, extensions;
- uint16_t server_version;
- uint16_t cipher_suite;
- uint8_t compression_method;
- if (!CBS_get_u16(&body, &server_version) ||
- !CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) ||
- !CBS_get_u8_length_prefixed(&body, &session_id) ||
- !CBS_mem_equal(&session_id, hs->session_id, hs->session_id_len) ||
- !CBS_get_u16(&body, &cipher_suite) ||
- !CBS_get_u8(&body, &compression_method) ||
- compression_method != 0 ||
- !CBS_get_u16_length_prefixed(&body, &extensions) ||
- CBS_len(&body) != 0) {
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- return ssl_hs_error;
- }
-
- if (server_version != TLS1_2_VERSION) {
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
+ ParsedServerHello server_hello;
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!parse_server_hello_tls13(hs, &server_hello, &alert, msg)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
// Forbid a second HelloRetryRequest.
- if (CBS_mem_equal(&server_random, kHelloRetryRequest, SSL3_RANDOM_SIZE)) {
+ if (is_hello_retry_request(server_hello)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
return ssl_hs_error;
}
- OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random),
- SSL3_RANDOM_SIZE);
-
- // Check if the cipher is a TLS 1.3 cipher.
- const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
- if (cipher == nullptr ||
- SSL_CIPHER_get_min_version(cipher) > ssl_protocol_version(ssl) ||
- SSL_CIPHER_get_max_version(cipher) < ssl_protocol_version(ssl)) {
+ // Check the cipher suite, in case this is after HelloRetryRequest.
+ if (SSL_CIPHER_get_value(hs->new_cipher) != server_hello.cipher_suite) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
- // Check that the cipher matches the one in the HelloRetryRequest.
- if (ssl->s3->used_hello_retry_request && hs->new_cipher != cipher) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
+ if (ssl->s3->ech_status == ssl_ech_accepted) {
+ if (ssl->s3->used_hello_retry_request) {
+ // HelloRetryRequest and ServerHello must accept ECH consistently.
+ bool ech_accepted;
+ if (!check_ech_confirmation(hs, &ech_accepted, &alert, server_hello)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+ if (!ech_accepted) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INCONSISTENT_ECH_NEGOTIATION);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_hs_error;
+ }
+ }
+
+ hs->transcript = std::move(hs->inner_transcript);
+ hs->extensions.sent = hs->inner_extensions_sent;
+ // Report the inner random value through |SSL_get_client_random|.
+ OPENSSL_memcpy(ssl->s3->client_random, hs->inner_client_random,
+ SSL3_RANDOM_SIZE);
}
- // Parse out the extensions.
- bool have_key_share = false, have_pre_shared_key = false,
- have_supported_versions = false;
- CBS key_share, pre_shared_key, supported_versions;
- SSL_EXTENSION_TYPE ext_types[] = {
- {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
- {TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
- {TLSEXT_TYPE_supported_versions, &have_supported_versions,
- &supported_versions},
- };
+ OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_hello.random),
+ SSL3_RANDOM_SIZE);
- uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ // When offering ECH, |ssl->session| is only offered in ClientHelloInner.
+ const bool pre_shared_key_allowed =
+ ssl->session != nullptr && ssl->s3->ech_status != ssl_ech_rejected;
+ SSLExtension key_share(TLSEXT_TYPE_key_share),
+ pre_shared_key(TLSEXT_TYPE_pre_shared_key, pre_shared_key_allowed),
+ supported_versions(TLSEXT_TYPE_supported_versions);
+ if (!ssl_parse_extensions(&server_hello.extensions, &alert,
+ {&key_share, &pre_shared_key, &supported_versions},
/*ignore_unknown=*/false)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
- // Recheck supported_versions, in case this is the second ServerHello.
+ // Recheck supported_versions, in case this is after HelloRetryRequest.
uint16_t version;
- if (!have_supported_versions ||
- !CBS_get_u16(&supported_versions, &version) ||
+ if (!supported_versions.present ||
+ !CBS_get_u16(&supported_versions.data, &version) ||
+ CBS_len(&supported_versions.data) != 0 ||
version != ssl->version) {
OPENSSL_PUT_ERROR(SSL, SSL_R_SECOND_SERVERHELLO_VERSION_MISMATCH);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
@@ -354,15 +428,9 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
}
alert = SSL_AD_DECODE_ERROR;
- if (have_pre_shared_key) {
- if (ssl->session == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return ssl_hs_error;
- }
-
+ if (pre_shared_key.present) {
if (!ssl_ext_pre_shared_key_parse_serverhello(hs, &alert,
- &pre_shared_key)) {
+ &pre_shared_key.data)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
@@ -373,7 +441,7 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- if (ssl->session->cipher->algorithm_prf != cipher->algorithm_prf) {
+ if (ssl->session->cipher->algorithm_prf != hs->new_cipher->algorithm_prf) {
OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_PRF_HASH_MISMATCH);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
@@ -388,6 +456,7 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
}
ssl->s3->session_reused = true;
+ hs->can_release_private_key = true;
// Only authentication information carries over in TLS 1.3.
hs->new_session =
SSL_SESSION_dup(ssl->session.get(), SSL_SESSION_DUP_AUTH_ONLY);
@@ -400,29 +469,25 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
// Resumption incorporates fresh key material, so refresh the timeout.
ssl_session_renew_timeout(ssl, hs->new_session.get(),
ssl->session_ctx->session_psk_dhe_timeout);
- } else if (!ssl_get_new_session(hs, 0)) {
+ } else if (!ssl_get_new_session(hs)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_hs_error;
}
- hs->new_session->cipher = cipher;
- hs->new_cipher = cipher;
-
- size_t hash_len =
- EVP_MD_size(ssl_get_handshake_digest(ssl_protocol_version(ssl), cipher));
+ hs->new_session->cipher = hs->new_cipher;
// Set up the key schedule and incorporate the PSK into the running secret.
- if (ssl->s3->session_reused) {
- if (!tls13_init_key_schedule(
- hs, MakeConstSpan(hs->new_session->secret,
- hs->new_session->secret_length))) {
- return ssl_hs_error;
- }
- } else if (!tls13_init_key_schedule(hs, MakeConstSpan(kZeroes, hash_len))) {
+ size_t hash_len = EVP_MD_size(
+ ssl_get_handshake_digest(ssl_protocol_version(ssl), hs->new_cipher));
+ if (!tls13_init_key_schedule(
+ hs, ssl->s3->session_reused
+ ? MakeConstSpan(hs->new_session->secret,
+ hs->new_session->secret_length)
+ : MakeConstSpan(kZeroes, hash_len))) {
return ssl_hs_error;
}
- if (!have_key_share) {
+ if (!key_share.present) {
// We do not support psk_ke and thus always require a key share.
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
@@ -433,7 +498,7 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
Array<uint8_t> dhe_secret;
alert = SSL_AD_DECODE_ERROR;
if (!ssl_ext_key_share_parse_serverhello(hs, &dhe_secret, &alert,
- &key_share)) {
+ &key_share.data)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
@@ -477,18 +542,27 @@ static enum ssl_hs_wait_t do_read_encrypted_extensions(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- CBS body = msg.body;
- if (!ssl_parse_serverhello_tlsext(hs, &body)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
- return ssl_hs_error;
- }
- if (CBS_len(&body) != 0) {
+ CBS body = msg.body, extensions;
+ if (!CBS_get_u16_length_prefixed(&body, &extensions) ||
+ CBS_len(&body) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
}
+ if (!ssl_parse_serverhello_tlsext(hs, &extensions)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ return ssl_hs_error;
+ }
+
if (ssl->s3->early_data_accepted) {
+ // The extension parser checks the server resumed the session.
+ assert(ssl->s3->session_reused);
+ // If offering ECH, the server may not accept early data with
+ // ClientHelloOuter. We do not offer sessions with ClientHelloOuter, so this
+ // this should be implied by checking |session_reused|.
+ assert(ssl->s3->ech_status != ssl_ech_rejected);
+
if (hs->early_session->cipher != hs->new_session->cipher) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_MISMATCH_ON_EARLY_DATA);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
@@ -500,9 +574,9 @@ static enum ssl_hs_wait_t do_read_encrypted_extensions(SSL_HANDSHAKE *hs) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
- // Channel ID and Token Binding are incompatible with 0-RTT. The ALPS
- // extension should be negotiated implicitly.
- if (ssl->s3->channel_id_valid || ssl->s3->token_binding_negotiated ||
+ // Channel ID is incompatible with 0-RTT. The ALPS extension should be
+ // negotiated implicitly.
+ if (hs->channel_id_negotiated ||
hs->new_session->has_application_settings) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION_ON_EARLY_DATA);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
@@ -564,25 +638,19 @@ static enum ssl_hs_wait_t do_read_certificate_request(SSL_HANDSHAKE *hs) {
}
- bool have_sigalgs = false, have_ca = false;
- CBS sigalgs, ca;
- const SSL_EXTENSION_TYPE ext_types[] = {
- {TLSEXT_TYPE_signature_algorithms, &have_sigalgs, &sigalgs},
- {TLSEXT_TYPE_certificate_authorities, &have_ca, &ca},
- };
-
+ SSLExtension sigalgs(TLSEXT_TYPE_signature_algorithms),
+ ca(TLSEXT_TYPE_certificate_authorities);
CBS body = msg.body, context, extensions, supported_signature_algorithms;
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!CBS_get_u8_length_prefixed(&body, &context) ||
// The request context is always empty during the handshake.
CBS_len(&context) != 0 ||
- !CBS_get_u16_length_prefixed(&body, &extensions) ||
+ !CBS_get_u16_length_prefixed(&body, &extensions) || //
CBS_len(&body) != 0 ||
- !ssl_parse_extensions(&extensions, &alert, ext_types,
+ !ssl_parse_extensions(&extensions, &alert, {&sigalgs, &ca},
/*ignore_unknown=*/true) ||
- (have_ca && CBS_len(&ca) == 0) ||
- !have_sigalgs ||
- !CBS_get_u16_length_prefixed(&sigalgs,
+ !sigalgs.present ||
+ !CBS_get_u16_length_prefixed(&sigalgs.data,
&supported_signature_algorithms) ||
!tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
@@ -590,8 +658,8 @@ static enum ssl_hs_wait_t do_read_certificate_request(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- if (have_ca) {
- hs->ca_names = ssl_parse_client_CA_list(ssl, &alert, &ca);
+ if (ca.present) {
+ hs->ca_names = ssl_parse_client_CA_list(ssl, &alert, &ca.data);
if (!hs->ca_names) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
@@ -712,8 +780,7 @@ static enum ssl_hs_wait_t do_send_end_of_early_data(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
if (ssl->s3->early_data_accepted) {
- // QUIC omits the EndOfEarlyData message. See draft-ietf-quic-tls-22,
- // section 8.3.
+ // QUIC omits the EndOfEarlyData message. See RFC 9001, section 8.3.
if (ssl->quic_method == nullptr) {
ScopedCBB cbb;
CBB body;
@@ -768,8 +835,12 @@ static enum ssl_hs_wait_t do_send_client_certificate(SSL_HANDSHAKE *hs) {
return ssl_hs_ok;
}
- // Call cert_cb to update the certificate.
- if (hs->config->cert->cert_cb != NULL) {
+ if (ssl->s3->ech_status == ssl_ech_rejected) {
+ // Do not send client certificates on ECH reject. We have not authenticated
+ // the server for the name that can learn the certificate.
+ SSL_certs_clear(ssl);
+ } else if (hs->config->cert->cert_cb != nullptr) {
+ // Call cert_cb to update the certificate.
int rv = hs->config->cert->cert_cb(ssl, hs->config->cert->cert_cb_arg);
if (rv == 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
@@ -817,18 +888,10 @@ static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_complete_second_flight(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+ hs->can_release_private_key = true;
// Send a Channel ID assertion if necessary.
- if (ssl->s3->channel_id_valid) {
- if (!ssl_do_channel_id_callback(hs)) {
- hs->tls13_state = state_complete_second_flight;
- return ssl_hs_error;
- }
-
- if (hs->config->channel_id_private == NULL) {
- return ssl_hs_channel_id_lookup;
- }
-
+ if (hs->channel_id_negotiated) {
ScopedCBB cbb;
CBB body;
if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CHANNEL_ID) ||
@@ -1019,30 +1082,24 @@ UniquePtr<SSL_SESSION> tls13_create_session_with_ticket(SSL *ssl, CBS *body) {
return nullptr;
}
- // Parse out the extensions.
- bool have_early_data = false;
- CBS early_data;
- const SSL_EXTENSION_TYPE ext_types[] = {
- {TLSEXT_TYPE_early_data, &have_early_data, &early_data},
- };
-
+ SSLExtension early_data(TLSEXT_TYPE_early_data);
uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ if (!ssl_parse_extensions(&extensions, &alert, {&early_data},
/*ignore_unknown=*/true)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return nullptr;
}
- if (have_early_data) {
- if (!CBS_get_u32(&early_data, &session->ticket_max_early_data) ||
- CBS_len(&early_data) != 0) {
+ if (early_data.present) {
+ if (!CBS_get_u32(&early_data.data, &session->ticket_max_early_data) ||
+ CBS_len(&early_data.data) != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return nullptr;
}
// QUIC does not use the max_early_data_size parameter and always sets it to
- // a fixed value. See draft-ietf-quic-tls-22, section 4.5.
+ // a fixed value. See RFC 9001, section 4.6.1.
if (ssl->quic_method != nullptr &&
session->ticket_max_early_data != 0xffffffff) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
@@ -1051,8 +1108,8 @@ UniquePtr<SSL_SESSION> tls13_create_session_with_ticket(SSL *ssl, CBS *body) {
}
}
- // Generate a session ID for this session. Some callers expect all sessions to
- // have a session ID.
+ // Historically, OpenSSL filled in fake session IDs for ticket-based sessions.
+ // Envoy's tests depend on this, although perhaps they shouldn't.
SHA256(CBS_data(&ticket), CBS_len(&ticket), session->session_id);
session->session_id_length = SHA256_DIGEST_LENGTH;
diff --git a/deps/boringssl/src/ssl/tls13_enc.cc b/deps/boringssl/src/ssl/tls13_enc.cc
index cda53ec..c7b75a6 100644
--- a/deps/boringssl/src/ssl/tls13_enc.cc
+++ b/deps/boringssl/src/ssl/tls13_enc.cc
@@ -33,24 +33,25 @@
BSSL_NAMESPACE_BEGIN
-static bool init_key_schedule(SSL_HANDSHAKE *hs, uint16_t version,
- const SSL_CIPHER *cipher) {
- if (!hs->transcript.InitHash(version, cipher)) {
+static bool init_key_schedule(SSL_HANDSHAKE *hs, SSLTranscript *transcript,
+ uint16_t version, const SSL_CIPHER *cipher) {
+ if (!transcript->InitHash(version, cipher)) {
return false;
}
// Initialize the secret to the zero key.
- hs->ResizeSecrets(hs->transcript.DigestLen());
+ hs->ResizeSecrets(transcript->DigestLen());
OPENSSL_memset(hs->secret().data(), 0, hs->secret().size());
return true;
}
-static bool hkdf_extract_to_secret(SSL_HANDSHAKE *hs, Span<const uint8_t> in) {
+static bool hkdf_extract_to_secret(SSL_HANDSHAKE *hs,
+ const SSLTranscript &transcript,
+ Span<const uint8_t> in) {
size_t len;
- if (!HKDF_extract(hs->secret().data(), &len, hs->transcript.Digest(),
- in.data(), in.size(), hs->secret().data(),
- hs->secret().size())) {
+ if (!HKDF_extract(hs->secret().data(), &len, transcript.Digest(), in.data(),
+ in.size(), hs->secret().data(), hs->secret().size())) {
return false;
}
assert(len == hs->secret().size());
@@ -58,7 +59,8 @@ static bool hkdf_extract_to_secret(SSL_HANDSHAKE *hs, Span<const uint8_t> in) {
}
bool tls13_init_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> psk) {
- if (!init_key_schedule(hs, ssl_protocol_version(hs->ssl), hs->new_cipher)) {
+ if (!init_key_schedule(hs, &hs->transcript, ssl_protocol_version(hs->ssl),
+ hs->new_cipher)) {
return false;
}
@@ -67,14 +69,22 @@ bool tls13_init_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> psk) {
if (!hs->handback) {
hs->transcript.FreeBuffer();
}
- return hkdf_extract_to_secret(hs, psk);
+ return hkdf_extract_to_secret(hs, hs->transcript, psk);
}
-bool tls13_init_early_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> psk) {
- SSL *const ssl = hs->ssl;
- return init_key_schedule(hs, ssl_session_protocol_version(ssl->session.get()),
- ssl->session->cipher) &&
- hkdf_extract_to_secret(hs, psk);
+bool tls13_init_early_key_schedule(SSL_HANDSHAKE *hs,
+ const SSL_SESSION *session) {
+ assert(!hs->ssl->server);
+ // When offering ECH, early data is associated with ClientHelloInner, not
+ // ClientHelloOuter.
+ SSLTranscript *transcript =
+ hs->selected_ech_config ? &hs->inner_transcript : &hs->transcript;
+ return init_key_schedule(hs, transcript,
+ ssl_session_protocol_version(session),
+ session->cipher) &&
+ hkdf_extract_to_secret(
+ hs, *transcript,
+ MakeConstSpan(session->secret, session->secret_length));
}
static Span<const char> label_to_span(const char *label) {
@@ -118,25 +128,31 @@ bool tls13_advance_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> in) {
hkdf_expand_label(hs->secret(), hs->transcript.Digest(), hs->secret(),
label_to_span(kTLS13LabelDerived),
MakeConstSpan(derive_context, derive_context_len)) &&
- hkdf_extract_to_secret(hs, in);
+ hkdf_extract_to_secret(hs, hs->transcript, in);
}
-// derive_secret derives a secret of length |out.size()| and writes the result
-// in |out| with the given label, the current base secret, and the most
-// recently-saved handshake context. It returns true on success and false on
-// error.
-static bool derive_secret(SSL_HANDSHAKE *hs, Span<uint8_t> out,
- Span<const char> label) {
+// derive_secret_with_transcript derives a secret of length |out.size()| and
+// writes the result in |out| with the given label, the current base secret, and
+// the state of |transcript|. It returns true on success and false on error.
+static bool derive_secret_with_transcript(const SSL_HANDSHAKE *hs,
+ Span<uint8_t> out,
+ const SSLTranscript &transcript,
+ Span<const char> label) {
uint8_t context_hash[EVP_MAX_MD_SIZE];
size_t context_hash_len;
- if (!hs->transcript.GetHash(context_hash, &context_hash_len)) {
+ if (!transcript.GetHash(context_hash, &context_hash_len)) {
return false;
}
- return hkdf_expand_label(out, hs->transcript.Digest(), hs->secret(), label,
+ return hkdf_expand_label(out, transcript.Digest(), hs->secret(), label,
MakeConstSpan(context_hash, context_hash_len));
}
+static bool derive_secret(SSL_HANDSHAKE *hs, Span<uint8_t> out,
+ Span<const char> label) {
+ return derive_secret_with_transcript(hs, out, hs->transcript, label);
+}
+
bool tls13_set_traffic_key(SSL *ssl, enum ssl_encryption_level_t level,
enum evp_aead_direction_t direction,
const SSL_SESSION *session,
@@ -228,8 +244,14 @@ static const char kTLS13LabelServerApplicationTraffic[] = "s ap traffic";
bool tls13_derive_early_secret(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- if (!derive_secret(hs, hs->early_traffic_secret(),
- label_to_span(kTLS13LabelClientEarlyTraffic)) ||
+ // When offering ECH on the client, early data is associated with
+ // ClientHelloInner, not ClientHelloOuter.
+ const SSLTranscript &transcript = (!ssl->server && hs->selected_ech_config)
+ ? hs->inner_transcript
+ : hs->transcript;
+ if (!derive_secret_with_transcript(
+ hs, hs->early_traffic_secret(), transcript,
+ label_to_span(kTLS13LabelClientEarlyTraffic)) ||
!ssl_log_secret(ssl, "CLIENT_EARLY_TRAFFIC_SECRET",
hs->early_traffic_secret())) {
return false;
@@ -395,98 +417,97 @@ bool tls13_export_keying_material(SSL *ssl, Span<uint8_t> out,
static const char kTLS13LabelPSKBinder[] = "res binder";
-static bool tls13_psk_binder(uint8_t *out, size_t *out_len, uint16_t version,
- const EVP_MD *digest, Span<const uint8_t> psk,
- Span<const uint8_t> context) {
+static bool tls13_psk_binder(uint8_t *out, size_t *out_len,
+ const SSL_SESSION *session,
+ const SSLTranscript &transcript,
+ Span<const uint8_t> client_hello,
+ size_t binders_len) {
+ const EVP_MD *digest = ssl_session_get_digest(session);
+
+ // Compute the binder key.
+ //
+ // TODO(davidben): Ideally we wouldn't recompute early secret and the binder
+ // key each time.
uint8_t binder_context[EVP_MAX_MD_SIZE];
unsigned binder_context_len;
- if (!EVP_Digest(NULL, 0, binder_context, &binder_context_len, digest, NULL)) {
- return false;
- }
-
uint8_t early_secret[EVP_MAX_MD_SIZE] = {0};
size_t early_secret_len;
- if (!HKDF_extract(early_secret, &early_secret_len, digest, psk.data(),
- psk.size(), NULL, 0)) {
- return false;
- }
-
uint8_t binder_key_buf[EVP_MAX_MD_SIZE] = {0};
auto binder_key = MakeSpan(binder_key_buf, EVP_MD_size(digest));
- if (!hkdf_expand_label(binder_key, digest,
+ if (!EVP_Digest(nullptr, 0, binder_context, &binder_context_len, digest,
+ nullptr) ||
+ !HKDF_extract(early_secret, &early_secret_len, digest, session->secret,
+ session->secret_length, nullptr, 0) ||
+ !hkdf_expand_label(binder_key, digest,
MakeConstSpan(early_secret, early_secret_len),
label_to_span(kTLS13LabelPSKBinder),
- MakeConstSpan(binder_context, binder_context_len)) ||
- !tls13_verify_data(out, out_len, digest, version, binder_key, context)) {
+ MakeConstSpan(binder_context, binder_context_len))) {
return false;
}
- assert(*out_len == EVP_MD_size(digest));
- return true;
-}
-
-static bool hash_transcript_and_truncated_client_hello(
- SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, const EVP_MD *digest,
- Span<const uint8_t> client_hello, size_t binders_len) {
- // Truncate the ClientHello.
- if (binders_len + 2 < binders_len || client_hello.size() < binders_len + 2) {
+ // Hash the transcript and truncated ClientHello.
+ if (client_hello.size() < binders_len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
- client_hello = client_hello.subspan(0, client_hello.size() - binders_len - 2);
-
+ auto truncated = client_hello.subspan(0, client_hello.size() - binders_len);
+ uint8_t context[EVP_MAX_MD_SIZE];
+ unsigned context_len;
ScopedEVP_MD_CTX ctx;
- unsigned len;
- if (!hs->transcript.CopyToHashContext(ctx.get(), digest) ||
- !EVP_DigestUpdate(ctx.get(), client_hello.data(), client_hello.size()) ||
- !EVP_DigestFinal_ex(ctx.get(), out, &len)) {
+ if (!transcript.CopyToHashContext(ctx.get(), digest) ||
+ !EVP_DigestUpdate(ctx.get(), truncated.data(),
+ truncated.size()) ||
+ !EVP_DigestFinal_ex(ctx.get(), context, &context_len)) {
return false;
}
- *out_len = len;
+ if (!tls13_verify_data(out, out_len, digest, session->ssl_version, binder_key,
+ MakeConstSpan(context, context_len))) {
+ return false;
+ }
+
+ assert(*out_len == EVP_MD_size(digest));
return true;
}
-bool tls13_write_psk_binder(SSL_HANDSHAKE *hs, Span<uint8_t> msg) {
- SSL *const ssl = hs->ssl;
+bool tls13_write_psk_binder(const SSL_HANDSHAKE *hs,
+ const SSLTranscript &transcript, Span<uint8_t> msg,
+ size_t *out_binder_len) {
+ const SSL *const ssl = hs->ssl;
const EVP_MD *digest = ssl_session_get_digest(ssl->session.get());
- size_t hash_len = EVP_MD_size(digest);
-
- ScopedEVP_MD_CTX ctx;
- uint8_t context[EVP_MAX_MD_SIZE];
- size_t context_len;
+ const size_t hash_len = EVP_MD_size(digest);
+ // We only offer one PSK, so the binders are a u16 and u8 length
+ // prefix, followed by the binder. The caller is assumed to have constructed
+ // |msg| with placeholder binders.
+ const size_t binders_len = 3 + hash_len;
uint8_t verify_data[EVP_MAX_MD_SIZE];
size_t verify_data_len;
- if (!hash_transcript_and_truncated_client_hello(
- hs, context, &context_len, digest, msg,
- 1 /* length prefix */ + hash_len) ||
- !tls13_psk_binder(
- verify_data, &verify_data_len, ssl->session->ssl_version, digest,
- MakeConstSpan(ssl->session->secret, ssl->session->secret_length),
- MakeConstSpan(context, context_len)) ||
+ if (!tls13_psk_binder(verify_data, &verify_data_len, ssl->session.get(),
+ transcript, msg, binders_len) ||
verify_data_len != hash_len) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
- OPENSSL_memcpy(msg.data() + msg.size() - verify_data_len, verify_data,
- verify_data_len);
+ auto msg_binder = msg.last(verify_data_len);
+ OPENSSL_memcpy(msg_binder.data(), verify_data, verify_data_len);
+ if (out_binder_len != nullptr) {
+ *out_binder_len = verify_data_len;
+ }
return true;
}
-bool tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
- const SSLMessage &msg, CBS *binders) {
- uint8_t context[EVP_MAX_MD_SIZE];
- size_t context_len;
+bool tls13_verify_psk_binder(const SSL_HANDSHAKE *hs,
+ const SSL_SESSION *session, const SSLMessage &msg,
+ CBS *binders) {
uint8_t verify_data[EVP_MAX_MD_SIZE];
size_t verify_data_len;
CBS binder;
- if (!hash_transcript_and_truncated_client_hello(hs, context, &context_len,
- hs->transcript.Digest(),
- msg.raw, CBS_len(binders)) ||
- !tls13_psk_binder(verify_data, &verify_data_len, hs->ssl->version,
- hs->transcript.Digest(),
- MakeConstSpan(session->secret, session->secret_length),
- MakeConstSpan(context, context_len)) ||
+ // The binders are computed over |msg| with |binders| and its u16 length
+ // prefix removed. The caller is assumed to have parsed |msg|, extracted
+ // |binders|, and verified the PSK extension is last.
+ if (!tls13_psk_binder(verify_data, &verify_data_len, session, hs->transcript,
+ msg.raw, 2 + CBS_len(binders)) ||
// We only consider the first PSK, so compare against the first binder.
!CBS_get_u8_length_prefixed(binders, &binder)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
@@ -507,40 +528,55 @@ bool tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
return true;
}
-bool tls13_ech_accept_confirmation(
- SSL_HANDSHAKE *hs, bssl::Span<uint8_t> out,
- bssl::Span<const uint8_t> server_hello_ech_conf) {
- // Compute the hash of the transcript concatenated with
- // |server_hello_ech_conf| without modifying |hs->transcript|.
- uint8_t context_hash[EVP_MAX_MD_SIZE];
- unsigned context_hash_len;
- ScopedEVP_MD_CTX ctx;
- if (!hs->transcript.CopyToHashContext(ctx.get(), hs->transcript.Digest()) ||
- !EVP_DigestUpdate(ctx.get(), server_hello_ech_conf.data(),
- server_hello_ech_conf.size()) ||
- !EVP_DigestFinal_ex(ctx.get(), context_hash, &context_hash_len)) {
+size_t ssl_ech_confirmation_signal_hello_offset(const SSL *ssl) {
+ static_assert(ECH_CONFIRMATION_SIGNAL_LEN < SSL3_RANDOM_SIZE,
+ "the confirmation signal is a suffix of the random");
+ const size_t header_len =
+ SSL_is_dtls(ssl) ? DTLS1_HM_HEADER_LENGTH : SSL3_HM_HEADER_LENGTH;
+ return header_len + 2 /* version */ + SSL3_RANDOM_SIZE -
+ ECH_CONFIRMATION_SIGNAL_LEN;
+}
+
+bool ssl_ech_accept_confirmation(const SSL_HANDSHAKE *hs, Span<uint8_t> out,
+ Span<const uint8_t> client_random,
+ const SSLTranscript &transcript, bool is_hrr,
+ Span<const uint8_t> msg, size_t offset) {
+ // See draft-ietf-tls-esni-13, sections 7.2 and 7.2.1.
+ static const uint8_t kZeros[EVP_MAX_MD_SIZE] = {0};
+
+ // We hash |msg|, with bytes from |offset| zeroed.
+ if (msg.size() < offset + ECH_CONFIRMATION_SIGNAL_LEN) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
- // Per draft-ietf-tls-esni-09, accept_confirmation is computed with
- // Derive-Secret, which derives a secret of size Hash.length. That value is
- // then truncated to the first 8 bytes. Note this differs from deriving an
- // 8-byte secret because the target length is included in the derivation.
- uint8_t accept_confirmation_buf[EVP_MAX_MD_SIZE];
- bssl::Span<uint8_t> accept_confirmation =
- MakeSpan(accept_confirmation_buf, hs->transcript.DigestLen());
- if (!hkdf_expand_label(accept_confirmation, hs->transcript.Digest(),
- hs->secret(), label_to_span("ech accept confirmation"),
- MakeConstSpan(context_hash, context_hash_len))) {
+ auto before_zeros = msg.subspan(0, offset);
+ auto after_zeros = msg.subspan(offset + ECH_CONFIRMATION_SIGNAL_LEN);
+ uint8_t context[EVP_MAX_MD_SIZE];
+ unsigned context_len;
+ ScopedEVP_MD_CTX ctx;
+ if (!transcript.CopyToHashContext(ctx.get(), transcript.Digest()) ||
+ !EVP_DigestUpdate(ctx.get(), before_zeros.data(), before_zeros.size()) ||
+ !EVP_DigestUpdate(ctx.get(), kZeros, ECH_CONFIRMATION_SIGNAL_LEN) ||
+ !EVP_DigestUpdate(ctx.get(), after_zeros.data(), after_zeros.size()) ||
+ !EVP_DigestFinal_ex(ctx.get(), context, &context_len)) {
return false;
}
- if (out.size() > accept_confirmation.size()) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ uint8_t secret[EVP_MAX_MD_SIZE];
+ size_t secret_len;
+ if (!HKDF_extract(secret, &secret_len, transcript.Digest(),
+ client_random.data(), client_random.size(), kZeros,
+ transcript.DigestLen())) {
return false;
}
- OPENSSL_memcpy(out.data(), accept_confirmation.data(), out.size());
- return true;
+
+ assert(out.size() == ECH_CONFIRMATION_SIGNAL_LEN);
+ return hkdf_expand_label(out, transcript.Digest(),
+ MakeConstSpan(secret, secret_len),
+ is_hrr ? label_to_span("hrr ech accept confirmation")
+ : label_to_span("ech accept confirmation"),
+ MakeConstSpan(context, context_len));
}
BSSL_NAMESPACE_END
diff --git a/deps/boringssl/src/ssl/tls13_server.cc b/deps/boringssl/src/ssl/tls13_server.cc
index 6e9cd07..2f000e5 100644
--- a/deps/boringssl/src/ssl/tls13_server.cc
+++ b/deps/boringssl/src/ssl/tls13_server.cc
@@ -23,6 +23,7 @@
#include <openssl/bytestring.h>
#include <openssl/digest.h>
#include <openssl/err.h>
+#include <openssl/hpke.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/stack.h>
@@ -41,35 +42,57 @@ static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
// See RFC 8446, section 8.3.
static const int32_t kMaxTicketAgeSkewSeconds = 60;
-static int resolve_ecdhe_secret(SSL_HANDSHAKE *hs, bool *out_need_retry,
- SSL_CLIENT_HELLO *client_hello) {
+static bool resolve_ecdhe_secret(SSL_HANDSHAKE *hs,
+ const SSL_CLIENT_HELLO *client_hello) {
SSL *const ssl = hs->ssl;
- *out_need_retry = false;
-
- // We only support connections that include an ECDHE key exchange.
- CBS key_share;
- if (!ssl_client_hello_get_extension(client_hello, &key_share,
- TLSEXT_TYPE_key_share)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
- return 0;
- }
+ const uint16_t group_id = hs->new_session->group_id;
bool found_key_share;
- Array<uint8_t> dhe_secret;
+ Span<const uint8_t> peer_key;
uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!ssl_ext_key_share_parse_clienthello(hs, &found_key_share, &dhe_secret,
- &alert, &key_share)) {
+ if (!ssl_ext_key_share_parse_clienthello(hs, &found_key_share, &peer_key,
+ &alert, client_hello)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
- return 0;
+ return false;
}
if (!found_key_share) {
- *out_need_retry = true;
- return 0;
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ return false;
+ }
+
+ Array<uint8_t> secret;
+ SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
+ if (hints && !hs->hints_requested && hints->key_share_group_id == group_id &&
+ !hints->key_share_secret.empty()) {
+ // Copy DH secret from hints.
+ if (!hs->ecdh_public_key.CopyFrom(hints->key_share_public_key) ||
+ !secret.CopyFrom(hints->key_share_secret)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return false;
+ }
+ } else {
+ ScopedCBB public_key;
+ UniquePtr<SSLKeyShare> key_share = SSLKeyShare::Create(group_id);
+ if (!key_share || //
+ !CBB_init(public_key.get(), 32) ||
+ !key_share->Accept(public_key.get(), &secret, &alert, peer_key) ||
+ !CBBFinishArray(public_key.get(), &hs->ecdh_public_key)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return false;
+ }
+ if (hints && hs->hints_requested) {
+ hints->key_share_group_id = group_id;
+ if (!hints->key_share_public_key.CopyFrom(hs->ecdh_public_key) ||
+ !hints->key_share_secret.CopyFrom(secret)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return false;
+ }
+ }
}
- return tls13_advance_key_schedule(hs, dhe_secret);
+ return tls13_advance_key_schedule(hs, secret);
}
static int ssl_ext_supported_versions_add_serverhello(SSL_HANDSHAKE *hs,
@@ -132,7 +155,7 @@ static bool add_new_session_tickets(SSL_HANDSHAKE *hs, bool *out_sent_tickets) {
(!ssl->quic_method || !ssl->config->quic_early_data_context.empty());
if (enable_early_data) {
// QUIC does not use the max_early_data_size parameter and always sets it
- // to a fixed value. See draft-ietf-quic-tls-22, section 4.5.
+ // to a fixed value. See RFC 9001, section 4.6.1.
session->ticket_max_early_data =
ssl->quic_method != nullptr ? 0xffffffff : kMaxEarlyDataAccepted;
}
@@ -165,7 +188,7 @@ static bool add_new_session_tickets(SSL_HANDSHAKE *hs, bool *out_sent_tickets) {
}
}
- // Add a fake extension. See draft-davidben-tls-grease-01.
+ // Add a fake extension. See RFC 8701.
if (!CBB_add_u16(&extensions,
ssl_get_grease_value(hs, ssl_grease_ticket_extension)) ||
!CBB_add_u16(&extensions, 0 /* empty */)) {
@@ -186,13 +209,8 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
// the common handshake logic. Resolve the remaining non-PSK parameters.
SSL *const ssl = hs->ssl;
SSLMessage msg;
- if (!ssl->method->get_message(ssl, &msg)) {
- return ssl_hs_read_message;
- }
SSL_CLIENT_HELLO client_hello;
- if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ if (!hs->GetClientHello(&msg, &client_hello)) {
return ssl_hs_error;
}
@@ -228,8 +246,7 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- // The PRF hash is now known. Set up the key schedule and hash the
- // ClientHello.
+ // The PRF hash is now known.
if (!hs->transcript.InitHash(ssl_protocol_version(ssl), hs->new_cipher)) {
return ssl_hs_error;
}
@@ -252,6 +269,16 @@ static enum ssl_ticket_aead_result_t select_session(
return ssl_ticket_aead_ignore_ticket;
}
+ // Per RFC 8446, section 4.2.9, servers MUST abort the handshake if the client
+ // sends pre_shared_key without psk_key_exchange_modes.
+ CBS unused;
+ if (!ssl_client_hello_get_extension(client_hello, &unused,
+ TLSEXT_TYPE_psk_key_exchange_modes)) {
+ *out_alert = SSL_AD_MISSING_EXTENSION;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
+ return ssl_ticket_aead_error;
+ }
+
CBS ticket, binders;
uint32_t client_ticket_age;
if (!ssl_ext_pre_shared_key_parse_clienthello(
@@ -337,13 +364,8 @@ static bool quic_ticket_compatible(const SSL_SESSION *session,
static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
SSLMessage msg;
- if (!ssl->method->get_message(ssl, &msg)) {
- return ssl_hs_read_message;
- }
SSL_CLIENT_HELLO client_hello;
- if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ if (!hs->GetClientHello(&msg, &client_hello)) {
return ssl_hs_error;
}
@@ -354,7 +376,7 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
&offered_ticket, msg, &client_hello)) {
case ssl_ticket_aead_ignore_ticket:
assert(!session);
- if (!ssl_get_new_session(hs, 1 /* server */)) {
+ if (!ssl_get_new_session(hs)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_hs_error;
}
@@ -371,6 +393,7 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
}
ssl->s3->session_reused = true;
+ hs->can_release_private_key = true;
// Resumption incorporates fresh key material, so refresh the timeout.
ssl_session_renew_timeout(ssl, hs->new_session.get(),
@@ -393,6 +416,23 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
+ // Record connection properties in the new session.
+ hs->new_session->cipher = hs->new_cipher;
+ if (!tls1_get_shared_group(hs, &hs->new_session->group_id)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_GROUP);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ return ssl_hs_error;
+ }
+
+ // Determine if we need HelloRetryRequest.
+ bool found_key_share;
+ if (!ssl_ext_key_share_parse_clienthello(hs, &found_key_share,
+ /*out_key_share=*/nullptr, &alert,
+ &client_hello)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
// Determine if we're negotiating 0-RTT.
if (!ssl->enable_early_data) {
ssl->s3->early_data_reason = ssl_early_data_disabled;
@@ -404,12 +444,9 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
ssl->s3->early_data_reason = ssl_early_data_unsupported_for_session;
} else if (!hs->early_data_offered) {
ssl->s3->early_data_reason = ssl_early_data_peer_declined;
- } else if (ssl->s3->channel_id_valid) {
+ } else if (hs->channel_id_negotiated) {
// Channel ID is incompatible with 0-RTT.
ssl->s3->early_data_reason = ssl_early_data_channel_id;
- } else if (ssl->s3->token_binding_negotiated) {
- // Token Binding is incompatible with 0-RTT.
- ssl->s3->early_data_reason = ssl_early_data_token_binding;
} else if (MakeConstSpan(ssl->s3->alpn_selected) != session->early_alpn) {
// The negotiated ALPN must match the one in the ticket.
ssl->s3->early_data_reason = ssl_early_data_alpn_mismatch;
@@ -423,6 +460,8 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
ssl->s3->early_data_reason = ssl_early_data_ticket_age_skew;
} else if (!quic_ticket_compatible(session.get(), hs->config)) {
ssl->s3->early_data_reason = ssl_early_data_quic_parameter_mismatch;
+ } else if (!found_key_share) {
+ ssl->s3->early_data_reason = ssl_early_data_hello_retry_request;
} else {
// |ssl_session_is_resumable| forbids cross-cipher resumptions even if the
// PRF hashes match.
@@ -432,9 +471,6 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
ssl->s3->early_data_accepted = true;
}
- // Record connection properties in the new session.
- hs->new_session->cipher = hs->new_cipher;
-
// Store the ALPN and ALPS values in the session for 0-RTT. Note the peer
// applications settings are not generally known until client
// EncryptedExtensions.
@@ -475,17 +511,12 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
ssl_get_handshake_digest(ssl_protocol_version(ssl), hs->new_cipher));
// Set up the key schedule and incorporate the PSK into the running secret.
- if (ssl->s3->session_reused) {
- if (!tls13_init_key_schedule(
- hs, MakeConstSpan(hs->new_session->secret,
- hs->new_session->secret_length))) {
- return ssl_hs_error;
- }
- } else if (!tls13_init_key_schedule(hs, MakeConstSpan(kZeroes, hash_len))) {
- return ssl_hs_error;
- }
-
- if (!ssl_hash_message(hs, msg)) {
+ if (!tls13_init_key_schedule(
+ hs, ssl->s3->session_reused
+ ? MakeConstSpan(hs->new_session->secret,
+ hs->new_session->secret_length)
+ : MakeConstSpan(kZeroes, hash_len)) ||
+ !ssl_hash_message(hs, msg)) {
return ssl_hs_error;
}
@@ -497,33 +528,30 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
ssl->s3->skip_early_data = true;
}
- // Resolve ECDHE and incorporate it into the secret.
- bool need_retry;
- if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) {
- if (need_retry) {
- if (ssl->s3->early_data_accepted) {
- ssl->s3->early_data_reason = ssl_early_data_hello_retry_request;
- ssl->s3->early_data_accepted = false;
- }
- ssl->s3->skip_early_data = true;
- ssl->method->next_message(ssl);
- if (!hs->transcript.UpdateForHelloRetryRequest()) {
- return ssl_hs_error;
- }
- hs->tls13_state = state13_send_hello_retry_request;
- return ssl_hs_ok;
+ if (!found_key_share) {
+ ssl->method->next_message(ssl);
+ if (!hs->transcript.UpdateForHelloRetryRequest()) {
+ return ssl_hs_error;
}
+ hs->tls13_state = state13_send_hello_retry_request;
+ return ssl_hs_ok;
+ }
+
+ if (!resolve_ecdhe_secret(hs, &client_hello)) {
return ssl_hs_error;
}
ssl->method->next_message(ssl);
+ hs->ech_client_hello_buf.Reset();
hs->tls13_state = state13_send_server_hello;
return ssl_hs_ok;
}
static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
-
+ if (hs->hints_requested) {
+ return ssl_hs_hints_ready;
+ }
ScopedCBB cbb;
CBB body, session_id, extensions;
@@ -542,12 +570,34 @@ static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) {
!CBB_add_u16(&extensions, ssl->version) ||
!CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
!CBB_add_u16(&extensions, 2 /* length */) ||
- !CBB_add_u16(&extensions, group_id) ||
- !ssl_add_message_cbb(ssl, cbb.get())) {
+ !CBB_add_u16(&extensions, group_id)) {
+ return ssl_hs_error;
+ }
+ if (hs->ech_is_inner) {
+ // Fill a placeholder for the ECH confirmation value.
+ if (!CBB_add_u16(&extensions, TLSEXT_TYPE_encrypted_client_hello) ||
+ !CBB_add_u16(&extensions, ECH_CONFIRMATION_SIGNAL_LEN) ||
+ !CBB_add_zeros(&extensions, ECH_CONFIRMATION_SIGNAL_LEN)) {
+ return ssl_hs_error;
+ }
+ }
+ Array<uint8_t> hrr;
+ if (!ssl->method->finish_message(ssl, cbb.get(), &hrr)) {
return ssl_hs_error;
}
+ if (hs->ech_is_inner) {
+ // Now that the message is encoded, fill in the whole value.
+ size_t offset = hrr.size() - ECH_CONFIRMATION_SIGNAL_LEN;
+ if (!ssl_ech_accept_confirmation(
+ hs, MakeSpan(hrr).last(ECH_CONFIRMATION_SIGNAL_LEN),
+ ssl->s3->client_random, hs->transcript, /*is_hrr=*/true, hrr,
+ offset)) {
+ return ssl_hs_error;
+ }
+ }
- if (!ssl->method->add_change_cipher_spec(ssl)) {
+ if (!ssl->method->add_message(ssl, std::move(hrr)) ||
+ !ssl->method->add_change_cipher_spec(ssl)) {
return ssl_hs_error;
}
@@ -566,12 +616,78 @@ static enum ssl_hs_wait_t do_read_second_client_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
SSL_CLIENT_HELLO client_hello;
- if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
+ if (!ssl_client_hello_init(ssl, &client_hello, msg.body)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
}
+ if (ssl->s3->ech_status == ssl_ech_accepted) {
+ // If we previously accepted the ClientHelloInner, the second ClientHello
+ // must contain an outer encrypted_client_hello extension.
+ CBS ech_body;
+ if (!ssl_client_hello_get_extension(&client_hello, &ech_body,
+ TLSEXT_TYPE_encrypted_client_hello)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
+ return ssl_hs_error;
+ }
+ uint16_t kdf_id, aead_id;
+ uint8_t type, config_id;
+ CBS enc, payload;
+ if (!CBS_get_u8(&ech_body, &type) || //
+ type != ECH_CLIENT_OUTER || //
+ !CBS_get_u16(&ech_body, &kdf_id) || //
+ !CBS_get_u16(&ech_body, &aead_id) ||
+ !CBS_get_u8(&ech_body, &config_id) ||
+ !CBS_get_u16_length_prefixed(&ech_body, &enc) ||
+ !CBS_get_u16_length_prefixed(&ech_body, &payload) ||
+ CBS_len(&ech_body) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ if (kdf_id != EVP_HPKE_KDF_id(EVP_HPKE_CTX_kdf(hs->ech_hpke_ctx.get())) ||
+ aead_id !=
+ EVP_HPKE_AEAD_id(EVP_HPKE_CTX_aead(hs->ech_hpke_ctx.get())) ||
+ config_id != hs->ech_config_id || CBS_len(&enc) > 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_hs_error;
+ }
+
+ // Decrypt the payload with the HPKE context from the first ClientHello.
+ Array<uint8_t> encoded_client_hello_inner;
+ bool unused;
+ if (!ssl_client_hello_decrypt(hs->ech_hpke_ctx.get(),
+ &encoded_client_hello_inner, &unused,
+ &client_hello, payload)) {
+ // Decryption failure is fatal in the second ClientHello.
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+ return ssl_hs_error;
+ }
+
+ // Recover the ClientHelloInner from the EncodedClientHelloInner.
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ bssl::Array<uint8_t> client_hello_inner;
+ if (!ssl_decode_client_hello_inner(ssl, &alert, &client_hello_inner,
+ encoded_client_hello_inner,
+ &client_hello)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+ hs->ech_client_hello_buf = std::move(client_hello_inner);
+
+ // Reparse |client_hello| from the buffer owned by |hs|.
+ if (!hs->GetClientHello(&msg, &client_hello)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ }
+
// We perform all our negotiation based on the first ClientHello (for
// consistency with what |select_certificate_cb| observed), which is in the
// transcript, so we can ignore most of this second one.
@@ -607,13 +723,7 @@ static enum ssl_hs_wait_t do_read_second_client_hello(SSL_HANDSHAKE *hs) {
}
}
- bool need_retry;
- if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) {
- if (need_retry) {
- // Only send one HelloRetryRequest.
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
- }
+ if (!resolve_ecdhe_secret(hs, &client_hello)) {
return ssl_hs_error;
}
@@ -629,6 +739,7 @@ static enum ssl_hs_wait_t do_read_second_client_hello(SSL_HANDSHAKE *hs) {
}
ssl->method->next_message(ssl);
+ hs->ech_client_hello_buf.Reset();
hs->tls13_state = state13_send_server_hello;
return ssl_hs_ok;
}
@@ -637,62 +748,61 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
Span<uint8_t> random(ssl->s3->server_random);
- RAND_bytes(random.data(), random.size());
-
- // If the ClientHello has an ech_is_inner extension, we must be the ECH
- // backend server. In response to ech_is_inner, we will overwrite part of the
- // ServerHello.random with the ECH acceptance confirmation.
- if (hs->ech_is_inner_present) {
- // Construct the ServerHelloECHConf message, which is the same as
- // ServerHello, except the last 8 bytes of its random field are zeroed out.
- Span<uint8_t> random_suffix = random.subspan(24);
- OPENSSL_memset(random_suffix.data(), 0, random_suffix.size());
-
- ScopedCBB cbb;
- CBB body, extensions, session_id;
- if (!ssl->method->init_message(ssl, cbb.get(), &body,
- SSL3_MT_SERVER_HELLO) ||
- !CBB_add_u16(&body, TLS1_2_VERSION) ||
- !CBB_add_bytes(&body, random.data(), random.size()) ||
- !CBB_add_u8_length_prefixed(&body, &session_id) ||
- !CBB_add_bytes(&session_id, hs->session_id, hs->session_id_len) ||
- !CBB_add_u16(&body, SSL_CIPHER_get_protocol_id(hs->new_cipher)) ||
- !CBB_add_u8(&body, 0) ||
- !CBB_add_u16_length_prefixed(&body, &extensions) ||
- !ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) ||
- !ssl_ext_key_share_add_serverhello(hs, &extensions, /*dry_run=*/true) ||
- !ssl_ext_supported_versions_add_serverhello(hs, &extensions) ||
- !CBB_flush(cbb.get())) {
- return ssl_hs_error;
- }
- // Note that |cbb| includes the message type and length fields, but not the
- // record layer header.
- if (!tls13_ech_accept_confirmation(
- hs, random_suffix,
- bssl::MakeConstSpan(CBB_data(cbb.get()), CBB_len(cbb.get())))) {
+ SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
+ if (hints && !hs->hints_requested &&
+ hints->server_random.size() == random.size()) {
+ OPENSSL_memcpy(random.data(), hints->server_random.data(), random.size());
+ } else {
+ RAND_bytes(random.data(), random.size());
+ if (hints && hs->hints_requested &&
+ !hints->server_random.CopyFrom(random)) {
return ssl_hs_error;
}
}
- // Send a ServerHello.
+ Array<uint8_t> server_hello;
ScopedCBB cbb;
CBB body, extensions, session_id;
if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_SERVER_HELLO) ||
!CBB_add_u16(&body, TLS1_2_VERSION) ||
- !CBB_add_bytes(&body, random.data(), random.size()) ||
+ !CBB_add_bytes(&body, ssl->s3->server_random,
+ sizeof(ssl->s3->server_random)) ||
!CBB_add_u8_length_prefixed(&body, &session_id) ||
!CBB_add_bytes(&session_id, hs->session_id, hs->session_id_len) ||
!CBB_add_u16(&body, SSL_CIPHER_get_protocol_id(hs->new_cipher)) ||
!CBB_add_u8(&body, 0) ||
!CBB_add_u16_length_prefixed(&body, &extensions) ||
!ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) ||
- !ssl_ext_key_share_add_serverhello(hs, &extensions, /*dry_run=*/false) ||
+ !ssl_ext_key_share_add_serverhello(hs, &extensions) ||
!ssl_ext_supported_versions_add_serverhello(hs, &extensions) ||
- !ssl_add_message_cbb(ssl, cbb.get())) {
+ !ssl->method->finish_message(ssl, cbb.get(), &server_hello)) {
+ return ssl_hs_error;
+ }
+
+ assert(ssl->s3->ech_status != ssl_ech_accepted || hs->ech_is_inner);
+ if (hs->ech_is_inner) {
+ // Fill in the ECH confirmation signal.
+ const size_t offset = ssl_ech_confirmation_signal_hello_offset(ssl);
+ Span<uint8_t> random_suffix = random.last(ECH_CONFIRMATION_SIGNAL_LEN);
+ if (!ssl_ech_accept_confirmation(hs, random_suffix, ssl->s3->client_random,
+ hs->transcript,
+ /*is_hrr=*/false, server_hello, offset)) {
+ return ssl_hs_error;
+ }
+
+ // Update |server_hello|.
+ Span<uint8_t> server_hello_out =
+ MakeSpan(server_hello).subspan(offset, ECH_CONFIRMATION_SIGNAL_LEN);
+ OPENSSL_memcpy(server_hello_out.data(), random_suffix.data(),
+ ECH_CONFIRMATION_SIGNAL_LEN);
+ }
+
+ if (!ssl->method->add_message(ssl, std::move(server_hello))) {
return ssl_hs_error;
}
+ hs->ecdh_public_key.Reset(); // No longer needed.
if (!ssl->s3->used_hello_retry_request &&
!ssl->method->add_change_cipher_spec(ssl)) {
return ssl_hs_error;
@@ -719,7 +829,7 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
hs->cert_request = !!(hs->config->verify_mode & SSL_VERIFY_PEER);
// Only request a certificate if Channel ID isn't negotiated.
if ((hs->config->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) &&
- ssl->s3->channel_id_valid) {
+ hs->channel_id_negotiated) {
hs->cert_request = false;
}
}
@@ -796,6 +906,11 @@ static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+ if (hs->hints_requested) {
+ return ssl_hs_hints_ready;
+ }
+
+ hs->can_release_private_key = true;
if (!tls13_add_finished(hs) ||
// Update the secret to the master secret and derive traffic keys.
!tls13_advance_key_schedule(
@@ -873,9 +988,8 @@ static enum ssl_hs_wait_t do_read_second_client_flight(SSL_HANDSHAKE *hs) {
hs->in_early_data = true;
}
- // QUIC doesn't use an EndOfEarlyData message (draft-ietf-quic-tls-22,
- // section 8.3), so we switch to client_handshake_secret before the early
- // return.
+ // QUIC doesn't use an EndOfEarlyData message (RFC 9001, section 8.3), so we
+ // switch to client_handshake_secret before the early return.
if (ssl->quic_method != nullptr) {
if (!tls13_set_traffic_key(ssl, ssl_encryption_handshake, evp_aead_open,
hs->new_session.get(),
@@ -946,20 +1060,15 @@ static enum ssl_hs_wait_t do_read_client_encrypted_extensions(
return ssl_hs_error;
}
- // Parse out the extensions.
- bool have_application_settings = false;
- CBS application_settings;
- SSL_EXTENSION_TYPE ext_types[] = {{TLSEXT_TYPE_application_settings,
- &have_application_settings,
- &application_settings}};
+ SSLExtension application_settings(TLSEXT_TYPE_application_settings);
uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ if (!ssl_parse_extensions(&extensions, &alert, {&application_settings},
/*ignore_unknown=*/false)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
- if (!have_application_settings) {
+ if (!application_settings.present) {
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
return ssl_hs_error;
@@ -968,7 +1077,7 @@ static enum ssl_hs_wait_t do_read_client_encrypted_extensions(
// Note that, if 0-RTT was accepted, these values will already have been
// initialized earlier.
if (!hs->new_session->peer_application_settings.CopyFrom(
- application_settings) ||
+ application_settings.data) ||
!ssl_hash_message(hs, msg)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_hs_error;
@@ -1051,7 +1160,7 @@ static enum ssl_hs_wait_t do_read_client_certificate_verify(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_read_channel_id(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- if (!ssl->s3->channel_id_valid) {
+ if (!hs->channel_id_negotiated) {
hs->tls13_state = state13_read_client_finished;
return ssl_hs_ok;
}
diff --git a/deps/boringssl/src/ssl/tls_method.cc b/deps/boringssl/src/ssl/tls_method.cc
index 8165d1c..326cbe7 100644
--- a/deps/boringssl/src/ssl/tls_method.cc
+++ b/deps/boringssl/src/ssl/tls_method.cc
@@ -93,7 +93,8 @@ static bool tls_set_read_state(SSL *ssl, ssl_encryption_level_t level,
}
if (ssl->quic_method != nullptr) {
- if (!ssl->quic_method->set_read_secret(ssl, level, aead_ctx->cipher(),
+ if ((ssl->s3->hs == nullptr || !ssl->s3->hs->hints_requested) &&
+ !ssl->quic_method->set_read_secret(ssl, level, aead_ctx->cipher(),
secret_for_quic.data(),
secret_for_quic.size())) {
return false;
@@ -121,7 +122,8 @@ static bool tls_set_write_state(SSL *ssl, ssl_encryption_level_t level,
}
if (ssl->quic_method != nullptr) {
- if (!ssl->quic_method->set_write_secret(ssl, level, aead_ctx->cipher(),
+ if ((ssl->s3->hs == nullptr || !ssl->s3->hs->hints_requested) &&
+ !ssl->quic_method->set_write_secret(ssl, level, aead_ctx->cipher(),
secret_for_quic.data(),
secret_for_quic.size())) {
return false;
diff --git a/deps/boringssl/src/tool/CMakeLists.txt b/deps/boringssl/src/tool/CMakeLists.txt
index e9e387b..a591b7d 100644
--- a/deps/boringssl/src/tool/CMakeLists.txt
+++ b/deps/boringssl/src/tool/CMakeLists.txt
@@ -10,6 +10,7 @@ add_executable(
digest.cc
fd.cc
file.cc
+ generate_ech.cc
generate_ed25519.cc
genrsa.cc
pkcs12.cc
diff --git a/deps/boringssl/src/tool/args.cc b/deps/boringssl/src/tool/args.cc
index 9ec18a3..4deb881 100644
--- a/deps/boringssl/src/tool/args.cc
+++ b/deps/boringssl/src/tool/args.cc
@@ -15,6 +15,7 @@
#include <string>
#include <vector>
+#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -92,13 +93,16 @@ bool GetUnsigned(unsigned *out, const std::string &arg_name,
return false;
}
+ errno = 0;
char *endptr;
unsigned long int num = strtoul(value.c_str(), &endptr, 10);
- if (*endptr ||
- num > UINT_MAX) {
+ if (num == ULONG_MAX && errno == ERANGE) {
return false;
}
+ if (*endptr != 0 || num > UINT_MAX) {
+ return false;
+ }
+ *out = static_cast<unsigned>(num);
- *out = num;
return true;
}
diff --git a/deps/boringssl/src/tool/client.cc b/deps/boringssl/src/tool/client.cc
index 31378d6..4301c22 100644
--- a/deps/boringssl/src/tool/client.cc
+++ b/deps/boringssl/src/tool/client.cc
@@ -64,6 +64,13 @@ static const struct argument kArguments[] = {
"-server-name", kOptionalArgument, "The server name to advertise",
},
{
+ "-ech-grease", kBooleanArgument, "Enable ECH GREASE",
+ },
+ {
+ "-ech-config-list", kOptionalArgument,
+ "Path to file containing serialized ECHConfigs",
+ },
+ {
"-select-next-proto", kOptionalArgument,
"An NPN protocol to select if the server supports NPN",
},
@@ -116,6 +123,11 @@ static const struct argument kArguments[] = {
"-grease", kBooleanArgument, "Enable GREASE",
},
{
+ "-permute-extensions",
+ kBooleanArgument,
+ "Permute extensions in handshake messages",
+ },
+ {
"-test-resumption", kBooleanArgument,
"Connect to the server twice. The first connection is closed once a "
"session is established. The second connection offers it.",
@@ -265,6 +277,24 @@ static bool DoConnection(SSL_CTX *ctx,
SSL_set_tlsext_host_name(ssl.get(), args_map["-server-name"].c_str());
}
+ if (args_map.count("-ech-grease") != 0) {
+ SSL_set_enable_ech_grease(ssl.get(), 1);
+ }
+
+ if (args_map.count("-ech-config-list") != 0) {
+ const char *filename = args_map["-ech-config-list"].c_str();
+ ScopedFILE f(fopen(filename, "rb"));
+ std::vector<uint8_t> data;
+ if (f == nullptr || !ReadAll(&data, f.get())) {
+ fprintf(stderr, "Error reading %s.\n", filename);
+ return false;
+ }
+ if (!SSL_set1_ech_config_list(ssl.get(), data.data(), data.size())) {
+ fprintf(stderr, "Error setting ECHConfigList\n");
+ return false;
+ }
+ }
+
if (args_map.count("-session-in") != 0) {
bssl::UniquePtr<BIO> in(BIO_new_file(args_map["-session-in"].c_str(),
"rb"));
@@ -313,15 +343,17 @@ static bool DoConnection(SSL_CTX *ctx,
}
early_data = std::string(data.begin(), data.end());
}
- int ed_size = early_data.size();
- int ssl_ret = SSL_write(ssl.get(), early_data.data(), ed_size);
- if (ssl_ret <= 0) {
- int ssl_err = SSL_get_error(ssl.get(), ssl_ret);
- PrintSSLError(stderr, "Error while writing", ssl_err, ssl_ret);
- return false;
- } else if (ssl_ret != ed_size) {
- fprintf(stderr, "Short write from SSL_write.\n");
- return false;
+ if (!early_data.empty()) {
+ int ed_size = early_data.size();
+ int ssl_ret = SSL_write(ssl.get(), early_data.data(), ed_size);
+ if (ssl_ret <= 0) {
+ int ssl_err = SSL_get_error(ssl.get(), ssl_ret);
+ PrintSSLError(stderr, "Error while writing", ssl_err, ssl_ret);
+ return false;
+ } else if (ssl_ret != ed_size) {
+ fprintf(stderr, "Short write from SSL_write.\n");
+ return false;
+ }
}
}
@@ -504,6 +536,10 @@ bool Client(const std::vector<std::string> &args) {
SSL_CTX_set_grease_enabled(ctx.get(), 1);
}
+ if (args_map.count("-permute-extensions") != 0) {
+ SSL_CTX_set_permute_extensions(ctx.get(), 1);
+ }
+
if (args_map.count("-root-certs") != 0) {
if (!SSL_CTX_load_verify_locations(
ctx.get(), args_map["-root-certs"].c_str(), nullptr)) {
diff --git a/deps/boringssl/src/tool/file.cc b/deps/boringssl/src/tool/file.cc
index 9b5ff1b..8d74e63 100644
--- a/deps/boringssl/src/tool/file.cc
+++ b/deps/boringssl/src/tool/file.cc
@@ -12,7 +12,11 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#include <openssl/bytestring.h>
+
+#include <errno.h>
#include <stdio.h>
+#include <string.h>
#include <algorithm>
#include <vector>
@@ -48,3 +52,17 @@ bool ReadAll(std::vector<uint8_t> *out, FILE *file) {
}
}
}
+
+bool WriteToFile(const std::string &path, bssl::Span<const uint8_t> in) {
+ ScopedFILE file(fopen(path.c_str(), "wb"));
+ if (!file) {
+ fprintf(stderr, "Failed to open '%s': %s\n", path.c_str(), strerror(errno));
+ return false;
+ }
+ if (fwrite(in.data(), in.size(), 1, file.get()) != 1) {
+ fprintf(stderr, "Failed to write to '%s': %s\n", path.c_str(),
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
diff --git a/deps/boringssl/src/tool/generate_ech.cc b/deps/boringssl/src/tool/generate_ech.cc
new file mode 100644
index 0000000..f1e8cbe
--- /dev/null
+++ b/deps/boringssl/src/tool/generate_ech.cc
@@ -0,0 +1,133 @@
+/* Copyright (c) 2021, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+
+#include <limits>
+#include <vector>
+
+#include <openssl/bytestring.h>
+#include <openssl/hpke.h>
+#include <openssl/span.h>
+#include <openssl/ssl.h>
+
+#include "internal.h"
+
+
+static const struct argument kArguments[] = {
+ {
+ "-out-ech-config-list",
+ kRequiredArgument,
+ "The path where the ECHConfigList should be written.",
+ },
+ {
+ "-out-ech-config",
+ kRequiredArgument,
+ "The path where the ECHConfig should be written.",
+ },
+ {
+ "-out-private-key",
+ kRequiredArgument,
+ "The path where the private key should be written.",
+ },
+ {
+ "-public-name",
+ kRequiredArgument,
+ "The public name for the new ECHConfig.",
+ },
+ {
+ "-config-id",
+ kRequiredArgument,
+ "The config ID for the new ECHConfig, from 0 to 255. Config IDs may be "
+ "reused, but should be unique among active configs on a server for "
+ "performance.",
+ },
+ {
+ "-max-name-length",
+ kOptionalArgument,
+ "The length of the longest name in the anonymity set, to guide client "
+ "padding.",
+ },
+ {
+ "",
+ kOptionalArgument,
+ "",
+ },
+};
+
+bool GenerateECH(const std::vector<std::string> &args) {
+ std::map<std::string, std::string> args_map;
+ if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
+ PrintUsage(kArguments);
+ return false;
+ }
+
+ unsigned config_id;
+ if (!GetUnsigned(&config_id, "-config-id", 0, args_map) ||
+ config_id > std::numeric_limits<uint8_t>::max()) {
+ fprintf(stderr, "Error parsing -config-id argument\n");
+ return false;
+ }
+
+ unsigned max_name_len = 0;
+ if (args_map.count("-max-name-length") != 0 &&
+ !GetUnsigned(&max_name_len, "-max-name-length", 0, args_map)) {
+ fprintf(stderr, "Error parsing -max-name-length argument\n");
+ return false;
+ }
+
+ bssl::ScopedEVP_HPKE_KEY key;
+ uint8_t public_key[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH];
+ uint8_t private_key[EVP_HPKE_MAX_PRIVATE_KEY_LENGTH];
+ size_t public_key_len, private_key_len;
+ if (!EVP_HPKE_KEY_generate(key.get(), EVP_hpke_x25519_hkdf_sha256()) ||
+ !EVP_HPKE_KEY_public_key(key.get(), public_key, &public_key_len,
+ sizeof(public_key)) ||
+ !EVP_HPKE_KEY_private_key(key.get(), private_key, &private_key_len,
+ sizeof(private_key))) {
+ fprintf(stderr, "Failed to generate the HPKE keypair\n");
+ return false;
+ }
+
+ uint8_t *ech_config;
+ size_t ech_config_len;
+ if (!SSL_marshal_ech_config(
+ &ech_config, &ech_config_len, static_cast<uint8_t>(config_id),
+ key.get(), args_map["-public-name"].c_str(), size_t{max_name_len})) {
+ fprintf(stderr, "Failed to serialize the ECHConfigList\n");
+ return false;
+ }
+ bssl::UniquePtr<uint8_t> free_ech_config(ech_config);
+
+ bssl::ScopedCBB cbb;
+ CBB body;
+ if (!CBB_init(cbb.get(), ech_config_len + sizeof(uint16_t)) ||
+ !CBB_add_u16_length_prefixed(cbb.get(), &body) ||
+ !CBB_add_bytes(&body, ech_config, ech_config_len) ||
+ !CBB_flush(cbb.get())) {
+ fprintf(stderr, "Failed to serialize the ECHConfigList\n");
+ return false;
+ }
+ if (!WriteToFile(
+ args_map["-out-ech-config-list"],
+ bssl::MakeConstSpan(CBB_data(cbb.get()), CBB_len(cbb.get()))) ||
+ !WriteToFile(args_map["-out-ech-config"],
+ bssl::MakeConstSpan(ech_config, ech_config_len)) ||
+ !WriteToFile(args_map["-out-private-key"],
+ bssl::MakeConstSpan(private_key, private_key_len))) {
+ fprintf(stderr, "Failed to write ECHConfig or private key to file\n");
+ return false;
+ }
+ return true;
+}
diff --git a/deps/boringssl/src/tool/generate_ed25519.cc b/deps/boringssl/src/tool/generate_ed25519.cc
index 6499dbe..8920099 100644
--- a/deps/boringssl/src/tool/generate_ed25519.cc
+++ b/deps/boringssl/src/tool/generate_ed25519.cc
@@ -34,21 +34,6 @@ static const struct argument kArguments[] = {
},
};
-static bool WriteToFile(const std::string &path, const uint8_t *in,
- size_t in_len) {
- ScopedFILE file(fopen(path.c_str(), "wb"));
- if (!file) {
- fprintf(stderr, "Failed to open '%s': %s\n", path.c_str(), strerror(errno));
- return false;
- }
- if (fwrite(in, in_len, 1, file.get()) != 1) {
- fprintf(stderr, "Failed to write to '%s': %s\n", path.c_str(),
- strerror(errno));
- return false;
- }
- return true;
-}
-
bool GenerateEd25519Key(const std::vector<std::string> &args) {
std::map<std::string, std::string> args_map;
@@ -60,7 +45,6 @@ bool GenerateEd25519Key(const std::vector<std::string> &args) {
uint8_t public_key[32], private_key[64];
ED25519_keypair(public_key, private_key);
- return WriteToFile(args_map["-out-public"], public_key, sizeof(public_key)) &&
- WriteToFile(args_map["-out-private"], private_key,
- sizeof(private_key));
+ return WriteToFile(args_map["-out-public"], public_key) &&
+ WriteToFile(args_map["-out-private"], private_key);
}
diff --git a/deps/boringssl/src/tool/internal.h b/deps/boringssl/src/tool/internal.h
index eb9e4ba..7f3692a 100644
--- a/deps/boringssl/src/tool/internal.h
+++ b/deps/boringssl/src/tool/internal.h
@@ -16,6 +16,7 @@
#define OPENSSL_HEADER_TOOL_INTERNAL_H
#include <openssl/base.h>
+#include <openssl/span.h>
#include <string>
#include <utility>
@@ -120,10 +121,12 @@ bool GetUnsigned(unsigned *out, const std::string &arg_name,
const std::map<std::string, std::string> &args);
bool ReadAll(std::vector<uint8_t> *out, FILE *in);
+bool WriteToFile(const std::string &path, bssl::Span<const uint8_t> in);
bool Ciphers(const std::vector<std::string> &args);
bool Client(const std::vector<std::string> &args);
bool DoPKCS12(const std::vector<std::string> &args);
+bool GenerateECH(const std::vector<std::string> &args);
bool GenerateEd25519Key(const std::vector<std::string> &args);
bool GenerateRSAKey(const std::vector<std::string> &args);
bool MD5Sum(const std::vector<std::string> &args);
diff --git a/deps/boringssl/src/tool/server.cc b/deps/boringssl/src/tool/server.cc
index 989d335..18b692d 100644
--- a/deps/boringssl/src/tool/server.cc
+++ b/deps/boringssl/src/tool/server.cc
@@ -17,6 +17,7 @@
#include <memory>
#include <openssl/err.h>
+#include <openssl/hpke.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
@@ -61,6 +62,16 @@ static const struct argument kArguments[] = {
"-ocsp-response", kOptionalArgument, "OCSP response file to send",
},
{
+ "-ech-key",
+ kOptionalArgument,
+ "File containing the private key corresponding to the ECHConfig.",
+ },
+ {
+ "-ech-config",
+ kOptionalArgument,
+ "File containing one ECHConfig.",
+ },
+ {
"-loop", kBooleanArgument,
"The server will continue accepting new sequential connections.",
},
@@ -261,6 +272,47 @@ bool Server(const std::vector<std::string> &args) {
}
}
+ if (args_map.count("-ech-key") + args_map.count("-ech-config") == 1) {
+ fprintf(stderr,
+ "-ech-config and -ech-key must be specified together.\n");
+ return false;
+ }
+
+ if (args_map.count("-ech-key") != 0) {
+ // Load the ECH private key.
+ std::string ech_key_path = args_map["-ech-key"];
+ ScopedFILE ech_key_file(fopen(ech_key_path.c_str(), "rb"));
+ std::vector<uint8_t> ech_key;
+ if (ech_key_file == nullptr ||
+ !ReadAll(&ech_key, ech_key_file.get())) {
+ fprintf(stderr, "Error reading %s\n", ech_key_path.c_str());
+ return false;
+ }
+
+ // Load the ECHConfig.
+ std::string ech_config_path = args_map["-ech-config"];
+ ScopedFILE ech_config_file(fopen(ech_config_path.c_str(), "rb"));
+ std::vector<uint8_t> ech_config;
+ if (ech_config_file == nullptr ||
+ !ReadAll(&ech_config, ech_config_file.get())) {
+ fprintf(stderr, "Error reading %s\n", ech_config_path.c_str());
+ return false;
+ }
+
+ bssl::UniquePtr<SSL_ECH_KEYS> keys(SSL_ECH_KEYS_new());
+ bssl::ScopedEVP_HPKE_KEY key;
+ if (!keys ||
+ !EVP_HPKE_KEY_init(key.get(), EVP_hpke_x25519_hkdf_sha256(),
+ ech_key.data(), ech_key.size()) ||
+ !SSL_ECH_KEYS_add(keys.get(),
+ /*is_retry_config=*/1, ech_config.data(),
+ ech_config.size(), key.get()) ||
+ !SSL_CTX_set1_ech_keys(ctx.get(), keys.get())) {
+ fprintf(stderr, "Error setting server's ECHConfig and private key\n");
+ return false;
+ }
+ }
+
if (args_map.count("-cipher") != 0 &&
!SSL_CTX_set_strict_cipher_list(ctx.get(), args_map["-cipher"].c_str())) {
fprintf(stderr, "Failed setting cipher list\n");
diff --git a/deps/boringssl/src/tool/speed.cc b/deps/boringssl/src/tool/speed.cc
index 1b89b42..613e630 100644
--- a/deps/boringssl/src/tool/speed.cc
+++ b/deps/boringssl/src/tool/speed.cc
@@ -270,6 +270,16 @@ static bool SpeedRSA(const std::string &selected) {
return false;
}
results.Print(name + " verify (fresh key)");
+
+ if (!TimeFunction(&results, [&]() -> bool {
+ return bssl::UniquePtr<RSA>(RSA_private_key_from_bytes(
+ kRSAKeys[i].key, kRSAKeys[i].key_len)) != nullptr;
+ })) {
+ fprintf(stderr, "Failed to parse %s key.\n", name.c_str());
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+ results.Print(name + " private key parse");
}
return true;
@@ -342,12 +352,6 @@ static bool SpeedRSAKeyGen(const std::string &selected) {
return true;
}
-static uint8_t *align(uint8_t *in, unsigned alignment) {
- return reinterpret_cast<uint8_t *>(
- (reinterpret_cast<uintptr_t>(in) + alignment) &
- ~static_cast<size_t>(alignment - 1));
-}
-
static std::string ChunkLenSuffix(size_t chunk_len) {
char buf[32];
snprintf(buf, sizeof(buf), " (%zu byte%s)", chunk_len,
@@ -384,13 +388,17 @@ static bool SpeedAEADChunk(const EVP_AEAD *aead, std::string name,
new uint8_t[overhead_len + kAlignment]);
- uint8_t *const in = align(in_storage.get(), kAlignment);
+ uint8_t *const in =
+ static_cast<uint8_t *>(align_pointer(in_storage.get(), kAlignment));
OPENSSL_memset(in, 0, chunk_len);
- uint8_t *const out = align(out_storage.get(), kAlignment);
+ uint8_t *const out =
+ static_cast<uint8_t *>(align_pointer(out_storage.get(), kAlignment));
OPENSSL_memset(out, 0, chunk_len + overhead_len);
- uint8_t *const tag = align(tag_storage.get(), kAlignment);
+ uint8_t *const tag =
+ static_cast<uint8_t *>(align_pointer(tag_storage.get(), kAlignment));
OPENSSL_memset(tag, 0, overhead_len);
- uint8_t *const in2 = align(in2_storage.get(), kAlignment);
+ uint8_t *const in2 =
+ static_cast<uint8_t *>(align_pointer(in2_storage.get(), kAlignment));
if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.get(), key_len,
EVP_AEAD_DEFAULT_TAG_LENGTH,
@@ -898,13 +906,12 @@ static bool SpeedHRSS(const std::string &selected) {
TimeResults results;
if (!TimeFunction(&results, []() -> bool {
- struct HRSS_public_key pub;
- struct HRSS_private_key priv;
- uint8_t entropy[HRSS_GENERATE_KEY_BYTES];
- RAND_bytes(entropy, sizeof(entropy));
- HRSS_generate_key(&pub, &priv, entropy);
- return true;
- })) {
+ struct HRSS_public_key pub;
+ struct HRSS_private_key priv;
+ uint8_t entropy[HRSS_GENERATE_KEY_BYTES];
+ RAND_bytes(entropy, sizeof(entropy));
+ return HRSS_generate_key(&pub, &priv, entropy);
+ })) {
fprintf(stderr, "Failed to time HRSS_generate_key.\n");
return false;
}
@@ -915,16 +922,17 @@ static bool SpeedHRSS(const std::string &selected) {
struct HRSS_private_key priv;
uint8_t key_entropy[HRSS_GENERATE_KEY_BYTES];
RAND_bytes(key_entropy, sizeof(key_entropy));
- HRSS_generate_key(&pub, &priv, key_entropy);
+ if (!HRSS_generate_key(&pub, &priv, key_entropy)) {
+ return false;
+ }
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES];
if (!TimeFunction(&results, [&pub, &ciphertext]() -> bool {
- uint8_t entropy[HRSS_ENCAP_BYTES];
- uint8_t shared_key[HRSS_KEY_BYTES];
- RAND_bytes(entropy, sizeof(entropy));
- HRSS_encap(ciphertext, shared_key, &pub, entropy);
- return true;
- })) {
+ uint8_t entropy[HRSS_ENCAP_BYTES];
+ uint8_t shared_key[HRSS_KEY_BYTES];
+ RAND_bytes(entropy, sizeof(entropy));
+ return HRSS_encap(ciphertext, shared_key, &pub, entropy);
+ })) {
fprintf(stderr, "Failed to time HRSS_encap.\n");
return false;
}
@@ -932,10 +940,9 @@ static bool SpeedHRSS(const std::string &selected) {
results.Print("HRSS encap");
if (!TimeFunction(&results, [&priv, &ciphertext]() -> bool {
- uint8_t shared_key[HRSS_KEY_BYTES];
- HRSS_decap(shared_key, &priv, ciphertext, sizeof(ciphertext));
- return true;
- })) {
+ uint8_t shared_key[HRSS_KEY_BYTES];
+ return HRSS_decap(shared_key, &priv, ciphertext, sizeof(ciphertext));
+ })) {
fprintf(stderr, "Failed to time HRSS_encap.\n");
return false;
}
diff --git a/deps/boringssl/src/tool/tool.cc b/deps/boringssl/src/tool/tool.cc
index d278535..7bec7a2 100644
--- a/deps/boringssl/src/tool/tool.cc
+++ b/deps/boringssl/src/tool/tool.cc
@@ -45,6 +45,7 @@ static const Tool kTools[] = {
{ "ciphers", Ciphers },
{ "client", Client },
{ "isfips", IsFIPS },
+ { "generate-ech", GenerateECH},
{ "generate-ed25519", GenerateEd25519Key },
{ "genrsa", GenerateRSAKey },
{ "md5sum", MD5Sum },
diff --git a/deps/boringssl/src/tool/transport_common.cc b/deps/boringssl/src/tool/transport_common.cc
index b985221..cba3c7b 100644
--- a/deps/boringssl/src/tool/transport_common.cc
+++ b/deps/boringssl/src/tool/transport_common.cc
@@ -335,6 +335,9 @@ void PrintConnectionInfo(BIO *bio, const SSL *ssl) {
bio, " Early data: %s\n",
(SSL_early_data_accepted(ssl) || SSL_in_early_data(ssl)) ? "yes" : "no");
+ BIO_printf(bio, " Encrypted ClientHello: %s\n",
+ SSL_ech_accepted(ssl) ? "yes" : "no");
+
// Print the server cert subject and issuer names.
bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(ssl));
if (peer != nullptr) {
diff --git a/deps/boringssl/src/util/fipstools/acvp/modulewrapper/CMakeLists.txt b/deps/boringssl/src/util/fipstools/acvp/modulewrapper/CMakeLists.txt
index 8bee5cd..267f82c 100644
--- a/deps/boringssl/src/util/fipstools/acvp/modulewrapper/CMakeLists.txt
+++ b/deps/boringssl/src/util/fipstools/acvp/modulewrapper/CMakeLists.txt
@@ -4,6 +4,7 @@ if(FIPS)
add_executable(
modulewrapper
+ main.cc
modulewrapper.cc
)
diff --git a/deps/boringssl/src/util/fipstools/acvp/modulewrapper/main.cc b/deps/boringssl/src/util/fipstools/acvp/modulewrapper/main.cc
new file mode 100644
index 0000000..a903361
--- /dev/null
+++ b/deps/boringssl/src/util/fipstools/acvp/modulewrapper/main.cc
@@ -0,0 +1,75 @@
+/* Copyright (c) 2021, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+#include <string>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/crypto.h>
+#include <openssl/span.h>
+
+#include "modulewrapper.h"
+
+
+int main(int argc, char **argv) {
+ if (argc == 2 && strcmp(argv[1], "--version") == 0) {
+ printf("Built for architecture: ");
+
+#if defined(OPENSSL_X86_64)
+ puts("x86-64 (64-bit)");
+#elif defined(OPENSSL_ARM)
+ puts("ARM (32-bit)");
+#elif defined(OPENSSL_AARCH64)
+ puts("aarch64 (64-bit)");
+#elif defined(OPENSSL_PPC64LE)
+ puts("PPC64LE (64-bit)");
+#else
+#error "FIPS build not supported on this architecture"
+#endif
+
+ printf("Hardware acceleration enabled: %s\n",
+ CRYPTO_has_asm() ? "yes" : "no");
+
+ return 0;
+ } else if (argc != 1) {
+ fprintf(stderr, "Usage: %s [--version]\n", argv[0]);
+ return 4;
+ }
+
+ std::unique_ptr<bssl::acvp::RequestBuffer> buffer =
+ bssl::acvp::RequestBuffer::New();
+ const bssl::acvp::ReplyCallback write_reply = std::bind(
+ bssl::acvp::WriteReplyToFd, STDOUT_FILENO, std::placeholders::_1);
+
+ for (;;) {
+ const bssl::Span<const bssl::Span<const uint8_t>> args =
+ ParseArgsFromFd(STDIN_FILENO, buffer.get());
+ if (args.empty()) {
+ return 1;
+ }
+
+ const bssl::acvp::Handler handler = bssl::acvp::FindHandler(args);
+ if (!handler) {
+ return 2;
+ }
+
+ if (!handler(args.subspan(1).data(), write_reply)) {
+ const std::string name(reinterpret_cast<const char *>(args[0].data()),
+ args[0].size());
+ fprintf(stderr, "\'%s\' operation failed.\n", name.c_str());
+ return 3;
+ }
+ }
+};
diff --git a/deps/boringssl/src/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/deps/boringssl/src/util/fipstools/acvp/modulewrapper/modulewrapper.cc
index 06eac8b..1974dce 100644
--- a/deps/boringssl/src/util/fipstools/acvp/modulewrapper/modulewrapper.cc
+++ b/deps/boringssl/src/util/fipstools/acvp/modulewrapper/modulewrapper.cc
@@ -45,15 +45,35 @@
#include "../../../../crypto/fipsmodule/ec/internal.h"
#include "../../../../crypto/fipsmodule/rand/internal.h"
#include "../../../../crypto/fipsmodule/tls/internal.h"
+#include "modulewrapper.h"
-static constexpr size_t kMaxArgs = 8;
-static constexpr size_t kMaxArgLength = (1 << 20);
-static constexpr size_t kMaxNameLength = 30;
-static_assert((kMaxArgs - 1 * kMaxArgLength) + kMaxNameLength > (1 << 30),
- "Argument limits permit excessive messages");
+namespace bssl {
+namespace acvp {
-using namespace bssl;
+#if defined(OPENSSL_TRUSTY)
+#include <trusty_log.h>
+#define LOG_ERROR(...) TLOGE(__VA_ARGS__)
+#else
+#define LOG_ERROR(...) fprintf(stderr, __VA_ARGS__)
+#endif // OPENSSL_TRUSTY
+
+constexpr size_t kMaxArgLength = (1 << 20);
+
+RequestBuffer::~RequestBuffer() = default;
+
+class RequestBufferImpl : public RequestBuffer {
+ public:
+ ~RequestBufferImpl() = default;
+
+ std::vector<uint8_t> buf;
+ Span<const uint8_t> args[kMaxArgs];
+};
+
+// static
+std::unique_ptr<RequestBuffer> RequestBuffer::New() {
+ return std::unique_ptr<RequestBuffer>(new RequestBufferImpl);
+}
static bool ReadAll(int fd, void *in_data, size_t data_len) {
uint8_t *data = reinterpret_cast<uint8_t *>(in_data);
@@ -75,9 +95,74 @@ static bool ReadAll(int fd, void *in_data, size_t data_len) {
return true;
}
-template <typename... Args>
-static bool WriteReply(int fd, Args... args) {
- std::vector<Span<const uint8_t>> spans = {args...};
+Span<const Span<const uint8_t>> ParseArgsFromFd(int fd,
+ RequestBuffer *in_buffer) {
+ RequestBufferImpl *buffer = reinterpret_cast<RequestBufferImpl *>(in_buffer);
+ uint32_t nums[1 + kMaxArgs];
+ const Span<const Span<const uint8_t>> empty_span;
+
+ if (!ReadAll(fd, nums, sizeof(uint32_t) * 2)) {
+ return empty_span;
+ }
+
+ const size_t num_args = nums[0];
+ if (num_args == 0) {
+ LOG_ERROR("Invalid, zero-argument operation requested.\n");
+ return empty_span;
+ } else if (num_args > kMaxArgs) {
+ LOG_ERROR("Operation requested with %zu args, but %zu is the limit.\n",
+ num_args, kMaxArgs);
+ return empty_span;
+ }
+
+ if (num_args > 1 &&
+ !ReadAll(fd, &nums[2], sizeof(uint32_t) * (num_args - 1))) {
+ return empty_span;
+ }
+
+ size_t need = 0;
+ for (size_t i = 0; i < num_args; i++) {
+ const size_t arg_length = nums[i + 1];
+ if (i == 0 && arg_length > kMaxNameLength) {
+ LOG_ERROR("Operation with name of length %zu exceeded limit of %zu.\n",
+ arg_length, kMaxNameLength);
+ return empty_span;
+ } else if (arg_length > kMaxArgLength) {
+ LOG_ERROR(
+ "Operation with argument of length %zu exceeded limit of %zu.\n",
+ arg_length, kMaxArgLength);
+ return empty_span;
+ }
+
+ // This static_assert confirms that the following addition doesn't
+ // overflow.
+ static_assert((kMaxArgs - 1 * kMaxArgLength) + kMaxNameLength > (1 << 30),
+ "Argument limits permit excessive messages");
+ need += arg_length;
+ }
+
+ if (need > buffer->buf.size()) {
+ size_t alloced = need + (need >> 1);
+ if (alloced < need) {
+ abort();
+ }
+ buffer->buf.resize(alloced);
+ }
+
+ if (!ReadAll(fd, buffer->buf.data(), need)) {
+ return empty_span;
+ }
+
+ size_t offset = 0;
+ for (size_t i = 0; i < num_args; i++) {
+ buffer->args[i] = Span<const uint8_t>(&buffer->buf[offset], nums[i + 1]);
+ offset += nums[i + 1];
+ }
+
+ return Span<const Span<const uint8_t>>(buffer->args, num_args);
+}
+
+bool WriteReplyToFd(int fd, const std::vector<Span<const uint8_t>> &spans) {
if (spans.empty() || spans.size() > kMaxArgs) {
abort();
}
@@ -136,7 +221,7 @@ static bool WriteReply(int fd, Args... args) {
return true;
}
-static bool GetConfig(const Span<const uint8_t> args[]) {
+static bool GetConfig(const Span<const uint8_t> args[], ReplyCallback write_reply) {
static constexpr char kConfig[] =
R"([
{
@@ -221,6 +306,21 @@ static bool GetConfig(const Span<const uint8_t> args[]) {
"ivGen": "external"
},
{
+ "algorithm": "ACVP-AES-GMAC",
+ "revision": "1.0",
+ "direction": ["encrypt", "decrypt"],
+ "keyLen": [128, 192, 256],
+ "payloadLen": [{
+ "min": 0, "max": 256, "increment": 8
+ }],
+ "aadLen": [{
+ "min": 0, "max": 320, "increment": 8
+ }],
+ "tagLen": [32, 64, 96, 104, 112, 120, 128],
+ "ivLen": [96],
+ "ivGen": "external"
+ },
+ {
"algorithm": "ACVP-AES-KW",
"revision": "1.0",
"direction": [
@@ -402,6 +502,7 @@ static bool GetConfig(const Span<const uint8_t> args[]) {
"P-521"
],
"hashAlg": [
+ "SHA-1",
"SHA2-224",
"SHA2-256",
"SHA2-384",
@@ -676,9 +777,10 @@ static bool GetConfig(const Span<const uint8_t> args[]) {
},
{
"algorithm": "CMAC-AES",
+ "acvptoolTestOnly": true,
"revision": "1.0",
"capabilities": [{
- "direction": ["gen"],
+ "direction": ["gen", "ver"],
"msgLen": [{
"min": 0,
"max": 65536,
@@ -715,6 +817,12 @@ static bool GetConfig(const Span<const uint8_t> args[]) {
"initiator",
"responder"
]
+ },
+ "staticUnified": {
+ "kasRole": [
+ "initiator",
+ "responder"
+ ]
}
},
"domainParameterGenerationMethods": [
@@ -740,35 +848,57 @@ static bool GetConfig(const Span<const uint8_t> args[]) {
]
}
])";
- return WriteReply(
- STDOUT_FILENO,
- Span<const uint8_t>(reinterpret_cast<const uint8_t *>(kConfig),
- sizeof(kConfig) - 1));
+ return write_reply({Span<const uint8_t>(
+ reinterpret_cast<const uint8_t *>(kConfig), sizeof(kConfig) - 1)});
}
template <uint8_t *(*OneShotHash)(const uint8_t *, size_t, uint8_t *),
size_t DigestLength>
-static bool Hash(const Span<const uint8_t> args[]) {
+static bool Hash(const Span<const uint8_t> args[], ReplyCallback write_reply) {
uint8_t digest[DigestLength];
OneShotHash(args[0].data(), args[0].size(), digest);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(digest));
+ return write_reply({Span<const uint8_t>(digest)});
+}
+
+template <uint8_t *(*OneShotHash)(const uint8_t *, size_t, uint8_t *),
+ size_t DigestLength>
+static bool HashMCT(const Span<const uint8_t> args[],
+ ReplyCallback write_reply) {
+ if (args[0].size() != DigestLength) {
+ return false;
+ }
+
+ uint8_t buf[DigestLength * 3];
+ memcpy(buf, args[0].data(), DigestLength);
+ memcpy(buf + DigestLength, args[0].data(), DigestLength);
+ memcpy(buf + 2 * DigestLength, args[0].data(), DigestLength);
+
+ for (size_t i = 0; i < 1000; i++) {
+ uint8_t digest[DigestLength];
+ OneShotHash(buf, sizeof(buf), digest);
+ memmove(buf, buf + DigestLength, DigestLength * 2);
+ memcpy(buf + DigestLength * 2, digest, DigestLength);
+ }
+
+ return write_reply(
+ {Span<const uint8_t>(buf + 2 * DigestLength, DigestLength)});
}
static uint32_t GetIterations(const Span<const uint8_t> iterations_bytes) {
uint32_t iterations;
if (iterations_bytes.size() != sizeof(iterations)) {
- fprintf(stderr,
- "Expected %u-byte input for number of iterations, but found %u "
- "bytes.\n",
- static_cast<unsigned>(sizeof(iterations)),
- static_cast<unsigned>(iterations_bytes.size()));
+ LOG_ERROR(
+ "Expected %u-byte input for number of iterations, but found %u "
+ "bytes.\n",
+ static_cast<unsigned>(sizeof(iterations)),
+ static_cast<unsigned>(iterations_bytes.size()));
abort();
}
memcpy(&iterations, iterations_bytes.data(), sizeof(iterations));
if (iterations == 0 || iterations == UINT32_MAX) {
- fprintf(stderr, "Invalid number of iterations: %x.\n",
- static_cast<unsigned>(iterations));
+ LOG_ERROR("Invalid number of iterations: %x.\n",
+ static_cast<unsigned>(iterations));
abort();
}
@@ -777,7 +907,7 @@ static uint32_t GetIterations(const Span<const uint8_t> iterations_bytes) {
template <int (*SetKey)(const uint8_t *key, unsigned bits, AES_KEY *out),
void (*Block)(const uint8_t *in, uint8_t *out, const AES_KEY *key)>
-static bool AES(const Span<const uint8_t> args[]) {
+static bool AES(const Span<const uint8_t> args[], ReplyCallback write_reply) {
AES_KEY key;
if (SetKey(args[0].data(), args[0].size() * 8, &key) != 0) {
return false;
@@ -799,13 +929,13 @@ static bool AES(const Span<const uint8_t> args[]) {
}
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(result),
- Span<const uint8_t>(prev_result));
+ return write_reply(
+ {Span<const uint8_t>(result), Span<const uint8_t>(prev_result)});
}
template <int (*SetKey)(const uint8_t *key, unsigned bits, AES_KEY *out),
int Direction>
-static bool AES_CBC(const Span<const uint8_t> args[]) {
+static bool AES_CBC(const Span<const uint8_t> args[], ReplyCallback write_reply) {
AES_KEY key;
if (SetKey(args[0].data(), args[0].size() * 8, &key) != 0) {
return false;
@@ -848,15 +978,15 @@ static bool AES_CBC(const Span<const uint8_t> args[]) {
}
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(result),
- Span<const uint8_t>(prev_result));
+ return write_reply(
+ {Span<const uint8_t>(result), Span<const uint8_t>(prev_result)});
}
-static bool AES_CTR(const Span<const uint8_t> args[]) {
+static bool AES_CTR(const Span<const uint8_t> args[], ReplyCallback write_reply) {
static const uint32_t kOneIteration = 1;
if (args[3].size() != sizeof(kOneIteration) ||
memcmp(args[3].data(), &kOneIteration, sizeof(kOneIteration))) {
- fprintf(stderr, "Only a single iteration supported with AES-CTR\n");
+ LOG_ERROR("Only a single iteration supported with AES-CTR\n");
return false;
}
@@ -870,7 +1000,7 @@ static bool AES_CTR(const Span<const uint8_t> args[]) {
uint8_t iv[AES_BLOCK_SIZE];
memcpy(iv, args[2].data(), AES_BLOCK_SIZE);
if (GetIterations(args[3]) != 1) {
- fprintf(stderr, "Multiple iterations of AES-CTR is not supported.\n");
+ LOG_ERROR("Multiple iterations of AES-CTR is not supported.\n");
return false;
}
@@ -880,15 +1010,15 @@ static bool AES_CTR(const Span<const uint8_t> args[]) {
uint8_t ecount_buf[AES_BLOCK_SIZE];
AES_ctr128_encrypt(args[1].data(), out.data(), args[1].size(), &key, iv,
ecount_buf, &num);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
static bool AESGCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key) {
uint32_t tag_len_32;
if (tag_len_span.size() != sizeof(tag_len_32)) {
- fprintf(stderr, "Tag size value is %u bytes, not an uint32_t\n",
- static_cast<unsigned>(tag_len_span.size()));
+ LOG_ERROR("Tag size value is %u bytes, not an uint32_t\n",
+ static_cast<unsigned>(tag_len_span.size()));
return false;
}
memcpy(&tag_len_32, tag_len_span.data(), sizeof(tag_len_32));
@@ -905,15 +1035,14 @@ static bool AESGCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
aead = EVP_aead_aes_256_gcm();
break;
default:
- fprintf(stderr, "Bad AES-GCM key length %u\n",
- static_cast<unsigned>(key.size()));
+ LOG_ERROR("Bad AES-GCM key length %u\n", static_cast<unsigned>(key.size()));
return false;
}
if (!EVP_AEAD_CTX_init(ctx, aead, key.data(), key.size(), tag_len_32,
nullptr)) {
- fprintf(stderr, "Failed to setup AES-GCM with tag length %u\n",
- static_cast<unsigned>(tag_len_32));
+ LOG_ERROR("Failed to setup AES-GCM with tag length %u\n",
+ static_cast<unsigned>(tag_len_32));
return false;
}
@@ -924,28 +1053,27 @@ static bool AESCCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key) {
uint32_t tag_len_32;
if (tag_len_span.size() != sizeof(tag_len_32)) {
- fprintf(stderr, "Tag size value is %u bytes, not an uint32_t\n",
- static_cast<unsigned>(tag_len_span.size()));
+ LOG_ERROR("Tag size value is %u bytes, not an uint32_t\n",
+ static_cast<unsigned>(tag_len_span.size()));
return false;
}
memcpy(&tag_len_32, tag_len_span.data(), sizeof(tag_len_32));
if (tag_len_32 != 4) {
- fprintf(stderr, "AES-CCM only supports 4-byte tags, but %u was requested\n",
- static_cast<unsigned>(tag_len_32));
+ LOG_ERROR("AES-CCM only supports 4-byte tags, but %u was requested\n",
+ static_cast<unsigned>(tag_len_32));
return false;
}
if (key.size() != 16) {
- fprintf(stderr,
- "AES-CCM only supports 128-bit keys, but %u bits were given\n",
- static_cast<unsigned>(key.size() * 8));
+ LOG_ERROR("AES-CCM only supports 128-bit keys, but %u bits were given\n",
+ static_cast<unsigned>(key.size() * 8));
return false;
}
if (!EVP_AEAD_CTX_init(ctx, EVP_aead_aes_128_ccm_bluetooth(), key.data(),
key.size(), tag_len_32, nullptr)) {
- fprintf(stderr, "Failed to setup AES-CCM with tag length %u\n",
- static_cast<unsigned>(tag_len_32));
+ LOG_ERROR("Failed to setup AES-CCM with tag length %u\n",
+ static_cast<unsigned>(tag_len_32));
return false;
}
@@ -954,7 +1082,7 @@ static bool AESCCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
template <bool (*SetupFunc)(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key)>
-static bool AEADSeal(const Span<const uint8_t> args[]) {
+static bool AEADSeal(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> tag_len_span = args[0];
Span<const uint8_t> key = args[1];
Span<const uint8_t> plaintext = args[2];
@@ -979,12 +1107,12 @@ static bool AEADSeal(const Span<const uint8_t> args[]) {
}
out.resize(out_len);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
template <bool (*SetupFunc)(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key)>
-static bool AEADOpen(const Span<const uint8_t> args[]) {
+static bool AEADOpen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> tag_len_span = args[0];
Span<const uint8_t> key = args[1];
Span<const uint8_t> ciphertext = args[2];
@@ -1003,22 +1131,22 @@ static bool AEADOpen(const Span<const uint8_t> args[]) {
if (!EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
nonce.data(), nonce.size(), ciphertext.data(),
ciphertext.size(), ad.data(), ad.size())) {
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>());
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>()});
}
out.resize(out_len);
success_flag[0] = 1;
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>(out));
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>(out)});
}
static bool AESPaddedKeyWrapSetup(AES_KEY *out, bool decrypt,
Span<const uint8_t> key) {
if ((decrypt ? AES_set_decrypt_key : AES_set_encrypt_key)(
key.data(), key.size() * 8, out) != 0) {
- fprintf(stderr, "Invalid AES key length for AES-KW(P): %u\n",
- static_cast<unsigned>(key.size()));
+ LOG_ERROR("Invalid AES key length for AES-KW(P): %u\n",
+ static_cast<unsigned>(key.size()));
return false;
}
return true;
@@ -1031,15 +1159,15 @@ static bool AESKeyWrapSetup(AES_KEY *out, bool decrypt, Span<const uint8_t> key,
}
if (input.size() % 8) {
- fprintf(stderr, "Invalid AES-KW input length: %u\n",
- static_cast<unsigned>(input.size()));
+ LOG_ERROR("Invalid AES-KW input length: %u\n",
+ static_cast<unsigned>(input.size()));
return false;
}
return true;
}
-static bool AESKeyWrapSeal(const Span<const uint8_t> args[]) {
+static bool AESKeyWrapSeal(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> key = args[1];
Span<const uint8_t> plaintext = args[2];
@@ -1052,21 +1180,20 @@ static bool AESKeyWrapSeal(const Span<const uint8_t> args[]) {
std::vector<uint8_t> out(plaintext.size() + 8);
if (AES_wrap_key(&aes, /*iv=*/nullptr, out.data(), plaintext.data(),
plaintext.size()) != static_cast<int>(out.size())) {
- fprintf(stderr, "AES-KW failed\n");
+ LOG_ERROR("AES-KW failed\n");
return false;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
-static bool AESKeyWrapOpen(const Span<const uint8_t> args[]) {
+static bool AESKeyWrapOpen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> key = args[1];
Span<const uint8_t> ciphertext = args[2];
AES_KEY aes;
if (!AESKeyWrapSetup(&aes, /*decrypt=*/true, key, ciphertext) ||
- ciphertext.size() < 8 ||
- ciphertext.size() > INT_MAX) {
+ ciphertext.size() < 8 || ciphertext.size() > INT_MAX) {
return false;
}
@@ -1074,16 +1201,16 @@ static bool AESKeyWrapOpen(const Span<const uint8_t> args[]) {
uint8_t success_flag[1] = {0};
if (AES_unwrap_key(&aes, /*iv=*/nullptr, out.data(), ciphertext.data(),
ciphertext.size()) != static_cast<int>(out.size())) {
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>());
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>()});
}
success_flag[0] = 1;
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>(out));
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>(out)});
}
-static bool AESPaddedKeyWrapSeal(const Span<const uint8_t> args[]) {
+static bool AESPaddedKeyWrapSeal(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> key = args[1];
Span<const uint8_t> plaintext = args[2];
@@ -1097,15 +1224,15 @@ static bool AESPaddedKeyWrapSeal(const Span<const uint8_t> args[]) {
size_t out_len;
if (!AES_wrap_key_padded(&aes, out.data(), &out_len, out.size(),
plaintext.data(), plaintext.size())) {
- fprintf(stderr, "AES-KWP failed\n");
+ LOG_ERROR("AES-KWP failed\n");
return false;
}
out.resize(out_len);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
-static bool AESPaddedKeyWrapOpen(const Span<const uint8_t> args[]) {
+static bool AESPaddedKeyWrapOpen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> key = args[1];
Span<const uint8_t> ciphertext = args[2];
@@ -1120,23 +1247,23 @@ static bool AESPaddedKeyWrapOpen(const Span<const uint8_t> args[]) {
uint8_t success_flag[1] = {0};
if (!AES_unwrap_key_padded(&aes, out.data(), &out_len, out.size(),
ciphertext.data(), ciphertext.size())) {
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>());
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>()});
}
success_flag[0] = 1;
out.resize(out_len);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>(out));
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>(out)});
}
template <bool Encrypt>
-static bool TDES(const Span<const uint8_t> args[]) {
+static bool TDES(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const EVP_CIPHER *cipher = EVP_des_ede3();
if (args[0].size() != 24) {
- fprintf(stderr, "Bad key length %u for 3DES.\n",
- static_cast<unsigned>(args[0].size()));
+ LOG_ERROR("Bad key length %u for 3DES.\n",
+ static_cast<unsigned>(args[0].size()));
return false;
}
bssl::ScopedEVP_CIPHER_CTX ctx;
@@ -1147,8 +1274,8 @@ static bool TDES(const Span<const uint8_t> args[]) {
}
if (args[1].size() % 8) {
- fprintf(stderr, "Bad input length %u for 3DES.\n",
- static_cast<unsigned>(args[1].size()));
+ LOG_ERROR("Bad input length %u for 3DES.\n",
+ static_cast<unsigned>(args[1].size()));
return false;
}
std::vector<uint8_t> result(args[1].begin(), args[1].end());
@@ -1171,31 +1298,31 @@ static bool TDES(const Span<const uint8_t> args[]) {
}
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(result),
- Span<const uint8_t>(prev_result),
- Span<const uint8_t>(prev_prev_result));
+ return write_reply({Span<const uint8_t>(result),
+ Span<const uint8_t>(prev_result),
+ Span<const uint8_t>(prev_prev_result)});
}
template <bool Encrypt>
-static bool TDES_CBC(const Span<const uint8_t> args[]) {
+static bool TDES_CBC(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const EVP_CIPHER *cipher = EVP_des_ede3_cbc();
if (args[0].size() != 24) {
- fprintf(stderr, "Bad key length %u for 3DES.\n",
- static_cast<unsigned>(args[0].size()));
+ LOG_ERROR("Bad key length %u for 3DES.\n",
+ static_cast<unsigned>(args[0].size()));
return false;
}
if (args[1].size() % 8 || args[1].size() == 0) {
- fprintf(stderr, "Bad input length %u for 3DES.\n",
- static_cast<unsigned>(args[1].size()));
+ LOG_ERROR("Bad input length %u for 3DES.\n",
+ static_cast<unsigned>(args[1].size()));
return false;
}
std::vector<uint8_t> input(args[1].begin(), args[1].end());
if (args[2].size() != EVP_CIPHER_iv_length(cipher)) {
- fprintf(stderr, "Bad IV length %u for 3DES.\n",
- static_cast<unsigned>(args[2].size()));
+ LOG_ERROR("Bad IV length %u for 3DES.\n",
+ static_cast<unsigned>(args[2].size()));
return false;
}
std::vector<uint8_t> iv(args[2].begin(), args[2].end());
@@ -1237,13 +1364,13 @@ static bool TDES_CBC(const Span<const uint8_t> args[]) {
}
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(result),
- Span<const uint8_t>(prev_result),
- Span<const uint8_t>(prev_prev_result));
+ return write_reply({Span<const uint8_t>(result),
+ Span<const uint8_t>(prev_result),
+ Span<const uint8_t>(prev_prev_result)});
}
template <const EVP_MD *HashFunc()>
-static bool HMAC(const Span<const uint8_t> args[]) {
+static bool HMAC(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const EVP_MD *const md = HashFunc();
uint8_t digest[EVP_MAX_MD_SIZE];
unsigned digest_len;
@@ -1251,10 +1378,10 @@ static bool HMAC(const Span<const uint8_t> args[]) {
digest, &digest_len) == nullptr) {
return false;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(digest, digest_len));
+ return write_reply({Span<const uint8_t>(digest, digest_len)});
}
-static bool DRBG(const Span<const uint8_t> args[]) {
+static bool DRBG(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const auto out_len_bytes = args[0];
const auto entropy = args[1];
const auto personalisation = args[2];
@@ -1285,7 +1412,7 @@ static bool DRBG(const Span<const uint8_t> args[]) {
return false;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
static bool StringEq(Span<const uint8_t> a, const char *b) {
@@ -1333,7 +1460,7 @@ static std::pair<std::vector<uint8_t>, std::vector<uint8_t>> GetPublicKeyBytes(
return std::make_pair(std::move(x_bytes), std::move(y_bytes));
}
-static bool ECDSAKeyGen(const Span<const uint8_t> args[]) {
+static bool ECDSAKeyGen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
if (!key || !EC_KEY_generate_key_fips(key.get())) {
return false;
@@ -1343,9 +1470,9 @@ static bool ECDSAKeyGen(const Span<const uint8_t> args[]) {
std::vector<uint8_t> d_bytes =
BIGNUMBytes(EC_KEY_get0_private_key(key.get()));
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(d_bytes),
- Span<const uint8_t>(pub_key.first),
- Span<const uint8_t>(pub_key.second));
+ return write_reply({Span<const uint8_t>(d_bytes),
+ Span<const uint8_t>(pub_key.first),
+ Span<const uint8_t>(pub_key.second)});
}
static bssl::UniquePtr<BIGNUM> BytesToBIGNUM(Span<const uint8_t> bytes) {
@@ -1354,7 +1481,7 @@ static bssl::UniquePtr<BIGNUM> BytesToBIGNUM(Span<const uint8_t> bytes) {
return bn;
}
-static bool ECDSAKeyVer(const Span<const uint8_t> args[]) {
+static bool ECDSAKeyVer(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
if (!key) {
return false;
@@ -1375,11 +1502,13 @@ static bool ECDSAKeyVer(const Span<const uint8_t> args[]) {
reply[0] = 1;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(reply));
+ return write_reply({Span<const uint8_t>(reply)});
}
static const EVP_MD *HashFromName(Span<const uint8_t> name) {
- if (StringEq(name, "SHA2-224")) {
+ if (StringEq(name, "SHA-1")) {
+ return EVP_sha1();
+ } else if (StringEq(name, "SHA2-224")) {
return EVP_sha224();
} else if (StringEq(name, "SHA2-256")) {
return EVP_sha256();
@@ -1392,7 +1521,7 @@ static const EVP_MD *HashFromName(Span<const uint8_t> name) {
}
}
-static bool ECDSASigGen(const Span<const uint8_t> args[]) {
+static bool ECDSASigGen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
bssl::UniquePtr<BIGNUM> d = BytesToBIGNUM(args[1]);
const EVP_MD *hash = HashFromName(args[2]);
@@ -1413,11 +1542,11 @@ static bool ECDSASigGen(const Span<const uint8_t> args[]) {
std::vector<uint8_t> r_bytes(BIGNUMBytes(sig->r));
std::vector<uint8_t> s_bytes(BIGNUMBytes(sig->s));
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(r_bytes),
- Span<const uint8_t>(s_bytes));
+ return write_reply(
+ {Span<const uint8_t>(r_bytes), Span<const uint8_t>(s_bytes)});
}
-static bool ECDSASigVer(const Span<const uint8_t> args[]) {
+static bool ECDSASigVer(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
const EVP_MD *hash = HashFromName(args[1]);
auto msg = args[2];
@@ -1450,10 +1579,10 @@ static bool ECDSASigVer(const Span<const uint8_t> args[]) {
reply[0] = 1;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(reply));
+ return write_reply({Span<const uint8_t>(reply)});
}
-static bool CMAC_AES(const Span<const uint8_t> args[]) {
+static bool CMAC_AES(const Span<const uint8_t> args[], ReplyCallback write_reply) {
uint8_t mac[16];
if (!AES_CMAC(mac, args[1].data(), args[1].size(), args[2].data(),
args[2].size())) {
@@ -1469,10 +1598,10 @@ static bool CMAC_AES(const Span<const uint8_t> args[]) {
return false;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(mac, mac_len));
+ return write_reply({Span<const uint8_t>(mac, mac_len)});
}
-static bool CMAC_AESVerify(const Span<const uint8_t> args[]) {
+static bool CMAC_AESVerify(const Span<const uint8_t> args[], ReplyCallback write_reply) {
// This function is just for testing since libcrypto doesn't do the
// verification itself. The regcap doesn't advertise "ver" support.
uint8_t mac[16];
@@ -1482,8 +1611,8 @@ static bool CMAC_AESVerify(const Span<const uint8_t> args[]) {
return false;
}
- const uint8_t ok = OPENSSL_memcmp(mac, args[2].data(), args[2].size());
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(&ok, sizeof(ok)));
+ const uint8_t ok = (OPENSSL_memcmp(mac, args[2].data(), args[2].size()) == 0);
+ return write_reply({Span<const uint8_t>(&ok, sizeof(ok))});
}
static std::map<unsigned, bssl::UniquePtr<RSA>>& CachedRSAKeys() {
@@ -1508,7 +1637,7 @@ static RSA* GetRSAKey(unsigned bits) {
return ret;
}
-static bool RSAKeyGen(const Span<const uint8_t> args[]) {
+static bool RSAKeyGen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
uint32_t bits;
if (args[0].size() != sizeof(bits)) {
return false;
@@ -1517,8 +1646,7 @@ static bool RSAKeyGen(const Span<const uint8_t> args[]) {
bssl::UniquePtr<RSA> key(RSA_new());
if (!RSA_generate_key_fips(key.get(), bits, nullptr)) {
- fprintf(stderr, "RSA_generate_key_fips failed for modulus length %u.\n",
- bits);
+ LOG_ERROR("RSA_generate_key_fips failed for modulus length %u.\n", bits);
return false;
}
@@ -1526,8 +1654,8 @@ static bool RSAKeyGen(const Span<const uint8_t> args[]) {
RSA_get0_key(key.get(), &n, &e, &d);
RSA_get0_factors(key.get(), &p, &q);
- if (!WriteReply(STDOUT_FILENO, BIGNUMBytes(e), BIGNUMBytes(p), BIGNUMBytes(q),
- BIGNUMBytes(n), BIGNUMBytes(d))) {
+ if (!write_reply({BIGNUMBytes(e), BIGNUMBytes(p), BIGNUMBytes(q),
+ BIGNUMBytes(n), BIGNUMBytes(d)})) {
return false;
}
@@ -1535,8 +1663,8 @@ static bool RSAKeyGen(const Span<const uint8_t> args[]) {
return true;
}
-template<const EVP_MD *(MDFunc)(), bool UsePSS>
-static bool RSASigGen(const Span<const uint8_t> args[]) {
+template <const EVP_MD *(MDFunc)(), bool UsePSS>
+static bool RSASigGen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
uint32_t bits;
if (args[0].size() != sizeof(bits)) {
return false;
@@ -1570,12 +1698,12 @@ static bool RSASigGen(const Span<const uint8_t> args[]) {
sig.resize(sig_len);
- return WriteReply(STDOUT_FILENO, BIGNUMBytes(RSA_get0_n(key)),
- BIGNUMBytes(RSA_get0_e(key)), sig);
+ return write_reply(
+ {BIGNUMBytes(RSA_get0_n(key)), BIGNUMBytes(RSA_get0_e(key)), sig});
}
-template<const EVP_MD *(MDFunc)(), bool UsePSS>
-static bool RSASigVer(const Span<const uint8_t> args[]) {
+template <const EVP_MD *(MDFunc)(), bool UsePSS>
+static bool RSASigVer(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const Span<const uint8_t> n_bytes = args[0];
const Span<const uint8_t> e_bytes = args[1];
const Span<const uint8_t> msg = args[2];
@@ -1607,11 +1735,11 @@ static bool RSASigVer(const Span<const uint8_t> args[]) {
}
ERR_clear_error();
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(&ok, 1));
+ return write_reply({Span<const uint8_t>(&ok, 1)});
}
-template<const EVP_MD *(MDFunc)()>
-static bool TLSKDF(const Span<const uint8_t> args[]) {
+template <const EVP_MD *(MDFunc)()>
+static bool TLSKDF(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const Span<const uint8_t> out_len_bytes = args[0];
const Span<const uint8_t> secret = args[1];
const Span<const uint8_t> label = args[2];
@@ -1633,11 +1761,11 @@ static bool TLSKDF(const Span<const uint8_t> args[]) {
return 0;
}
- return WriteReply(STDOUT_FILENO, out);
+ return write_reply({out});
}
template <int Nid>
-static bool ECDH(const Span<const uint8_t> args[]) {
+static bool ECDH(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<BIGNUM> their_x(BytesToBIGNUM(args[0]));
bssl::UniquePtr<BIGNUM> their_y(BytesToBIGNUM(args[1]));
const Span<const uint8_t> private_key = args[2];
@@ -1649,14 +1777,14 @@ static bool ECDH(const Span<const uint8_t> args[]) {
bssl::UniquePtr<EC_POINT> their_point(EC_POINT_new(group));
if (!EC_POINT_set_affine_coordinates_GFp(
group, their_point.get(), their_x.get(), their_y.get(), ctx.get())) {
- fprintf(stderr, "Invalid peer point for ECDH.\n");
+ LOG_ERROR("Invalid peer point for ECDH.\n");
return false;
}
if (!private_key.empty()) {
bssl::UniquePtr<BIGNUM> our_k(BytesToBIGNUM(private_key));
if (!EC_KEY_set_private_key(ec_key.get(), our_k.get())) {
- fprintf(stderr, "EC_KEY_set_private_key failed.\n");
+ LOG_ERROR("EC_KEY_set_private_key failed.\n");
return false;
}
@@ -1664,11 +1792,11 @@ static bool ECDH(const Span<const uint8_t> args[]) {
if (!EC_POINT_mul(group, our_pub.get(), our_k.get(), nullptr, nullptr,
ctx.get()) ||
!EC_KEY_set_public_key(ec_key.get(), our_pub.get())) {
- fprintf(stderr, "Calculating public key failed.\n");
+ LOG_ERROR("Calculating public key failed.\n");
return false;
}
} else if (!EC_KEY_generate_key_fips(ec_key.get())) {
- fprintf(stderr, "EC_KEY_generate_key_fips failed.\n");
+ LOG_ERROR("EC_KEY_generate_key_fips failed.\n");
return false;
}
@@ -1679,10 +1807,10 @@ static bool ECDH(const Span<const uint8_t> args[]) {
ECDH_compute_key(output.data(), output.size(), their_point.get(),
ec_key.get(), /*kdf=*/nullptr);
if (out_len < 0) {
- fprintf(stderr, "ECDH_compute_key failed.\n");
+ LOG_ERROR("ECDH_compute_key failed.\n");
return false;
} else if (static_cast<size_t>(out_len) == output.size()) {
- fprintf(stderr, "ECDH_compute_key output may have been truncated.\n");
+ LOG_ERROR("ECDH_compute_key output may have been truncated.\n");
return false;
}
output.resize(static_cast<size_t>(out_len));
@@ -1692,15 +1820,14 @@ static bool ECDH(const Span<const uint8_t> args[]) {
bssl::UniquePtr<BIGNUM> y(BN_new());
if (!EC_POINT_get_affine_coordinates_GFp(group, pub, x.get(), y.get(),
ctx.get())) {
- fprintf(stderr, "EC_POINT_get_affine_coordinates_GFp failed.\n");
+ LOG_ERROR("EC_POINT_get_affine_coordinates_GFp failed.\n");
return false;
}
- return WriteReply(STDOUT_FILENO, BIGNUMBytes(x.get()), BIGNUMBytes(y.get()),
- output);
+ return write_reply({BIGNUMBytes(x.get()), BIGNUMBytes(y.get()), output});
}
-static bool FFDH(const Span<const uint8_t> args[]) {
+static bool FFDH(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<BIGNUM> p(BytesToBIGNUM(args[0]));
bssl::UniquePtr<BIGNUM> q(BytesToBIGNUM(args[1]));
bssl::UniquePtr<BIGNUM> g(BytesToBIGNUM(args[2]));
@@ -1710,7 +1837,7 @@ static bool FFDH(const Span<const uint8_t> args[]) {
bssl::UniquePtr<DH> dh(DH_new());
if (!DH_set0_pqg(dh.get(), p.get(), q.get(), g.get())) {
- fprintf(stderr, "DH_set0_pqg failed.\n");
+ LOG_ERROR("DH_set0_pqg failed.\n");
return 0;
}
@@ -1724,7 +1851,7 @@ static bool FFDH(const Span<const uint8_t> args[]) {
bssl::UniquePtr<BIGNUM> public_key(BytesToBIGNUM(public_key_span));
if (!DH_set0_key(dh.get(), public_key.get(), private_key.get())) {
- fprintf(stderr, "DH_set0_key failed.\n");
+ LOG_ERROR("DH_set0_key failed.\n");
return 0;
}
@@ -1732,24 +1859,24 @@ static bool FFDH(const Span<const uint8_t> args[]) {
public_key.release();
private_key.release();
} else if (!DH_generate_key(dh.get())) {
- fprintf(stderr, "DH_generate_key failed.\n");
+ LOG_ERROR("DH_generate_key failed.\n");
return false;
}
std::vector<uint8_t> z(DH_size(dh.get()));
if (DH_compute_key_padded(z.data(), their_pub.get(), dh.get()) !=
static_cast<int>(z.size())) {
- fprintf(stderr, "DH_compute_key_hashed failed.\n");
+ LOG_ERROR("DH_compute_key_hashed failed.\n");
return false;
}
- return WriteReply(STDOUT_FILENO, BIGNUMBytes(DH_get0_pub_key(dh.get())), z);
+ return write_reply({BIGNUMBytes(DH_get0_pub_key(dh.get())), z});
}
static constexpr struct {
- const char name[kMaxNameLength + 1];
- uint8_t expected_args;
- bool (*handler)(const Span<const uint8_t>[]);
+ char name[kMaxNameLength + 1];
+ uint8_t num_expected_args;
+ bool (*handler)(const Span<const uint8_t> args[], ReplyCallback write_reply);
} kFunctions[] = {
{"getConfig", 0, GetConfig},
{"SHA-1", 1, Hash<SHA1, SHA_DIGEST_LENGTH>},
@@ -1758,6 +1885,12 @@ static constexpr struct {
{"SHA2-384", 1, Hash<SHA384, SHA384_DIGEST_LENGTH>},
{"SHA2-512", 1, Hash<SHA512, SHA512_DIGEST_LENGTH>},
{"SHA2-512/256", 1, Hash<SHA512_256, SHA512_256_DIGEST_LENGTH>},
+ {"SHA-1/MCT", 1, HashMCT<SHA1, SHA_DIGEST_LENGTH>},
+ {"SHA2-224/MCT", 1, HashMCT<SHA224, SHA224_DIGEST_LENGTH>},
+ {"SHA2-256/MCT", 1, HashMCT<SHA256, SHA256_DIGEST_LENGTH>},
+ {"SHA2-384/MCT", 1, HashMCT<SHA384, SHA384_DIGEST_LENGTH>},
+ {"SHA2-512/MCT", 1, HashMCT<SHA512, SHA512_DIGEST_LENGTH>},
+ {"SHA2-512/256/MCT", 1, HashMCT<SHA512_256, SHA512_256_DIGEST_LENGTH>},
{"AES/encrypt", 3, AES<AES_set_encrypt_key, AES_encrypt>},
{"AES/decrypt", 3, AES<AES_set_decrypt_key, AES_decrypt>},
{"AES-CBC/encrypt", 4, AES_CBC<AES_set_encrypt_key, AES_ENCRYPT>},
@@ -1820,98 +1953,26 @@ static constexpr struct {
{"FFDH", 6, FFDH},
};
-int main() {
- uint32_t nums[1 + kMaxArgs];
- std::unique_ptr<uint8_t[]> buf;
- size_t buf_len = 0;
- Span<const uint8_t> args[kMaxArgs];
-
- for (;;) {
- if (!ReadAll(STDIN_FILENO, nums, sizeof(uint32_t) * 2)) {
- return 1;
- }
-
- const size_t num_args = nums[0];
- if (num_args == 0) {
- fprintf(stderr, "Invalid, zero-argument operation requested.\n");
- return 2;
- } else if (num_args > kMaxArgs) {
- fprintf(stderr,
- "Operation requested with %zu args, but %zu is the limit.\n",
- num_args, kMaxArgs);
- return 2;
- }
-
- if (num_args > 1 &&
- !ReadAll(STDIN_FILENO, &nums[2], sizeof(uint32_t) * (num_args - 1))) {
- return 1;
- }
-
- size_t need = 0;
- for (size_t i = 0; i < num_args; i++) {
- const size_t arg_length = nums[i + 1];
- if (i == 0 && arg_length > kMaxNameLength) {
- fprintf(stderr,
- "Operation with name of length %zu exceeded limit of %zu.\n",
- arg_length, kMaxNameLength);
- return 2;
- } else if (arg_length > kMaxArgLength) {
- fprintf(
- stderr,
- "Operation with argument of length %zu exceeded limit of %zu.\n",
- arg_length, kMaxArgLength);
- return 2;
+Handler FindHandler(Span<const Span<const uint8_t>> args) {
+ const bssl::Span<const uint8_t> algorithm = args[0];
+ for (const auto &func : kFunctions) {
+ if (algorithm.size() == strlen(func.name) &&
+ memcmp(algorithm.data(), func.name, algorithm.size()) == 0) {
+ if (args.size() - 1 != func.num_expected_args) {
+ LOG_ERROR("\'%s\' operation received %zu arguments but expected %u.\n",
+ func.name, args.size() - 1, func.num_expected_args);
+ return nullptr;
}
- // static_assert around kMaxArgs etc enforces that this doesn't overflow.
- need += arg_length;
- }
-
- if (need > buf_len) {
- size_t alloced = need + (need >> 1);
- if (alloced < need) {
- abort();
- }
- buf.reset(new uint8_t[alloced]);
- buf_len = alloced;
- }
-
- if (!ReadAll(STDIN_FILENO, buf.get(), need)) {
- return 1;
- }
-
- size_t offset = 0;
- for (size_t i = 0; i < num_args; i++) {
- args[i] = Span<const uint8_t>(&buf[offset], nums[i + 1]);
- offset += nums[i + 1];
- }
-
- bool found = false;
- for (const auto &func : kFunctions) {
- if (args[0].size() == strlen(func.name) &&
- memcmp(args[0].data(), func.name, args[0].size()) == 0) {
- if (num_args - 1 != func.expected_args) {
- fprintf(stderr,
- "\'%s\' operation received %zu arguments but expected %u.\n",
- func.name, num_args - 1, func.expected_args);
- return 2;
- }
-
- if (!func.handler(&args[1])) {
- fprintf(stderr, "\'%s\' operation failed.\n", func.name);
- return 4;
- }
-
- found = true;
- break;
- }
- }
-
- if (!found) {
- const std::string name(reinterpret_cast<const char *>(args[0].data()),
- args[0].size());
- fprintf(stderr, "Unknown operation: %s\n", name.c_str());
- return 3;
+ return func.handler;
}
}
+
+ const std::string name(reinterpret_cast<const char *>(algorithm.data()),
+ algorithm.size());
+ LOG_ERROR("Unknown operation: %s\n", name.c_str());
+ return nullptr;
}
+
+} // namespace acvp
+} // namespace bssl
diff --git a/deps/boringssl/src/util/fipstools/acvp/modulewrapper/modulewrapper.h b/deps/boringssl/src/util/fipstools/acvp/modulewrapper/modulewrapper.h
new file mode 100644
index 0000000..0472800
--- /dev/null
+++ b/deps/boringssl/src/util/fipstools/acvp/modulewrapper/modulewrapper.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2021, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/base.h>
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include <openssl/span.h>
+
+
+namespace bssl {
+namespace acvp {
+
+// kMaxArgs is the maximum number of arguments (including the function name)
+// that an ACVP request can contain.
+constexpr size_t kMaxArgs = 8;
+// kMaxNameLength is the maximum length of a function name in an ACVP request.
+constexpr size_t kMaxNameLength = 30;
+
+// RequestBuffer holds various buffers needed for parsing an ACVP request. It
+// can be reused between requests.
+class RequestBuffer {
+ public:
+ virtual ~RequestBuffer();
+
+ static std::unique_ptr<RequestBuffer> New();
+};
+
+// ParseArgsFromFd returns a span of arguments, the first of which is the name
+// of the requested function, from |fd|. The return values point into |buffer|
+// and so must not be used after |buffer| has been freed or reused for a
+// subsequent call. It returns an empty span on error, because std::optional
+// is still too new.
+Span<const Span<const uint8_t>> ParseArgsFromFd(int fd, RequestBuffer *buffer);
+
+// WriteReplyToFd writes a reply to the given file descriptor.
+bool WriteReplyToFd(int fd, const std::vector<Span<const uint8_t>> &spans);
+
+// ReplyCallback is the type of a callback that writes a reply to an ACVP
+// request.
+typedef std::function<bool(const std::vector<Span<const uint8_t>> &)>
+ ReplyCallback;
+
+// Handler is the type of a function that handles a specific ACVP request. If
+// successful it will call |write_reply| with the response arguments and return
+// |write_reply|'s return value. Otherwise it will return false. The given args
+// must not include the name at the beginning.
+typedef bool (*Handler)(const Span<const uint8_t> args[],
+ ReplyCallback write_reply);
+
+// FindHandler returns a |Handler| that can process the given arguments, or logs
+// a reason and returns |nullptr| if none is found.
+Handler FindHandler(Span<const Span<const uint8_t>> args);
+
+} // namespace acvp
+} // namespace bssl
diff --git a/deps/boringssl/win-aarch64/crypto/fipsmodule/ghashv8-armx64.S b/deps/boringssl/win-aarch64/crypto/fipsmodule/ghashv8-armx64.S
index 75f7b64..7cba4da 100644
--- a/deps/boringssl/win-aarch64/crypto/fipsmodule/ghashv8-armx64.S
+++ b/deps/boringssl/win-aarch64/crypto/fipsmodule/ghashv8-armx64.S
@@ -15,6 +15,7 @@
#endif
#include <openssl/arm_arch.h>
+#if __ARM_MAX_ARCH__>=7
.text
.arch armv8-a+crypto
.globl gcm_init_v8
@@ -67,8 +68,48 @@ gcm_init_v8:
ext v17.16b,v22.16b,v22.16b,#8 //Karatsuba pre-processing
eor v17.16b,v17.16b,v22.16b
ext v21.16b,v16.16b,v17.16b,#8 //pack Karatsuba pre-processed
- st1 {v21.2d,v22.2d},[x0] //store Htable[1..2]
+ st1 {v21.2d,v22.2d},[x0],#32 //store Htable[1..2]
+ //calculate H^3 and H^4
+ pmull v0.1q,v20.1d, v22.1d
+ pmull v5.1q,v22.1d,v22.1d
+ pmull2 v2.1q,v20.2d, v22.2d
+ pmull2 v7.1q,v22.2d,v22.2d
+ pmull v1.1q,v16.1d,v17.1d
+ pmull v6.1q,v17.1d,v17.1d
+
+ ext v16.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ ext v17.16b,v5.16b,v7.16b,#8
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v16.16b
+ eor v4.16b,v5.16b,v7.16b
+ eor v6.16b,v6.16b,v17.16b
+ eor v1.16b,v1.16b,v18.16b
+ pmull v18.1q,v0.1d,v19.1d //1st phase
+ eor v6.16b,v6.16b,v4.16b
+ pmull v4.1q,v5.1d,v19.1d
+
+ ins v2.d[0],v1.d[1]
+ ins v7.d[0],v6.d[1]
+ ins v1.d[1],v0.d[0]
+ ins v6.d[1],v5.d[0]
+ eor v0.16b,v1.16b,v18.16b
+ eor v5.16b,v6.16b,v4.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase
+ ext v4.16b,v5.16b,v5.16b,#8
+ pmull v0.1q,v0.1d,v19.1d
+ pmull v5.1q,v5.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v4.16b,v4.16b,v7.16b
+ eor v20.16b, v0.16b,v18.16b //H^3
+ eor v22.16b,v5.16b,v4.16b //H^4
+ ext v16.16b,v20.16b, v20.16b,#8 //Karatsuba pre-processing
+ ext v17.16b,v22.16b,v22.16b,#8
+ eor v16.16b,v16.16b,v20.16b
+ eor v17.16b,v17.16b,v22.16b
+ ext v21.16b,v16.16b,v17.16b,#8 //pack Karatsuba pre-processed
+ st1 {v20.2d,v21.2d,v22.2d},[x0] //store Htable[3..5]
ret
.globl gcm_gmult_v8
@@ -124,6 +165,8 @@ gcm_gmult_v8:
.align 4
gcm_ghash_v8:
AARCH64_VALID_CALL_TARGET
+ cmp x3,#64
+ b.hs Lgcm_ghash_v8_4x
ld1 {v0.2d},[x0] //load [rotated] Xi
//"[rotated]" means that
//loaded value would have
@@ -250,8 +293,291 @@ Ldone_v8:
ret
+.def gcm_ghash_v8_4x
+ .type 32
+.endef
+.align 4
+gcm_ghash_v8_4x:
+Lgcm_ghash_v8_4x:
+ ld1 {v0.2d},[x0] //load [rotated] Xi
+ ld1 {v20.2d,v21.2d,v22.2d},[x1],#48 //load twisted H, ..., H^2
+ movi v19.16b,#0xe1
+ ld1 {v26.2d,v27.2d,v28.2d},[x1] //load twisted H^3, ..., H^4
+ shl v19.2d,v19.2d,#57 //compose 0xc2.0 constant
+
+ ld1 {v4.2d,v5.2d,v6.2d,v7.2d},[x2],#64
+#ifndef __ARMEB__
+ rev64 v0.16b,v0.16b
+ rev64 v5.16b,v5.16b
+ rev64 v6.16b,v6.16b
+ rev64 v7.16b,v7.16b
+ rev64 v4.16b,v4.16b
+#endif
+ ext v25.16b,v7.16b,v7.16b,#8
+ ext v24.16b,v6.16b,v6.16b,#8
+ ext v23.16b,v5.16b,v5.16b,#8
+
+ pmull v29.1q,v20.1d,v25.1d //H·Ii+3
+ eor v7.16b,v7.16b,v25.16b
+ pmull2 v31.1q,v20.2d,v25.2d
+ pmull v30.1q,v21.1d,v7.1d
+
+ pmull v16.1q,v22.1d,v24.1d //H^2·Ii+2
+ eor v6.16b,v6.16b,v24.16b
+ pmull2 v24.1q,v22.2d,v24.2d
+ pmull2 v6.1q,v21.2d,v6.2d
+
+ eor v29.16b,v29.16b,v16.16b
+ eor v31.16b,v31.16b,v24.16b
+ eor v30.16b,v30.16b,v6.16b
+
+ pmull v7.1q,v26.1d,v23.1d //H^3·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+ pmull2 v23.1q,v26.2d,v23.2d
+ pmull v5.1q,v27.1d,v5.1d
+
+ eor v29.16b,v29.16b,v7.16b
+ eor v31.16b,v31.16b,v23.16b
+ eor v30.16b,v30.16b,v5.16b
+
+ subs x3,x3,#128
+ b.lo Ltail4x
+
+ b Loop4x
+
+.align 4
+Loop4x:
+ eor v16.16b,v4.16b,v0.16b
+ ld1 {v4.2d,v5.2d,v6.2d,v7.2d},[x2],#64
+ ext v3.16b,v16.16b,v16.16b,#8
+#ifndef __ARMEB__
+ rev64 v5.16b,v5.16b
+ rev64 v6.16b,v6.16b
+ rev64 v7.16b,v7.16b
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v0.1q,v28.1d,v3.1d //H^4·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v28.2d,v3.2d
+ ext v25.16b,v7.16b,v7.16b,#8
+ pmull2 v1.1q,v27.2d,v16.2d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ ext v24.16b,v6.16b,v6.16b,#8
+ eor v1.16b,v1.16b,v30.16b
+ ext v23.16b,v5.16b,v5.16b,#8
+
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ pmull v29.1q,v20.1d,v25.1d //H·Ii+3
+ eor v7.16b,v7.16b,v25.16b
+ eor v1.16b,v1.16b,v17.16b
+ pmull2 v31.1q,v20.2d,v25.2d
+ eor v1.16b,v1.16b,v18.16b
+ pmull v30.1q,v21.1d,v7.1d
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ pmull v16.1q,v22.1d,v24.1d //H^2·Ii+2
+ eor v6.16b,v6.16b,v24.16b
+ pmull2 v24.1q,v22.2d,v24.2d
+ eor v0.16b,v1.16b,v18.16b
+ pmull2 v6.1q,v21.2d,v6.2d
+
+ eor v29.16b,v29.16b,v16.16b
+ eor v31.16b,v31.16b,v24.16b
+ eor v30.16b,v30.16b,v6.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ pmull v7.1q,v26.1d,v23.1d //H^3·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+ eor v18.16b,v18.16b,v2.16b
+ pmull2 v23.1q,v26.2d,v23.2d
+ pmull v5.1q,v27.1d,v5.1d
+
+ eor v0.16b,v0.16b,v18.16b
+ eor v29.16b,v29.16b,v7.16b
+ eor v31.16b,v31.16b,v23.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+ eor v30.16b,v30.16b,v5.16b
+
+ subs x3,x3,#64
+ b.hs Loop4x
+
+Ltail4x:
+ eor v16.16b,v4.16b,v0.16b
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ pmull v0.1q,v28.1d,v3.1d //H^4·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v28.2d,v3.2d
+ pmull2 v1.1q,v27.2d,v16.2d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ eor v1.16b,v1.16b,v30.16b
+
+ adds x3,x3,#64
+ b.eq Ldone4x
+
+ cmp x3,#32
+ b.lo Lone
+ b.eq Ltwo
+Lthree:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ ld1 {v4.2d,v5.2d,v6.2d},[x2]
+ eor v1.16b,v1.16b,v18.16b
+#ifndef __ARMEB__
+ rev64 v5.16b,v5.16b
+ rev64 v6.16b,v6.16b
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ ext v24.16b,v6.16b,v6.16b,#8
+ ext v23.16b,v5.16b,v5.16b,#8
+ eor v0.16b,v1.16b,v18.16b
+
+ pmull v29.1q,v20.1d,v24.1d //H·Ii+2
+ eor v6.16b,v6.16b,v24.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ pmull2 v31.1q,v20.2d,v24.2d
+ pmull v30.1q,v21.1d,v6.1d
+ eor v0.16b,v0.16b,v18.16b
+ pmull v7.1q,v22.1d,v23.1d //H^2·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+ pmull2 v23.1q,v22.2d,v23.2d
+ eor v16.16b,v4.16b,v0.16b
+ pmull2 v5.1q,v21.2d,v5.2d
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ eor v29.16b,v29.16b,v7.16b
+ eor v31.16b,v31.16b,v23.16b
+ eor v30.16b,v30.16b,v5.16b
+
+ pmull v0.1q,v26.1d,v3.1d //H^3·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v26.2d,v3.2d
+ pmull v1.1q,v27.1d,v16.1d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ eor v1.16b,v1.16b,v30.16b
+ b Ldone4x
+
+.align 4
+Ltwo:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ ld1 {v4.2d,v5.2d},[x2]
+ eor v1.16b,v1.16b,v18.16b
+#ifndef __ARMEB__
+ rev64 v5.16b,v5.16b
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ ext v23.16b,v5.16b,v5.16b,#8
+ eor v0.16b,v1.16b,v18.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v0.16b,v0.16b,v18.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+ pmull v29.1q,v20.1d,v23.1d //H·Ii+1
+ eor v5.16b,v5.16b,v23.16b
+
+ eor v16.16b,v4.16b,v0.16b
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ pmull2 v31.1q,v20.2d,v23.2d
+ pmull v30.1q,v21.1d,v5.1d
+
+ pmull v0.1q,v22.1d,v3.1d //H^2·(Xi+Ii)
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v22.2d,v3.2d
+ pmull2 v1.1q,v21.2d,v16.2d
+
+ eor v0.16b,v0.16b,v29.16b
+ eor v2.16b,v2.16b,v31.16b
+ eor v1.16b,v1.16b,v30.16b
+ b Ldone4x
+
+.align 4
+Lone:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ ld1 {v4.2d},[x2]
+ eor v1.16b,v1.16b,v18.16b
+#ifndef __ARMEB__
+ rev64 v4.16b,v4.16b
+#endif
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ eor v0.16b,v1.16b,v18.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v0.16b,v0.16b,v18.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+ eor v16.16b,v4.16b,v0.16b
+ ext v3.16b,v16.16b,v16.16b,#8
+
+ pmull v0.1q,v20.1d,v3.1d
+ eor v16.16b,v16.16b,v3.16b
+ pmull2 v2.1q,v20.2d,v3.2d
+ pmull v1.1q,v21.1d,v16.1d
+
+Ldone4x:
+ ext v17.16b,v0.16b,v2.16b,#8 //Karatsuba post-processing
+ eor v18.16b,v0.16b,v2.16b
+ eor v1.16b,v1.16b,v17.16b
+ eor v1.16b,v1.16b,v18.16b
+
+ pmull v18.1q,v0.1d,v19.1d //1st phase of reduction
+ ins v2.d[0],v1.d[1]
+ ins v1.d[1],v0.d[0]
+ eor v0.16b,v1.16b,v18.16b
+
+ ext v18.16b,v0.16b,v0.16b,#8 //2nd phase of reduction
+ pmull v0.1q,v0.1d,v19.1d
+ eor v18.16b,v18.16b,v2.16b
+ eor v0.16b,v0.16b,v18.16b
+ ext v0.16b,v0.16b,v0.16b,#8
+
+#ifndef __ARMEB__
+ rev64 v0.16b,v0.16b
+#endif
+ st1 {v0.2d},[x0] //write out Xi
+
+ ret
+
.byte 71,72,65,83,72,32,102,111,114,32,65,82,77,118,56,44,32,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0
.align 2
.align 2
#endif
+#endif
#endif // !OPENSSL_NO_ASM
diff --git a/examples/Makefile b/examples/Makefile
index 5660bbd..82db2e4 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -17,7 +17,7 @@ LIBSSL_DIR = $(dir $(shell find ${BUILD_DIR} -name libssl.a))
LDFLAGS = -L$(LIBCRYPTO_DIR) -L$(LIBSSL_DIR) -L$(LIB_DIR)
-LIBS = $(LIB_DIR)/libquiche.a -lev -ldl -pthread
+LIBS = $(LIB_DIR)/libquiche.a -lev -ldl -pthread -lm
all: client server http3-client http3-server
diff --git a/examples/client.rs b/examples/client.rs
index 88490aa..24966e7 100644
--- a/examples/client.rs
+++ b/examples/client.rs
@@ -52,7 +52,7 @@ fn main() {
let url = url::Url::parse(&args.next().unwrap()).unwrap();
// Setup the event loop.
- let poll = mio::Poll::new().unwrap();
+ let mut poll = mio::Poll::new().unwrap();
let mut events = mio::Events::with_capacity(1024);
// Resolve server address.
@@ -68,16 +68,11 @@ fn main() {
// Create the UDP socket backing the QUIC connection, and register it with
// the event loop.
- let socket = std::net::UdpSocket::bind(bind_addr).unwrap();
-
- let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
- poll.register(
- &socket,
- mio::Token(0),
- mio::Ready::readable(),
- mio::PollOpt::edge(),
- )
- .unwrap();
+ let mut socket =
+ mio::net::UdpSocket::bind(bind_addr.parse().unwrap()).unwrap();
+ poll.registry()
+ .register(&mut socket, mio::Token(0), mio::Interest::READABLE)
+ .unwrap();
// Create the configuration for the QUIC connection.
let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
@@ -120,7 +115,7 @@ fn main() {
let (write, send_info) = conn.send(&mut out).expect("initial send failed");
- while let Err(e) = socket.send_to(&out[..write], &send_info.to) {
+ while let Err(e) = socket.send_to(&out[..write], send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
continue;
@@ -216,7 +211,7 @@ fn main() {
);
print!("{}", unsafe {
- std::str::from_utf8_unchecked(&stream_buf)
+ std::str::from_utf8_unchecked(stream_buf)
});
// The server reported that it has no more data to send, which
@@ -251,7 +246,7 @@ fn main() {
},
};
- if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
+ if let Err(e) = socket.send_to(&out[..write], send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
diff --git a/examples/http3-client.c b/examples/http3-client.c
index 6b263ff..1dad8c8 100644
--- a/examples/http3-client.c
+++ b/examples/http3-client.c
@@ -98,6 +98,14 @@ static void flush_egress(struct ev_loop *loop, struct conn_io *conn_io) {
ev_timer_again(loop, &conn_io->timer);
}
+static int for_each_setting(uint64_t identifier, uint64_t value,
+ void *argp) {
+ fprintf(stderr, "got HTTP/3 SETTING: %" PRIu64 "=%" PRIu64 "\n",
+ identifier, value);
+
+ return 0;
+}
+
static int for_each_header(uint8_t *name, size_t name_len,
uint8_t *value, size_t value_len,
void *argp) {
@@ -109,6 +117,7 @@ static int for_each_header(uint8_t *name, size_t name_len,
static void recv_cb(EV_P_ ev_io *w, int revents) {
static bool req_sent = false;
+ static bool settings_received = false;
struct conn_io *conn_io = w->data;
@@ -244,6 +253,16 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
break;
}
+ if (!settings_received) {
+ int rc = quiche_h3_for_each_setting(conn_io->http3,
+ for_each_setting,
+ NULL);
+
+ if (rc == 0) {
+ settings_received = true;
+ }
+ }
+
switch (quiche_h3_event_type(ev)) {
case QUICHE_H3_EVENT_HEADERS: {
int rc = quiche_h3_event_for_each_header(ev, for_each_header,
@@ -278,6 +297,17 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
}
break;
+ case QUICHE_H3_EVENT_RESET:
+ fprintf(stderr, "request was reset\n");
+
+ if (quiche_conn_close(conn_io->conn, true, 0, NULL, 0) < 0) {
+ fprintf(stderr, "failed to close connection\n");
+ }
+ break;
+
+ case QUICHE_H3_EVENT_PRIORITY_UPDATE:
+ break;
+
case QUICHE_H3_EVENT_DATAGRAM:
break;
diff --git a/examples/http3-client.rs b/examples/http3-client.rs
index 2acb2ca..d4b8219 100644
--- a/examples/http3-client.rs
+++ b/examples/http3-client.rs
@@ -29,6 +29,8 @@ extern crate log;
use std::net::ToSocketAddrs;
+use quiche::h3::NameValue;
+
use ring::rand::*;
const MAX_DATAGRAM_SIZE: usize = 1350;
@@ -50,7 +52,7 @@ fn main() {
let url = url::Url::parse(&args.next().unwrap()).unwrap();
// Setup the event loop.
- let poll = mio::Poll::new().unwrap();
+ let mut poll = mio::Poll::new().unwrap();
let mut events = mio::Events::with_capacity(1024);
// Resolve server address.
@@ -66,16 +68,11 @@ fn main() {
// Create the UDP socket backing the QUIC connection, and register it with
// the event loop.
- let socket = std::net::UdpSocket::bind(bind_addr).unwrap();
-
- let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
- poll.register(
- &socket,
- mio::Token(0),
- mio::Ready::readable(),
- mio::PollOpt::edge(),
- )
- .unwrap();
+ let mut socket =
+ mio::net::UdpSocket::bind(bind_addr.parse().unwrap()).unwrap();
+ poll.registry()
+ .register(&mut socket, mio::Token(0), mio::Interest::READABLE)
+ .unwrap();
// Create the configuration for the QUIC connection.
let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
@@ -119,7 +116,7 @@ fn main() {
let (write, send_info) = conn.send(&mut out).expect("initial send failed");
- while let Err(e) = socket.send_to(&out[..write], &send_info.to) {
+ while let Err(e) = socket.send_to(&out[..write], send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
continue;
@@ -238,7 +235,8 @@ fn main() {
Ok((stream_id, quiche::h3::Event::Headers { list, .. })) => {
info!(
"got response headers {:?} on stream id {}",
- list, stream_id
+ hdrs_to_strings(&list),
+ stream_id
);
},
@@ -266,8 +264,19 @@ fn main() {
conn.close(true, 0x00, b"kthxbye").unwrap();
},
+ Ok((_stream_id, quiche::h3::Event::Reset(e))) => {
+ error!(
+ "request was reset by peer with {}, closing...",
+ e
+ );
+
+ conn.close(true, 0x00, b"kthxbye").unwrap();
+ },
+
Ok((_flow_id, quiche::h3::Event::Datagram)) => (),
+ Ok((_, quiche::h3::Event::PriorityUpdate)) => unreachable!(),
+
Ok((goaway_id, quiche::h3::Event::GoAway)) => {
info!("GOAWAY id={}", goaway_id);
},
@@ -304,7 +313,7 @@ fn main() {
},
};
- if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
+ if let Err(e) = socket.send_to(&out[..write], send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -328,3 +337,14 @@ fn hex_dump(buf: &[u8]) -> String {
vec.join("")
}
+
+fn hdrs_to_strings(hdrs: &[quiche::h3::Header]) -> Vec<(String, String)> {
+ hdrs.iter()
+ .map(|h| {
+ (
+ String::from_utf8(h.name().into()).unwrap(),
+ String::from_utf8(h.value().into()).unwrap(),
+ )
+ })
+ .collect()
+}
diff --git a/examples/http3-server.c b/examples/http3-server.c
index 73c29ae..058ee6b 100644
--- a/examples/http3-server.c
+++ b/examples/http3-server.c
@@ -205,7 +205,7 @@ static struct conn_io *create_conn(uint8_t *scid, size_t scid_len,
conn_io->sock = conns->sock;
conn_io->conn = conn;
- memcpy(&conn_io->peer_addr, &peer_addr, peer_addr_len);
+ memcpy(&conn_io->peer_addr, peer_addr, peer_addr_len);
conn_io->peer_addr_len = peer_addr_len;
ev_init(&conn_io->timer, timeout_cb);
@@ -442,6 +442,12 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
case QUICHE_H3_EVENT_FINISHED:
break;
+ case QUICHE_H3_EVENT_RESET:
+ break;
+
+ case QUICHE_H3_EVENT_PRIORITY_UPDATE:
+ break;
+
case QUICHE_H3_EVENT_DATAGRAM:
break;
diff --git a/examples/http3-server.rs b/examples/http3-server.rs
index e84d1ea..c2d9d84 100644
--- a/examples/http3-server.rs
+++ b/examples/http3-server.rs
@@ -46,7 +46,7 @@ struct PartialResponse {
}
struct Client {
- conn: std::pin::Pin<Box<quiche::Connection>>,
+ conn: quiche::Connection,
http3_conn: Option<quiche::h3::Connection>,
@@ -70,20 +70,15 @@ fn main() {
}
// Setup the event loop.
- let poll = mio::Poll::new().unwrap();
+ let mut poll = mio::Poll::new().unwrap();
let mut events = mio::Events::with_capacity(1024);
// Create the UDP listening socket, and register it with the event loop.
- let socket = net::UdpSocket::bind("127.0.0.1:4433").unwrap();
-
- let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
- poll.register(
- &socket,
- mio::Token(0),
- mio::Ready::readable(),
- mio::PollOpt::edge(),
- )
- .unwrap();
+ let mut socket =
+ mio::net::UdpSocket::bind("127.0.0.1:4433".parse().unwrap()).unwrap();
+ poll.registry()
+ .register(&mut socket, mio::Token(0), mio::Interest::READABLE)
+ .unwrap();
// Create the configuration for the QUIC connections.
let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
@@ -198,7 +193,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &from) {
+ if let Err(e) = socket.send_to(out, from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -235,7 +230,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &from) {
+ if let Err(e) = socket.send_to(out, from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -360,8 +355,15 @@ fn main() {
Ok((_stream_id, quiche::h3::Event::Finished)) => (),
+ Ok((_stream_id, quiche::h3::Event::Reset { .. })) => (),
+
Ok((_flow_id, quiche::h3::Event::Datagram)) => (),
+ Ok((
+ _prioritized_element_id,
+ quiche::h3::Event::PriorityUpdate,
+ )) => (),
+
Ok((_goaway_id, quiche::h3::Event::GoAway)) => (),
Err(quiche::h3::Error::Done) => {
@@ -403,7 +405,7 @@ fn main() {
},
};
- if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
+ if let Err(e) = socket.send_to(&out[..write], send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -500,7 +502,7 @@ fn handle_request(
info!(
"{} got request {:?} on stream id {}",
conn.trace_id(),
- headers,
+ hdrs_to_strings(headers),
stream_id
);
@@ -620,7 +622,7 @@ fn handle_writable(client: &mut Client, stream_id: u64) {
let resp = client.partial_responses.get_mut(&stream_id).unwrap();
if let Some(ref headers) = resp.headers {
- match http3_conn.send_response(conn, stream_id, &headers, false) {
+ match http3_conn.send_response(conn, stream_id, headers, false) {
Ok(_) => (),
Err(quiche::h3::Error::StreamBlocked) => {
@@ -657,3 +659,14 @@ fn handle_writable(client: &mut Client, stream_id: u64) {
client.partial_responses.remove(&stream_id);
}
}
+
+fn hdrs_to_strings(hdrs: &[quiche::h3::Header]) -> Vec<(String, String)> {
+ hdrs.iter()
+ .map(|h| {
+ (
+ String::from_utf8(h.name().into()).unwrap(),
+ String::from_utf8(h.value().into()).unwrap(),
+ )
+ })
+ .collect()
+}
diff --git a/examples/server.c b/examples/server.c
index a97250f..b6ac1f2 100644
--- a/examples/server.c
+++ b/examples/server.c
@@ -203,7 +203,7 @@ static struct conn_io *create_conn(uint8_t *scid, size_t scid_len,
conn_io->sock = conns->sock;
conn_io->conn = conn;
- memcpy(&conn_io->peer_addr, &peer_addr, peer_addr_len);
+ memcpy(&conn_io->peer_addr, peer_addr, peer_addr_len);
conn_io->peer_addr_len = peer_addr_len;
ev_init(&conn_io->timer, timeout_cb);
diff --git a/examples/server.rs b/examples/server.rs
index 90f0102..9a846e2 100644
--- a/examples/server.rs
+++ b/examples/server.rs
@@ -42,7 +42,7 @@ struct PartialResponse {
}
struct Client {
- conn: std::pin::Pin<Box<quiche::Connection>>,
+ conn: quiche::Connection,
partial_responses: HashMap<u64, PartialResponse>,
}
@@ -64,20 +64,15 @@ fn main() {
}
// Setup the event loop.
- let poll = mio::Poll::new().unwrap();
+ let mut poll = mio::Poll::new().unwrap();
let mut events = mio::Events::with_capacity(1024);
// Create the UDP listening socket, and register it with the event loop.
- let socket = net::UdpSocket::bind("127.0.0.1:4433").unwrap();
-
- let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
- poll.register(
- &socket,
- mio::Token(0),
- mio::Ready::readable(),
- mio::PollOpt::edge(),
- )
- .unwrap();
+ let mut socket =
+ mio::net::UdpSocket::bind("127.0.0.1:4433".parse().unwrap()).unwrap();
+ poll.registry()
+ .register(&mut socket, mio::Token(0), mio::Interest::READABLE)
+ .unwrap();
// Create the configuration for the QUIC connections.
let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
@@ -192,7 +187,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &from) {
+ if let Err(e) = socket.send_to(out, from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -229,7 +224,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &from) {
+ if let Err(e) = socket.send_to(out, from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -348,7 +343,7 @@ fn main() {
},
};
- if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
+ if let Err(e) = socket.send_to(&out[..write], send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -499,7 +494,7 @@ fn handle_writable(client: &mut Client, stream_id: u64) {
let resp = client.partial_responses.get_mut(&stream_id).unwrap();
let body = &resp.body[resp.written..];
- let written = match conn.stream_send(stream_id, &body, true) {
+ let written = match conn.stream_send(stream_id, body, true) {
Ok(v) => v,
Err(quiche::Error::Done) => 0,
diff --git a/include/quiche.h b/include/quiche.h
index ba0f04a..25318f9 100644
--- a/include/quiche.h
+++ b/include/quiche.h
@@ -34,6 +34,16 @@ extern "C" {
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <time.h>
+#else
+#include <sys/socket.h>
+#include <sys/time.h>
+#endif
+
#ifdef __unix__
#include <sys/types.h>
#endif
@@ -97,6 +107,9 @@ enum quiche_error {
// The specified stream was stopped by the peer.
QUICHE_ERR_STREAM_STOPPED = -15,
+ // The specified stream was reset by the peer.
+ QUICHE_ERR_STREAM_RESET = -16,
+
// The received data exceeds the stream's final size.
QUICHE_ERR_FINAL_SIZE = -13,
@@ -129,6 +142,10 @@ int quiche_config_load_priv_key_from_pem_file(quiche_config *config,
int quiche_config_load_verify_locations_from_file(quiche_config *config,
const char *path);
+// Specifies a directory where trusted CA certificates are stored for the purposes of certificate verification.
+int quiche_config_load_verify_locations_from_directory(quiche_config *config,
+ const char *path);
+
// Configures whether to verify the peer's certificate.
void quiche_config_verify_peer(quiche_config *config, bool v);
@@ -199,6 +216,12 @@ void quiche_config_enable_dgram(quiche_config *config, bool enabled,
size_t recv_queue_len,
size_t send_queue_len);
+// Sets the maximum connection window.
+void quiche_config_set_max_connection_window(quiche_config *config, uint64_t v);
+
+// Sets the maximum stream window.
+void quiche_config_set_max_stream_window(quiche_config *config, uint64_t v);
+
// Frees the config object.
void quiche_config_free(quiche_config *config);
@@ -285,6 +308,9 @@ typedef struct {
ssize_t quiche_conn_send(quiche_conn *conn, uint8_t *out, size_t out_len,
quiche_send_info *out_info);
+// Returns the size of the send quantum, in bytes.
+size_t quiche_conn_send_quantum(quiche_conn *conn);
+
// Reads contiguous data from a stream.
ssize_t quiche_conn_stream_recv(quiche_conn *conn, uint64_t stream_id,
uint8_t *out, size_t buf_len, bool *fin);
@@ -350,6 +376,9 @@ void quiche_conn_destination_id(quiche_conn *conn, const uint8_t **out, size_t *
void quiche_conn_application_proto(quiche_conn *conn, const uint8_t **out,
size_t *out_len);
+// Returns the peer's leaf certificate (if any) as a DER-encoded buffer.
+void quiche_conn_peer_cert(quiche_conn *conn, const uint8_t **out, size_t *out_len);
+
// Returns the serialized cryptographic session for the connection.
void quiche_conn_session(quiche_conn *conn, const uint8_t **out, size_t *out_len);
@@ -377,6 +406,9 @@ uint64_t quiche_conn_peer_streams_left_uni(quiche_conn *conn);
// Returns true if the connection is closed.
bool quiche_conn_is_closed(quiche_conn *conn);
+// Returns true if the connection was closed due to the idle timeout.
+bool quiche_conn_is_timed_out(quiche_conn *conn);
+
// Returns true if a connection error was received, and updates the provided
// parameters accordingly.
bool quiche_conn_peer_error(quiche_conn *conn,
@@ -385,6 +417,14 @@ bool quiche_conn_peer_error(quiche_conn *conn,
const uint8_t **reason,
size_t *reason_len);
+// Returns true if a connection error was queued or sent, and updates the provided
+// parameters accordingly.
+bool quiche_conn_local_error(quiche_conn *conn,
+ bool *is_app,
+ uint64_t *error_code,
+ const uint8_t **reason,
+ size_t *reason_len);
+
// Initializes the stream's application data.
//
// Stream data can only be initialized once. Additional calls to this method
@@ -415,14 +455,71 @@ typedef struct {
// The number of QUIC packets that were lost.
size_t lost;
+ // The number of sent QUIC packets with retranmitted data.
+ size_t retrans;
+
// The estimated round-trip time of the connection (in nanoseconds).
uint64_t rtt;
// The size of the connection's congestion window in bytes.
size_t cwnd;
- // The estimated data delivery rate in bytes/s.
+ // The number of sent bytes.
+ uint64_t sent_bytes;
+
+ // The number of recevied bytes.
+ uint64_t recv_bytes;
+
+ // The number of bytes lost.
+ uint64_t lost_bytes;
+
+ // The number of stream bytes retransmitted.
+ uint64_t stream_retrans_bytes;
+
+ // The current PMTU for the connection.
+ size_t pmtu;
+
+ // The most recent data delivery rate estimate in bytes/s.
uint64_t delivery_rate;
+
+ // The maximum idle timeout.
+ uint64_t peer_max_idle_timeout;
+
+ // The maximum UDP payload size.
+ uint64_t peer_max_udp_payload_size;
+
+ // The initial flow control maximum data for the connection.
+ uint64_t peer_initial_max_data;
+
+ // The initial flow control maximum data for local bidirectional streams.
+ uint64_t peer_initial_max_stream_data_bidi_local;
+
+ // The initial flow control maximum data for remote bidirectional streams.
+ uint64_t peer_initial_max_stream_data_bidi_remote;
+
+ // The initial flow control maximum data for unidirectional streams.
+ uint64_t peer_initial_max_stream_data_uni;
+
+ // The initial maximum bidirectional streams.
+ uint64_t peer_initial_max_streams_bidi;
+
+ // The initial maximum unidirectional streams.
+ uint64_t peer_initial_max_streams_uni;
+
+ // The ACK delay exponent.
+ uint64_t peer_ack_delay_exponent;
+
+ // The max ACK delay.
+ uint64_t peer_max_ack_delay;
+
+ // Whether active migration is disabled.
+ bool peer_disable_active_migration;
+
+ // The active connection ID limit.
+ uint64_t peer_active_conn_id_limit;
+
+ // DATAGRAM frame extension parameter, if any.
+ ssize_t peer_max_datagram_frame_size;
} quiche_stats;
// Collects and returns statistics about the connection.
@@ -437,7 +534,7 @@ ssize_t quiche_conn_dgram_recv_front_len(quiche_conn *conn);
// Returns the number of items in the DATAGRAM receive queue.
ssize_t quiche_conn_dgram_recv_queue_len(quiche_conn *conn);
-///Returns the total size of all items in the DATAGRAM receive queue.
+// Returns the total size of all items in the DATAGRAM receive queue.
ssize_t quiche_conn_dgram_recv_queue_byte_size(quiche_conn *conn);
// Returns the number of items in the DATAGRAM send queue.
@@ -469,73 +566,123 @@ void quiche_conn_free(quiche_conn *conn);
#define QUICHE_H3_APPLICATION_PROTOCOL "\x02h3\x05h3-29\x05h3-28\x05h3-27"
enum quiche_h3_error {
- /// There is no error or no work to do
+ // There is no error or no work to do
QUICHE_H3_ERR_DONE = -1,
- /// The provided buffer is too short.
+ // The provided buffer is too short.
QUICHE_H3_ERR_BUFFER_TOO_SHORT = -2,
- /// Internal error in the HTTP/3 stack.
+ // Internal error in the HTTP/3 stack.
QUICHE_H3_ERR_INTERNAL_ERROR = -3,
- /// Endpoint detected that the peer is exhibiting behavior that causes.
- /// excessive load.
+ // Endpoint detected that the peer is exhibiting behavior that causes.
+ // excessive load.
QUICHE_H3_ERR_EXCESSIVE_LOAD = -4,
- /// Stream ID or Push ID greater that current maximum was
- /// used incorrectly, such as exceeding a limit, reducing a limit,
- /// or being reused.
+ // Stream ID or Push ID greater that current maximum was
+ // used incorrectly, such as exceeding a limit, reducing a limit,
+ // or being reused.
QUICHE_H3_ERR_ID_ERROR= -5,
- /// The endpoint detected that its peer created a stream that it will not
- /// accept.
+ // The endpoint detected that its peer created a stream that it will not
+ // accept.
QUICHE_H3_ERR_STREAM_CREATION_ERROR = -6,
- /// A required critical stream was closed.
+ // A required critical stream was closed.
QUICHE_H3_ERR_CLOSED_CRITICAL_STREAM = -7,
- /// No SETTINGS frame at beginning of control stream.
+ // No SETTINGS frame at beginning of control stream.
QUICHE_H3_ERR_MISSING_SETTINGS = -8,
- /// A frame was received which is not permitted in the current state.
+ // A frame was received which is not permitted in the current state.
QUICHE_H3_ERR_FRAME_UNEXPECTED = -9,
- /// Frame violated layout or size rules.
+ // Frame violated layout or size rules.
QUICHE_H3_ERR_FRAME_ERROR = -10,
- /// QPACK Header block decompression failure.
+ // QPACK Header block decompression failure.
QUICHE_H3_ERR_QPACK_DECOMPRESSION_FAILED = -11,
- /// Error originated from the transport layer.
- QUICHE_H3_ERR_TRANSPORT_ERROR = -12,
+ // -12 was previously used for TransportError, skip it
- /// The underlying QUIC stream (or connection) doesn't have enough capacity
- /// for the operation to complete. The application should retry later on.
+ // The underlying QUIC stream (or connection) doesn't have enough capacity
+ // for the operation to complete. The application should retry later on.
QUICHE_H3_ERR_STREAM_BLOCKED = -13,
- /// Error in the payload of a SETTINGS frame.
+ // Error in the payload of a SETTINGS frame.
QUICHE_H3_ERR_SETTINGS_ERROR = -14,
- /// Server rejected request.
+ // Server rejected request.
QUICHE_H3_ERR_REQUEST_REJECTED = -15,
- /// Request or its response cancelled.
+ // Request or its response cancelled.
QUICHE_H3_ERR_REQUEST_CANCELLED = -16,
- /// Client's request stream terminated without containing a full-formed
- /// request.
+ // Client's request stream terminated without containing a full-formed
+ // request.
QUICHE_H3_ERR_REQUEST_INCOMPLETE = -17,
- /// An HTTP message was malformed and cannot be processed.
+ // An HTTP message was malformed and cannot be processed.
QUICHE_H3_ERR_MESSAGE_ERROR = -18,
// The TCP connection established in response to a CONNECT request was
- /// reset or abnormally closed.
+ // reset or abnormally closed.
QUICHE_H3_ERR_CONNECT_ERROR = -19,
- /// The requested operation cannot be served over HTTP/3. Peer should retry
- /// over HTTP/1.1.
+ // The requested operation cannot be served over HTTP/3. Peer should retry
+ // over HTTP/1.1.
QUICHE_H3_ERR_VERSION_FALLBACK = -20,
+
+ // The following QUICHE_H3_TRANSPORT_ERR_* errors are propagated
+ // from the QUIC transport layer.
+
+ // See QUICHE_ERR_DONE.
+ QUICHE_H3_TRANSPORT_ERR_DONE = QUICHE_ERR_DONE - 1000,
+
+ // See QUICHE_ERR_BUFFER_TOO_SHORT.
+ QUICHE_H3_TRANSPORT_ERR_BUFFER_TOO_SHORT = QUICHE_ERR_BUFFER_TOO_SHORT - 1000,
+
+ // See QUICHE_ERR_UNKNOWN_VERSION.
+ QUICHE_H3_TRANSPORT_ERR_UNKNOWN_VERSION = QUICHE_ERR_UNKNOWN_VERSION - 1000,
+
+ // See QUICHE_ERR_INVALID_FRAME.
+ QUICHE_H3_TRANSPORT_ERR_INVALID_FRAME = QUICHE_ERR_INVALID_FRAME - 1000,
+
+ // See QUICHE_ERR_INVALID_PACKET.
+ QUICHE_H3_TRANSPORT_ERR_INVALID_PACKET = QUICHE_ERR_INVALID_PACKET - 1000,
+
+ // See QUICHE_ERR_INVALID_STATE.
+ QUICHE_H3_TRANSPORT_ERR_INVALID_STATE = QUICHE_ERR_INVALID_STATE - 1000,
+
+ // See QUICHE_ERR_INVALID_STREAM_STATE.
+ QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE = QUICHE_ERR_INVALID_STREAM_STATE - 1000,
+
+ // See QUICHE_ERR_INVALID_TRANSPORT_PARAM.
+ QUICHE_H3_TRANSPORT_ERR_INVALID_TRANSPORT_PARAM = QUICHE_ERR_INVALID_TRANSPORT_PARAM - 1000,
+
+ // See QUICHE_ERR_CRYPTO_FAIL.
+ QUICHE_H3_TRANSPORT_ERR_CRYPTO_FAIL = QUICHE_ERR_CRYPTO_FAIL - 1000,
+
+ // See QUICHE_ERR_TLS_FAIL.
+ QUICHE_H3_TRANSPORT_ERR_TLS_FAIL = QUICHE_ERR_TLS_FAIL - 1000,
+
+ // See QUICHE_ERR_FLOW_CONTROL.
+ QUICHE_H3_TRANSPORT_ERR_FLOW_CONTROL = QUICHE_ERR_FLOW_CONTROL - 1000,
+
+ // See QUICHE_ERR_STREAM_LIMIT.
+ QUICHE_H3_TRANSPORT_ERR_STREAM_LIMIT = QUICHE_ERR_STREAM_LIMIT - 1000,
+
+ // See QUICHE_ERR_STREAM_STOPPED.
+ QUICHE_H3_TRANSPORT_ERR_STREAM_STOPPED = QUICHE_ERR_STREAM_STOPPED - 1000,
+
+ // See QUICHE_ERR_STREAM_RESET.
+ QUICHE_H3_TRANSPORT_ERR_STREAM_RESET = QUICHE_ERR_STREAM_RESET - 1000,
+
+ // See QUICHE_ERR_FINAL_SIZE.
+ QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE = QUICHE_ERR_FINAL_SIZE - 1000,
+
+ // See QUICHE_ERR_CONGESTION_CONTROL.
+ QUICHE_H3_TRANSPORT_ERR_CONGESTION_CONTROL = QUICHE_ERR_CONGESTION_CONTROL - 1000,
};
// Stores configuration shared between multiple connections.
@@ -544,8 +691,8 @@ typedef struct Http3Config quiche_h3_config;
// Creates an HTTP/3 config object with default settings values.
quiche_h3_config *quiche_h3_config_new(void);
-// Sets the `SETTINGS_MAX_HEADER_LIST_SIZE` setting.
-void quiche_h3_config_set_max_header_list_size(quiche_h3_config *config, uint64_t v);
+// Sets the `SETTINGS_MAX_FIELD_SECTION_SIZE` setting.
+void quiche_h3_config_set_max_field_section_size(quiche_h3_config *config, uint64_t v);
// Sets the `SETTINGS_QPACK_MAX_TABLE_CAPACITY` setting.
void quiche_h3_config_set_qpack_max_table_capacity(quiche_h3_config *config, uint64_t v);
@@ -573,6 +720,8 @@ enum quiche_h3_event_type {
QUICHE_H3_EVENT_FINISHED,
QUICHE_H3_EVENT_DATAGRAM,
QUICHE_H3_EVENT_GOAWAY,
+ QUICHE_H3_EVENT_RESET,
+ QUICHE_H3_EVENT_PRIORITY_UPDATE,
};
typedef struct Http3Event quiche_h3_event;
@@ -596,6 +745,16 @@ int quiche_h3_event_for_each_header(quiche_h3_event *ev,
void *argp),
void *argp);
+// Iterates over the peer's HTTP/3 settings.
+//
+// The `cb` callback will be called for each setting in `conn`.
+// If `cb` returns any value other than `0`, processing will be interrupted and
+// the value is returned to the caller.
+int quiche_h3_for_each_setting(quiche_h3_conn *conn,
+ int (*cb)(uint64_t identifier,
+ uint64_t value, void *argp),
+ void *argp);
+
// Check whether data will follow the headers on the stream.
bool quiche_h3_event_headers_has_body(quiche_h3_event *ev);
@@ -610,6 +769,12 @@ typedef struct {
size_t value_len;
} quiche_h3_header;
+// Extensible Priorities parameters.
+typedef struct {
+ uint8_t urgency;
+ bool incremental;
+} quiche_h3_priority;
+
// Sends an HTTP/3 request.
int64_t quiche_h3_send_request(quiche_h3_conn *conn, quiche_conn *quic_conn,
quiche_h3_header *headers, size_t headers_len,
@@ -624,7 +789,7 @@ int quiche_h3_send_response(quiche_h3_conn *conn, quiche_conn *quic_conn,
int quiche_h3_send_response_with_priority(quiche_h3_conn *conn,
quiche_conn *quic_conn, uint64_t stream_id,
quiche_h3_header *headers, size_t headers_len,
- const char *priority, bool fin);
+ quiche_h3_priority *priority, bool fin);
// Sends an HTTP/3 body chunk on the given stream.
ssize_t quiche_h3_send_body(quiche_h3_conn *conn, quiche_conn *quic_conn,
@@ -635,6 +800,23 @@ ssize_t quiche_h3_send_body(quiche_h3_conn *conn, quiche_conn *quic_conn,
ssize_t quiche_h3_recv_body(quiche_h3_conn *conn, quiche_conn *quic_conn,
uint64_t stream_id, uint8_t *out, size_t out_len);
+// Try to parse an Extensible Priority field value.
+int quiche_h3_parse_extensible_priority(uint8_t *priority,
+ size_t priority_len,
+ quiche_h3_priority *parsed);
+
+// Take the last received PRIORITY_UPDATE frame for a stream.
+//
+// The `cb` callback will be called once. `cb` should check the validity of
+// priority field value contents. If `cb` returns any value other than `0`,
+// processing will be interrupted and the value is returned to the caller.
+int quiche_h3_take_last_priority_update(quiche_h3_conn *conn,
+ uint64_t prioritized_element_id,
+ int (*cb)(uint8_t *priority_field_value,
+ uint64_t priority_field_value_len,
+ void *argp),
+ void *argp);
+
// Returns whether the peer enabled HTTP/3 DATAGRAM frame support.
bool quiche_h3_dgram_enabled_by_peer(quiche_h3_conn *conn,
quiche_conn *quic_conn);
diff --git a/patches/Android.bp.patch b/patches/Android.bp.patch
index 48c6dee..f77d468 100644
--- a/patches/Android.bp.patch
+++ b/patches/Android.bp.patch
@@ -1,8 +1,8 @@
diff --git a/Android.bp b/Android.bp
-index aced8a6..578cc68 100644
+index 38dd21b..bc3ee19 100644
--- a/Android.bp
+++ b/Android.bp
-@@ -43,26 +43,39 @@ cc_library_headers {
+@@ -43,8 +43,8 @@ cc_library_headers {
min_sdk_version: "29",
}
@@ -13,7 +13,7 @@ index aced8a6..578cc68 100644
stem: "libquiche",
host_supported: true,
crate_name: "quiche",
- cargo_env_compat: true,
+@@ -52,10 +52,11 @@ rust_ffi_shared {
srcs: ["src/lib.rs"],
edition: "2018",
features: [
@@ -27,30 +27,25 @@ index aced8a6..578cc68 100644
"liblazy_static",
"liblibc",
"liblibm",
- "liblog_rust",
+@@ -63,10 +64,8 @@ rust_ffi_shared {
+ "liboctets",
"libring",
],
- static_libs: [
+- "libcrypto",
+- "libssl",
+- ],
+ prefer_rlib: true,
+ // For DnsResolver (Mainline module introduced in Q).
-+ apex_available: [
-+ "//apex_available:platform",
-+ "com.android.resolv",
-+ ],
-+ min_sdk_version: "29",
-+}
-+
-+rust_ffi {
-+ name: "libquiche_ffi",
-+ defaults: ["libquiche_defaults"],
-+ shared_libs: [
- "libcrypto",
- "libssl",
- ],
-@@ -69,54 +82,20 @@ rust_ffi_shared {
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.resolv",
+@@ -74,26 +73,10 @@ rust_ffi_shared {
+ min_sdk_version: "29",
+ }
- rust_library {
- name: "libquiche",
+-rust_library {
+- name: "libquiche",
- host_supported: true,
- crate_name: "quiche",
- cargo_env_compat: true,
@@ -65,26 +60,23 @@ index aced8a6..578cc68 100644
- "liblibc",
- "liblibm",
- "liblog_rust",
+- "liboctets",
- "libring",
- ],
- static_libs: [
++rust_ffi {
++ name: "libquiche_ffi",
+ defaults: ["libquiche_defaults"],
+ shared_libs: [
"libcrypto",
"libssl",
],
-- apex_available: [
-- "//apex_available:platform",
-- "com.android.resolv",
-- ],
-- min_sdk_version: "29",
+@@ -104,28 +87,22 @@ rust_library {
+ min_sdk_version: "29",
}
-rust_ffi_static {
-+// This target is used by doh_unit_test to prevent compatibility issues
-+// because doh_unit_test needs to be run on the R platform.
-+rust_library_rlib {
- name: "libquiche_static",
+- name: "libquiche_static",
- stem: "libquiche",
- host_supported: true,
- crate_name: "quiche",
@@ -100,8 +92,21 @@ index aced8a6..578cc68 100644
- "liblibc",
- "liblibm",
- "liblog_rust",
+- "liboctets",
- "libring",
-- ],
++rust_library {
++ name: "libquiche",
++ defaults: ["libquiche_defaults"],
++ shared_libs: [
++ "libcrypto",
++ "libssl",
+ ],
++}
++
++// This target is used by doh_unit_test to prevent compatibility issues
++// because doh_unit_test needs to be run on the R platform.
++rust_library_rlib {
++ name: "libquiche_static",
+ defaults: ["libquiche_defaults"],
static_libs: [
- "libcrypto",
@@ -109,7 +114,7 @@ index aced8a6..578cc68 100644
"libssl",
],
apex_available: [
-@@ -111,17 +90,13 @@ rust_library_rlib {
+@@ -135,17 +112,13 @@ rust_ffi_static {
min_sdk_version: "29",
}
@@ -128,8 +133,8 @@ index aced8a6..578cc68 100644
- },
edition: "2018",
features: [
- "boringssl",
-@@ -136,10 +132,6 @@ rust_test {
+ "boringssl-vendored",
+@@ -161,10 +134,6 @@ rust_test {
"libring",
"liburl",
],
@@ -140,7 +145,7 @@ index aced8a6..578cc68 100644
data: [
"examples/cert.crt",
"examples/cert.key",
-@@ -149,3 +118,26 @@ rust_test {
+@@ -172,3 +141,26 @@ rust_test {
"examples/rootca.crt",
],
}
diff --git a/patches/lib.rs-app-proto.patch b/patches/lib.rs-app-proto.patch
deleted file mode 100644
index cd02a46..0000000
--- a/patches/lib.rs-app-proto.patch
+++ /dev/null
@@ -1,47 +0,0 @@
---- a/src/lib.rs
-+++ b/src/lib.rs
-@@ -6301,7 +6301,7 @@ mod tests {
- .load_priv_key_from_pem_file("examples/cert.key")
- .unwrap();
- config
-- .set_application_protos(b"\x06proto1\06proto2")
-+ .set_application_protos(b"\x06proto1\x06proto2")
- .unwrap();
-
- let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap();
-@@ -8347,7 +8347,7 @@ mod tests {
- .load_priv_key_from_pem_file("examples/cert.key")
- .unwrap();
- config
-- .set_application_protos(b"\x06proto1\06proto2")
-+ .set_application_protos(b"\x06proto1\x06proto2")
- .unwrap();
-
- let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap();
-@@ -8407,7 +8407,7 @@ mod tests {
- .load_priv_key_from_pem_file("examples/cert.key")
- .unwrap();
- config
-- .set_application_protos(b"\x06proto1\06proto2")
-+ .set_application_protos(b"\x06proto1\x06proto2")
- .unwrap();
-
- let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap();
-@@ -8465,7 +8465,7 @@ mod tests {
- .load_priv_key_from_pem_file("examples/cert.key")
- .unwrap();
- config
-- .set_application_protos(b"\x06proto1\06proto2")
-+ .set_application_protos(b"\x06proto1\x06proto2")
- .unwrap();
-
- let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap();
-@@ -9509,7 +9509,7 @@ mod tests {
- .load_priv_key_from_pem_file("examples/cert.key")
- .unwrap();
- config
-- .set_application_protos(b"\x06proto1\06proto2")
-+ .set_application_protos(b"\x06proto1\x06proto2")
- .unwrap();
-
- let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap();
diff --git a/src/build.rs b/src/build.rs
index 875f556..e675bfe 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -1,26 +1,6 @@
// Additional parameters for Android build of BoringSSL.
//
-// Android NDK < 18 with GCC.
-const CMAKE_PARAMS_ANDROID_NDK_OLD_GCC: &[(&str, &[(&str, &str)])] = &[
- ("aarch64", &[(
- "ANDROID_TOOLCHAIN_NAME",
- "aarch64-linux-android-4.9",
- )]),
- ("arm", &[(
- "ANDROID_TOOLCHAIN_NAME",
- "arm-linux-androideabi-4.9",
- )]),
- ("x86", &[(
- "ANDROID_TOOLCHAIN_NAME",
- "x86-linux-android-4.9",
- )]),
- ("x86_64", &[(
- "ANDROID_TOOLCHAIN_NAME",
- "x86_64-linux-android-4.9",
- )]),
-];
-
-// Android NDK >= 19.
+// Requires Android NDK >= 19.
const CMAKE_PARAMS_ANDROID_NDK: &[(&str, &[(&str, &str)])] = &[
("aarch64", &[("ANDROID_ABI", "arm64-v8a")]),
("arm", &[("ANDROID_ABI", "armeabi-v7a")]),
@@ -97,17 +77,11 @@ fn get_boringssl_cmake_config() -> cmake::Config {
// Add platform-specific parameters.
match os.as_ref() {
"android" => {
- let cmake_params_android = if cfg!(feature = "ndk-old-gcc") {
- CMAKE_PARAMS_ANDROID_NDK_OLD_GCC
- } else {
- CMAKE_PARAMS_ANDROID_NDK
- };
-
// We need ANDROID_NDK_HOME to be set properly.
let android_ndk_home = std::env::var("ANDROID_NDK_HOME")
.expect("Please set ANDROID_NDK_HOME for Android build");
let android_ndk_home = std::path::Path::new(&android_ndk_home);
- for (android_arch, params) in cmake_params_android {
+ for (android_arch, params) in CMAKE_PARAMS_ANDROID_NDK {
if *android_arch == arch {
for (name, value) in *params {
boringssl_cmake.define(name, value);
@@ -199,11 +173,10 @@ fn get_boringssl_cmake_config() -> cmake::Config {
fn write_pkg_config() {
use std::io::prelude::*;
- let profile = std::env::var("PROFILE").unwrap();
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
- let target_dir = format!("{}/target/{}", manifest_dir, profile);
+ let target_dir = target_dir_path();
- let out_path = std::path::Path::new(&target_dir).join("quiche.pc");
+ let out_path = target_dir.as_path().join("quiche.pc");
let mut out_file = std::fs::File::create(&out_path).unwrap();
let include_dir = format!("{}/include", manifest_dir);
@@ -222,14 +195,31 @@ Version: {}
Libs: -Wl,-rpath,${{libdir}} -L${{libdir}} -lquiche
Cflags: -I${{includedir}}
",
- include_dir, target_dir, version
+ include_dir,
+ target_dir.to_str().unwrap(),
+ version
);
out_file.write_all(output.as_bytes()).unwrap();
}
+fn target_dir_path() -> std::path::PathBuf {
+ let out_dir = std::env::var("OUT_DIR").unwrap();
+ let out_dir = std::path::Path::new(&out_dir);
+
+ for p in out_dir.ancestors() {
+ if p.ends_with("build") {
+ return p.parent().unwrap().to_path_buf();
+ }
+ }
+
+ unreachable!();
+}
+
fn main() {
- if cfg!(feature = "boringssl-vendored") && !cfg!(feature = "boring-sys") {
+ if cfg!(feature = "boringssl-vendored") &&
+ !cfg!(feature = "boringssl-boring-crate")
+ {
let bssl_dir = std::env::var("QUICHE_BSSL_PATH").unwrap_or_else(|_| {
let mut cfg = get_boringssl_cmake_config();
@@ -249,13 +239,14 @@ fn main() {
println!("cargo:rustc-link-lib=static=ssl");
}
- if cfg!(feature = "boring-sys") {
+ if cfg!(feature = "boringssl-boring-crate") {
println!("cargo:rustc-link-lib=static=crypto");
println!("cargo:rustc-link-lib=static=ssl");
}
// MacOS: Allow cdylib to link with undefined symbols
- if cfg!(target_os = "macos") {
+ let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
+ if target_os == "macos" {
println!("cargo:rustc-cdylib-link-arg=-Wl,-undefined,dynamic_lookup");
}
diff --git a/src/crypto.rs b/src/crypto.rs
index 6e33957..079961f 100644
--- a/src/crypto.rs
+++ b/src/crypto.rs
@@ -24,9 +24,14 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+use std::mem::MaybeUninit;
+
use ring::aead;
use ring::hkdf;
+use libc::c_int;
+use libc::c_void;
+
use crate::Error;
use crate::Result;
@@ -68,11 +73,13 @@ pub enum Algorithm {
}
impl Algorithm {
- fn get_ring_aead(self) -> &'static aead::Algorithm {
+ fn get_evp_aead(self) -> *const EVP_AEAD {
match self {
- Algorithm::AES128_GCM => &aead::AES_128_GCM,
- Algorithm::AES256_GCM => &aead::AES_256_GCM,
- Algorithm::ChaCha20_Poly1305 => &aead::CHACHA20_POLY1305,
+ Algorithm::AES128_GCM => unsafe { EVP_aead_aes_128_gcm() },
+ Algorithm::AES256_GCM => unsafe { EVP_aead_aes_256_gcm() },
+ Algorithm::ChaCha20_Poly1305 => unsafe {
+ EVP_aead_chacha20_poly1305()
+ },
}
}
@@ -93,7 +100,11 @@ impl Algorithm {
}
pub fn key_len(self) -> usize {
- self.get_ring_aead().key_len()
+ match self {
+ Algorithm::AES128_GCM => 16,
+ Algorithm::AES256_GCM => 32,
+ Algorithm::ChaCha20_Poly1305 => 32,
+ }
}
pub fn tag_len(self) -> usize {
@@ -101,20 +112,28 @@ impl Algorithm {
return 0;
}
- self.get_ring_aead().tag_len()
+ match self {
+ Algorithm::AES128_GCM => 16,
+ Algorithm::AES256_GCM => 16,
+ Algorithm::ChaCha20_Poly1305 => 16,
+ }
}
pub fn nonce_len(self) -> usize {
- self.get_ring_aead().nonce_len()
+ match self {
+ Algorithm::AES128_GCM => 12,
+ Algorithm::AES256_GCM => 12,
+ Algorithm::ChaCha20_Poly1305 => 12,
+ }
}
}
pub struct Open {
alg: Algorithm,
- hp_key: aead::quic::HeaderProtectionKey,
+ ctx: EVP_AEAD_CTX,
- key: aead::LessSafeKey,
+ hp_key: aead::quic::HeaderProtectionKey,
nonce: Vec<u8>,
}
@@ -124,20 +143,17 @@ impl Open {
alg: Algorithm, key: &[u8], iv: &[u8], hp_key: &[u8],
) -> Result<Open> {
Ok(Open {
+ alg,
+
+ ctx: make_aead_ctx(alg, key)?,
+
hp_key: aead::quic::HeaderProtectionKey::new(
alg.get_ring_hp(),
hp_key,
)
.map_err(|_| Error::CryptoFail)?,
- key: aead::LessSafeKey::new(
- aead::UnboundKey::new(alg.get_ring_aead(), key)
- .map_err(|_| Error::CryptoFail)?,
- ),
-
nonce: Vec::from(iv),
-
- alg,
})
}
@@ -149,9 +165,9 @@ impl Open {
let mut iv = vec![0; nonce_len];
let mut pn_key = vec![0; key_len];
- derive_pkt_key(aead, &secret, &mut key)?;
- derive_pkt_iv(aead, &secret, &mut iv)?;
- derive_hdr_key(aead, &secret, &mut pn_key)?;
+ derive_pkt_key(aead, secret, &mut key)?;
+ derive_pkt_iv(aead, secret, &mut iv)?;
+ derive_hdr_key(aead, secret, &mut pn_key)?;
Open::new(aead, &key, &iv, &pn_key)
}
@@ -163,16 +179,37 @@ impl Open {
return Ok(buf.len());
}
+ let tag_len = self.alg().tag_len();
+
+ let mut out_len = match buf.len().checked_sub(tag_len) {
+ Some(n) => n,
+ None => return Err(Error::CryptoFail),
+ };
+
+ let max_out_len = out_len;
+
let nonce = make_nonce(&self.nonce, counter);
- let ad = aead::Aad::from(ad);
+ let rc = unsafe {
+ EVP_AEAD_CTX_open(
+ &self.ctx, // ctx
+ buf.as_mut_ptr(), // out
+ &mut out_len, // out_len
+ max_out_len, // max_out_len
+ nonce[..].as_ptr(), // nonce
+ nonce.len(), // nonce_len
+ buf.as_ptr(), // inp
+ buf.len(), // in_len
+ ad.as_ptr(), // ad
+ ad.len(), // ad_len
+ )
+ };
- let plain = self
- .key
- .open_in_place(nonce, ad, buf)
- .map_err(|_| Error::CryptoFail)?;
+ if rc != 1 {
+ return Err(Error::CryptoFail);
+ }
- Ok(plain.len())
+ Ok(out_len)
}
pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> {
@@ -196,9 +233,9 @@ impl Open {
pub struct Seal {
alg: Algorithm,
- hp_key: aead::quic::HeaderProtectionKey,
+ ctx: EVP_AEAD_CTX,
- key: aead::LessSafeKey,
+ hp_key: aead::quic::HeaderProtectionKey,
nonce: Vec<u8>,
}
@@ -208,20 +245,17 @@ impl Seal {
alg: Algorithm, key: &[u8], iv: &[u8], hp_key: &[u8],
) -> Result<Seal> {
Ok(Seal {
+ alg,
+
+ ctx: make_aead_ctx(alg, key)?,
+
hp_key: aead::quic::HeaderProtectionKey::new(
alg.get_ring_hp(),
hp_key,
)
.map_err(|_| Error::CryptoFail)?,
- key: aead::LessSafeKey::new(
- aead::UnboundKey::new(alg.get_ring_aead(), key)
- .map_err(|_| Error::CryptoFail)?,
- ),
-
nonce: Vec::from(iv),
-
- alg,
})
}
@@ -233,40 +267,66 @@ impl Seal {
let mut iv = vec![0; nonce_len];
let mut pn_key = vec![0; key_len];
- derive_pkt_key(aead, &secret, &mut key)?;
- derive_pkt_iv(aead, &secret, &mut iv)?;
- derive_hdr_key(aead, &secret, &mut pn_key)?;
+ derive_pkt_key(aead, secret, &mut key)?;
+ derive_pkt_iv(aead, secret, &mut iv)?;
+ derive_hdr_key(aead, secret, &mut pn_key)?;
Seal::new(aead, &key, &iv, &pn_key)
}
pub fn seal_with_u64_counter(
- &self, counter: u64, ad: &[u8], buf: &mut [u8],
- ) -> Result<()> {
+ &self, counter: u64, ad: &[u8], buf: &mut [u8], in_len: usize,
+ extra_in: Option<&[u8]>,
+ ) -> Result<usize> {
if cfg!(feature = "fuzzing") {
- return Ok(());
+ if let Some(extra) = extra_in {
+ buf[in_len..in_len + extra.len()].copy_from_slice(extra);
+ return Ok(in_len + extra.len());
+ }
+
+ return Ok(in_len);
}
- let nonce = make_nonce(&self.nonce, counter);
+ let tag_len = self.alg().tag_len();
- let ad = aead::Aad::from(ad);
+ let mut out_tag_len = tag_len;
- let tag_len = self.alg().tag_len();
+ let (extra_in_ptr, extra_in_len) = match extra_in {
+ Some(v) => (v.as_ptr(), v.len()),
- let in_out_len =
- buf.len().checked_sub(tag_len).ok_or(Error::CryptoFail)?;
+ None => (std::ptr::null(), 0),
+ };
- let (in_out, tag_out) = buf.split_at_mut(in_out_len);
+ // Make sure all the outputs combined fit in the buffer.
+ if in_len + tag_len + extra_in_len > buf.len() {
+ return Err(Error::CryptoFail);
+ }
- let tag = self
- .key
- .seal_in_place_separate_tag(nonce, ad, in_out)
- .map_err(|_| Error::CryptoFail)?;
+ let nonce = make_nonce(&self.nonce, counter);
- // Append the AEAD tag to the end of the sealed buffer.
- tag_out.copy_from_slice(tag.as_ref());
+ let rc = unsafe {
+ EVP_AEAD_CTX_seal_scatter(
+ &self.ctx, // ctx
+ buf.as_mut_ptr(), // out
+ buf[in_len..].as_mut_ptr(), // out_tag
+ &mut out_tag_len, // out_tag_len
+ tag_len + extra_in_len, // max_out_tag_len
+ nonce[..].as_ptr(), // nonce
+ nonce.len(), // nonce_len
+ buf.as_ptr(), // inp
+ in_len, // in_len
+ extra_in_ptr, // extra_in
+ extra_in_len, // extra_in_len
+ ad.as_ptr(), // ad
+ ad.len(), // ad_len
+ )
+ };
+
+ if rc != 1 {
+ return Err(Error::CryptoFail);
+ }
- Ok(())
+ Ok(in_len + out_tag_len)
}
pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> {
@@ -297,7 +357,7 @@ pub fn derive_initial_key_material(
let key_len = aead.key_len();
let nonce_len = aead.nonce_len();
- let initial_secret = derive_initial_secret(&cid, version);
+ let initial_secret = derive_initial_secret(cid, version);
// Client.
let mut client_key = vec![0; key_len];
@@ -418,6 +478,31 @@ pub fn derive_pkt_iv(
hkdf_expand_label(&secret, LABEL, &mut out[..nonce_len])
}
+fn make_aead_ctx(alg: Algorithm, key: &[u8]) -> Result<EVP_AEAD_CTX> {
+ let mut ctx = MaybeUninit::uninit();
+
+ let ctx = unsafe {
+ let aead = alg.get_evp_aead();
+
+ let rc = EVP_AEAD_CTX_init(
+ ctx.as_mut_ptr(),
+ aead,
+ key.as_ptr(),
+ alg.key_len(),
+ alg.tag_len(),
+ std::ptr::null_mut(),
+ );
+
+ if rc != 1 {
+ return Err(Error::CryptoFail);
+ }
+
+ ctx.assume_init()
+ };
+
+ Ok(ctx)
+}
+
fn hkdf_expand_label(
prk: &hkdf::Prk, label: &[u8], out: &mut [u8],
) -> Result<()> {
@@ -436,9 +521,9 @@ fn hkdf_expand_label(
Ok(())
}
-fn make_nonce(iv: &[u8], counter: u64) -> aead::Nonce {
+fn make_nonce(iv: &[u8], counter: u64) -> [u8; aead::NONCE_LEN] {
let mut nonce = [0; aead::NONCE_LEN];
- nonce.copy_from_slice(&iv);
+ nonce.copy_from_slice(iv);
// XOR the last bytes of the IV with the counter. This is equivalent to
// left-padding the counter with zero bytes.
@@ -446,7 +531,7 @@ fn make_nonce(iv: &[u8], counter: u64) -> aead::Nonce {
*a ^= b;
}
- aead::Nonce::assume_unique_for_key(nonce)
+ nonce
}
// The ring HKDF expand() API does not accept an arbitrary output length, so we
@@ -460,6 +545,49 @@ impl hkdf::KeyType for ArbitraryOutputLen {
}
}
+#[allow(non_camel_case_types)]
+#[repr(transparent)]
+struct EVP_AEAD(c_void);
+
+// NOTE: This structure is copied from <openssl/aead.h> in order to be able to
+// statically allocate it. While it is not often modified upstream, it needs to
+// be kept in sync.
+#[repr(C)]
+struct EVP_AEAD_CTX {
+ aead: libc::uintptr_t,
+ opaque: [u8; 580],
+ alignment: u64,
+ tag_len: u8,
+}
+
+extern {
+ // EVP_AEAD
+ fn EVP_aead_aes_128_gcm() -> *const EVP_AEAD;
+
+ fn EVP_aead_aes_256_gcm() -> *const EVP_AEAD;
+
+ fn EVP_aead_chacha20_poly1305() -> *const EVP_AEAD;
+
+ // EVP_AEAD_CTX
+ fn EVP_AEAD_CTX_init(
+ ctx: *mut EVP_AEAD_CTX, aead: *const EVP_AEAD, key: *const u8,
+ key_len: usize, tag_len: usize, engine: *mut c_void,
+ ) -> c_int;
+
+ fn EVP_AEAD_CTX_open(
+ ctx: *const EVP_AEAD_CTX, out: *mut u8, out_len: *mut usize,
+ max_out_len: usize, nonce: *const u8, nonce_len: usize, inp: *const u8,
+ in_len: usize, ad: *const u8, ad_len: usize,
+ ) -> c_int;
+
+ fn EVP_AEAD_CTX_seal_scatter(
+ ctx: *const EVP_AEAD_CTX, out: *mut u8, out_tag: *mut u8,
+ out_tag_len: *mut usize, max_out_tag_len: usize, nonce: *const u8,
+ nonce_len: usize, inp: *const u8, in_len: usize, extra_in: *const u8,
+ extra_in_len: usize, ad: *const u8, ad_len: usize,
+ ) -> c_int;
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/dgram.rs b/src/dgram.rs
index 023df5f..5da185e 100644
--- a/src/dgram.rs
+++ b/src/dgram.rs
@@ -46,13 +46,14 @@ impl DatagramQueue {
}
}
- pub fn push(&mut self, data: &[u8]) -> Result<()> {
+ pub fn push(&mut self, data: Vec<u8>) -> Result<()> {
if self.is_full() {
return Err(Error::Done);
}
- self.queue.push_back(data.to_vec());
self.queue_bytes_size += data.len();
+ self.queue.push_back(data);
+
Ok(())
}
diff --git a/src/ffi.rs b/src/ffi.rs
index 3290964..cdc6915 100644
--- a/src/ffi.rs
+++ b/src/ffi.rs
@@ -76,7 +76,7 @@ use crate::*;
#[no_mangle]
pub extern fn quiche_version() -> *const u8 {
- //static VERSION: &str = concat!("0.9.0", "\0");
+ //static VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");
// ANDROID's build system doesn't support environment variables
// so we hardcode the package version here.
static VERSION: &str = concat!("0.6.0", "\0");
@@ -166,6 +166,19 @@ pub extern fn quiche_config_load_verify_locations_from_file(
}
#[no_mangle]
+pub extern fn quiche_config_load_verify_locations_from_directory(
+ config: &mut Config, path: *const c_char,
+) -> c_int {
+ let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
+
+ match config.load_verify_locations_from_directory(path) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
pub extern fn quiche_config_verify_peer(config: &mut Config, v: bool) {
config.verify_peer(v);
}
@@ -307,6 +320,18 @@ pub extern fn quiche_config_set_max_send_udp_payload_size(
}
#[no_mangle]
+pub extern fn quiche_config_set_max_connection_window(
+ config: &mut Config, v: u64,
+) {
+ config.set_max_connection_window(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_max_stream_window(config: &mut Config, v: u64) {
+ config.set_max_stream_window(v);
+}
+
+#[no_mangle]
pub extern fn quiche_config_free(config: *mut Config) {
unsafe { Box::from_raw(config) };
}
@@ -395,7 +420,7 @@ pub extern fn quiche_accept(
let from = std_addr_from_c(from, from_len);
match accept(&scid, odcid.as_ref(), from, config) {
- Ok(c) => Box::into_raw(Pin::into_inner(c)),
+ Ok(c) => Box::into_raw(Box::new(c)),
Err(_) => ptr::null_mut(),
}
@@ -418,7 +443,7 @@ pub extern fn quiche_connect(
let to = std_addr_from_c(to, to_len);
match connect(server_name, &scid, to, config) {
- Ok(c) => Box::into_raw(Pin::into_inner(c)),
+ Ok(c) => Box::into_raw(Box::new(c)),
Err(_) => ptr::null_mut(),
}
@@ -503,7 +528,7 @@ pub extern fn quiche_conn_new_with_tls(
tls,
is_server,
) {
- Ok(c) => Box::into_raw(Pin::into_inner(c)),
+ Ok(c) => Box::into_raw(Box::new(c)),
Err(_) => ptr::null_mut(),
}
@@ -877,6 +902,20 @@ pub extern fn quiche_conn_application_proto(
}
#[no_mangle]
+pub extern fn quiche_conn_peer_cert(
+ conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t,
+) {
+ match conn.peer_cert() {
+ Some(peer_cert) => {
+ *out = peer_cert.as_ptr();
+ *out_len = peer_cert.len();
+ },
+
+ None => *out_len = 0,
+ }
+}
+
+#[no_mangle]
pub extern fn quiche_conn_session(
conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t,
) {
@@ -911,6 +950,11 @@ pub extern fn quiche_conn_is_closed(conn: &mut Connection) -> bool {
}
#[no_mangle]
+pub extern fn quiche_conn_is_timed_out(conn: &mut Connection) -> bool {
+ conn.is_timed_out()
+}
+
+#[no_mangle]
pub extern fn quiche_conn_peer_error(
conn: &mut Connection, is_app: *mut bool, error_code: *mut u64,
reason: &mut *const u8, reason_len: &mut size_t,
@@ -930,6 +974,25 @@ pub extern fn quiche_conn_peer_error(
}
#[no_mangle]
+pub extern fn quiche_conn_local_error(
+ conn: &mut Connection, is_app: *mut bool, error_code: *mut u64,
+ reason: &mut *const u8, reason_len: &mut size_t,
+) -> bool {
+ match &conn.local_error {
+ Some(conn_err) => unsafe {
+ *is_app = conn_err.is_app;
+ *error_code = conn_err.error_code;
+ *reason = conn_err.reason.as_ptr();
+ *reason_len = conn_err.reason.len();
+
+ true
+ },
+
+ None => false,
+ }
+}
+
+#[no_mangle]
pub extern fn quiche_stream_iter_next(
iter: &mut StreamIter, stream_id: *mut u64,
) -> bool {
@@ -951,9 +1014,28 @@ pub struct Stats {
recv: usize,
sent: usize,
lost: usize,
+ retrans: usize,
rtt: u64,
cwnd: usize,
+ sent_bytes: u64,
+ lost_bytes: u64,
+ recv_bytes: u64,
+ stream_retrans_bytes: u64,
+ pmtu: usize,
delivery_rate: u64,
+ peer_max_idle_timeout: u64,
+ peer_max_udp_payload_size: u64,
+ peer_initial_max_data: u64,
+ peer_initial_max_stream_data_bidi_local: u64,
+ peer_initial_max_stream_data_bidi_remote: u64,
+ peer_initial_max_stream_data_uni: u64,
+ peer_initial_max_streams_bidi: u64,
+ peer_initial_max_streams_uni: u64,
+ peer_ack_delay_exponent: u64,
+ peer_max_ack_delay: u64,
+ peer_disable_active_migration: bool,
+ peer_active_conn_id_limit: u64,
+ peer_max_datagram_frame_size: ssize_t,
}
#[no_mangle]
@@ -963,9 +1045,34 @@ pub extern fn quiche_conn_stats(conn: &Connection, out: &mut Stats) {
out.recv = stats.recv;
out.sent = stats.sent;
out.lost = stats.lost;
+ out.retrans = stats.retrans;
out.rtt = stats.rtt.as_nanos() as u64;
out.cwnd = stats.cwnd;
+ out.sent_bytes = stats.sent_bytes;
+ out.lost_bytes = stats.lost_bytes;
+ out.recv_bytes = stats.recv_bytes;
+ out.stream_retrans_bytes = stats.stream_retrans_bytes;
+ out.pmtu = stats.pmtu;
out.delivery_rate = stats.delivery_rate;
+ out.peer_max_idle_timeout = stats.peer_max_idle_timeout;
+ out.peer_max_udp_payload_size = stats.peer_max_udp_payload_size;
+ out.peer_initial_max_data = stats.peer_initial_max_data;
+ out.peer_initial_max_stream_data_bidi_local =
+ stats.peer_initial_max_stream_data_bidi_local;
+ out.peer_initial_max_stream_data_bidi_remote =
+ stats.peer_initial_max_stream_data_bidi_remote;
+ out.peer_initial_max_stream_data_uni = stats.peer_initial_max_stream_data_uni;
+ out.peer_initial_max_streams_bidi = stats.peer_initial_max_streams_bidi;
+ out.peer_initial_max_streams_uni = stats.peer_initial_max_streams_uni;
+ out.peer_ack_delay_exponent = stats.peer_ack_delay_exponent;
+ out.peer_max_ack_delay = stats.peer_max_ack_delay;
+ out.peer_disable_active_migration = stats.peer_disable_active_migration;
+ out.peer_active_conn_id_limit = stats.peer_active_conn_id_limit;
+ out.peer_max_datagram_frame_size = match stats.peer_max_datagram_frame_size {
+ None => Error::Done.to_c(),
+
+ Some(v) => v as ssize_t,
+ }
}
#[no_mangle]
@@ -1073,6 +1180,11 @@ pub extern fn quiche_conn_peer_streams_left_uni(conn: &mut Connection) -> u64 {
conn.peer_streams_left_uni()
}
+#[no_mangle]
+pub extern fn quiche_conn_send_quantum(conn: &mut Connection) -> size_t {
+ conn.send_quantum() as size_t
+}
+
fn std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr {
unsafe {
match addr.sa_family as i32 {
diff --git a/src/flowcontrol.rs b/src/flowcontrol.rs
new file mode 100644
index 0000000..6731c26
--- /dev/null
+++ b/src/flowcontrol.rs
@@ -0,0 +1,220 @@
+// Copyright (C) 2021, Cloudflare, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use std::time::Duration;
+use std::time::Instant;
+
+// When autotuning the receiver window, decide how much
+// we increase the window.
+const WINDOW_INCREASE_FACTOR: u64 = 2;
+
+// When autotuning the receiver window, check if the last
+// update is within RTT * this constant.
+const WINDOW_TRIGGER_FACTOR: u32 = 2;
+
+#[derive(Default, Debug)]
+pub struct FlowControl {
+ /// Total consumed bytes by the receiver.
+ consumed: u64,
+
+ /// Flow control limit.
+ max_data: u64,
+
+ /// The receive window. This value is used for updating
+ /// flow control limit.
+ window: u64,
+
+ /// The maximum receive window.
+ max_window: u64,
+
+ /// Last update time of max_data for autotuning the window.
+ last_update: Option<Instant>,
+}
+
+impl FlowControl {
+ pub fn new(max_data: u64, window: u64, max_window: u64) -> Self {
+ Self {
+ max_data,
+
+ window,
+
+ max_window,
+
+ ..Default::default()
+ }
+ }
+
+ /// Returns the current window size.
+ pub fn window(&self) -> u64 {
+ self.window
+ }
+
+ /// Returns the current flow limit.
+ pub fn max_data(&self) -> u64 {
+ self.max_data
+ }
+
+ /// Update consumed bytes.
+ pub fn add_consumed(&mut self, consumed: u64) {
+ self.consumed += consumed;
+ }
+
+ /// Returns true if the flow control needs to update max_data.
+ ///
+ /// This happens when the available window is smaller than the half
+ /// of the current window.
+ pub fn should_update_max_data(&self) -> bool {
+ let available_window = self.max_data - self.consumed;
+
+ available_window < (self.window / 2)
+ }
+
+ /// Returns the new max_data limit.
+ pub fn max_data_next(&self) -> u64 {
+ self.consumed + self.window
+ }
+
+ /// Commits the new max_data limit.
+ pub fn update_max_data(&mut self, now: Instant) {
+ self.max_data = self.max_data_next();
+ self.last_update = Some(now);
+ }
+
+ /// Autotune the window size. When there is an another update
+ /// within RTT x 2, bump the window x 1.5, capped by
+ /// max_window.
+ pub fn autotune_window(&mut self, now: Instant, rtt: Duration) {
+ if let Some(last_update) = self.last_update {
+ if now - last_update < rtt * WINDOW_TRIGGER_FACTOR {
+ self.window = std::cmp::min(
+ self.window * WINDOW_INCREASE_FACTOR,
+ self.max_window,
+ );
+ }
+ }
+ }
+
+ /// Make sure the lower bound of the window is same to
+ /// the current window.
+ pub fn ensure_window_lower_bound(&mut self, min_window: u64) {
+ if min_window > self.window {
+ self.window = min_window;
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn max_data() {
+ let fc = FlowControl::new(100, 20, 100);
+
+ assert_eq!(fc.max_data(), 100);
+ }
+
+ #[test]
+ fn should_update_max_data() {
+ let mut fc = FlowControl::new(100, 20, 100);
+
+ fc.add_consumed(85);
+ assert_eq!(fc.should_update_max_data(), false);
+
+ fc.add_consumed(10);
+ assert_eq!(fc.should_update_max_data(), true);
+ }
+
+ #[test]
+ fn max_data_next() {
+ let mut fc = FlowControl::new(100, 20, 100);
+
+ let consumed = 95;
+
+ fc.add_consumed(consumed);
+ assert_eq!(fc.should_update_max_data(), true);
+ assert_eq!(fc.max_data_next(), consumed + 20);
+ }
+
+ #[test]
+ fn update_max_data() {
+ let mut fc = FlowControl::new(100, 20, 100);
+
+ let consumed = 95;
+
+ fc.add_consumed(consumed);
+ assert_eq!(fc.should_update_max_data(), true);
+
+ let max_data_next = fc.max_data_next();
+ assert_eq!(fc.max_data_next(), consumed + 20);
+
+ fc.update_max_data(Instant::now());
+ assert_eq!(fc.max_data(), max_data_next);
+ }
+
+ #[test]
+ fn autotune_window() {
+ let w = 20;
+ let mut fc = FlowControl::new(100, w, 100);
+
+ let consumed = 95;
+
+ fc.add_consumed(consumed);
+ assert_eq!(fc.should_update_max_data(), true);
+
+ let max_data_next = fc.max_data_next();
+ assert_eq!(max_data_next, consumed + w);
+
+ fc.update_max_data(Instant::now());
+ assert_eq!(fc.max_data(), max_data_next);
+
+ // Window size should be doubled.
+ fc.autotune_window(Instant::now(), Duration::from_millis(100));
+
+ let w = w * 2;
+ let consumed_inc = 15;
+
+ fc.add_consumed(consumed_inc);
+ assert_eq!(fc.should_update_max_data(), true);
+
+ let max_data_next = fc.max_data_next();
+ assert_eq!(max_data_next, consumed + consumed_inc + w);
+ }
+
+ #[test]
+ fn ensure_window_lower_bound() {
+ let w = 20;
+ let mut fc = FlowControl::new(100, w, 100);
+
+ // Window doesn't change.
+ fc.ensure_window_lower_bound(w);
+ assert_eq!(fc.window(), 20);
+
+ // Window changed to the new value.
+ fc.ensure_window_lower_bound(w * 2);
+ assert_eq!(fc.window(), 40);
+ }
+}
diff --git a/src/frame.rs b/src/frame.rs
index c0cba7e..f568b29 100644
--- a/src/frame.rs
+++ b/src/frame.rs
@@ -24,19 +24,36 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+use std::convert::TryInto;
+
use crate::Error;
use crate::Result;
-use crate::octets;
use crate::packet;
use crate::ranges;
use crate::stream;
+#[cfg(feature = "qlog")]
+use qlog::events::quic::AckedRanges;
+#[cfg(feature = "qlog")]
+use qlog::events::quic::ErrorSpace;
+#[cfg(feature = "qlog")]
+use qlog::events::quic::QuicFrame;
+#[cfg(feature = "qlog")]
+use qlog::events::quic::StreamType;
+
pub const MAX_CRYPTO_OVERHEAD: usize = 8;
pub const MAX_DGRAM_OVERHEAD: usize = 2;
pub const MAX_STREAM_OVERHEAD: usize = 12;
pub const MAX_STREAM_SIZE: u64 = 1 << 62;
+#[derive(Clone, Debug, PartialEq)]
+pub struct EcnCounts {
+ ect0_count: u64,
+ ect1_count: u64,
+ ecn_ce_count: u64,
+}
+
#[derive(Clone, PartialEq)]
pub enum Frame {
Padding {
@@ -48,6 +65,7 @@ pub enum Frame {
ACK {
ack_delay: u64,
ranges: ranges::RangeSet,
+ ecn_counts: Option<EcnCounts>,
},
ResetStream {
@@ -124,7 +142,7 @@ pub enum Frame {
seq_num: u64,
retire_prior_to: u64,
conn_id: Vec<u8>,
- reset_token: Vec<u8>,
+ reset_token: [u8; 16],
},
RetireConnectionId {
@@ -132,11 +150,11 @@ pub enum Frame {
},
PathChallenge {
- data: Vec<u8>,
+ data: [u8; 8],
},
PathResponse {
- data: Vec<u8>,
+ data: [u8; 8],
},
ConnectionClose {
@@ -155,6 +173,10 @@ pub enum Frame {
Datagram {
data: Vec<u8>,
},
+
+ DatagramHeader {
+ length: usize,
+ },
}
impl Frame {
@@ -180,7 +202,7 @@ impl Frame {
0x01 => Frame::Ping,
- 0x02 => parse_ack_frame(frame_type, b)?,
+ 0x02..=0x03 => parse_ack_frame(frame_type, b)?,
0x04 => Frame::ResetStream {
stream_id: b.get_varint()?,
@@ -245,7 +267,11 @@ impl Frame {
seq_num: b.get_varint()?,
retire_prior_to: b.get_varint()?,
conn_id: b.get_bytes_with_u8_length()?.to_vec(),
- reset_token: b.get_bytes(16)?.to_vec(),
+ reset_token: b
+ .get_bytes(16)?
+ .buf()
+ .try_into()
+ .map_err(|_| Error::BufferTooShort)?,
},
0x19 => Frame::RetireConnectionId {
@@ -253,11 +279,19 @@ impl Frame {
},
0x1a => Frame::PathChallenge {
- data: b.get_bytes(8)?.to_vec(),
+ data: b
+ .get_bytes(8)?
+ .buf()
+ .try_into()
+ .map_err(|_| Error::BufferTooShort)?,
},
0x1b => Frame::PathResponse {
- data: b.get_bytes(8)?.to_vec(),
+ data: b
+ .get_bytes(8)?
+ .buf()
+ .try_into()
+ .map_err(|_| Error::BufferTooShort)?,
},
0x1c => Frame::ConnectionClose {
@@ -331,8 +365,16 @@ impl Frame {
b.put_varint(0x01)?;
},
- Frame::ACK { ack_delay, ranges } => {
- b.put_varint(0x02)?;
+ Frame::ACK {
+ ack_delay,
+ ranges,
+ ecn_counts,
+ } => {
+ if ecn_counts.is_none() {
+ b.put_varint(0x02)?;
+ } else {
+ b.put_varint(0x03)?;
+ }
let mut it = ranges.iter().rev();
@@ -355,6 +397,12 @@ impl Frame {
smallest_ack = block.start;
}
+
+ if let Some(ecn) = ecn_counts {
+ b.put_varint(ecn.ect0_count)?;
+ b.put_varint(ecn.ect1_count)?;
+ b.put_varint(ecn.ecn_ce_count)?;
+ }
},
Frame::ResetStream {
@@ -382,7 +430,7 @@ impl Frame {
Frame::Crypto { data } => {
encode_crypto_header(data.off() as u64, data.len() as u64, b)?;
- b.put_bytes(&data)?;
+ b.put_bytes(data)?;
},
Frame::CryptoHeader { .. } => (),
@@ -391,7 +439,7 @@ impl Frame {
b.put_varint(0x07)?;
b.put_varint(token.len() as u64)?;
- b.put_bytes(&token)?;
+ b.put_bytes(token)?;
},
Frame::Stream { stream_id, data } => {
@@ -403,7 +451,7 @@ impl Frame {
b,
)?;
- b.put_bytes(&data)?;
+ b.put_bytes(data)?;
},
Frame::StreamHeader { .. } => (),
@@ -517,16 +565,12 @@ impl Frame {
},
Frame::Datagram { data } => {
- let mut ty: u8 = 0x30;
-
- // Always encode length
- ty |= 0x01;
+ encode_dgram_header(data.len() as u64, b)?;
- b.put_varint(u64::from(ty))?;
-
- b.put_varint(data.len() as u64)?;
b.put_bytes(data.as_ref())?;
},
+
+ Frame::DatagramHeader { .. } => (),
}
Ok(before - b.cap())
@@ -538,7 +582,11 @@ impl Frame {
Frame::Ping => 1,
- Frame::ACK { ack_delay, ranges } => {
+ Frame::ACK {
+ ack_delay,
+ ranges,
+ ecn_counts,
+ } => {
let mut it = ranges.iter().rev();
let first = it.next().unwrap();
@@ -562,6 +610,12 @@ impl Frame {
smallest_ack = block.start;
}
+ if let Some(ecn) = ecn_counts {
+ len += octets::varint_len(ecn.ect0_count) +
+ octets::varint_len(ecn.ect1_count) +
+ octets::varint_len(ecn.ecn_ce_count);
+ }
+
len
},
@@ -723,9 +777,15 @@ impl Frame {
Frame::Datagram { data } => {
1 + // frame type
- octets::varint_len(data.len() as u64) + // length
+ 2 + // length, always encode as 2-byte varint
data.len() // data
},
+
+ Frame::DatagramHeader { length } => {
+ 1 + // frame type
+ 2 + // length, always encode as 2-byte varint
+ *length // data
+ },
}
}
@@ -740,176 +800,194 @@ impl Frame {
)
}
- pub fn shrink_for_retransmission(&mut self) {
- if let Frame::Datagram { data } = self {
- *data = Vec::new();
- }
- }
-
#[cfg(feature = "qlog")]
- pub fn to_qlog(&self) -> qlog::QuicFrame {
+ pub fn to_qlog(&self) -> QuicFrame {
match self {
- Frame::Padding { .. } => qlog::QuicFrame::padding(),
+ Frame::Padding { .. } => QuicFrame::Padding,
- Frame::Ping { .. } => qlog::QuicFrame::ping(),
+ Frame::Ping { .. } => QuicFrame::Ping,
- Frame::ACK { ack_delay, ranges } => {
- let ack_ranges =
- ranges.iter().map(|r| (r.start, r.end - 1)).collect();
- qlog::QuicFrame::ack(
- Some(ack_delay.to_string()),
- Some(ack_ranges),
- None,
- None,
- None,
- )
+ Frame::ACK {
+ ack_delay,
+ ranges,
+ ecn_counts,
+ } => {
+ let ack_ranges = AckedRanges::Double(
+ ranges.iter().map(|r| (r.start, r.end - 1)).collect(),
+ );
+
+ let (ect0, ect1, ce) = match ecn_counts {
+ Some(ecn) => (
+ Some(ecn.ect0_count),
+ Some(ecn.ect1_count),
+ Some(ecn.ecn_ce_count),
+ ),
+
+ None => (None, None, None),
+ };
+
+ QuicFrame::Ack {
+ ack_delay: Some(*ack_delay as f32 / 1000.0),
+ acked_ranges: Some(ack_ranges),
+ ect1,
+ ect0,
+ ce,
+ }
},
Frame::ResetStream {
stream_id,
error_code,
final_size,
- } => qlog::QuicFrame::reset_stream(
- stream_id.to_string(),
- *error_code,
- final_size.to_string(),
- ),
+ } => QuicFrame::ResetStream {
+ stream_id: *stream_id,
+ error_code: *error_code,
+ final_size: *final_size,
+ },
Frame::StopSending {
stream_id,
error_code,
- } =>
- qlog::QuicFrame::stop_sending(stream_id.to_string(), *error_code),
-
- Frame::Crypto { data } => qlog::QuicFrame::crypto(
- data.off().to_string(),
- data.len().to_string(),
- ),
-
- Frame::CryptoHeader { offset, length } =>
- qlog::QuicFrame::crypto(offset.to_string(), length.to_string()),
-
- Frame::NewToken { token } => qlog::QuicFrame::new_token(
- token.len().to_string(),
- "TODO: https://github.com/quiclog/internet-drafts/issues/36"
- .to_string(),
- ),
-
- Frame::Stream { stream_id, data } => qlog::QuicFrame::stream(
- stream_id.to_string(),
- data.off().to_string(),
- data.len().to_string(),
- data.fin(),
- None,
- ),
+ } => QuicFrame::StopSending {
+ stream_id: *stream_id,
+ error_code: *error_code,
+ },
+
+ Frame::Crypto { data } => QuicFrame::Crypto {
+ offset: data.off(),
+ length: data.len() as u64,
+ },
+
+ Frame::CryptoHeader { offset, length } => QuicFrame::Crypto {
+ offset: *offset,
+ length: *length as u64,
+ },
+
+ Frame::NewToken { token } => QuicFrame::NewToken {
+ token: qlog::Token {
+ // TODO: pick the token type some how
+ ty: Some(qlog::TokenType::StatelessReset),
+ length: None,
+ data: qlog::HexSlice::maybe_string(Some(token)),
+ details: None,
+ },
+ },
+
+ Frame::Stream { stream_id, data } => QuicFrame::Stream {
+ stream_id: *stream_id,
+ offset: data.off() as u64,
+ length: data.len() as u64,
+ fin: data.fin().then(|| true),
+ raw: None,
+ },
Frame::StreamHeader {
stream_id,
offset,
length,
fin,
- } => qlog::QuicFrame::stream(
- stream_id.to_string(),
- offset.to_string(),
- length.to_string(),
- *fin,
- None,
- ),
-
- Frame::MaxData { max } => qlog::QuicFrame::max_data(max.to_string()),
-
- Frame::MaxStreamData { stream_id, max } =>
- qlog::QuicFrame::max_stream_data(
- stream_id.to_string(),
- max.to_string(),
- ),
-
- Frame::MaxStreamsBidi { max } => qlog::QuicFrame::max_streams(
- qlog::StreamType::Bidirectional,
- max.to_string(),
- ),
-
- Frame::MaxStreamsUni { max } => qlog::QuicFrame::max_streams(
- qlog::StreamType::Unidirectional,
- max.to_string(),
- ),
+ } => QuicFrame::Stream {
+ stream_id: *stream_id,
+ offset: *offset,
+ length: *length as u64,
+ fin: fin.then(|| true),
+ raw: None,
+ },
+
+ Frame::MaxData { max } => QuicFrame::MaxData { maximum: *max },
+
+ Frame::MaxStreamData { stream_id, max } => QuicFrame::MaxStreamData {
+ stream_id: *stream_id,
+ maximum: *max,
+ },
+
+ Frame::MaxStreamsBidi { max } => QuicFrame::MaxStreams {
+ stream_type: StreamType::Bidirectional,
+ maximum: *max,
+ },
+
+ Frame::MaxStreamsUni { max } => QuicFrame::MaxStreams {
+ stream_type: StreamType::Unidirectional,
+ maximum: *max,
+ },
Frame::DataBlocked { limit } =>
- qlog::QuicFrame::data_blocked(limit.to_string()),
+ QuicFrame::DataBlocked { limit: *limit },
Frame::StreamDataBlocked { stream_id, limit } =>
- qlog::QuicFrame::stream_data_blocked(
- stream_id.to_string(),
- limit.to_string(),
- ),
-
- Frame::StreamsBlockedBidi { limit } =>
- qlog::QuicFrame::streams_blocked(
- qlog::StreamType::Bidirectional,
- limit.to_string(),
- ),
-
- Frame::StreamsBlockedUni { limit } =>
- qlog::QuicFrame::streams_blocked(
- qlog::StreamType::Unidirectional,
- limit.to_string(),
- ),
+ QuicFrame::StreamDataBlocked {
+ stream_id: *stream_id,
+ limit: *limit,
+ },
+
+ Frame::StreamsBlockedBidi { limit } => QuicFrame::StreamsBlocked {
+ stream_type: StreamType::Bidirectional,
+ limit: *limit,
+ },
+
+ Frame::StreamsBlockedUni { limit } => QuicFrame::StreamsBlocked {
+ stream_type: StreamType::Unidirectional,
+ limit: *limit,
+ },
Frame::NewConnectionId {
seq_num,
retire_prior_to,
conn_id,
- ..
- } => qlog::QuicFrame::new_connection_id(
- seq_num.to_string(),
- retire_prior_to.to_string(),
- conn_id.len() as u64,
- "TODO: https://github.com/quiclog/internet-drafts/issues/36"
- .to_string(),
- "TODO: https://github.com/quiclog/internet-drafts/issues/36"
- .to_string(),
- ),
+ reset_token,
+ } => QuicFrame::NewConnectionId {
+ sequence_number: *seq_num as u32,
+ retire_prior_to: *retire_prior_to as u32,
+ connection_id_length: Some(conn_id.len() as u8),
+ connection_id: format!("{}", qlog::HexSlice::new(conn_id)),
+ stateless_reset_token: Some(qlog::Token {
+ ty: Some(qlog::TokenType::StatelessReset),
+ length: None,
+ data: qlog::HexSlice::maybe_string(Some(reset_token)),
+ details: None,
+ }),
+ },
Frame::RetireConnectionId { seq_num } =>
- qlog::QuicFrame::retire_connection_id(seq_num.to_string()),
+ QuicFrame::RetireConnectionId {
+ sequence_number: *seq_num as u32,
+ },
- Frame::PathChallenge { .. } => qlog::QuicFrame::path_challenge(Some(
- "TODO: https://github.com/quiclog/internet-drafts/issues/36"
- .to_string(),
- )),
+ Frame::PathChallenge { .. } =>
+ QuicFrame::PathChallenge { data: None },
- Frame::PathResponse { .. } => qlog::QuicFrame::path_response(Some(
- "TODO: https://github.com/quiclog/internet-drafts/issues/36"
- .to_string(),
- )),
+ Frame::PathResponse { .. } => QuicFrame::PathResponse { data: None },
Frame::ConnectionClose {
error_code, reason, ..
- } => qlog::QuicFrame::connection_close(
- qlog::ErrorSpace::TransportError,
- *error_code,
- *error_code,
- String::from_utf8(reason.clone()).unwrap(),
- Some(
- "TODO: https://github.com/quiclog/internet-drafts/issues/36"
- .to_string(),
- ),
- ),
+ } => QuicFrame::ConnectionClose {
+ error_space: Some(ErrorSpace::TransportError),
+ error_code: Some(*error_code),
+ raw_error_code: None, // raw error is no different for us
+ reason: Some(String::from_utf8(reason.clone()).unwrap()),
+ trigger_frame_type: None, // don't know trigger type
+ },
Frame::ApplicationClose { error_code, reason } =>
- qlog::QuicFrame::connection_close(
- qlog::ErrorSpace::ApplicationError,
- *error_code,
- *error_code,
- String::from_utf8(reason.clone()).unwrap(),
- None, /* Application variant of the frame has no trigger
- * frame type */
- ),
-
- Frame::HandshakeDone => qlog::QuicFrame::handshake_done(),
-
- Frame::Datagram { data } =>
- qlog::QuicFrame::datagram(data.len().to_string(), None),
+ QuicFrame::ConnectionClose {
+ error_space: Some(ErrorSpace::ApplicationError),
+ error_code: Some(*error_code),
+ raw_error_code: None, // raw error is no different for us
+ reason: Some(String::from_utf8(reason.clone()).unwrap()),
+ trigger_frame_type: None, // don't know trigger type
+ },
+
+ Frame::HandshakeDone => QuicFrame::HandshakeDone,
+
+ Frame::Datagram { data } => QuicFrame::Datagram {
+ length: data.len() as u64,
+ raw: None,
+ },
+
+ Frame::DatagramHeader { length } => QuicFrame::Datagram {
+ length: *length as u64,
+ raw: None,
+ },
}
}
}
@@ -925,8 +1003,16 @@ impl std::fmt::Debug for Frame {
write!(f, "PING")?;
},
- Frame::ACK { ack_delay, ranges } => {
- write!(f, "ACK delay={} blocks={:?}", ack_delay, ranges)?;
+ Frame::ACK {
+ ack_delay,
+ ranges,
+ ecn_counts,
+ } => {
+ write!(
+ f,
+ "ACK delay={} blocks={:?} ecn_counts={:?}",
+ ack_delay, ranges, ecn_counts
+ )?;
},
Frame::ResetStream {
@@ -1065,7 +1151,11 @@ impl std::fmt::Debug for Frame {
},
Frame::Datagram { data } => {
- write!(f, "DATAGRAM len={}", data.len(),)?;
+ write!(f, "DATAGRAM len={}", data.len())?;
+ },
+
+ Frame::DatagramHeader { length } => {
+ write!(f, "DATAGRAM len={}", length)?;
},
}
@@ -1073,7 +1163,9 @@ impl std::fmt::Debug for Frame {
}
}
-fn parse_ack_frame(_ty: u64, b: &mut octets::Octets) -> Result<Frame> {
+fn parse_ack_frame(ty: u64, b: &mut octets::Octets) -> Result<Frame> {
+ let first = ty as u8;
+
let largest_ack = b.get_varint()?;
let ack_delay = b.get_varint()?;
let block_count = b.get_varint()?;
@@ -1087,7 +1179,6 @@ fn parse_ack_frame(_ty: u64, b: &mut octets::Octets) -> Result<Frame> {
let mut ranges = ranges::RangeSet::default();
- #[allow(clippy::range_plus_one)]
ranges.insert(smallest_ack..largest_ack + 1);
for _i in 0..block_count {
@@ -1106,11 +1197,26 @@ fn parse_ack_frame(_ty: u64, b: &mut octets::Octets) -> Result<Frame> {
smallest_ack = largest_ack - ack_block;
- #[allow(clippy::range_plus_one)]
ranges.insert(smallest_ack..largest_ack + 1);
}
- Ok(Frame::ACK { ack_delay, ranges })
+ let ecn_counts = if first & 0x01 != 0 {
+ let ecn = EcnCounts {
+ ect0_count: b.get_varint()?,
+ ect1_count: b.get_varint()?,
+ ecn_ce_count: b.get_varint()?,
+ };
+
+ Some(ecn)
+ } else {
+ None
+ };
+
+ Ok(Frame::ACK {
+ ack_delay,
+ ranges,
+ ecn_counts,
+ })
}
pub fn encode_crypto_header(
@@ -1153,6 +1259,20 @@ pub fn encode_stream_header(
Ok(())
}
+pub fn encode_dgram_header(length: u64, b: &mut octets::OctetsMut) -> Result<()> {
+ let mut ty: u8 = 0x30;
+
+ // Always encode length
+ ty |= 0x01;
+
+ b.put_varint(u64::from(ty))?;
+
+ // Always encode length field as 2-byte varint.
+ b.put_varint_with_len(length, 2)?;
+
+ Ok(())
+}
+
fn parse_stream_frame(ty: u64, b: &mut octets::Octets) -> Result<Frame> {
let first = ty as u8;
@@ -1268,6 +1388,7 @@ mod tests {
let frame = Frame::ACK {
ack_delay: 874_656_534,
ranges,
+ ecn_counts: None,
};
let wire_len = {
@@ -1291,6 +1412,48 @@ mod tests {
}
#[test]
+ fn ack_ecn() {
+ let mut d = [42; 128];
+
+ let mut ranges = ranges::RangeSet::default();
+ ranges.insert(4..7);
+ ranges.insert(9..12);
+ ranges.insert(15..19);
+ ranges.insert(3000..5000);
+
+ let ecn_counts = Some(EcnCounts {
+ ect0_count: 100,
+ ect1_count: 200,
+ ecn_ce_count: 300,
+ });
+
+ let frame = Frame::ACK {
+ ack_delay: 874_656_534,
+ ranges,
+ ecn_counts,
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 23);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok());
+ }
+
+ #[test]
fn reset_stream() {
let mut d = [42; 128];
@@ -1685,7 +1848,7 @@ mod tests {
seq_num: 123_213,
retire_prior_to: 122_211,
conn_id: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
- reset_token: vec![0x42; 16],
+ reset_token: [0x42; 16],
};
let wire_len = {
@@ -1739,7 +1902,7 @@ mod tests {
let mut d = [42; 128];
let frame = Frame::PathChallenge {
- data: vec![1, 2, 3, 4, 5, 6, 7, 8],
+ data: [1, 2, 3, 4, 5, 6, 7, 8],
};
let wire_len = {
@@ -1767,7 +1930,7 @@ mod tests {
let mut d = [42; 128];
let frame = Frame::PathResponse {
- data: vec![1, 2, 3, 4, 5, 6, 7, 8],
+ data: [1, 2, 3, 4, 5, 6, 7, 8],
};
let wire_len = {
@@ -1881,14 +2044,14 @@ mod tests {
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
- let mut frame = Frame::Datagram { data: data.clone() };
+ let frame = Frame::Datagram { data: data.clone() };
let wire_len = {
let mut b = octets::OctetsMut::with_slice(&mut d);
frame.to_bytes(&mut b).unwrap()
};
- assert_eq!(wire_len, 14);
+ assert_eq!(wire_len, 15);
let mut b = octets::Octets::with_slice(&mut d);
assert_eq!(
@@ -1912,15 +2075,5 @@ mod tests {
};
assert_eq!(frame_data, data);
-
- frame.shrink_for_retransmission();
-
- let frame_data = match &frame {
- Frame::Datagram { data } => data.clone(),
-
- _ => unreachable!(),
- };
-
- assert_eq!(frame_data.len(), 0);
}
}
diff --git a/src/h3/ffi.rs b/src/h3/ffi.rs
index fc254b0..d32b1be 100644
--- a/src/h3/ffi.rs
+++ b/src/h3/ffi.rs
@@ -24,11 +24,12 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-use std::ffi;
+#[cfg(feature = "sfv")]
+use std::convert::TryFrom;
+
use std::ptr;
use std::slice;
-use libc::c_char;
use libc::c_int;
use libc::c_void;
use libc::size_t;
@@ -37,6 +38,7 @@ use libc::ssize_t;
use crate::*;
use crate::h3::NameValue;
+use crate::h3::Priority;
#[no_mangle]
pub extern fn quiche_h3_config_new() -> *mut h3::Config {
@@ -48,10 +50,10 @@ pub extern fn quiche_h3_config_new() -> *mut h3::Config {
}
#[no_mangle]
-pub extern fn quiche_h3_config_set_max_header_list_size(
+pub extern fn quiche_h3_config_set_max_field_section_size(
config: &mut h3::Config, v: u64,
) {
- config.set_max_header_list_size(v);
+ config.set_max_field_section_size(v);
}
#[no_mangle]
@@ -85,6 +87,29 @@ pub extern fn quiche_h3_conn_new_with_transport(
}
#[no_mangle]
+pub extern fn quiche_h3_for_each_setting(
+ conn: &h3::Connection,
+ cb: extern fn(identifier: u64, value: u64, argp: *mut c_void) -> c_int,
+ argp: *mut c_void,
+) -> c_int {
+ match conn.peer_settings_raw() {
+ Some(raw) => {
+ for setting in raw {
+ let rc = cb(setting.0, setting.1, argp);
+
+ if rc != 0 {
+ return rc;
+ }
+ }
+
+ 0
+ },
+
+ None => -1,
+ }
+}
+
+#[no_mangle]
pub extern fn quiche_h3_conn_poll(
conn: &mut h3::Connection, quic_conn: &mut Connection,
ev: *mut *const h3::Event,
@@ -114,6 +139,10 @@ pub extern fn quiche_h3_event_type(ev: &h3::Event) -> u32 {
h3::Event::Datagram { .. } => 3,
h3::Event::GoAway { .. } => 4,
+
+ h3::Event::Reset { .. } => 5,
+
+ h3::Event::PriorityUpdate { .. } => 6,
}
}
@@ -207,17 +236,15 @@ pub extern fn quiche_h3_send_response(
#[no_mangle]
pub extern fn quiche_h3_send_response_with_priority(
conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
- headers: *const Header, headers_len: size_t, priority: *const c_char,
- fin: bool,
+ headers: *const Header, headers_len: size_t, priority: &Priority, fin: bool,
) -> c_int {
let resp_headers = headers_from_ptr(headers, headers_len);
- let priority = unsafe { ffi::CStr::from_ptr(priority).to_str().unwrap() };
match conn.send_response_with_priority(
quic_conn,
stream_id,
&resp_headers,
- &priority,
+ priority,
fin,
) {
Ok(_) => 0,
@@ -263,6 +290,49 @@ pub extern fn quiche_h3_recv_body(
}
#[no_mangle]
+#[cfg(feature = "sfv")]
+pub extern fn quiche_h3_parse_extensible_priority(
+ priority: *const u8, priority_len: size_t, parsed: &mut Priority,
+) -> c_int {
+ let priority = unsafe { slice::from_raw_parts(priority, priority_len) };
+
+ match h3::Priority::try_from(priority) {
+ Ok(v) => {
+ parsed.urgency = v.urgency;
+ parsed.incremental = v.incremental;
+ 0
+ },
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_take_last_priority_update(
+ conn: &mut h3::Connection, prioritized_element_id: u64,
+ cb: extern fn(
+ priority_field_value: *const u8,
+ priority_field_value_len: size_t,
+ argp: *mut c_void,
+ ) -> c_int,
+ argp: *mut c_void,
+) -> c_int {
+ match conn.take_last_priority_update(prioritized_element_id) {
+ Ok(priority) => {
+ let rc = cb(priority.as_ptr(), priority.len(), argp);
+
+ if rc != 0 {
+ return rc;
+ }
+
+ 0
+ },
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
pub extern fn quiche_h3_dgram_enabled_by_peer(
conn: &h3::Connection, quic_conn: &Connection,
) -> bool {
diff --git a/src/h3/frame.rs b/src/h3/frame.rs
index 085524b..46b802d 100644
--- a/src/h3/frame.rs
+++ b/src/h3/frame.rs
@@ -26,7 +26,8 @@
use super::Result;
-use crate::octets;
+#[cfg(feature = "qlog")]
+use qlog::events::h3::Http3Frame;
pub const DATA_FRAME_TYPE_ID: u64 = 0x0;
pub const HEADERS_FRAME_TYPE_ID: u64 = 0x1;
@@ -35,11 +36,13 @@ pub const SETTINGS_FRAME_TYPE_ID: u64 = 0x4;
pub const PUSH_PROMISE_FRAME_TYPE_ID: u64 = 0x5;
pub const GOAWAY_FRAME_TYPE_ID: u64 = 0x6;
pub const MAX_PUSH_FRAME_TYPE_ID: u64 = 0xD;
+pub const PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID: u64 = 0xF0700;
+pub const PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID: u64 = 0xF0701;
-const SETTINGS_QPACK_MAX_TABLE_CAPACITY: u64 = 0x1;
-const SETTINGS_MAX_HEADER_LIST_SIZE: u64 = 0x6;
-const SETTINGS_QPACK_BLOCKED_STREAMS: u64 = 0x7;
-const SETTINGS_H3_DATAGRAM: u64 = 0x276;
+pub const SETTINGS_QPACK_MAX_TABLE_CAPACITY: u64 = 0x1;
+pub const SETTINGS_MAX_FIELD_SECTION_SIZE: u64 = 0x6;
+pub const SETTINGS_QPACK_BLOCKED_STREAMS: u64 = 0x7;
+pub const SETTINGS_H3_DATAGRAM: u64 = 0x276;
// Permit between 16 maximally-encoded and 128 minimally-encoded SETTINGS.
const MAX_SETTINGS_PAYLOAD_SIZE: usize = 256;
@@ -59,11 +62,12 @@ pub enum Frame {
},
Settings {
- max_header_list_size: Option<u64>,
+ max_field_section_size: Option<u64>,
qpack_max_table_capacity: Option<u64>,
qpack_blocked_streams: Option<u64>,
h3_datagram: Option<u64>,
grease: Option<(u64, u64)>,
+ raw: Option<Vec<(u64, u64)>>,
},
PushPromise {
@@ -79,7 +83,20 @@ pub enum Frame {
push_id: u64,
},
- Unknown,
+ PriorityUpdateRequest {
+ prioritized_element_id: u64,
+ priority_field_value: Vec<u8>,
+ },
+
+ PriorityUpdatePush {
+ prioritized_element_id: u64,
+ priority_field_value: Vec<u8>,
+ },
+
+ Unknown {
+ raw_type: u64,
+ payload_length: u64,
+ },
}
impl Frame {
@@ -116,7 +133,14 @@ impl Frame {
push_id: b.get_varint()?,
},
- _ => Frame::Unknown,
+ PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID |
+ PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID =>
+ parse_priority_update(frame_type, payload_length, &mut b)?,
+
+ _ => Frame::Unknown {
+ raw_type: frame_type,
+ payload_length,
+ },
};
Ok(frame)
@@ -148,16 +172,17 @@ impl Frame {
},
Frame::Settings {
- max_header_list_size,
+ max_field_section_size,
qpack_max_table_capacity,
qpack_blocked_streams,
h3_datagram,
grease,
+ ..
} => {
let mut len = 0;
- if let Some(val) = max_header_list_size {
- len += octets::varint_len(SETTINGS_MAX_HEADER_LIST_SIZE);
+ if let Some(val) = max_field_section_size {
+ len += octets::varint_len(SETTINGS_MAX_FIELD_SECTION_SIZE);
len += octets::varint_len(*val);
}
@@ -184,8 +209,8 @@ impl Frame {
b.put_varint(SETTINGS_FRAME_TYPE_ID)?;
b.put_varint(len as u64)?;
- if let Some(val) = max_header_list_size {
- b.put_varint(SETTINGS_MAX_HEADER_LIST_SIZE)?;
+ if let Some(val) = max_field_section_size {
+ b.put_varint(SETTINGS_MAX_FIELD_SECTION_SIZE)?;
b.put_varint(*val as u64)?;
}
@@ -236,22 +261,161 @@ impl Frame {
b.put_varint(*push_id)?;
},
- Frame::Unknown => unreachable!(),
+ Frame::PriorityUpdateRequest {
+ prioritized_element_id,
+ priority_field_value,
+ } => {
+ let len = octets::varint_len(*prioritized_element_id) +
+ priority_field_value.len();
+
+ b.put_varint(PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID)?;
+ b.put_varint(len as u64)?;
+
+ b.put_varint(*prioritized_element_id as u64)?;
+ b.put_bytes(priority_field_value)?;
+ },
+
+ Frame::PriorityUpdatePush {
+ prioritized_element_id,
+ priority_field_value,
+ } => {
+ let len = octets::varint_len(*prioritized_element_id) +
+ priority_field_value.len();
+
+ b.put_varint(PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID)?;
+ b.put_varint(len as u64)?;
+
+ b.put_varint(*prioritized_element_id as u64)?;
+ b.put_bytes(priority_field_value)?;
+ },
+
+ Frame::Unknown { .. } => unreachable!(),
}
Ok(before - b.cap())
}
+
+ #[cfg(feature = "qlog")]
+ pub fn to_qlog(&self) -> Http3Frame {
+ match self {
+ Frame::Data { .. } => Http3Frame::Data { raw: None },
+
+ // Qlog expects the `headers` to be represented as an array of
+ // name:value pairs. At this stage, we only have the qpack block, so
+ // populate the field with an empty vec.
+ Frame::Headers { .. } => Http3Frame::Headers { headers: vec![] },
+
+ Frame::CancelPush { push_id } =>
+ Http3Frame::CancelPush { push_id: *push_id },
+
+ Frame::Settings {
+ max_field_section_size,
+ qpack_max_table_capacity,
+ qpack_blocked_streams,
+ h3_datagram,
+ grease,
+ ..
+ } => {
+ let mut settings = vec![];
+
+ if let Some(v) = max_field_section_size {
+ settings.push(qlog::events::h3::Setting {
+ name: "MAX_FIELD_SECTION_SIZE".to_string(),
+ value: *v,
+ });
+ }
+
+ if let Some(v) = qpack_max_table_capacity {
+ settings.push(qlog::events::h3::Setting {
+ name: "QPACK_MAX_TABLE_CAPACITY".to_string(),
+ value: *v,
+ });
+ }
+
+ if let Some(v) = qpack_blocked_streams {
+ settings.push(qlog::events::h3::Setting {
+ name: "QPACK_BLOCKED_STREAMS".to_string(),
+ value: *v,
+ });
+ }
+
+ if let Some(v) = h3_datagram {
+ settings.push(qlog::events::h3::Setting {
+ name: "H3_DATAGRAM".to_string(),
+ value: *v,
+ });
+ }
+
+ if let Some((k, v)) = grease {
+ settings.push(qlog::events::h3::Setting {
+ name: k.to_string(),
+ value: *v,
+ });
+ }
+
+ qlog::events::h3::Http3Frame::Settings { settings }
+ },
+
+ // Qlog expects the `headers` to be represented as an array of
+ // name:value pairs. At this stage, we only have the qpack block, so
+ // populate the field with an empty vec.
+ Frame::PushPromise { push_id, .. } => Http3Frame::PushPromise {
+ push_id: *push_id,
+ headers: vec![],
+ },
+
+ Frame::GoAway { id } => Http3Frame::Goaway { id: *id },
+
+ Frame::MaxPushId { push_id } =>
+ Http3Frame::MaxPushId { push_id: *push_id },
+
+ Frame::PriorityUpdateRequest {
+ prioritized_element_id,
+ priority_field_value,
+ } => Http3Frame::PriorityUpdate {
+ target_stream_type:
+ qlog::events::h3::H3PriorityTargetStreamType::Request,
+ prioritized_element_id: *prioritized_element_id,
+ priority_field_value: String::from_utf8_lossy(
+ priority_field_value,
+ )
+ .into_owned(),
+ },
+
+ Frame::PriorityUpdatePush {
+ prioritized_element_id,
+ priority_field_value,
+ } => Http3Frame::PriorityUpdate {
+ target_stream_type:
+ qlog::events::h3::H3PriorityTargetStreamType::Request,
+ prioritized_element_id: *prioritized_element_id,
+ priority_field_value: String::from_utf8_lossy(
+ priority_field_value,
+ )
+ .into_owned(),
+ },
+
+ Frame::Unknown {
+ raw_type,
+ payload_length,
+ } => Http3Frame::Unknown {
+ raw_frame_type: *raw_type,
+ raw_length: Some(*payload_length as u32),
+ raw: None,
+ },
+ }
+ }
}
impl std::fmt::Debug for Frame {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
- Frame::Data { payload } => {
- write!(f, "DATA len={}", payload.len())?;
+ Frame::Data { .. } => {
+ write!(f, "DATA")?;
},
- Frame::Headers { header_block } => {
- write!(f, "HEADERS len={}", header_block.len())?;
+ Frame::Headers { .. } => {
+ write!(f, "HEADERS")?;
},
Frame::CancelPush { push_id } => {
@@ -259,12 +423,13 @@ impl std::fmt::Debug for Frame {
},
Frame::Settings {
- max_header_list_size,
+ max_field_section_size,
qpack_max_table_capacity,
qpack_blocked_streams,
+ raw,
..
} => {
- write!(f, "SETTINGS max_headers={:?}, qpack_max_table={:?}, qpack_blocked={:?} ", max_header_list_size, qpack_max_table_capacity, qpack_blocked_streams)?;
+ write!(f, "SETTINGS max_field_section={:?}, qpack_max_table={:?}, qpack_blocked={:?} raw={:?}", max_field_section_size, qpack_max_table_capacity, qpack_blocked_streams, raw)?;
},
Frame::PushPromise {
@@ -287,8 +452,32 @@ impl std::fmt::Debug for Frame {
write!(f, "MAX_PUSH_ID push_id={}", push_id)?;
},
- Frame::Unknown => {
- write!(f, "UNKNOWN")?;
+ Frame::PriorityUpdateRequest {
+ prioritized_element_id,
+ priority_field_value,
+ } => {
+ write!(
+ f,
+ "PRIORITY_UPDATE request_stream_id={}, priority_field_len={}",
+ prioritized_element_id,
+ priority_field_value.len()
+ )?;
+ },
+
+ Frame::PriorityUpdatePush {
+ prioritized_element_id,
+ priority_field_value,
+ } => {
+ write!(
+ f,
+ "PRIORITY_UPDATE push_id={}, priority_field_len={}",
+ prioritized_element_id,
+ priority_field_value.len()
+ )?;
+ },
+
+ Frame::Unknown { raw_type, .. } => {
+ write!(f, "UNKNOWN raw_type={}", raw_type,)?;
},
}
@@ -299,10 +488,11 @@ impl std::fmt::Debug for Frame {
fn parse_settings_frame(
b: &mut octets::Octets, settings_length: usize,
) -> Result<Frame> {
- let mut max_header_list_size = None;
+ let mut max_field_section_size = None;
let mut qpack_max_table_capacity = None;
let mut qpack_blocked_streams = None;
let mut h3_datagram = None;
+ let mut raw = Vec::new();
// Reject SETTINGS frames that are too long.
if settings_length > MAX_SETTINGS_PAYLOAD_SIZE {
@@ -310,28 +500,32 @@ fn parse_settings_frame(
}
while b.off() < settings_length {
- let setting_ty = b.get_varint()?;
- let settings_val = b.get_varint()?;
+ let identifier = b.get_varint()?;
+ let value = b.get_varint()?;
+
+ // MAX_SETTINGS_PAYLOAD_SIZE protects us from storing too many raw
+ // settings.
+ raw.push((identifier, value));
- match setting_ty {
+ match identifier {
SETTINGS_QPACK_MAX_TABLE_CAPACITY => {
- qpack_max_table_capacity = Some(settings_val);
+ qpack_max_table_capacity = Some(value);
},
- SETTINGS_MAX_HEADER_LIST_SIZE => {
- max_header_list_size = Some(settings_val);
+ SETTINGS_MAX_FIELD_SECTION_SIZE => {
+ max_field_section_size = Some(value);
},
SETTINGS_QPACK_BLOCKED_STREAMS => {
- qpack_blocked_streams = Some(settings_val);
+ qpack_blocked_streams = Some(value);
},
SETTINGS_H3_DATAGRAM => {
- if settings_val > 1 {
+ if value > 1 {
return Err(super::Error::SettingsError);
}
- h3_datagram = Some(settings_val);
+ h3_datagram = Some(value);
},
// Reserved values overlap with HTTP/2 and MUST be rejected
@@ -344,11 +538,12 @@ fn parse_settings_frame(
}
Ok(Frame::Settings {
- max_header_list_size,
+ max_field_section_size,
qpack_max_table_capacity,
qpack_blocked_streams,
h3_datagram,
grease: None,
+ raw: Some(raw),
})
}
@@ -365,6 +560,31 @@ fn parse_push_promise(
})
}
+fn parse_priority_update(
+ frame_type: u64, payload_length: u64, b: &mut octets::Octets,
+) -> Result<Frame> {
+ let prioritized_element_id = b.get_varint()?;
+ let priority_field_value_length =
+ payload_length - octets::varint_len(prioritized_element_id) as u64;
+ let priority_field_value =
+ b.get_bytes(priority_field_value_length as usize)?.to_vec();
+
+ match frame_type {
+ PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID =>
+ Ok(Frame::PriorityUpdateRequest {
+ prioritized_element_id,
+ priority_field_value,
+ }),
+
+ PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID => Ok(Frame::PriorityUpdatePush {
+ prioritized_element_id,
+ priority_field_value,
+ }),
+
+ _ => unreachable!(),
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -456,12 +676,20 @@ mod tests {
fn settings_all_no_grease() {
let mut d = [42; 128];
+ let raw_settings = vec![
+ (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
+ (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
+ (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
+ (SETTINGS_H3_DATAGRAM, 0),
+ ];
+
let frame = Frame::Settings {
- max_header_list_size: Some(0),
+ max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
h3_datagram: Some(0),
grease: None,
+ raw: Some(raw_settings),
};
let frame_payload_len = 9;
@@ -490,20 +718,31 @@ mod tests {
let mut d = [42; 128];
let frame = Frame::Settings {
- max_header_list_size: Some(0),
+ max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
h3_datagram: Some(0),
grease: Some((33, 33)),
+ raw: Default::default(),
};
- // Frame parsing will always ignore GREASE values.
+ let raw_settings = vec![
+ (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
+ (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
+ (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
+ (SETTINGS_H3_DATAGRAM, 0),
+ (33, 33),
+ ];
+
+ // Frame parsing will not populate GREASE property but will be in the
+ // raw info.
let frame_parsed = Frame::Settings {
- max_header_list_size: Some(0),
+ max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
h3_datagram: Some(0),
grease: None,
+ raw: Some(raw_settings),
};
let frame_payload_len = 11;
@@ -531,12 +770,15 @@ mod tests {
fn settings_h3_only() {
let mut d = [42; 128];
+ let raw_settings = vec![(SETTINGS_MAX_FIELD_SECTION_SIZE, 1024)];
+
let frame = Frame::Settings {
- max_header_list_size: Some(1024),
+ max_field_section_size: Some(1024),
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
h3_datagram: None,
grease: None,
+ raw: Some(raw_settings),
};
let frame_payload_len = 3;
@@ -564,12 +806,15 @@ mod tests {
fn settings_h3_dgram_only() {
let mut d = [42; 128];
+ let raw_settings = vec![(SETTINGS_H3_DATAGRAM, 1)];
+
let frame = Frame::Settings {
- max_header_list_size: None,
+ max_field_section_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
h3_datagram: Some(1),
grease: None,
+ raw: Some(raw_settings),
};
let frame_payload_len = 3;
@@ -598,11 +843,12 @@ mod tests {
let mut d = [42; 128];
let frame = Frame::Settings {
- max_header_list_size: None,
+ max_field_section_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
h3_datagram: Some(5),
grease: None,
+ raw: Default::default(),
};
let frame_payload_len = 3;
@@ -629,12 +875,18 @@ mod tests {
fn settings_qpack_only() {
let mut d = [42; 128];
+ let raw_settings = vec![
+ (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
+ (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
+ ];
+
let frame = Frame::Settings {
- max_header_list_size: None,
+ max_field_section_size: None,
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
h3_datagram: None,
grease: None,
+ raw: Some(raw_settings),
};
let frame_payload_len = 4;
@@ -837,9 +1089,79 @@ mod tests {
}
#[test]
+ fn priority_update_request() {
+ let mut d = [42; 128];
+
+ let prioritized_element_id = 4;
+ let priority_field_value = b"abcdefghijklm".to_vec();
+ let frame_payload_len = 1 + priority_field_value.len();
+ let frame_header_len = 5;
+
+ let frame = Frame::PriorityUpdateRequest {
+ prioritized_element_id,
+ priority_field_value,
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn priority_update_push() {
+ let mut d = [42; 128];
+
+ let prioritized_element_id = 6;
+ let priority_field_value = b"abcdefghijklm".to_vec();
+ let frame_payload_len = 1 + priority_field_value.len();
+ let frame_header_len = 5;
+
+ let frame = Frame::PriorityUpdatePush {
+ prioritized_element_id,
+ priority_field_value,
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
fn unknown_type() {
let d = [42; 12];
- assert_eq!(Frame::from_bytes(255, 12345, &d[..]), Ok(Frame::Unknown));
+ assert_eq!(
+ Frame::from_bytes(255, 12345, &d[..]),
+ Ok(Frame::Unknown {
+ raw_type: 255,
+ payload_length: 12345
+ })
+ );
}
}
diff --git a/src/h3/mod.rs b/src/h3/mod.rs
index dd2a51a..f3d9e06 100644
--- a/src/h3/mod.rs
+++ b/src/h3/mod.rs
@@ -164,8 +164,14 @@
//! // Peer terminated stream, handle it.
//! },
//!
+//! Ok((stream_id, quiche::h3::Event::Reset(err))) => {
+//! // Peer reset the stream, handle it.
+//! },
+//!
//! Ok((_flow_id, quiche::h3::Event::Datagram)) => (),
//!
+//! Ok((_flow_id, quiche::h3::Event::PriorityUpdate)) => (),
+//!
//! Ok((goaway_id, quiche::h3::Event::GoAway)) => {
//! // Peer signalled it is going away, handle it.
//! },
@@ -220,8 +226,14 @@
//! // Peer terminated stream, handle it.
//! },
//!
+//! Ok((stream_id, quiche::h3::Event::Reset(err))) => {
+//! // Peer reset the stream, handle it.
+//! },
+//!
//! Ok((_flow_id, quiche::h3::Event::Datagram)) => (),
//!
+//! Ok((_prioritized_element_id, quiche::h3::Event::PriorityUpdate)) => (),
+//!
//! Ok((goaway_id, quiche::h3::Event::GoAway)) => {
//! // Peer signalled it is going away, handle it.
//! },
@@ -269,10 +281,31 @@
//! [`send_response()`]: struct.Connection.html#method.send_response
//! [`send_body()`]: struct.Connection.html#method.send_body
-use std::collections::HashMap;
use std::collections::VecDeque;
-use crate::octets;
+#[cfg(feature = "sfv")]
+use std::convert::TryFrom;
+
+#[cfg(feature = "qlog")]
+use qlog::events::h3::H3FrameCreated;
+#[cfg(feature = "qlog")]
+use qlog::events::h3::H3FrameParsed;
+#[cfg(feature = "qlog")]
+use qlog::events::h3::H3Owner;
+#[cfg(feature = "qlog")]
+use qlog::events::h3::H3StreamType;
+#[cfg(feature = "qlog")]
+use qlog::events::h3::H3StreamTypeSet;
+#[cfg(feature = "qlog")]
+use qlog::events::h3::Http3EventType;
+#[cfg(feature = "qlog")]
+use qlog::events::h3::Http3Frame;
+#[cfg(feature = "qlog")]
+use qlog::events::EventData;
+#[cfg(feature = "qlog")]
+use qlog::events::EventImportance;
+#[cfg(feature = "qlog")]
+use qlog::events::EventType;
/// List of ALPN tokens of supported HTTP/3 versions.
///
@@ -286,6 +319,24 @@ pub const APPLICATION_PROTOCOL: &[u8] = b"\x02h3\x05h3-29\x05h3-28\x05h3-27";
// The offset used when converting HTTP/3 urgency to quiche urgency.
const PRIORITY_URGENCY_OFFSET: u8 = 124;
+// Parameter values as specified in [Extensible Priorities].
+//
+// [Extensible Priorities]: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-priority-12#section-4.
+const PRIORITY_URGENCY_LOWER_BOUND: u8 = 0;
+const PRIORITY_URGENCY_UPPER_BOUND: u8 = 7;
+const PRIORITY_URGENCY_DEFAULT: u8 = 3;
+const PRIORITY_INCREMENTAL_DEFAULT: bool = false;
+
+#[cfg(feature = "qlog")]
+const QLOG_FRAME_CREATED: EventType =
+ EventType::Http3EventType(Http3EventType::FrameCreated);
+#[cfg(feature = "qlog")]
+const QLOG_FRAME_PARSED: EventType =
+ EventType::Http3EventType(Http3EventType::FrameParsed);
+#[cfg(feature = "qlog")]
+const QLOG_STREAM_TYPE_SET: EventType =
+ EventType::Http3EventType(Http3EventType::StreamTypeSet);
+
/// A specialized [`Result`] type for quiche HTTP/3 operations.
///
/// This type is used throughout quiche's HTTP/3 public API for any operation
@@ -406,7 +457,7 @@ impl Error {
Error::FrameUnexpected => -9,
Error::FrameError => -10,
Error::QpackDecompressionFailed => -11,
- Error::TransportError { .. } => -12,
+ // -12 was previously used for TransportError, skip it
Error::StreamBlocked => -13,
Error::SettingsError => -14,
Error::RequestRejected => -15,
@@ -415,6 +466,8 @@ impl Error {
Error::MessageError => -18,
Error::ConnectError => -19,
Error::VersionFallback => -20,
+
+ Error::TransportError(quic_error) => quic_error.to_c() - 1000,
}
}
}
@@ -449,22 +502,22 @@ impl std::convert::From<octets::BufferTooShortError> for Error {
/// An HTTP/3 configuration.
pub struct Config {
- max_header_list_size: Option<u64>,
+ max_field_section_size: Option<u64>,
qpack_max_table_capacity: Option<u64>,
qpack_blocked_streams: Option<u64>,
}
impl Config {
/// Creates a new configuration object with default settings.
- pub fn new() -> Result<Config> {
+ pub const fn new() -> Result<Config> {
Ok(Config {
- max_header_list_size: None,
+ max_field_section_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
})
}
- /// Sets the `SETTINGS_MAX_HEADER_LIST_SIZE` setting.
+ /// Sets the `SETTINGS_MAX_FIELD_SECTION_SIZE` setting.
///
/// By default no limit is enforced. When a request whose headers exceed
/// the limit set by the application is received, the call to the [`poll()`]
@@ -473,8 +526,8 @@ impl Config {
///
/// [`poll()`]: struct.Connection.html#method.poll
/// [`Error::ExcessiveLoad`]: enum.Error.html#variant.ExcessiveLoad
- pub fn set_max_header_list_size(&mut self, v: u64) {
- self.max_header_list_size = Some(v);
+ pub fn set_max_field_section_size(&mut self, v: u64) {
+ self.max_field_section_size = Some(v);
}
/// Sets the `SETTINGS_QPACK_MAX_TABLE_CAPACITY` setting.
@@ -530,7 +583,7 @@ pub struct HeaderRef<'a>(&'a [u8], &'a [u8]);
impl<'a> HeaderRef<'a> {
/// Creates a new header.
- pub fn new(name: &'a [u8], value: &'a [u8]) -> Self {
+ pub const fn new(name: &'a [u8], value: &'a [u8]) -> Self {
Self(name, value)
}
}
@@ -574,6 +627,11 @@ pub enum Event {
/// Stream was closed,
Finished,
+ /// Stream was reset.
+ ///
+ /// The associated data represents the error code sent by the peer.
+ Reset(u64),
+
/// DATAGRAM was received.
///
/// This indicates that the application can use the [`recv_dgram()`] method
@@ -587,15 +645,129 @@ pub enum Event {
/// [`Done`]: enum.Error.html#variant.Done
Datagram,
+ /// PRIORITY_UPDATE was received.
+ ///
+ /// This indicates that the application can use the
+ /// [`take_last_priority_update()`] method to take the last received
+ /// PRIORITY_UPDATE for a specified stream.
+ ///
+ /// This event is triggered once per stream until the last PRIORITY_UPDATE
+ /// is taken. It is recommended that applications defer taking the
+ /// PRIORITY_UPDATE until after [`poll()`] returns [`Done`].
+ ///
+ /// [`take_last_priority_update()`]: struct.Connection.html#method.take_last_priority_update
+ /// [`poll()`]: struct.Connection.html#method.poll
+ /// [`Done`]: enum.Error.html#variant.Done
+ PriorityUpdate,
+
/// GOAWAY was received.
GoAway,
}
+/// Extensible Priorities parameters.
+///
+/// The `TryFrom` trait supports constructing this object from the serialized
+/// Structured Fields Dictionary field value. I.e, use `TryFrom` to parse the
+/// value of a Priority header field or a PRIORITY_UPDATE frame. Using this
+/// trait requires the `sfv` feature to be enabled.
+#[derive(Debug, PartialEq)]
+#[repr(C)]
+pub struct Priority {
+ urgency: u8,
+ incremental: bool,
+}
+
+impl Default for Priority {
+ fn default() -> Self {
+ Priority {
+ urgency: PRIORITY_URGENCY_DEFAULT as u8,
+ incremental: PRIORITY_INCREMENTAL_DEFAULT,
+ }
+ }
+}
+
+impl Priority {
+ /// Creates a new Priority.
+ pub const fn new(urgency: u8, incremental: bool) -> Self {
+ Priority {
+ urgency,
+ incremental,
+ }
+ }
+}
+
+#[cfg(feature = "sfv")]
+#[cfg_attr(docsrs, doc(cfg(feature = "sfv")))]
+impl TryFrom<&[u8]> for Priority {
+ type Error = crate::h3::Error;
+
+ /// Try to parse an Extensible Priority field value.
+ ///
+ /// The field value is expected to be a Structured Fields Dictionary; see
+ /// [Extensible Priorities].
+ ///
+ /// If the `u` or `i` fields are contained with correct types, a constructed
+ /// Priority object is returned. Note that urgency values outside of valid
+ /// range (0 through 7) are clamped to 7.
+ ///
+ /// If the `u` or `i` fields are contained with the wrong types,
+ /// Error::Done is returned.
+ ///
+ /// Omitted parameters will yield default values.
+ ///
+ /// [Extensible Priorities]: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-priority-12#section-4.
+ fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
+ let dict = match sfv::Parser::parse_dictionary(value) {
+ Ok(v) => v,
+
+ Err(_) => return Err(Error::Done),
+ };
+
+ let urgency = match dict.get("u") {
+ // If there is a u parameter, try to read it as an Item of type
+ // Integer. If the value out of the spec's allowed range
+ // (0 through 7), that's an error so set it to the upper
+ // bound (lowest priority) to avoid interference with
+ // other streams.
+ Some(sfv::ListEntry::Item(item)) => match item.bare_item.as_int() {
+ Some(v) => {
+ if !(PRIORITY_URGENCY_LOWER_BOUND as i64..=
+ PRIORITY_URGENCY_UPPER_BOUND as i64)
+ .contains(&v)
+ {
+ PRIORITY_URGENCY_UPPER_BOUND
+ } else {
+ v as u8
+ }
+ },
+
+ None => return Err(Error::Done),
+ },
+
+ Some(sfv::ListEntry::InnerList(_)) => return Err(Error::Done),
+
+ // Omitted so use default value.
+ None => PRIORITY_URGENCY_DEFAULT,
+ };
+
+ let incremental = match dict.get("i") {
+ Some(sfv::ListEntry::Item(item)) =>
+ item.bare_item.as_bool().ok_or(Error::Done)?,
+
+ // Omitted so use default value.
+ _ => false,
+ };
+
+ Ok(Priority::new(urgency as u8, incremental))
+ }
+}
+
struct ConnectionSettings {
- pub max_header_list_size: Option<u64>,
+ pub max_field_section_size: Option<u64>,
pub qpack_max_table_capacity: Option<u64>,
pub qpack_blocked_streams: Option<u64>,
pub h3_datagram: Option<u64>,
+ pub raw: Option<Vec<(u64, u64)>>,
}
struct QpackStreams {
@@ -610,7 +782,7 @@ pub struct Connection {
next_request_stream_id: u64,
next_uni_stream_id: u64,
- streams: HashMap<u64, stream::Stream>,
+ streams: crate::stream::StreamIdHashMap<stream::Stream>,
local_settings: ConnectionSettings,
peer_settings: ConnectionSettings,
@@ -621,7 +793,6 @@ pub struct Connection {
qpack_encoder: qpack::Encoder,
qpack_decoder: qpack::Decoder,
- #[allow(dead_code)]
local_qpack_streams: QpackStreams,
peer_qpack_streams: QpackStreams,
@@ -638,7 +809,6 @@ pub struct Connection {
}
impl Connection {
- #[allow(clippy::unnecessary_wraps)]
fn new(
config: &Config, is_server: bool, enable_dgram: bool,
) -> Result<Connection> {
@@ -652,20 +822,22 @@ impl Connection {
next_uni_stream_id: initial_uni_stream_id,
- streams: HashMap::new(),
+ streams: Default::default(),
local_settings: ConnectionSettings {
- max_header_list_size: config.max_header_list_size,
+ max_field_section_size: config.max_field_section_size,
qpack_max_table_capacity: config.qpack_max_table_capacity,
qpack_blocked_streams: config.qpack_blocked_streams,
h3_datagram,
+ raw: Default::default(),
},
peer_settings: ConnectionSettings {
- max_header_list_size: None,
+ max_field_section_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
h3_datagram: None,
+ raw: Default::default(),
},
control_stream_id: None,
@@ -774,6 +946,10 @@ impl Connection {
if let Err(e) = conn.stream_send(stream_id, b"", false) {
self.streams.remove(&stream_id);
+ if e == super::Error::Done {
+ return Err(Error::StreamBlocked);
+ }
+
return Err(e.into());
};
@@ -806,10 +982,10 @@ impl Connection {
&mut self, conn: &mut super::Connection, stream_id: u64, headers: &[T],
fin: bool,
) -> Result<()> {
- let priority = "u=3";
+ let priority = Default::default();
self.send_response_with_priority(
- conn, stream_id, headers, priority, fin,
+ conn, stream_id, headers, &priority, fin,
)?;
Ok(())
@@ -818,56 +994,32 @@ impl Connection {
/// Sends an HTTP/3 response on the specified stream with specified
/// priority.
///
+ /// The `priority` parameter represents [Extensible Priority]
+ /// parameters. If the urgency is outside the range 0-7, it will be clamped
+ /// to 7.
+ ///
/// The [`StreamBlocked`] error is returned when the underlying QUIC stream
/// doesn't have enough capacity for the operation to complete. When this
/// happens the application should retry the operation once the stream is
/// reported as writable again.
///
/// [`StreamBlocked`]: enum.Error.html#variant.StreamBlocked
+ /// [Extensible Priority]: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-priority-12#section-4.
pub fn send_response_with_priority<T: NameValue>(
&mut self, conn: &mut super::Connection, stream_id: u64, headers: &[T],
- priority: &str, fin: bool,
+ priority: &Priority, fin: bool,
) -> Result<()> {
if !self.streams.contains_key(&stream_id) {
return Err(Error::FrameUnexpected);
}
- let mut urgency = 3u8.saturating_add(PRIORITY_URGENCY_OFFSET);
- let mut incremental = false;
+ // Clamp and shift urgency into quiche-priority space
+ let urgency = priority
+ .urgency
+ .clamp(PRIORITY_URGENCY_LOWER_BOUND, PRIORITY_URGENCY_UPPER_BOUND) +
+ PRIORITY_URGENCY_OFFSET;
- for param in priority.split(',') {
- if param.trim() == "i" {
- incremental = true;
- continue;
- }
-
- if param.trim().starts_with("u=") {
- // u is an sh-integer (an i64) but it has a constrained range of
- // 0-7. So detect anything outside that range and clamp it to
- // the lowest urgency in order to avoid it interfering with
- // valid items.
- //
- // TODO: this also detects when u is not an sh-integer and
- // clamps it in the same way. A real structured header parser
- // would actually fail to parse.
- let mut u = param
- .rsplit('=')
- .next()
- .unwrap()
- .parse::<i64>()
- .unwrap_or(7);
-
- if !(0..=7).contains(&u) {
- u = 7;
- }
-
- // The HTTP/3 urgency needs to be shifted into the quiche
- // urgency range.
- urgency = (u as u8).saturating_add(PRIORITY_URGENCY_OFFSET);
- }
- }
-
- conn.stream_priority(stream_id, urgency, incremental)?;
+ conn.stream_priority(stream_id, urgency, priority.incremental)?;
self.send_headers(conn, stream_id, headers, fin)?;
@@ -884,7 +1036,7 @@ impl Connection {
let mut header_block = vec![0; headers_len];
let len = self
.qpack_encoder
- .encode(&headers, &mut header_block)
+ .encode(headers, &mut header_block)
.map_err(|_| Error::InternalError)?;
header_block.truncate(len);
@@ -904,8 +1056,17 @@ impl Connection {
self.frames_greased = true;
}
- let stream_cap = match conn.stream_capacity(stream_id) {
- Ok(v) => v,
+ let header_block = self.encode_header_block(headers)?;
+
+ let overhead = octets::varint_len(frame::HEADERS_FRAME_TYPE_ID) +
+ octets::varint_len(header_block.len() as u64);
+
+ // Headers need to be sent atomically, so make sure the stream has
+ // enough capacity.
+ match conn.stream_writable(stream_id, overhead + header_block.len()) {
+ Ok(true) => (),
+
+ Ok(false) => return Err(Error::StreamBlocked),
Err(e) => {
if conn.stream_finished(stream_id) {
@@ -916,14 +1077,13 @@ impl Connection {
},
};
- let header_block = self.encode_header_block(headers)?;
-
- let overhead = octets::varint_len(frame::HEADERS_FRAME_TYPE_ID) +
- octets::varint_len(header_block.len() as u64);
+ b.put_varint(frame::HEADERS_FRAME_TYPE_ID)?;
+ b.put_varint(header_block.len() as u64)?;
+ let off = b.off();
+ conn.stream_send(stream_id, &d[..off], false)?;
- if stream_cap < overhead + header_block.len() {
- return Err(Error::StreamBlocked);
- }
+ // Sending header block separately avoids unnecessary copy.
+ conn.stream_send(stream_id, &header_block, fin)?;
trace!(
"{} tx frm HEADERS stream={} len={} fin={}",
@@ -933,13 +1093,27 @@ impl Connection {
fin
);
- b.put_varint(frame::HEADERS_FRAME_TYPE_ID)?;
- b.put_varint(header_block.len() as u64)?;
- let off = b.off();
- conn.stream_send(stream_id, &d[..off], false)?;
+ qlog_with_type!(QLOG_FRAME_CREATED, conn.qlog, q, {
+ let qlog_headers = headers
+ .iter()
+ .map(|h| qlog::events::h3::HttpHeader {
+ name: String::from_utf8_lossy(h.name()).into_owned(),
+ value: String::from_utf8_lossy(h.value()).into_owned(),
+ })
+ .collect();
+
+ let frame = Http3Frame::Headers {
+ headers: qlog_headers,
+ };
+ let ev_data = EventData::H3FrameCreated(H3FrameCreated {
+ stream_id,
+ length: Some(header_block.len() as u64),
+ frame,
+ raw: None,
+ });
- // Sending header block separately avoids unnecessary copy.
- conn.stream_send(stream_id, &header_block, fin)?;
+ q.add_event_data_now(ev_data).ok();
+ });
if let Some(s) = self.streams.get_mut(&stream_id) {
s.initialize_local();
@@ -1009,6 +1183,12 @@ impl Connection {
},
};
+ if stream_cap < overhead + body.len() {
+ // Ensure the peer is notified that the connection or stream is
+ // blocked when the stream's capacity is limited by flow control.
+ let _ = conn.stream_writable(stream_id, overhead + body.len());
+ }
+
// Make sure there is enough capacity to send the DATA frame header.
if stream_cap < overhead {
return Err(Error::Done);
@@ -1026,14 +1206,6 @@ impl Connection {
return Err(Error::Done);
}
- trace!(
- "{} tx frm DATA stream={} len={} fin={}",
- conn.trace_id(),
- stream_id,
- body_len,
- fin
- );
-
b.put_varint(frame::DATA_FRAME_TYPE_ID)?;
b.put_varint(body_len as u64)?;
let off = b.off();
@@ -1043,6 +1215,26 @@ impl Connection {
// Sending body separately avoids unnecessary copy.
let written = conn.stream_send(stream_id, &body[..body_len], fin)?;
+ trace!(
+ "{} tx frm DATA stream={} len={} fin={}",
+ conn.trace_id(),
+ stream_id,
+ written,
+ fin
+ );
+
+ qlog_with_type!(QLOG_FRAME_CREATED, conn.qlog, q, {
+ let frame = Http3Frame::Data { raw: None };
+ let ev_data = EventData::H3FrameCreated(H3FrameCreated {
+ stream_id,
+ length: Some(written as u64),
+ frame,
+ raw: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
+
if fin && written == body.len() && conn.stream_finished(stream_id) {
self.streams.remove(&stream_id);
}
@@ -1073,7 +1265,7 @@ impl Connection {
b.put_varint(flow_id)?;
b.put_bytes(buf)?;
- conn.dgram_send(&d)?;
+ conn.dgram_send_vec(d)?;
Ok(())
}
@@ -1215,6 +1407,30 @@ impl Connection {
Ok(total)
}
+ /// Take the last PRIORITY_UPDATE for a prioritized element ID.
+ ///
+ /// When the [`poll()`] method returns a [`PriorityUpdate`] event for a
+ /// prioritized element, the event has triggered and will not rearm until
+ /// applications call this method. It is recommended that applications defer
+ /// taking the PRIORITY_UPDATE until after [`poll()`] returns [`Done`].
+ ///
+ /// On success the Priority Field Value is returned, or [`Done`] if there is
+ /// no PRIORITY_UPDATE to read (either because there is no value to take, or
+ /// because the prioritized element does not exist).
+ ///
+ /// [`poll()`]: struct.Connection.html#method.poll
+ /// [`PriorityUpdate`]: enum.Event.html#variant.PriorityUpdate
+ /// [`Done`]: enum.Error.html#variant.Done
+ pub fn take_last_priority_update(
+ &mut self, prioritized_element_id: u64,
+ ) -> Result<Vec<u8>> {
+ if let Some(stream) = self.streams.get_mut(&prioritized_element_id) {
+ return stream.take_last_priority_update().ok_or(Error::Done);
+ }
+
+ Err(Error::Done)
+ }
+
/// Processes HTTP/3 data received from the peer.
///
/// On success it returns an [`Event`] and an ID, or [`Done`] when there are
@@ -1235,6 +1451,10 @@ impl Connection {
/// A client receives the largest processed stream ID. A server receives the
/// the largest permitted push ID.
///
+ /// The event [`PriorityUpdate`] only occurs at servers. It returns a
+ /// prioritized element ID that is used in the method
+ /// [`take_last_priority_update()`], which rearms the event for that ID.
+ ///
/// If an error occurs while processing data, the connection is closed with
/// the appropriate error code, using the transport's [`close()`] method.
///
@@ -1245,10 +1465,12 @@ impl Connection {
/// [`Finished`]: enum.Event.html#variant.Finished
/// [`Datagram`]: enum.Event.html#variant.Datagram
/// [`GoAway`]: enum.Event.html#variant.GoAWay
+ /// [`PriorityUpdate`]: enum.Event.html#variant.PriorityUpdate
/// [`recv_body()`]: struct.Connection.html#method.recv_body
/// [`send_response()`]: struct.Connection.html#method.send_response
/// [`send_body()`]: struct.Connection.html#method.send_body
/// [`recv_dgram()`]: struct.Connection.html#method.recv_dgram
+ /// [`take_last_priority_update()`]: struct.Connection.html#method.take_last_priority_update
/// [`close()`]: ../struct.Connection.html#method.close
pub fn poll(&mut self, conn: &mut super::Connection) -> Result<(u64, Event)> {
// When connection close is initiated by the local application (e.g. due
@@ -1312,6 +1534,11 @@ impl Connection {
Err(Error::Done) => None,
+ // Return early if the stream was reset, to avoid returning
+ // a Finished event later as well.
+ Err(Error::TransportError(crate::Error::StreamReset(e))) =>
+ return Ok((s, Event::Reset(e))),
+
Err(e) => return Err(e),
};
@@ -1383,6 +1610,17 @@ impl Connection {
trace!("{} tx frm {:?}", conn.trace_id(), frame);
+ qlog_with_type!(QLOG_FRAME_CREATED, conn.qlog, q, {
+ let ev_data = EventData::H3FrameCreated(H3FrameCreated {
+ stream_id,
+ length: Some(octets::varint_len(id) as u64),
+ frame: frame.to_qlog(),
+ raw: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
+
let off = b.off();
conn.stream_send(stream_id, &d[..off], false)?;
@@ -1392,6 +1630,13 @@ impl Connection {
Ok(())
}
+ /// Gets the raw settings from peer including unknown and reserved types.
+ ///
+ /// The order of settings is the same as received in the SETTINGS frame.
+ pub fn peer_settings_raw(&self) -> Option<&[(u64, u64)]> {
+ self.peer_settings.raw.as_deref()
+ }
+
fn open_uni_stream(
&mut self, conn: &mut super::Connection, ty: u64,
) -> Result<u64> {
@@ -1432,9 +1677,22 @@ impl Connection {
fn open_qpack_encoder_stream(
&mut self, conn: &mut super::Connection,
) -> Result<()> {
- self.local_qpack_streams.encoder_stream_id = Some(
- self.open_uni_stream(conn, stream::QPACK_ENCODER_STREAM_TYPE_ID)?,
- );
+ let stream_id =
+ self.open_uni_stream(conn, stream::QPACK_ENCODER_STREAM_TYPE_ID)?;
+
+ self.local_qpack_streams.encoder_stream_id = Some(stream_id);
+
+ qlog_with_type!(QLOG_STREAM_TYPE_SET, conn.qlog, q, {
+ let ev_data = EventData::H3StreamTypeSet(H3StreamTypeSet {
+ stream_id,
+ owner: Some(H3Owner::Local),
+ old: None,
+ new: H3StreamType::QpackEncode,
+ associated_push_id: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
Ok(())
}
@@ -1442,9 +1700,22 @@ impl Connection {
fn open_qpack_decoder_stream(
&mut self, conn: &mut super::Connection,
) -> Result<()> {
- self.local_qpack_streams.decoder_stream_id = Some(
- self.open_uni_stream(conn, stream::QPACK_DECODER_STREAM_TYPE_ID)?,
- );
+ let stream_id =
+ self.open_uni_stream(conn, stream::QPACK_DECODER_STREAM_TYPE_ID)?;
+
+ self.local_qpack_streams.decoder_stream_id = Some(stream_id);
+
+ qlog_with_type!(QLOG_STREAM_TYPE_SET, conn.qlog, q, {
+ let ev_data = EventData::H3StreamTypeSet(H3StreamTypeSet {
+ stream_id,
+ owner: Some(H3Owner::Local),
+ old: None,
+ new: H3StreamType::QpackDecode,
+ associated_push_id: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
Ok(())
}
@@ -1483,8 +1754,6 @@ impl Connection {
return Ok(());
}
- trace!("{} tx frm GREASE stream={}", conn.trace_id(), stream_id);
-
// Empty GREASE frame.
let mut b = octets::OctetsMut::with_slice(&mut d);
conn.stream_send(stream_id, b.put_varint(grease_frame1)?, false)?;
@@ -1492,6 +1761,24 @@ impl Connection {
let mut b = octets::OctetsMut::with_slice(&mut d);
conn.stream_send(stream_id, b.put_varint(0)?, false)?;
+ trace!(
+ "{} tx frm GREASE stream={} len=0",
+ conn.trace_id(),
+ stream_id
+ );
+
+ qlog_with_type!(QLOG_FRAME_CREATED, conn.qlog, q, {
+ let frame = Http3Frame::Reserved { length: Some(0) };
+ let ev_data = EventData::H3FrameCreated(H3FrameCreated {
+ stream_id,
+ length: Some(0),
+ frame,
+ raw: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
+
// GREASE frame with payload.
let mut b = octets::OctetsMut::with_slice(&mut d);
conn.stream_send(stream_id, b.put_varint(grease_frame2)?, false)?;
@@ -1501,6 +1788,27 @@ impl Connection {
conn.stream_send(stream_id, grease_payload, false)?;
+ trace!(
+ "{} tx frm GREASE stream={} len={}",
+ conn.trace_id(),
+ stream_id,
+ grease_payload.len()
+ );
+
+ qlog_with_type!(QLOG_FRAME_CREATED, conn.qlog, q, {
+ let frame = Http3Frame::Reserved {
+ length: Some(grease_payload.len() as u64),
+ };
+ let ev_data = EventData::H3FrameCreated(H3FrameCreated {
+ stream_id,
+ length: Some(grease_payload.len() as u64),
+ frame,
+ raw: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
+
Ok(())
}
@@ -1509,9 +1817,21 @@ impl Connection {
fn open_grease_stream(&mut self, conn: &mut super::Connection) -> Result<()> {
match self.open_uni_stream(conn, grease_value()) {
Ok(stream_id) => {
+ conn.stream_send(stream_id, b"GREASE is the word", true)?;
+
trace!("{} open GREASE stream {}", conn.trace_id(), stream_id);
- conn.stream_send(stream_id, b"GREASE is the word", true)?;
+ qlog_with_type!(QLOG_STREAM_TYPE_SET, conn.qlog, q, {
+ let ev_data = EventData::H3StreamTypeSet(H3StreamTypeSet {
+ stream_id,
+ owner: Some(H3Owner::Local),
+ old: None,
+ new: H3StreamType::Unknown,
+ associated_push_id: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
},
Err(Error::IdError) => {
@@ -1528,9 +1848,22 @@ impl Connection {
/// Sends SETTINGS frame based on HTTP/3 configuration.
fn send_settings(&mut self, conn: &mut super::Connection) -> Result<()> {
- self.control_stream_id = Some(
- self.open_uni_stream(conn, stream::HTTP3_CONTROL_STREAM_TYPE_ID)?,
- );
+ let stream_id =
+ self.open_uni_stream(conn, stream::HTTP3_CONTROL_STREAM_TYPE_ID)?;
+
+ self.control_stream_id = Some(stream_id);
+
+ qlog_with_type!(QLOG_STREAM_TYPE_SET, conn.qlog, q, {
+ let ev_data = EventData::H3StreamTypeSet(H3StreamTypeSet {
+ stream_id,
+ owner: Some(H3Owner::Local),
+ old: None,
+ new: H3StreamType::Control,
+ associated_push_id: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
let grease = if conn.grease {
Some((grease_value(), grease_value()))
@@ -1539,13 +1872,14 @@ impl Connection {
};
let frame = frame::Frame::Settings {
- max_header_list_size: self.local_settings.max_header_list_size,
+ max_field_section_size: self.local_settings.max_field_section_size,
qpack_max_table_capacity: self
.local_settings
.qpack_max_table_capacity,
qpack_blocked_streams: self.local_settings.qpack_blocked_streams,
h3_datagram: self.local_settings.h3_datagram,
grease,
+ raw: Default::default(),
};
let mut d = [42; 128];
@@ -1557,6 +1891,25 @@ impl Connection {
if let Some(id) = self.control_stream_id {
conn.stream_send(id, &d[..off], false)?;
+
+ trace!(
+ "{} tx frm SETTINGS stream={} len={}",
+ conn.trace_id(),
+ id,
+ off
+ );
+
+ qlog_with_type!(QLOG_FRAME_CREATED, conn.qlog, q, {
+ let frame = frame.to_qlog();
+ let ev_data = EventData::H3FrameCreated(H3FrameCreated {
+ stream_id: id,
+ length: Some(off as u64),
+ frame,
+ raw: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
}
Ok(())
@@ -1625,6 +1978,19 @@ impl Connection {
return Err(e);
}
+ qlog_with_type!(QLOG_STREAM_TYPE_SET, conn.qlog, q, {
+ let ev_data =
+ EventData::H3StreamTypeSet(H3StreamTypeSet {
+ stream_id,
+ owner: Some(H3Owner::Remote),
+ old: None,
+ new: ty.to_qlog(),
+ associated_push_id: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
+
match &ty {
stream::Type::Control => {
// Only one control stream allowed.
@@ -1757,13 +2123,38 @@ impl Connection {
stream::State::FramePayloadLen => {
stream.try_fill_buffer(conn)?;
- let varint = match stream.try_consume_varint() {
+ let payload_len = match stream.try_consume_varint() {
Ok(v) => v,
Err(_) => continue,
};
- if let Err(e) = stream.set_frame_payload_len(varint) {
+ // DATA frames are handled uniquely. After this point we lose
+ // visibility of DATA framing, so just log here.
+ if Some(frame::DATA_FRAME_TYPE_ID) == stream.frame_type() {
+ trace!(
+ "{} rx frm DATA stream={} wire_payload_len={}",
+ conn.trace_id(),
+ stream_id,
+ payload_len
+ );
+
+ qlog_with_type!(QLOG_FRAME_PARSED, conn.qlog, q, {
+ let frame = Http3Frame::Data { raw: None };
+
+ let ev_data =
+ EventData::H3FrameParsed(H3FrameParsed {
+ stream_id,
+ length: Some(payload_len),
+ frame,
+ raw: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
+ }
+
+ if let Err(e) = stream.set_frame_payload_len(payload_len) {
conn.close(true, e.to_wire(), b"")?;
return Err(e);
}
@@ -1777,7 +2168,7 @@ impl Connection {
stream.try_fill_buffer(conn)?;
- let frame = match stream.try_consume_frame() {
+ let (frame, payload_len) = match stream.try_consume_frame() {
Ok(frame) => frame,
Err(Error::Done) => return Err(Error::Done),
@@ -1793,7 +2184,8 @@ impl Connection {
},
};
- match self.process_frame(conn, stream_id, frame) {
+ match self.process_frame(conn, stream_id, frame, payload_len)
+ {
Ok(ev) => return Ok(ev),
Err(Error::Done) => (),
@@ -1866,28 +2258,46 @@ impl Connection {
fn process_frame(
&mut self, conn: &mut super::Connection, stream_id: u64,
- frame: frame::Frame,
+ frame: frame::Frame, payload_len: u64,
) -> Result<(u64, Event)> {
trace!(
- "{} rx frm {:?} stream={}",
+ "{} rx frm {:?} stream={} payload_len={}",
conn.trace_id(),
frame,
- stream_id
+ stream_id,
+ payload_len
);
+ qlog_with_type!(QLOG_FRAME_PARSED, conn.qlog, q, {
+ // HEADERS frames are special case and will be logged below.
+ if !matches!(frame, frame::Frame::Headers { .. }) {
+ let frame = frame.to_qlog();
+ let ev_data = EventData::H3FrameParsed(H3FrameParsed {
+ stream_id,
+ length: Some(payload_len),
+ frame,
+ raw: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ }
+ });
+
match frame {
frame::Frame::Settings {
- max_header_list_size,
+ max_field_section_size,
qpack_max_table_capacity,
qpack_blocked_streams,
h3_datagram,
+ raw,
..
} => {
self.peer_settings = ConnectionSettings {
- max_header_list_size,
+ max_field_section_size,
qpack_max_table_capacity,
qpack_blocked_streams,
h3_datagram,
+ raw,
};
if let Some(1) = h3_datagram {
@@ -1915,11 +2325,11 @@ impl Connection {
return Err(Error::FrameUnexpected);
}
- // Use "infinite" as default value for max_header_list_size if
+ // Use "infinite" as default value for max_field_section_size if
// it is not configured by the application.
let max_size = self
.local_settings
- .max_header_list_size
+ .max_field_section_size
.unwrap_or(std::u64::MAX);
let headers = match self
@@ -1942,6 +2352,30 @@ impl Connection {
},
};
+ qlog_with_type!(QLOG_FRAME_PARSED, conn.qlog, q, {
+ let qlog_headers = headers
+ .iter()
+ .map(|h| qlog::events::h3::HttpHeader {
+ name: String::from_utf8_lossy(h.name()).into_owned(),
+ value: String::from_utf8_lossy(h.value())
+ .into_owned(),
+ })
+ .collect();
+
+ let frame = Http3Frame::Headers {
+ headers: qlog_headers,
+ };
+
+ let ev_data = EventData::H3FrameParsed(H3FrameParsed {
+ stream_id,
+ length: Some(payload_len),
+ frame,
+ raw: None,
+ });
+
+ q.add_event_data_now(ev_data).ok();
+ });
+
let has_body = !conn.stream_finished(stream_id);
return Ok((stream_id, Event::Headers {
@@ -2074,7 +2508,116 @@ impl Connection {
// TODO: implement CANCEL_PUSH frame
},
- frame::Frame::Unknown => (),
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id,
+ priority_field_value,
+ } => {
+ if !self.is_server {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PRIORITY_UPDATE received by client",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if Some(stream_id) != self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PRIORITY_UPDATE received on non-control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if prioritized_element_id % 4 != 0 {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PRIORITY_UPDATE for request stream type with wrong ID",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if prioritized_element_id > conn.streams.max_streams_bidi() * 4 {
+ conn.close(
+ true,
+ Error::IdError.to_wire(),
+ b"PRIORITY_UPDATE for request stream beyond max streams limit",
+ )?;
+
+ return Err(Error::IdError);
+ }
+
+ // If the PRIORITY_UPDATE is valid, consider storing the latest
+ // contents. Due to reordering, it is possible that we might
+ // receive frames that reference streams that have not yet to
+ // been opened and that's OK because it's within our concurrency
+ // limit. However, we discard PRIORITY_UPDATE that refers to
+ // streams that we know have been collected.
+ if conn.streams.is_collected(prioritized_element_id) {
+ return Err(Error::Done);
+ }
+
+ // If the stream did not yet exist, create it and store.
+ let stream =
+ self.streams.entry(prioritized_element_id).or_insert_with(
+ || stream::Stream::new(prioritized_element_id, false),
+ );
+
+ let had_priority_update = stream.has_last_priority_update();
+ stream.set_last_priority_update(Some(priority_field_value));
+
+ // Only trigger the event when there wasn't already a stored
+ // PRIORITY_UPDATE.
+ if !had_priority_update {
+ return Ok((prioritized_element_id, Event::PriorityUpdate));
+ } else {
+ return Err(Error::Done);
+ }
+ },
+
+ frame::Frame::PriorityUpdatePush {
+ prioritized_element_id,
+ ..
+ } => {
+ if !self.is_server {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PRIORITY_UPDATE received by client",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if Some(stream_id) != self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PRIORITY_UPDATE received on non-control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if prioritized_element_id % 3 != 0 {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PRIORITY_UPDATE for push stream type with wrong ID",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // TODO: we only implement this if we implement server push
+ },
+
+ frame::Frame::Unknown { .. } => (),
}
Err(Error::Done)
@@ -2127,6 +2670,7 @@ pub mod testing {
config.set_initial_max_streams_uni(5);
config.verify_peer(false);
config.enable_dgram(true, 3, 3);
+ config.set_ack_delay_exponent(8);
let h3_config = Config::new()?;
Session::with_configs(&mut config, &h3_config)
@@ -2140,8 +2684,8 @@ pub mod testing {
let server_dgram = pipe.server.dgram_enabled();
Ok(Session {
pipe,
- client: Connection::new(&h3_config, false, client_dgram)?,
- server: Connection::new(&h3_config, true, server_dgram)?,
+ client: Connection::new(h3_config, false, client_dgram)?,
+ server: Connection::new(h3_config, true, server_dgram)?,
})
}
@@ -3110,6 +3654,484 @@ mod tests {
}
#[test]
+ #[cfg(feature = "sfv")]
+ fn parse_priority_field_value() {
+ // Legal dicts
+ assert_eq!(
+ Ok(Priority::new(0, false)),
+ Priority::try_from(b"u=0".as_slice())
+ );
+ assert_eq!(
+ Ok(Priority::new(3, false)),
+ Priority::try_from(b"u=3".as_slice())
+ );
+ assert_eq!(
+ Ok(Priority::new(7, false)),
+ Priority::try_from(b"u=7".as_slice())
+ );
+
+ assert_eq!(
+ Ok(Priority::new(0, true)),
+ Priority::try_from(b"u=0, i".as_slice())
+ );
+ assert_eq!(
+ Ok(Priority::new(3, true)),
+ Priority::try_from(b"u=3, i".as_slice())
+ );
+ assert_eq!(
+ Ok(Priority::new(7, true)),
+ Priority::try_from(b"u=7, i".as_slice())
+ );
+
+ assert_eq!(
+ Ok(Priority::new(0, true)),
+ Priority::try_from(b"u=0, i=?1".as_slice())
+ );
+ assert_eq!(
+ Ok(Priority::new(3, true)),
+ Priority::try_from(b"u=3, i=?1".as_slice())
+ );
+ assert_eq!(
+ Ok(Priority::new(7, true)),
+ Priority::try_from(b"u=7, i=?1".as_slice())
+ );
+
+ assert_eq!(
+ Ok(Priority::new(3, false)),
+ Priority::try_from(b"".as_slice())
+ );
+
+ assert_eq!(
+ Ok(Priority::new(0, true)),
+ Priority::try_from(b"u=0;foo, i;bar".as_slice())
+ );
+ assert_eq!(
+ Ok(Priority::new(3, true)),
+ Priority::try_from(b"u=3;hello, i;world".as_slice())
+ );
+ assert_eq!(
+ Ok(Priority::new(7, true)),
+ Priority::try_from(b"u=7;croeso, i;gymru".as_slice())
+ );
+
+ assert_eq!(
+ Ok(Priority::new(0, true)),
+ Priority::try_from(b"u=0, i, spinaltap=11".as_slice())
+ );
+
+ // Illegal formats
+ assert_eq!(Err(Error::Done), Priority::try_from(b"0".as_slice()));
+ assert_eq!(
+ Ok(Priority::new(7, false)),
+ Priority::try_from(b"u=-1".as_slice())
+ );
+ assert_eq!(Err(Error::Done), Priority::try_from(b"u=0.2".as_slice()));
+ assert_eq!(
+ Ok(Priority::new(7, false)),
+ Priority::try_from(b"u=100".as_slice())
+ );
+ assert_eq!(
+ Err(Error::Done),
+ Priority::try_from(b"u=3, i=true".as_slice())
+ );
+
+ // Trailing comma in dict is malformed
+ assert_eq!(Err(Error::Done), Priority::try_from(b"u=7, ".as_slice()));
+ }
+
+ #[test]
+ /// Send a PRIORITY_UPDATE for request stream from the client.
+ fn priority_update_request() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a PRIORITY_UPDATE for request stream from the client.
+ fn priority_update_single_stream_rearm() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ // Once the PriorityUpdate event was fired, subsequent frames will not
+ // rearm it.
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=5".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ // There is only one PRIORITY_UPDATE frame to read. Once read, the event
+ // will rearm ready for more.
+ assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=5".to_vec()));
+ assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done));
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=7".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=7".to_vec()));
+ assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send multiple PRIORITY_UPDATE frames for different streams from the
+ /// client across multiple flights of exchange.
+ fn priority_update_request_multiple_stream_arm_multiple_flights() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 4,
+ priority_field_value: b"u=1".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Ok((4, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 8,
+ priority_field_value: b"u=2".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Ok((8, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=3".to_vec()));
+ assert_eq!(s.server.take_last_priority_update(4), Ok(b"u=1".to_vec()));
+ assert_eq!(s.server.take_last_priority_update(8), Ok(b"u=2".to_vec()));
+ assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send multiple PRIORITY_UPDATE frames for different streams from the
+ /// client across a single flight.
+ fn priority_update_request_multiple_stream_arm_single_flight() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut d = [42; 65535];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let p1 = frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ };
+
+ let p2 = frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 4,
+ priority_field_value: b"u=3".to_vec(),
+ };
+
+ let p3 = frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 8,
+ priority_field_value: b"u=3".to_vec(),
+ };
+
+ p1.to_bytes(&mut b).unwrap();
+ p2.to_bytes(&mut b).unwrap();
+ p3.to_bytes(&mut b).unwrap();
+
+ let off = b.off();
+ s.pipe
+ .client
+ .stream_send(s.client.control_stream_id.unwrap(), &d[..off], false)
+ .unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Ok((4, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Ok((8, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=3".to_vec()));
+ assert_eq!(s.server.take_last_priority_update(4), Ok(b"u=3".to_vec()));
+ assert_eq!(s.server.take_last_priority_update(8), Ok(b"u=3".to_vec()));
+
+ assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a PRIORITY_UPDATE for a request stream, before and after the stream
+ /// has been completed.
+ fn priority_update_request_collected_completed() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ let (stream, req) = s.send_request(true).unwrap();
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: false,
+ };
+
+ // Priority event is generated before request headers.
+ assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=3".to_vec()));
+ assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done));
+
+ let resp = s.send_response(stream, true).unwrap();
+
+ let ev_headers = Event::Headers {
+ list: resp,
+ has_body: false,
+ };
+
+ assert_eq!(s.poll_client(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ assert_eq!(s.poll_client(), Err(Error::Done));
+
+ // Now send a PRIORITY_UPDATE for the completed request stream.
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ // No event generated at server
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a PRIORITY_UPDATE for a request stream, before and after the stream
+ /// has been stopped.
+ fn priority_update_request_collected_stopped() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ let (stream, req) = s.send_request(false).unwrap();
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: true,
+ };
+
+ // Priority event is generated before request headers.
+ assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate)));
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=3".to_vec()));
+ assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done));
+
+ s.pipe
+ .client
+ .stream_shutdown(stream, crate::Shutdown::Write, 0x100)
+ .unwrap();
+ s.pipe
+ .client
+ .stream_shutdown(stream, crate::Shutdown::Read, 0x100)
+ .unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.poll_server(), Ok((0, Event::Reset(0x100))));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ // Now send a PRIORITY_UPDATE for the closed request stream.
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ // No event generated at server
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a PRIORITY_UPDATE for push stream from the client.
+ fn priority_update_push() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdatePush {
+ prioritized_element_id: 3,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a PRIORITY_UPDATE for request stream from the client but for an
+ /// incorrect stream type.
+ fn priority_update_request_bad_stream() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 5,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ /// Send a PRIORITY_UPDATE for push stream from the client but for an
+ /// incorrect stream type.
+ fn priority_update_push_bad_stream() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::PriorityUpdatePush {
+ prioritized_element_id: 5,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ /// Send a PRIORITY_UPDATE for request stream from the server.
+ fn priority_update_request_from_server() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_server(
+ frame::Frame::PriorityUpdateRequest {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.server.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_client(), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ /// Send a PRIORITY_UPDATE for request stream from the server.
+ fn priority_update_push_from_server() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_server(
+ frame::Frame::PriorityUpdatePush {
+ prioritized_element_id: 0,
+ priority_field_value: b"u=3".to_vec(),
+ },
+ s.server.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_client(), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
/// Ensure quiche allocates streams for client and server roles as expected.
fn uni_stream_local_counting() {
let config = Config::new().unwrap();
@@ -3311,7 +4333,7 @@ mod tests {
s.advance().ok();
- assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::InternalError));
+ assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::ExcessiveLoad));
}
#[test]
@@ -3392,7 +4414,7 @@ mod tests {
config.verify_peer(false);
let mut h3_config = Config::new().unwrap();
- h3_config.set_max_header_list_size(65);
+ h3_config.set_max_field_section_size(65);
let mut s = Session::with_configs(&mut config, &mut h3_config).unwrap();
@@ -3503,7 +4525,7 @@ mod tests {
s.advance().ok();
- assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::InternalError));
+ assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::ExcessiveLoad));
// Try to call poll() again after an error occurred.
assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::Done));
@@ -3556,6 +4578,61 @@ mod tests {
}
#[test]
+ /// Ensure StreamBlocked when connection flow control prevents headers.
+ fn headers_blocked_on_conn() {
+ let mut config = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ config
+ .load_cert_chain_from_pem_file("examples/cert.crt")
+ .unwrap();
+ config
+ .load_priv_key_from_pem_file("examples/cert.key")
+ .unwrap();
+ config.set_application_protos(b"\x02h3").unwrap();
+ config.set_initial_max_data(70);
+ config.set_initial_max_stream_data_bidi_local(150);
+ config.set_initial_max_stream_data_bidi_remote(150);
+ config.set_initial_max_stream_data_uni(150);
+ config.set_initial_max_streams_bidi(100);
+ config.set_initial_max_streams_uni(5);
+ config.verify_peer(false);
+
+ let mut h3_config = Config::new().unwrap();
+
+ let mut s = Session::with_configs(&mut config, &mut h3_config).unwrap();
+
+ s.handshake().unwrap();
+
+ // After the HTTP handshake, some bytes of connection flow control have
+ // been consumed. Fill the connection with more grease data on the control
+ // stream.
+ let d = [42; 28];
+ assert_eq!(s.pipe.client.stream_send(2, &d, false), Ok(23));
+
+ let req = vec![
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", b"https"),
+ Header::new(b":authority", b"quic.tech"),
+ Header::new(b":path", b"/test"),
+ ];
+
+ // There is 0 connection-level flow control, so sending a request is
+ // blocked.
+ assert_eq!(
+ s.client.send_request(&mut s.pipe.client, &req, true),
+ Err(Error::StreamBlocked)
+ );
+
+ // Emit the control stream data and drain it at the server via poll() to
+ // consumes it via poll() and gives back flow control.
+ s.advance().ok();
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ s.advance().ok();
+
+ // Now we can send the request.
+ assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(0));
+ }
+
+ #[test]
/// Test handling of 0-length DATA writes with and without fin.
fn zero_length_data() {
let mut s = Session::default().unwrap();
@@ -3737,11 +4814,12 @@ mod tests {
);
let settings = frame::Frame::Settings {
- max_header_list_size: None,
+ max_field_section_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
h3_datagram: Some(1),
grease: None,
+ raw: Default::default(),
};
s.send_frame_client(settings, s.client.control_stream_id.unwrap(), false)
@@ -4485,6 +5563,183 @@ mod tests {
assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len()));
assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
}
+
+ #[test]
+ fn reset_stream() {
+ let mut buf = [0; 65535];
+
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ // Client sends request.
+ let (stream, req) = s.send_request(false).unwrap();
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: true,
+ };
+
+ // Server sends response and closes stream.
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ let resp = s.send_response(stream, true).unwrap();
+
+ let ev_headers = Event::Headers {
+ list: resp,
+ has_body: false,
+ };
+
+ assert_eq!(s.poll_client(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ assert_eq!(s.poll_client(), Err(Error::Done));
+
+ // Client sends RESET_STREAM, closing stream.
+ let frames = [crate::frame::Frame::ResetStream {
+ stream_id: stream,
+ error_code: 42,
+ final_size: 68,
+ }];
+
+ let pkt_type = crate::packet::Type::Short;
+ assert_eq!(
+ s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
+ Ok(39)
+ );
+
+ // Server issues Reset event for the stream.
+ assert_eq!(s.poll_server(), Ok((stream, Event::Reset(42))));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ // Sending RESET_STREAM again shouldn't trigger another Reset event.
+ assert_eq!(
+ s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
+ Ok(39)
+ );
+
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ fn reset_finished_at_server() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ // Client sends HEADERS and doesn't fin
+ let (stream, _req) = s.send_request(false).unwrap();
+
+ // ..then Client sends RESET_STREAM
+ assert_eq!(
+ s.pipe.client.stream_shutdown(0, crate::Shutdown::Write, 0),
+ Ok(())
+ );
+
+ assert_eq!(s.pipe.advance(), Ok(()));
+
+ // Server receives just a reset
+ assert_eq!(s.poll_server(), Ok((stream, Event::Reset(0))));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ // Client sends HEADERS and fin
+ let (stream, req) = s.send_request(true).unwrap();
+
+ // ..then Client sends RESET_STREAM
+ assert_eq!(
+ s.pipe.client.stream_shutdown(4, crate::Shutdown::Write, 0),
+ Ok(())
+ );
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: false,
+ };
+
+ // Server receives headers and fin.
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ fn reset_finished_at_client() {
+ let mut buf = [0; 65535];
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ // Client sends HEADERS and doesn't fin
+ let (stream, req) = s.send_request(false).unwrap();
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: true,
+ };
+
+ // Server receives headers.
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ // Server sends response and doesn't fin
+ s.send_response(stream, false).unwrap();
+
+ assert_eq!(s.pipe.advance(), Ok(()));
+
+ // .. then Server sends RESET_STREAM
+ assert_eq!(
+ s.pipe
+ .server
+ .stream_shutdown(stream, crate::Shutdown::Write, 0),
+ Ok(())
+ );
+
+ assert_eq!(s.pipe.advance(), Ok(()));
+
+ // Client receives Reset only
+ assert_eq!(s.poll_client(), Ok((stream, Event::Reset(0))));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ // Client sends headers and fin.
+ let (stream, req) = s.send_request(true).unwrap();
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: false,
+ };
+
+ // Server receives headers and fin.
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ // Server sends response and fin
+ let resp = s.send_response(stream, true).unwrap();
+
+ assert_eq!(s.pipe.advance(), Ok(()));
+
+ // ..then Server sends RESET_STREAM
+ let frames = [crate::frame::Frame::ResetStream {
+ stream_id: stream,
+ error_code: 42,
+ final_size: 68,
+ }];
+
+ let pkt_type = crate::packet::Type::Short;
+ assert_eq!(
+ s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
+ Ok(39)
+ );
+
+ assert_eq!(s.pipe.advance(), Ok(()));
+
+ let ev_headers = Event::Headers {
+ list: resp,
+ has_body: false,
+ };
+
+ // Client receives headers and fin.
+ assert_eq!(s.poll_client(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ assert_eq!(s.poll_client(), Err(Error::Done));
+ }
}
#[cfg(feature = "ffi")]
diff --git a/src/h3/qpack/decoder.rs b/src/h3/qpack/decoder.rs
index 1bc5755..e8c7dc7 100644
--- a/src/h3/qpack/decoder.rs
+++ b/src/h3/qpack/decoder.rs
@@ -24,8 +24,6 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-use crate::octets;
-
use super::Error;
use super::Result;
@@ -68,14 +66,9 @@ impl Representation {
}
/// A QPACK decoder.
+#[derive(Default)]
pub struct Decoder {}
-impl Default for Decoder {
- fn default() -> Decoder {
- Decoder {}
- }
-}
-
impl Decoder {
/// Creates a new QPACK decoder.
pub fn new() -> Decoder {
@@ -274,8 +267,6 @@ fn decode_str(b: &mut octets::Octets) -> Result<Vec<u8>> {
mod tests {
use super::*;
- use crate::octets;
-
#[test]
fn decode_int1() {
let mut encoded = [0b01010, 0x02];
diff --git a/src/h3/qpack/encoder.rs b/src/h3/qpack/encoder.rs
index 09c8b08..ae75f27 100644
--- a/src/h3/qpack/encoder.rs
+++ b/src/h3/qpack/encoder.rs
@@ -26,8 +26,6 @@
use super::Result;
-use crate::octets;
-
use crate::h3::NameValue;
use super::INDEXED;
@@ -35,14 +33,9 @@ use super::LITERAL;
use super::LITERAL_WITH_NAME_REF;
/// A QPACK encoder.
+#[derive(Default)]
pub struct Encoder {}
-impl Default for Encoder {
- fn default() -> Encoder {
- Encoder {}
- }
-}
-
impl Encoder {
/// Creates a new QPACK encoder.
pub fn new() -> Encoder {
@@ -163,8 +156,6 @@ fn encode_str(v: &[u8], prefix: usize, b: &mut octets::OctetsMut) -> Result<()>
mod tests {
use super::*;
- use crate::octets;
-
#[test]
fn encode_int1() {
let expected = [0b01010];
diff --git a/src/h3/qpack/huffman/mod.rs b/src/h3/qpack/huffman/mod.rs
index 3a6ff06..04391ab 100644
--- a/src/h3/qpack/huffman/mod.rs
+++ b/src/h3/qpack/huffman/mod.rs
@@ -24,8 +24,6 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-use crate::octets;
-
use super::Error;
use super::Result;
diff --git a/src/h3/qpack/huffman/table.rs b/src/h3/qpack/huffman/table.rs
index 7162aff..011272c 100644
--- a/src/h3/qpack/huffman/table.rs
+++ b/src/h3/qpack/huffman/table.rs
@@ -1,5 +1,3 @@
-#[allow(clippy::unreadable_literal)]
-
// (num-bits, bits)
pub const ENCODE_TABLE: [(usize, u64); 257] = [
(13, 0x1ff8),
diff --git a/src/h3/qpack/mod.rs b/src/h3/qpack/mod.rs
index 0a23306..8a14aa3 100644
--- a/src/h3/qpack/mod.rs
+++ b/src/h3/qpack/mod.rs
@@ -70,8 +70,8 @@ impl std::error::Error for Error {
}
}
-impl std::convert::From<crate::octets::BufferTooShortError> for Error {
- fn from(_err: crate::octets::BufferTooShortError) -> Self {
+impl std::convert::From<octets::BufferTooShortError> for Error {
+ fn from(_err: octets::BufferTooShortError) -> Self {
Error::BufferTooShort
}
}
diff --git a/src/h3/stream.rs b/src/h3/stream.rs
index 58e2873..cd2c10e 100644
--- a/src/h3/stream.rs
+++ b/src/h3/stream.rs
@@ -27,8 +27,6 @@
use super::Error;
use super::Result;
-use crate::octets;
-
use super::frame;
pub const HTTP3_CONTROL_STREAM_TYPE_ID: u64 = 0x0;
@@ -48,6 +46,20 @@ pub enum Type {
Unknown,
}
+impl Type {
+ #[cfg(feature = "qlog")]
+ pub fn to_qlog(self) -> qlog::events::h3::H3StreamType {
+ match self {
+ Type::Control => qlog::events::h3::H3StreamType::Control,
+ Type::Request => qlog::events::h3::H3StreamType::Data,
+ Type::Push => qlog::events::h3::H3StreamType::Push,
+ Type::QpackEncoder => qlog::events::h3::H3StreamType::QpackEncode,
+ Type::QpackDecoder => qlog::events::h3::H3StreamType::QpackDecode,
+ Type::Unknown => qlog::events::h3::H3StreamType::Unknown,
+ }
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum State {
/// Reading the stream's type.
@@ -141,6 +153,9 @@ pub struct Stream {
/// Whether a `Data` event has been triggered for this stream.
data_event_triggered: bool,
+
+ /// The last `PRIORITY_UPDATE` frame encoded field value, if any.
+ last_priority_update: Option<Vec<u8>>,
}
impl Stream {
@@ -179,6 +194,8 @@ impl Stream {
local_initialized: false,
data_event_triggered: false,
+
+ last_priority_update: None,
}
}
@@ -327,6 +344,11 @@ impl Stream {
Ok(())
}
+ // Returns the stream's current frame type, if any
+ pub fn frame_type(&self) -> Option<u64> {
+ self.frame_type
+ }
+
/// Sets the frame's payload length and transitions to the next state.
pub fn set_frame_payload_len(&mut self, len: u64) -> Result<()> {
assert_eq!(self.state, State::FramePayloadLen);
@@ -441,20 +463,24 @@ impl Stream {
}
/// Tries to parse a frame from the state buffer.
- pub fn try_consume_frame(&mut self) -> Result<frame::Frame> {
+ ///
+ /// If successful, returns the `frame::Frame` and the payload length.
+ pub fn try_consume_frame(&mut self) -> Result<(frame::Frame, u64)> {
// Processing a frame other than DATA, so re-arm the Data event.
self.reset_data_event();
+ let payload_len = self.state_len as u64;
+
// TODO: properly propagate frame parsing errors.
let frame = frame::Frame::from_bytes(
self.frame_type.unwrap(),
- self.state_len as u64,
+ payload_len,
&self.state_buf,
)?;
self.state_transition(State::FrameType, 1, true)?;
- Ok(frame)
+ Ok((frame, payload_len))
}
/// Tries to read DATA payload from the transport stream.
@@ -535,6 +561,21 @@ impl Stream {
self.data_event_triggered = false;
}
+ /// Set the last priority update for the stream.
+ pub fn set_last_priority_update(&mut self, priority_update: Option<Vec<u8>>) {
+ self.last_priority_update = priority_update;
+ }
+
+ /// Take the last priority update and leave `None` in its place.
+ pub fn take_last_priority_update(&mut self) -> Option<Vec<u8>> {
+ self.last_priority_update.take()
+ }
+
+ /// Returns `true` if there is a priority update.
+ pub fn has_last_priority_update(&self) -> bool {
+ self.last_priority_update.is_some()
+ }
+
/// Returns true if the state buffer has enough data to complete the state.
fn state_buffer_complete(&self) -> bool {
self.state_off == self.state_len
@@ -545,29 +586,31 @@ impl Stream {
fn state_transition(
&mut self, new_state: State, expected_len: usize, resize: bool,
) -> Result<()> {
- self.state = new_state;
- self.state_off = 0;
- self.state_len = expected_len;
-
// Some states don't need the state buffer, so don't resize it if not
// necessary.
if resize {
// A peer can influence the size of the state buffer (e.g. with the
// payload size of a GREASE frame), so we need to limit the maximum
// size to avoid DoS.
- if self.state_len > MAX_STATE_BUF_SIZE {
- return Err(Error::InternalError);
+ if expected_len > MAX_STATE_BUF_SIZE {
+ return Err(Error::ExcessiveLoad);
}
- self.state_buf.resize(self.state_len, 0);
+ self.state_buf.resize(expected_len, 0);
}
+ self.state = new_state;
+ self.state_off = 0;
+ self.state_len = expected_len;
+
Ok(())
}
}
#[cfg(test)]
mod tests {
+ use crate::h3::frame::*;
+
use super::*;
#[test]
@@ -579,12 +622,19 @@ mod tests {
let mut d = vec![42; 40];
let mut b = octets::OctetsMut::with_slice(&mut d);
- let frame = frame::Frame::Settings {
- max_header_list_size: Some(0),
+ let raw_settings = vec![
+ (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
+ (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
+ (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
+ ];
+
+ let frame = Frame::Settings {
+ max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
h3_datagram: None,
grease: None,
+ raw: Some(raw_settings),
};
b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
@@ -622,7 +672,7 @@ mod tests {
// Parse the SETTINGS frame payload.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
- assert_eq!(stream.try_consume_frame(), Ok(frame));
+ assert_eq!(stream.try_consume_frame(), Ok((frame, 6)));
assert_eq!(stream.state, State::FrameType);
}
@@ -635,12 +685,19 @@ mod tests {
let mut d = vec![42; 40];
let mut b = octets::OctetsMut::with_slice(&mut d);
+ let raw_settings = vec![
+ (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
+ (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
+ (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
+ ];
+
let frame = frame::Frame::Settings {
- max_header_list_size: Some(0),
+ max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
h3_datagram: None,
grease: None,
+ raw: Some(raw_settings),
};
b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
@@ -679,7 +736,7 @@ mod tests {
// Parse the SETTINGS frame payload.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
- assert_eq!(stream.try_consume_frame(), Ok(frame));
+ assert_eq!(stream.try_consume_frame(), Ok((frame, 6)));
assert_eq!(stream.state, State::FrameType);
// Parse the second SETTINGS frame type.
@@ -700,12 +757,19 @@ mod tests {
let goaway = frame::Frame::GoAway { id: 0 };
+ let raw_settings = vec![
+ (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
+ (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
+ (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
+ ];
+
let settings = frame::Frame::Settings {
- max_header_list_size: Some(0),
+ max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
h3_datagram: None,
grease: None,
+ raw: Some(raw_settings),
};
b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
@@ -743,12 +807,20 @@ mod tests {
let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let hdrs = frame::Frame::Headers { header_block };
+ let raw_settings = vec![
+ (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
+ (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
+ (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
+ (33, 33),
+ ];
+
let settings = frame::Frame::Settings {
- max_header_list_size: Some(0),
+ max_field_section_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
h3_datagram: None,
grease: None,
+ raw: Some(raw_settings),
};
b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
@@ -837,7 +909,7 @@ mod tests {
// Parse the HEADERS frame.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
- assert_eq!(stream.try_consume_frame(), Ok(hdrs));
+ assert_eq!(stream.try_consume_frame(), Ok((hdrs, 12)));
assert_eq!(stream.state, State::FrameType);
// Parse the DATA frame type.
@@ -930,7 +1002,7 @@ mod tests {
// Parse the HEADERS frame.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
- assert_eq!(stream.try_consume_frame(), Ok(hdrs));
+ assert_eq!(stream.try_consume_frame(), Ok((hdrs, 12)));
assert_eq!(stream.state, State::FrameType);
// Parse the DATA frame type.
diff --git a/src/lib.rs b/src/lib.rs
index 0087b52..2e13278 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -196,6 +196,25 @@
//! # Ok::<(), quiche::Error>(())
//! ```
//!
+//! ### Pacing
+//!
+//! It is recommended that applications [pace] sending of outgoing packets to
+//! avoid creating packet bursts that could cause short-term congestion and
+//! losses in the network.
+//!
+//! quiche exposes pacing hints for outgoing packets through the [`at`] field
+//! of the [`SendInfo`] structure that is returned by the [`send()`] method.
+//! This field represents the time when a specific packet should be sent into
+//! the network.
+//!
+//! Applications can use these hints by artificially delaying the sending of
+//! packets through platform-specific mechanisms (such as the [`SO_TXTIME`]
+//! socket option on Linux), or custom methods (for example by using user-space
+//! timers).
+//!
+//! [pace]: https://datatracker.ietf.org/doc/html/rfc9002#section-7.7
+//! [`SO_TXTIME`]: https://man7.org/linux/man-pages/man8/tc-etf.8.html
+//!
//! ## Sending and receiving stream data
//!
//! After some back and forth, the connection will complete its handshake and
@@ -251,6 +270,7 @@
//! [`RecvInfo`]: struct.RecvInfo.html
//! [`send()`]: struct.Connection.html#method.send
//! [`SendInfo`]: struct.SendInfo.html
+//! [`at`]: struct.SendInfo.html#structfield.at
//! [`timeout()`]: struct.Connection.html#method.timeout
//! [`on_timeout()`]: struct.Connection.html#method.on_timeout
//! [`stream_send()`]: struct.Connection.html#method.stream_send
@@ -286,25 +306,61 @@
//! or [`accept()`]. Otherwise the connection will use a default CC algorithm.
//!
//! [`CongestionControlAlgorithm`]: enum.CongestionControlAlgorithm.html
+//!
+//! ## Feature flags
+//!
+//! quiche defines a number of [feature flags] to reduce the amount of compiled
+//! code and dependencies:
+//!
+//! * `boringssl-vendored` (default): Build the vendored BoringSSL library.
+//!
+//! * `boringssl-boring-crate`: Use the BoringSSL library provided by the
+//! [boring] crate. It takes precedence over `boringssl-vendored` if both
+//! features are enabled.
+//!
+//! * `pkg-config-meta`: Generate pkg-config metadata file for libquiche.
+//!
+//! * `ffi`: Build and expose the FFI API.
+//!
+//! * `qlog`: Enable support for the [qlog] logging format.
+//!
+//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
+//! [boring]: https://crates.io/crates/boring
+//! [qlog]: https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema
-#![allow(improper_ctypes)]
-#![allow(clippy::suspicious_operation_groupings)]
#![allow(clippy::upper_case_acronyms)]
#![warn(missing_docs)]
+#![cfg_attr(docsrs, feature(doc_cfg))]
#[macro_use]
extern crate log;
+#[cfg(feature = "qlog")]
+use qlog::events::connectivity::TransportOwner;
+#[cfg(feature = "qlog")]
+use qlog::events::quic::RecoveryEventType;
+#[cfg(feature = "qlog")]
+use qlog::events::quic::TransportEventType;
+#[cfg(feature = "qlog")]
+use qlog::events::DataRecipient;
+#[cfg(feature = "qlog")]
+use qlog::events::Event;
+#[cfg(feature = "qlog")]
+use qlog::events::EventData;
+#[cfg(feature = "qlog")]
+use qlog::events::EventImportance;
+#[cfg(feature = "qlog")]
+use qlog::events::EventType;
+#[cfg(feature = "qlog")]
+use qlog::events::RawInfo;
+
use std::cmp;
use std::time;
use std::net::SocketAddr;
-use std::pin::Pin;
use std::str::FromStr;
-use std::sync::Mutex;
-
use std::collections::VecDeque;
/// The current QUIC wire version.
@@ -361,6 +417,16 @@ const MAX_UNDECRYPTABLE_PACKETS: usize = 10;
const RESERVED_VERSION_MASK: u32 = 0xfafafafa;
+// The default size of the receiver connection flow control window.
+const DEFAULT_CONNECTION_WINDOW: u64 = 48 * 1024;
+
+// The maximum size of the receiver connection flow control window.
+const MAX_CONNECTION_WINDOW: u64 = 24 * 1024 * 1024;
+
+// How much larger the connection flow control window need to be larger than
+// the stream flow control window.
+const CONNECTION_WINDOW_FACTOR: f64 = 1.5;
+
/// A specialized [`Result`] type for quiche operations.
///
/// This type is used throughout quiche's public API for any operation that
@@ -419,6 +485,12 @@ pub enum Error {
/// associated data.
StreamStopped(u64),
+ /// The specified stream was reset by the peer.
+ ///
+ /// The error code sent as part of the `RESET_STREAM` frame is provided as
+ /// associated data.
+ StreamReset(u64),
+
/// The received data exceeds the stream's final size.
FinalSize,
@@ -458,6 +530,7 @@ impl Error {
Error::FinalSize => -13,
Error::CongestionControl => -14,
Error::StreamStopped { .. } => -15,
+ Error::StreamReset { .. } => -16,
}
}
}
@@ -494,6 +567,10 @@ pub struct SendInfo {
pub to: SocketAddr,
/// The time to send the packet out.
+ ///
+ /// See [Pacing] for more details.
+ ///
+ /// [Pacing]: index.html#pacing
pub at: time::Instant,
}
@@ -524,17 +601,28 @@ pub enum Shutdown {
Write = 1,
}
+/// Qlog logging level.
+#[repr(C)]
+#[cfg(feature = "qlog")]
+#[cfg_attr(docsrs, doc(cfg(feature = "qlog")))]
+pub enum QlogLevel {
+ /// Logs any events of Core importance.
+ Core = 0,
+
+ /// Logs any events of Core and Base importance.
+ Base = 1,
+
+ /// Logs any events of Core, Base and Extra importance
+ Extra = 2,
+}
+
/// Stores configuration shared between multiple connections.
pub struct Config {
local_transport_params: TransportParams,
version: u32,
- // BoringSSL's SSL_CTX structure is technically safe to share across threads
- // but once shared, functions that modify it can't be used any more. We can't
- // encode that in Rust, so just make it Send+Sync with a mutex to fulfill
- // the Sync constraint.
- tls_ctx: Mutex<tls::Context>,
+ tls_ctx: tls::Context,
application_protos: Vec<Vec<u8>>,
@@ -548,6 +636,9 @@ pub struct Config {
dgram_send_max_queue_len: usize,
max_send_udp_payload_size: usize,
+
+ max_connection_window: u64,
+ max_stream_window: u64,
}
// See https://quicwg.org/base-drafts/rfc9000.html#section-15
@@ -565,12 +656,28 @@ impl Config {
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn new(version: u32) -> Result<Config> {
+ Self::with_tls_ctx(version, tls::Context::new()?)
+ }
+
+ /// Creates a config object with the given version and [`SslContext`].
+ ///
+ /// This is useful for applications that wish to manually configure
+ /// [`SslContext`].
+ ///
+ /// [`SslContext`]: https://docs.rs/boring/latest/boring/ssl/struct.SslContext.html
+ #[cfg(feature = "boringssl-boring-crate")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "boringssl-boring-crate")))]
+ pub fn with_boring_ssl_ctx(
+ version: u32, tls_ctx: boring::ssl::SslContext,
+ ) -> Result<Config> {
+ Self::with_tls_ctx(version, tls::Context::from_boring(tls_ctx))
+ }
+
+ fn with_tls_ctx(version: u32, tls_ctx: tls::Context) -> Result<Config> {
if !is_reserved_version(version) && !version_is_supported(version) {
return Err(Error::UnknownVersion);
}
- let tls_ctx = Mutex::new(tls::Context::new()?);
-
Ok(Config {
local_transport_params: TransportParams::default(),
version,
@@ -584,6 +691,9 @@ impl Config {
dgram_send_max_queue_len: DEFAULT_MAX_DGRAM_QUEUE_LEN,
max_send_udp_payload_size: MAX_SEND_UDP_PAYLOAD_SIZE,
+
+ max_connection_window: MAX_CONNECTION_WINDOW,
+ max_stream_window: stream::MAX_STREAM_WINDOW,
})
}
@@ -600,10 +710,7 @@ impl Config {
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn load_cert_chain_from_pem_file(&mut self, file: &str) -> Result<()> {
- self.tls_ctx
- .lock()
- .unwrap()
- .use_certificate_chain_file(file)
+ self.tls_ctx.use_certificate_chain_file(file)
}
/// Configures the given private key.
@@ -618,7 +725,7 @@ impl Config {
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn load_priv_key_from_pem_file(&mut self, file: &str) -> Result<()> {
- self.tls_ctx.lock().unwrap().use_privkey_file(file)
+ self.tls_ctx.use_privkey_file(file)
}
/// Specifies a file where trusted CA certificates are stored for the
@@ -634,10 +741,7 @@ impl Config {
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn load_verify_locations_from_file(&mut self, file: &str) -> Result<()> {
- self.tls_ctx
- .lock()
- .unwrap()
- .load_verify_locations_from_file(file)
+ self.tls_ctx.load_verify_locations_from_file(file)
}
/// Specifies a directory where trusted CA certificates are stored for the
@@ -655,10 +759,7 @@ impl Config {
pub fn load_verify_locations_from_directory(
&mut self, dir: &str,
) -> Result<()> {
- self.tls_ctx
- .lock()
- .unwrap()
- .load_verify_locations_from_directory(dir)
+ self.tls_ctx.load_verify_locations_from_directory(dir)
}
/// Configures whether to verify the peer's certificate.
@@ -666,7 +767,7 @@ impl Config {
/// The default value is `true` for client connections, and `false` for
/// server ones.
pub fn verify_peer(&mut self, verify: bool) {
- self.tls_ctx.lock().unwrap().set_verify(verify);
+ self.tls_ctx.set_verify(verify);
}
/// Configures whether to send GREASE values.
@@ -685,7 +786,7 @@ impl Config {
/// [`set_keylog()`]: struct.Connection.html#method.set_keylog
/// [keylog]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
pub fn log_keys(&mut self) {
- self.tls_ctx.lock().unwrap().enable_keylog();
+ self.tls_ctx.enable_keylog();
}
/// Configures the session ticket key material.
@@ -699,12 +800,12 @@ impl Config {
/// servers), in which case the application is also responsible for
/// rotating the key to provide forward secrecy.
pub fn set_ticket_key(&mut self, key: &[u8]) -> Result<()> {
- self.tls_ctx.lock().unwrap().set_ticket_key(key)
+ self.tls_ctx.set_ticket_key(key)
}
/// Enables sending or receiving early data.
pub fn enable_early_data(&mut self) {
- self.tls_ctx.lock().unwrap().set_early_data_enabled(true);
+ self.tls_ctx.set_early_data_enabled(true);
}
/// Configures the list of supported application protocols.
@@ -728,7 +829,7 @@ impl Config {
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn set_application_protos(&mut self, protos: &[u8]) -> Result<()> {
- let mut b = octets::Octets::with_slice(&protos);
+ let mut b = octets::Octets::with_slice(protos);
let mut protos_list = Vec::new();
@@ -738,10 +839,7 @@ impl Config {
self.application_protos = protos_list;
- self.tls_ctx
- .lock()
- .unwrap()
- .set_alpn(&self.application_protos)
+ self.tls_ctx.set_alpn(&self.application_protos)
}
/// Sets the `max_idle_timeout` transport parameter, in milliseconds.
@@ -921,6 +1019,20 @@ impl Config {
self.dgram_recv_max_queue_len = recv_queue_len;
self.dgram_send_max_queue_len = send_queue_len;
}
+
+ /// Sets the maximum size of the connection window.
+ ///
+ /// The default value is MAX_CONNECTION_WINDOW (24MBytes).
+ pub fn set_max_connection_window(&mut self, v: u64) {
+ self.max_connection_window = v;
+ }
+
+ /// Sets the maximum size of the stream window.
+ ///
+ /// The default value is MAX_STREAM_WINDOW (16MBytes).
+ pub fn set_max_stream_window(&mut self, v: u64) {
+ self.max_stream_window = v;
+ }
}
/// A QUIC connection.
@@ -947,11 +1059,7 @@ pub struct Connection {
local_transport_params: TransportParams,
/// TLS handshake state.
- ///
- /// Due to the requirement for `Connection` to be Send+Sync, and the fact
- /// that BoringSSL's SSL structure is not thread safe, we need to wrap the
- /// handshake object in a mutex.
- handshake: Mutex<tls::Handshake>,
+ handshake: tls::Handshake,
/// Serialized TLS session buffer.
///
@@ -973,15 +1081,14 @@ pub struct Connection {
/// Total number of sent packets.
sent_count: usize,
+ /// Total number of packets sent with data retransmitted.
+ retrans_count: usize,
+
/// Total number of bytes received from the peer.
rx_data: u64,
- /// Local flow control limit for the connection.
- max_rx_data: u64,
-
- /// Updated local flow control limit for the connection. This is used to
- /// trigger sending MAX_DATA frames after a certain threshold.
- max_rx_data_next: u64,
+ /// Receiver flow controller.
+ flow_control: flowcontrol::FlowControl,
/// Whether we send MAX_DATA frame.
almost_full: bool,
@@ -995,10 +1102,23 @@ pub struct Connection {
/// Peer's flow control limit for the connection.
max_tx_data: u64,
+ /// Last tx_data before running a full send() loop.
+ last_tx_data: u64,
+
/// Total number of bytes the server can send before the peer's address
/// is verified.
max_send_bytes: usize,
+ /// Total number of bytes retransmitted over the connection.
+ /// This counts only STREAM and CRYPTO data.
+ stream_retrans_bytes: u64,
+
+ /// Total number of bytes sent over the connection.
+ sent_bytes: u64,
+
+ /// Total number of bytes received over the connection.
+ recv_bytes: u64,
+
/// Streams map, indexed by stream ID.
streams: stream::StreamMap,
@@ -1022,7 +1142,7 @@ pub struct Connection {
peer_error: Option<ConnectionError>,
/// Received path challenge.
- challenge: Option<Vec<u8>>,
+ challenge: Option<[u8; 8]>,
/// The connection-level limit at which send blocking occurred.
blocked_limit: Option<u64>,
@@ -1067,9 +1187,12 @@ pub struct Connection {
/// Whether the connection handshake has been completed.
handshake_completed: bool,
- /// Whether the HANDSHAKE_DONE has been sent.
+ /// Whether the HANDSHAKE_DONE frame has been sent.
handshake_done_sent: bool,
+ /// Whether the HANDSHAKE_DONE frame has been acked.
+ handshake_done_acked: bool,
+
/// Whether the connection handshake has been confirmed.
handshake_confirmed: bool,
@@ -1080,19 +1203,17 @@ pub struct Connection {
/// Whether the connection is closed.
closed: bool,
+ // Whether the connection was timed out
+ timed_out: bool,
+
/// Whether to send GREASE.
grease: bool,
/// TLS keylog writer.
keylog: Option<Box<dyn std::io::Write + Send + Sync>>,
- /// Qlog streaming output.
#[cfg(feature = "qlog")]
- qlog_streamer: Option<qlog::QlogStreamer>,
-
- /// Whether peer transport parameters were qlogged.
- #[cfg(feature = "qlog")]
- qlogged_peer_params: bool,
+ qlog: QlogInfo,
/// DATAGRAM queues.
dgram_recv_queue: dgram::DatagramQueue,
@@ -1124,7 +1245,7 @@ pub struct Connection {
pub fn accept(
scid: &ConnectionId, odcid: Option<&ConnectionId>, from: SocketAddr,
config: &mut Config,
-) -> Result<Pin<Box<Connection>>> {
+) -> Result<Connection> {
let conn = Connection::new(scid, odcid, from, config, true)?;
Ok(conn)
@@ -1150,11 +1271,11 @@ pub fn accept(
pub fn connect(
server_name: Option<&str>, scid: &ConnectionId, to: SocketAddr,
config: &mut Config,
-) -> Result<Pin<Box<Connection>>> {
- let conn = Connection::new(scid, None, to, config, false)?;
+) -> Result<Connection> {
+ let mut conn = Connection::new(scid, None, to, config, false)?;
if let Some(server_name) = server_name {
- conn.handshake.lock().unwrap().set_host_name(server_name)?;
+ conn.handshake.set_host_name(server_name)?;
}
Ok(conn)
@@ -1289,40 +1410,94 @@ macro_rules! push_frame_to_pkt {
}};
}
-/// Conditional qlog action.
+/// Conditional qlog actions.
///
/// Executes the provided body if the qlog feature is enabled and quiche
-/// has been condifigured with a log writer.
+/// has been configured with a log writer.
macro_rules! qlog_with {
- ($qlog_streamer:expr, $qlog_streamer_ref:ident, $body:block) => {{
+ ($qlog:expr, $qlog_streamer_ref:ident, $body:block) => {{
#[cfg(feature = "qlog")]
{
- if let Some($qlog_streamer_ref) = &mut $qlog_streamer {
+ if let Some($qlog_streamer_ref) = &mut $qlog.streamer {
$body
}
}
}};
}
+/// Executes the provided body if the qlog feature is enabled, quiche has been
+/// configured with a log writer, the event's importance is within the
+/// configured level.
+macro_rules! qlog_with_type {
+ ($ty:expr, $qlog:expr, $qlog_streamer_ref:ident, $body:block) => {{
+ #[cfg(feature = "qlog")]
+ {
+ if EventImportance::from($ty).is_contained_in(&$qlog.level) {
+ if let Some($qlog_streamer_ref) = &mut $qlog.streamer {
+ $body
+ }
+ }
+ }
+ }};
+}
+
+#[cfg(feature = "qlog")]
+const QLOG_PARAMS_SET: EventType =
+ EventType::TransportEventType(TransportEventType::ParametersSet);
+
+#[cfg(feature = "qlog")]
+const QLOG_PACKET_RX: EventType =
+ EventType::TransportEventType(TransportEventType::PacketReceived);
+
+#[cfg(feature = "qlog")]
+const QLOG_PACKET_TX: EventType =
+ EventType::TransportEventType(TransportEventType::PacketSent);
+
+#[cfg(feature = "qlog")]
+const QLOG_DATA_MV: EventType =
+ EventType::TransportEventType(TransportEventType::DataMoved);
+
+#[cfg(feature = "qlog")]
+const QLOG_METRICS: EventType =
+ EventType::RecoveryEventType(RecoveryEventType::MetricsUpdated);
+
+#[cfg(feature = "qlog")]
+struct QlogInfo {
+ streamer: Option<qlog::streamer::QlogStreamer>,
+ logged_peer_params: bool,
+ level: EventImportance,
+}
+
+#[cfg(feature = "qlog")]
+impl Default for QlogInfo {
+ fn default() -> Self {
+ QlogInfo {
+ streamer: None,
+ logged_peer_params: false,
+ level: EventImportance::Base,
+ }
+ }
+}
+
impl Connection {
fn new(
scid: &ConnectionId, odcid: Option<&ConnectionId>, peer: SocketAddr,
config: &mut Config, is_server: bool,
- ) -> Result<Pin<Box<Connection>>> {
- let tls = config.tls_ctx.lock().unwrap().new_handshake()?;
+ ) -> Result<Connection> {
+ let tls = config.tls_ctx.new_handshake()?;
Connection::with_tls(scid, odcid, peer, config, tls, is_server)
}
fn with_tls(
scid: &ConnectionId, odcid: Option<&ConnectionId>, peer: SocketAddr,
config: &mut Config, tls: tls::Handshake, is_server: bool,
- ) -> Result<Pin<Box<Connection>>> {
+ ) -> Result<Connection> {
let max_rx_data = config.local_transport_params.initial_max_data;
let scid_as_hex: Vec<String> =
scid.iter().map(|b| format!("{:02x}", b)).collect();
- let mut conn = Box::pin(Connection {
+ let mut conn = Connection {
version: config.version,
dcid: ConnectionId::default(),
@@ -1340,11 +1515,11 @@ impl Connection {
local_transport_params: config.local_transport_params.clone(),
- handshake: Mutex::new(tls),
+ handshake: tls,
session: None,
- recovery: recovery::Recovery::new(&config),
+ recovery: recovery::Recovery::new(config),
peer_addr: peer,
@@ -1352,22 +1527,32 @@ impl Connection {
recv_count: 0,
sent_count: 0,
+ retrans_count: 0,
+ sent_bytes: 0,
+ recv_bytes: 0,
rx_data: 0,
- max_rx_data,
- max_rx_data_next: max_rx_data,
+ flow_control: flowcontrol::FlowControl::new(
+ max_rx_data,
+ cmp::min(max_rx_data / 2 * 3, DEFAULT_CONNECTION_WINDOW),
+ config.max_connection_window,
+ ),
almost_full: false,
tx_cap: 0,
tx_data: 0,
max_tx_data: 0,
+ last_tx_data: 0,
+
+ stream_retrans_bytes: 0,
max_send_bytes: 0,
streams: stream::StreamMap::new(
config.local_transport_params.initial_max_streams_bidi,
config.local_transport_params.initial_max_streams_uni,
+ config.max_stream_window,
),
odcid: None,
@@ -1413,6 +1598,7 @@ impl Connection {
handshake_completed: false,
handshake_done_sent: false,
+ handshake_done_acked: false,
handshake_confirmed: false,
@@ -1420,15 +1606,14 @@ impl Connection {
closed: false,
+ timed_out: false,
+
grease: config.grease,
keylog: None,
#[cfg(feature = "qlog")]
- qlog_streamer: None,
-
- #[cfg(feature = "qlog")]
- qlogged_peer_params: false,
+ qlog: Default::default(),
dgram_recv_queue: dgram::DatagramQueue::new(
config.dgram_recv_max_queue_len,
@@ -1439,7 +1624,7 @@ impl Connection {
),
emit_dgram: true,
- });
+ };
if let Some(odcid) = odcid {
conn.local_transport_params
@@ -1454,11 +1639,9 @@ impl Connection {
conn.local_transport_params.initial_source_connection_id =
Some(scid.to_vec().into());
- conn.handshake.lock().unwrap().init(&conn)?;
+ conn.handshake.init(is_server)?;
conn.handshake
- .lock()
- .unwrap()
.use_legacy_codepoint(config.version != PROTOCOL_VERSION_V1);
conn.encode_transport_params()?;
@@ -1485,6 +1668,8 @@ impl Connection {
conn.derived_initial_secrets = true;
}
+ conn.recovery.on_init();
+
Ok(conn)
}
@@ -1501,22 +1686,54 @@ impl Connection {
/// Sets qlog output to the designated [`Writer`].
///
+ /// Only events included in `QlogLevel::Base` are written. The serialization
+ /// format is JSON-SEQ.
+ ///
/// This needs to be called as soon as the connection is created, to avoid
/// missing some early logs.
///
/// [`Writer`]: https://doc.rust-lang.org/std/io/trait.Write.html
#[cfg(feature = "qlog")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "qlog")))]
pub fn set_qlog(
&mut self, writer: Box<dyn std::io::Write + Send + Sync>, title: String,
description: String,
) {
+ self.set_qlog_with_level(writer, title, description, QlogLevel::Base)
+ }
+
+ /// Sets qlog output to the designated [`Writer`].
+ ///
+ /// Only qlog events included in the specified `QlogLevel` are written. The
+ /// serialization format is JSON-SEQ.
+ ///
+ /// This needs to be called as soon as the connection is created, to avoid
+ /// missing some early logs.
+ ///
+ /// [`Writer`]: https://doc.rust-lang.org/std/io/trait.Write.html
+ #[cfg(feature = "qlog")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "qlog")))]
+ pub fn set_qlog_with_level(
+ &mut self, writer: Box<dyn std::io::Write + Send + Sync>, title: String,
+ description: String, qlog_level: QlogLevel,
+ ) {
let vp = if self.is_server {
qlog::VantagePointType::Server
} else {
qlog::VantagePointType::Client
};
- let trace = qlog::Trace::new(
+ let level = match qlog_level {
+ QlogLevel::Core => EventImportance::Core,
+
+ QlogLevel::Base => EventImportance::Base,
+
+ QlogLevel::Extra => EventImportance::Extra,
+ };
+
+ self.qlog.level = level;
+
+ let trace = qlog::TraceSeq::new(
qlog::VantagePoint {
name: None,
ty: vp,
@@ -1525,37 +1742,33 @@ impl Connection {
Some(title.to_string()),
Some(description.to_string()),
Some(qlog::Configuration {
- time_offset: Some("0".to_string()),
- time_units: Some(qlog::TimeUnits::Ms),
+ time_offset: Some(0.0),
original_uris: None,
}),
None,
);
- let mut streamer = qlog::QlogStreamer::new(
+ let mut streamer = qlog::streamer::QlogStreamer::new(
qlog::QLOG_VERSION.to_string(),
Some(title),
Some(description),
None,
- std::time::Instant::now(),
+ time::Instant::now(),
trace,
+ self.qlog.level.clone(),
writer,
);
streamer.start_log().ok();
- let handshake = self.handshake.lock().unwrap();
-
- let ev = self.local_transport_params.to_qlog(
- qlog::TransportOwner::Local,
- self.version,
- handshake.alpn_protocol(),
- handshake.cipher(),
- );
+ let ev_data = self
+ .local_transport_params
+ .to_qlog(TransportOwner::Local, self.handshake.cipher());
- streamer.add_event(ev).ok();
+ // This event occurs very early, so just mark the relative time as 0.0.
+ streamer.add_event(Event::with_time(0.0, ev_data)).ok();
- self.qlog_streamer = Some(streamer);
+ self.qlog.streamer = Some(streamer);
}
/// Configures the given session for resumption.
@@ -1574,10 +1787,7 @@ impl Connection {
let session_len = b.get_u64()? as usize;
let session_bytes = b.get_bytes(session_len)?;
- self.handshake
- .lock()
- .unwrap()
- .set_session(session_bytes.as_ref())?;
+ self.handshake.set_session(session_bytes.as_ref())?;
let raw_params_len = b.get_u64()? as usize;
let raw_params_bytes = b.get_bytes(raw_params_len)?;
@@ -1803,7 +2013,7 @@ impl Connection {
// Reset connection state to force sending another Initial packet.
self.drop_epoch_state(packet::EPOCH_INITIAL, now);
self.got_peer_conn_id = false;
- self.handshake.lock().unwrap().clear()?;
+ self.handshake.clear()?;
self.pkt_num_spaces[packet::EPOCH_INITIAL].crypto_open =
Some(aead_open);
@@ -1811,8 +2021,6 @@ impl Connection {
Some(aead_seal);
self.handshake
- .lock()
- .unwrap()
.use_legacy_codepoint(self.version != PROTOCOL_VERSION_V1);
// Encode transport parameters again, as the new version might be
@@ -1862,7 +2070,7 @@ impl Connection {
// Reset connection state to force sending another Initial packet.
self.drop_epoch_state(packet::EPOCH_INITIAL, now);
self.got_peer_conn_id = false;
- self.handshake.lock().unwrap().clear()?;
+ self.handshake.clear()?;
self.pkt_num_spaces[packet::EPOCH_INITIAL].crypto_open =
Some(aead_open);
@@ -1881,8 +2089,6 @@ impl Connection {
self.did_version_negotiation = true;
self.handshake
- .lock()
- .unwrap()
.use_legacy_codepoint(self.version != PROTOCOL_VERSION_V1);
// Encode transport parameters again, as the new version might be
@@ -1984,7 +2190,7 @@ impl Connection {
let aead_tag_len = aead.alg().tag_len();
- packet::decrypt_hdr(&mut b, &mut hdr, &aead).map_err(|e| {
+ packet::decrypt_hdr(&mut b, &mut hdr, aead).map_err(|e| {
drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id)
})?;
@@ -2004,36 +2210,15 @@ impl Connection {
pn
);
- qlog_with!(self.qlog_streamer, q, {
- let packet_size = b.len();
-
- let qlog_pkt_hdr = qlog::PacketHeader::with_type(
- hdr.ty.to_qlog(),
- pn,
- Some(packet_size as u64),
- Some(payload_len as u64),
- Some(hdr.version),
- Some(&hdr.scid),
- Some(&hdr.dcid),
- );
-
- q.add_event(qlog::event::Event::packet_received(
- hdr.ty.to_qlog(),
- qlog_pkt_hdr,
- Some(Vec::new()),
- None,
- None,
- None,
- ))
- .ok();
- });
+ #[cfg(feature = "qlog")]
+ let mut qlog_frames = vec![];
let mut payload = packet::decrypt_pkt(
&mut b,
pn,
pn_len,
payload_len,
- &aead,
+ aead,
)
.map_err(|e| {
drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id)
@@ -2083,12 +2268,15 @@ impl Connection {
// ACK and PADDING.
let mut ack_elicited = false;
- // Process packet payload.
+ // Process packet payload. If a frame cannot be processed, store the
+ // error and stop further packet processing.
+ let mut frame_processing_err = None;
+
while payload.cap() > 0 {
let frame = frame::Frame::from_bytes(&mut payload, hdr.ty)?;
- qlog_with!(self.qlog_streamer, q, {
- q.add_frame(frame.to_qlog(), false).ok();
+ qlog_with_type!(QLOG_PACKET_RX, self.qlog, _q, {
+ qlog_frames.push(frame.to_qlog());
});
if frame.ack_eliciting() {
@@ -2096,43 +2284,68 @@ impl Connection {
}
if let Err(e) = self.process_frame(frame, epoch, now) {
- qlog_with!(self.qlog_streamer, q, {
- // Always conclude frame writing on error.
- q.finish_frames().ok();
- });
-
- return Err(e);
+ frame_processing_err = Some(e);
+ break;
}
}
- qlog_with!(self.qlog_streamer, q, {
- // Always conclude frame writing.
- q.finish_frames().ok();
+ qlog_with_type!(QLOG_PACKET_RX, self.qlog, q, {
+ let packet_size = b.len();
+
+ let qlog_pkt_hdr = qlog::events::quic::PacketHeader::with_type(
+ hdr.ty.to_qlog(),
+ pn,
+ Some(hdr.version),
+ Some(&hdr.scid),
+ Some(&hdr.dcid),
+ );
+
+ let qlog_raw_info = RawInfo {
+ length: Some(packet_size as u64),
+ payload_length: Some(payload_len as u64),
+ data: None,
+ };
+
+ let ev_data =
+ EventData::PacketReceived(qlog::events::quic::PacketReceived {
+ header: qlog_pkt_hdr,
+ frames: Some(qlog_frames),
+ is_coalesced: None,
+ retry_token: None,
+ stateless_reset_token: None,
+ supported_versions: None,
+ raw: Some(qlog_raw_info),
+ datagram_id: None,
+ trigger: None,
+ });
+
+ q.add_event_data_with_instant(ev_data, now).ok();
});
- qlog_with!(self.qlog_streamer, q, {
- let ev = self.recovery.to_qlog();
- q.add_event(ev).ok();
+ qlog_with_type!(QLOG_PACKET_RX, self.qlog, q, {
+ if let Some(ev_data) = self.recovery.maybe_qlog() {
+ q.add_event_data_with_instant(ev_data, now).ok();
+ }
});
+ if let Some(e) = frame_processing_err {
+ // Any frame error is terminal, so now just return.
+ return Err(e);
+ }
+
// Only log the remote transport parameters once the connection is
// established (i.e. after frames have been fully parsed) and only
// once per connection.
if self.is_established() {
- qlog_with!(self.qlog_streamer, q, {
- if !self.qlogged_peer_params {
- let handshake = self.handshake.lock().unwrap();
-
- let ev = self.peer_transport_params.to_qlog(
- qlog::TransportOwner::Remote,
- self.version,
- handshake.alpn_protocol(),
- handshake.cipher(),
- );
+ qlog_with_type!(QLOG_PARAMS_SET, self.qlog, q, {
+ if !self.qlog.logged_peer_params {
+ let ev_data = self
+ .peer_transport_params
+ .to_qlog(TransportOwner::Remote, self.handshake.cipher());
- q.add_event(ev).ok();
+ q.add_event_data_with_instant(ev_data, now).ok();
- self.qlogged_peer_params = true;
+ self.qlog.logged_peer_params = true;
}
});
}
@@ -2181,6 +2394,14 @@ impl Connection {
}
},
+ frame::Frame::HandshakeDone => {
+ // Explicitly set this to true, so that if the frame was
+ // already scheduled for retransmission, it is aborted.
+ self.handshake_done_sent = true;
+
+ self.handshake_done_acked = true;
+ },
+
frame::Frame::ResetStream { stream_id, .. } => {
let stream = match self.streams.get_mut(stream_id) {
Some(v) => v,
@@ -2222,15 +2443,14 @@ impl Connection {
}
// Update send capacity.
- self.tx_cap = cmp::min(
- self.recovery.cwnd_available() as u64,
- self.max_tx_data - self.tx_data,
- ) as usize;
+ self.update_tx_cap();
self.recv_count += 1;
let read = b.off() + aead_tag_len;
+ self.recv_bytes += read as u64;
+
// An Handshake packet has been received from the client and has been
// successfully processed, so we can drop the initial state and consider
// the client's address to be verified.
@@ -2260,14 +2480,18 @@ impl Connection {
/// * When the connection timer expires (that is, any time [`on_timeout()`]
/// is also called).
///
- /// * When the application sends data to the peer (for examples, any time
+ /// * When the application sends data to the peer (for example, any time
/// [`stream_send()`] or [`stream_shutdown()`] are called).
///
+ /// * When the application receives data from the peer (for example any
+ /// time [`stream_recv()`] is called).
+ ///
/// [`Done`]: enum.Error.html#variant.Done
/// [`recv()`]: struct.Connection.html#method.recv
/// [`on_timeout()`]: struct.Connection.html#method.on_timeout
/// [`stream_send()`]: struct.Connection.html#method.stream_send
/// [`stream_shutdown()`]: struct.Connection.html#method.stream_shutdown
+ /// [`stream_recv()`]: struct.Connection.html#method.stream_recv
///
/// ## Examples:
///
@@ -2386,6 +2610,8 @@ impl Connection {
}
if done == 0 {
+ self.last_tx_data = self.tx_data;
+
return Err(Error::Done);
}
@@ -2403,10 +2629,7 @@ impl Connection {
let info = SendInfo {
to: self.peer_addr,
- at: self
- .recovery
- .get_packet_send_time()
- .unwrap_or_else(time::Instant::now),
+ at: self.recovery.get_packet_send_time(),
};
Ok((done, info))
@@ -2441,6 +2664,10 @@ impl Connection {
.crypto_stream
.send
.retransmit(offset, length);
+
+ self.stream_retrans_bytes += length as u64;
+
+ self.retrans_count += 1;
},
frame::Frame::StreamHeader {
@@ -2475,6 +2702,10 @@ impl Connection {
incremental,
);
}
+
+ self.stream_retrans_bytes += length as u64;
+
+ self.retrans_count += 1;
},
frame::Frame::ACK { .. } => {
@@ -2491,7 +2722,9 @@ impl Connection {
.mark_reset(stream_id, true, error_code, final_size);
},
- frame::Frame::HandshakeDone => {
+ // Retransmit HANDSHAKE_DONE only if it hasn't been acked at
+ // least once already.
+ frame::Frame::HandshakeDone if !self.handshake_done_acked => {
self.handshake_done_sent = false;
},
@@ -2616,6 +2849,7 @@ impl Connection {
let frame = frame::Frame::ACK {
ack_delay,
ranges: self.pkt_num_spaces[epoch].recv_pkt_need_ack.clone(),
+ ecn_counts: None, // sending ECN is not supported at this time
};
if push_frame_to_pkt!(b, frames, frame, left) {
@@ -2625,10 +2859,7 @@ impl Connection {
if pkt_type == packet::Type::Short && !is_closing {
// Create HANDSHAKE_DONE frame.
- if self.is_established() &&
- !self.handshake_done_sent &&
- self.is_server
- {
+ if self.should_send_handshake_done() {
let frame = frame::Frame::HandshakeDone;
if push_frame_to_pkt!(b, frames, frame, left) {
@@ -2692,19 +2923,30 @@ impl Connection {
},
};
+ // Autotune the stream window size.
+ stream.recv.autotune_window(now, self.recovery.rtt());
+
let frame = frame::Frame::MaxStreamData {
stream_id,
max: stream.recv.max_data_next(),
};
if push_frame_to_pkt!(b, frames, frame, left) {
- stream.recv.update_max_data();
+ let recv_win = stream.recv.window();
+
+ stream.recv.update_max_data(now);
self.streams.mark_almost_full(stream_id, false);
ack_eliciting = true;
in_flight = true;
+ // Make sure the connection window always has some
+ // room compared to the stream window.
+ self.flow_control.ensure_window_lower_bound(
+ (recv_win as f64 * CONNECTION_WINDOW_FACTOR) as u64,
+ );
+
// Also send MAX_DATA when MAX_STREAM_DATA is sent, to avoid a
// potential race condition.
self.almost_full = true;
@@ -2712,16 +2954,19 @@ impl Connection {
}
// Create MAX_DATA frame as needed.
- if self.almost_full && self.max_rx_data < self.max_rx_data_next {
+ if self.almost_full && self.max_rx_data() < self.max_rx_data_next() {
+ // Autotune the connection window size.
+ self.flow_control.autotune_window(now, self.recovery.rtt());
+
let frame = frame::Frame::MaxData {
- max: self.max_rx_data_next,
+ max: self.max_rx_data_next(),
};
if push_frame_to_pkt!(b, frames, frame, left) {
self.almost_full = false;
// Commits the new max_rx_data limit.
- self.max_rx_data = self.max_rx_data_next;
+ self.flow_control.update_max_data(now);
ack_eliciting = true;
in_flight = true;
@@ -2823,10 +3068,8 @@ impl Connection {
}
// Create PATH_RESPONSE frame.
- if let Some(ref challenge) = self.challenge {
- let frame = frame::Frame::PathResponse {
- data: challenge.clone(),
- };
+ if let Some(challenge) = self.challenge {
+ let frame = frame::Frame::PathResponse { data: challenge };
if push_frame_to_pkt!(b, frames, frame, left) {
self.challenge = None;
@@ -2926,11 +3169,55 @@ impl Connection {
{
if let Some(max_dgram_payload) = self.dgram_max_writable_len() {
while let Some(len) = self.dgram_send_queue.peek_front_len() {
- if (len + frame::MAX_DGRAM_OVERHEAD) <= left {
- // Front of the queue fits this packet, send it
+ let hdr_off = b.off();
+ let hdr_len = 1 + // frame type
+ 2; // length, always encode as 2-byte varint
+
+ if (hdr_len + len) <= left {
+ // Front of the queue fits this packet, send it.
match self.dgram_send_queue.pop() {
Some(data) => {
- let frame = frame::Frame::Datagram { data };
+ // Encode the frame.
+ //
+ // Instead of creating a `frame::Frame` object,
+ // encode the frame directly into the packet
+ // buffer.
+ //
+ // First we reserve some space in the output
+ // buffer for writing the frame header (we
+ // assume the length field is always a 2-byte
+ // varint as we don't know the value yet).
+ //
+ // Then we emit the data from the DATAGRAM's
+ // buffer.
+ //
+ // Finally we go back and encode the frame
+ // header with the now available information.
+ let (mut dgram_hdr, mut dgram_payload) =
+ b.split_at(hdr_off + hdr_len)?;
+
+ dgram_payload.as_mut()[..len]
+ .copy_from_slice(&data);
+
+ // Encode the frame's header.
+ //
+ // Due to how `OctetsMut::split_at()` works,
+ // `dgram_hdr` starts from the initial offset
+ // of `b` (rather than the current offset), so
+ // it needs to be advanced to the initial frame
+ // offset.
+ dgram_hdr.skip(hdr_off)?;
+
+ frame::encode_dgram_header(
+ len as u64,
+ &mut dgram_hdr,
+ )?;
+
+ // Advance the packet buffer's offset.
+ b.skip(hdr_len + len)?;
+
+ let frame =
+ frame::Frame::DatagramHeader { length: len };
if push_frame_to_pkt!(b, frames, frame, left) {
ack_eliciting = true;
@@ -2980,9 +3267,8 @@ impl Connection {
// directly into the packet buffer.
//
// First we reserve some space in the output buffer for writing
- // the frame header (we assume the length field is
- // always a 2-byte varint as we don't know the
- // value yet).
+ // the frame header (we assume the length field is always a
+ // 2-byte varint as we don't know the value yet).
//
// Then we emit the data from the stream's send buffer.
//
@@ -3061,7 +3347,7 @@ impl Connection {
// Alternate trying to send DATAGRAMs next time.
self.emit_dgram = !dgram_emitted;
- // Create PING for PTO probe if no other ack-elicitng frame is sent.
+ // Create PING for PTO probe if no other ack-eliciting frame is sent.
if self.recovery.loss_probes[epoch] > 0 &&
!ack_eliciting &&
left >= 1 &&
@@ -3115,11 +3401,10 @@ impl Connection {
}
let payload_len = b.off() - payload_offset;
- let payload_len = payload_len + crypto_overhead;
// Fill in payload length.
if pkt_type != packet::Type::Short {
- let len = pn_len + payload_len;
+ let len = pn_len + payload_len + crypto_overhead;
let (_, mut payload_with_len) = b.split_at(header_offset)?;
payload_with_len
@@ -3134,41 +3419,50 @@ impl Connection {
pn
);
- qlog_with!(self.qlog_streamer, q, {
- let qlog_pkt_hdr = qlog::PacketHeader::with_type(
+ #[cfg(feature = "qlog")]
+ let mut qlog_frames = Vec::with_capacity(frames.len());
+
+ for frame in &mut frames {
+ trace!("{} tx frm {:?}", self.trace_id, frame);
+
+ qlog_with_type!(QLOG_PACKET_TX, self.qlog, _q, {
+ qlog_frames.push(frame.to_qlog());
+ });
+ }
+
+ qlog_with_type!(QLOG_PACKET_TX, self.qlog, q, {
+ let qlog_pkt_hdr = qlog::events::quic::PacketHeader::with_type(
hdr.ty.to_qlog(),
pn,
- Some(payload_len as u64 + payload_offset as u64),
- Some(payload_len as u64),
Some(hdr.version),
Some(&hdr.scid),
Some(&hdr.dcid),
);
- let packet_sent_ev = qlog::event::Event::packet_sent_min(
- hdr.ty.to_qlog(),
- qlog_pkt_hdr,
- Some(Vec::new()),
- );
-
- q.add_event(packet_sent_ev).ok();
- });
-
- for frame in &mut frames {
- trace!("{} tx frm {:?}", self.trace_id, frame);
+ // Qlog packet raw info described at
+ // https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema-00#section-5.1
+ //
+ // `length` includes packet headers and trailers (AEAD tag).
+ let length = payload_len + payload_offset + crypto_overhead;
+ let qlog_raw_info = RawInfo {
+ length: Some(length as u64),
+ payload_length: Some(payload_len as u64),
+ data: None,
+ };
- qlog_with!(self.qlog_streamer, q, {
- q.add_frame(frame.to_qlog(), false).ok();
+ let ev_data = EventData::PacketSent(qlog::events::quic::PacketSent {
+ header: qlog_pkt_hdr,
+ frames: Some(qlog_frames),
+ is_coalesced: None,
+ retry_token: None,
+ stateless_reset_token: None,
+ supported_versions: None,
+ raw: Some(qlog_raw_info),
+ datagram_id: None,
+ trigger: None,
});
- // Once frames have been serialized they are passed to the Recovery
- // module which manages retransmission. However, some frames do not
- // contain retransmittable data, so drop it here.
- frame.shrink_for_retransmission();
- }
-
- qlog_with!(self.qlog_streamer, q, {
- q.finish_frames().ok();
+ q.add_event_data_with_instant(ev_data, now).ok();
});
let aead = match self.pkt_num_spaces[epoch].crypto_seal {
@@ -3182,6 +3476,7 @@ impl Connection {
pn_len,
payload_len,
payload_offset,
+ None,
aead,
)?;
@@ -3196,11 +3491,15 @@ impl Connection {
in_flight,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data,
};
+ if in_flight && self.delivery_rate_check_if_app_limited() {
+ self.recovery.delivery_rate_update_app_limited(true);
+ }
+
self.recovery.on_packet_sent(
sent_pkt,
epoch,
@@ -3209,14 +3508,16 @@ impl Connection {
&self.trace_id,
);
- qlog_with!(self.qlog_streamer, q, {
- let ev = self.recovery.to_qlog();
- q.add_event(ev).ok();
+ qlog_with_type!(QLOG_METRICS, self.qlog, q, {
+ if let Some(ev_data) = self.recovery.maybe_qlog() {
+ q.add_event_data_with_instant(ev_data, now).ok();
+ }
});
self.pkt_num_spaces[epoch].next_pkt_num += 1;
self.sent_count += 1;
+ self.sent_bytes += written as u64;
if self.dgram_send_queue.byte_size() > self.recovery.cwnd_available() {
self.recovery.update_app_limited(false);
@@ -3244,6 +3545,19 @@ impl Connection {
Ok((pkt_type, written))
}
+ /// Returns the size of the send quantum, in bytes.
+ ///
+ /// This represents the maximum size of a packet burst as determined by the
+ /// congestion control algorithm in use.
+ ///
+ /// Applications can, for example, use it in conjuction with segmentatation
+ /// offloading mechanisms as the maximum limit for outgoing aggregates of
+ /// multiple packets.
+ #[inline]
+ pub fn send_quantum(&mut self) -> usize {
+ self.recovery.send_quantum()
+ }
+
/// Reads contiguous data from a stream into the provided slice.
///
/// The slice must be sized by the caller and will be populated up to its
@@ -3252,7 +3566,11 @@ impl Connection {
/// On success the amount of bytes read and a flag indicating the fin state
/// is returned as a tuple, or [`Done`] if there is no data to read.
///
+ /// Reading data from a stream may trigger queueing of control messages
+ /// (e.g. MAX_STREAM_DATA). [`send()`] should be called after reading.
+ ///
/// [`Done`]: enum.Error.html#variant.Done
+ /// [`send()`]: struct.Connection.html#method.send
///
/// ## Examples:
///
@@ -3288,19 +3606,34 @@ impl Connection {
return Err(Error::Done);
}
+ let local = stream.local;
+
#[cfg(feature = "qlog")]
let offset = stream.recv.off_front();
- let (read, fin) = stream.recv.emit(out)?;
+ let (read, fin) = match stream.recv.emit(out) {
+ Ok(v) => v,
+
+ Err(e) => {
+ // Collect the stream if it is now complete. This can happen if
+ // we got a `StreamReset` error which will now be propagated to
+ // the application, so we don't need to keep the stream's state
+ // anymore.
+ if stream.is_complete() {
+ self.streams.collect(stream_id, local);
+ }
+
+ self.streams.mark_readable(stream_id, false);
+ return Err(e);
+ },
+ };
- self.max_rx_data_next = self.max_rx_data_next.saturating_add(read as u64);
+ self.flow_control.add_consumed(read as u64);
let readable = stream.is_readable();
let complete = stream.is_complete();
- let local = stream.local;
-
if stream.recv.almost_full() {
self.streams.mark_almost_full(stream_id, true);
}
@@ -3313,16 +3646,18 @@ impl Connection {
self.streams.collect(stream_id, local);
}
- qlog_with!(self.qlog_streamer, q, {
- let ev = qlog::event::Event::h3_data_moved(
- stream_id.to_string(),
- Some(offset.to_string()),
- Some(read as u64),
- Some(qlog::H3DataRecipient::Transport),
- None,
- None,
- );
- q.add_event(ev).ok();
+ qlog_with_type!(QLOG_DATA_MV, self.qlog, q, {
+ let ev_data = EventData::DataMoved(qlog::events::quic::DataMoved {
+ stream_id: Some(stream_id),
+ offset: Some(offset),
+ length: Some(read as u64),
+ from: Some(DataRecipient::Transport),
+ to: Some(DataRecipient::Application),
+ data: None,
+ });
+
+ let now = time::Instant::now();
+ q.add_event_data_with_instant(ev_data, now).ok();
});
if self.should_update_max_data() {
@@ -3337,6 +3672,11 @@ impl Connection {
/// On success the number of bytes written is returned, or [`Done`] if no
/// data was written (e.g. because the stream has no capacity).
///
+ /// Applications can provide a 0-length buffer with the fin flag set to
+ /// true. This will lead to a 0-length FIN STREAM frame being sent at the
+ /// latest offset. The `Ok(0)` value is only returned when the application
+ /// provided a 0-length buffer.
+ ///
/// In addition, if the peer has signalled that it doesn't want to receive
/// any more data from this stream by sending the `STOP_SENDING` frame, the
/// [`StreamStopped`] error will be returned instead of any data.
@@ -3394,7 +3734,13 @@ impl Connection {
// Truncate the input buffer based on the connection's send capacity if
// necessary.
+ //
+ // When the cap is zero, the method returns Ok(0) *only* when the passed
+ // buffer is empty. We return Error::Done otherwise.
let cap = self.tx_cap;
+ if cap == 0 && !(fin && buf.is_empty()) {
+ return Err(Error::Done);
+ }
let (buf, fin) = if cap < buf.len() {
(&buf[..cap], false)
@@ -3431,8 +3777,12 @@ impl Connection {
if sent < buf.len() {
let max_off = stream.send.max_off();
- self.streams.mark_blocked(stream_id, true, max_off);
+ if stream.send.blocked_at() != Some(max_off) {
+ stream.send.update_blocked_at(Some(max_off));
+ self.streams.mark_blocked(stream_id, true, max_off);
+ }
} else {
+ stream.send.update_blocked_at(None);
self.streams.mark_blocked(stream_id, false, 0);
}
@@ -3453,20 +3803,24 @@ impl Connection {
self.tx_data += sent as u64;
- self.recovery.rate_check_app_limited();
+ qlog_with_type!(QLOG_DATA_MV, self.qlog, q, {
+ let ev_data = EventData::DataMoved(qlog::events::quic::DataMoved {
+ stream_id: Some(stream_id),
+ offset: Some(offset),
+ length: Some(sent as u64),
+ from: Some(DataRecipient::Application),
+ to: Some(DataRecipient::Transport),
+ data: None,
+ });
- qlog_with!(self.qlog_streamer, q, {
- let ev = qlog::event::Event::h3_data_moved(
- stream_id.to_string(),
- Some(offset.to_string()),
- Some(sent as u64),
- None,
- Some(qlog::H3DataRecipient::Transport),
- None,
- );
- q.add_event(ev).ok();
+ let now = time::Instant::now();
+ q.add_event_data_with_instant(ev_data, now).ok();
});
+ if sent == 0 && !buf.is_empty() {
+ return Err(Error::Done);
+ }
+
Ok(sent)
}
@@ -3540,7 +3894,14 @@ impl Connection {
},
Shutdown::Write => {
- let final_size = stream.send.shutdown()?;
+ let (final_size, unsent) = stream.send.shutdown()?;
+
+ // Claw back some flow control allowance from data that was
+ // buffered but not actually sent before the stream was reset.
+ self.tx_data = self.tx_data.saturating_sub(unsent);
+
+ // Update send capacity.
+ self.update_tx_cap();
self.streams.mark_reset(stream_id, true, err, final_size);
@@ -3585,6 +3946,50 @@ impl Connection {
stream.is_readable()
}
+ /// Returns true if the stream has enough send capacity.
+ ///
+ /// When `len` more bytes can be buffered into the given stream's send
+ /// buffer, `true` will be returned, `false` otherwise.
+ ///
+ /// In the latter case, if the additional data can't be buffered due to
+ /// flow control limits, the peer will also be notified.
+ ///
+ /// If the specified stream doesn't exist (including when it has already
+ /// been completed and closed), the [`InvalidStreamState`] error will be
+ /// returned.
+ ///
+ /// In addition, if the peer has signalled that it doesn't want to receive
+ /// any more data from this stream by sending the `STOP_SENDING` frame, the
+ /// [`StreamStopped`] error will be returned.
+ ///
+ /// [`InvalidStreamState`]: enum.Error.html#variant.InvalidStreamState
+ /// [`StreamStopped`]: enum.Error.html#variant.StreamStopped
+ #[inline]
+ pub fn stream_writable(
+ &mut self, stream_id: u64, len: usize,
+ ) -> Result<bool> {
+ if self.stream_capacity(stream_id)? >= len {
+ return Ok(true);
+ }
+
+ let stream = match self.streams.get(stream_id) {
+ Some(v) => v,
+
+ None => return Err(Error::InvalidStreamState(stream_id)),
+ };
+
+ if self.max_tx_data - self.tx_data < len as u64 {
+ self.blocked_limit = Some(self.max_tx_data);
+ }
+
+ if stream.send.cap()? < len {
+ let max_off = stream.send.max_off();
+ self.streams.mark_blocked(stream_id, true, max_off);
+ }
+
+ Ok(false)
+ }
+
/// Returns true if all the data has been read from the specified stream.
///
/// This instructs the application that all the data received from the
@@ -3810,6 +4215,21 @@ impl Connection {
}
}
+ /// Reads the first received DATAGRAM.
+ ///
+ /// This is the same as [`dgram_recv()`] but returns the DATAGRAM as a
+ /// `Vec<u8>` instead of copying into the provided buffer.
+ ///
+ /// [`dgram_recv()`]: struct.Connection.html#method.dgram_recv
+ #[inline]
+ pub fn dgram_recv_vec(&mut self) -> Result<Vec<u8>> {
+ match self.dgram_recv_queue.pop() {
+ Some(d) => Ok(d),
+
+ None => Err(Error::Done),
+ }
+ }
+
/// Reads the first received DATAGRAM without removing it from the queue.
///
/// On success the DATAGRAM's data is returned along with the actual number
@@ -3891,10 +4311,35 @@ impl Connection {
/// ```
pub fn dgram_send(&mut self, buf: &[u8]) -> Result<()> {
let max_payload_len = match self.dgram_max_writable_len() {
- Some(v) => v as usize,
- None => {
- return Err(Error::InvalidState);
- },
+ Some(v) => v,
+
+ None => return Err(Error::InvalidState),
+ };
+
+ if buf.len() > max_payload_len {
+ return Err(Error::BufferTooShort);
+ }
+
+ self.dgram_send_queue.push(buf.to_vec())?;
+
+ if self.dgram_send_queue.byte_size() > self.recovery.cwnd_available() {
+ self.recovery.update_app_limited(false);
+ }
+
+ Ok(())
+ }
+
+ /// Sends data in a DATAGRAM frame.
+ ///
+ /// This is the same as [`dgram_send()`] but takes a `Vec<u8>` instead of
+ /// a slice.
+ ///
+ /// [`dgram_send()`]: struct.Connection.html#method.dgram_send
+ pub fn dgram_send_vec(&mut self, buf: Vec<u8>) -> Result<()> {
+ let max_payload_len = match self.dgram_max_writable_len() {
+ Some(v) => v,
+
+ None => return Err(Error::InvalidState),
};
if buf.len() > max_payload_len {
@@ -4013,7 +4458,7 @@ impl Connection {
let now = time::Instant::now();
if timeout <= now {
- return Some(time::Duration::new(0, 0));
+ return Some(time::Duration::ZERO);
}
return Some(timeout.duration_since(now));
@@ -4032,7 +4477,7 @@ impl Connection {
if draining_timer <= now {
trace!("{} draining timeout expired", self.trace_id);
- qlog_with!(self.qlog_streamer, q, {
+ qlog_with!(self.qlog, q, {
q.finish_log().ok();
});
@@ -4049,11 +4494,12 @@ impl Connection {
if timer <= now {
trace!("{} idle timeout expired", self.trace_id);
- qlog_with!(self.qlog_streamer, q, {
+ qlog_with!(self.qlog, q, {
q.finish_log().ok();
});
self.closed = true;
+ self.timed_out = true;
return;
}
}
@@ -4068,12 +4514,11 @@ impl Connection {
&self.trace_id,
);
- qlog_with!(self.qlog_streamer, q, {
- let ev = self.recovery.to_qlog();
- q.add_event(ev).ok();
+ qlog_with_type!(QLOG_METRICS, self.qlog, q, {
+ if let Some(ev_data) = self.recovery.maybe_qlog() {
+ q.add_event_data_with_instant(ev_data, now).ok();
+ }
});
-
- return;
}
}
}
@@ -4136,10 +4581,16 @@ impl Connection {
self.alpn.as_ref()
}
+ /// Returns the server name requested by the client.
+ #[inline]
+ pub fn server_name(&self) -> Option<&str> {
+ self.handshake.server_name()
+ }
+
/// Returns the peer's leaf certificate (if any) as a DER-encoded buffer.
#[inline]
- pub fn peer_cert(&self) -> Option<Vec<u8>> {
- self.handshake.lock().unwrap().peer_cert()
+ pub fn peer_cert(&self) -> Option<&[u8]> {
+ self.handshake.peer_cert()
}
/// Returns the serialized cryptographic session for the connection.
@@ -4149,8 +4600,8 @@ impl Connection {
///
/// [`set_session()`]: struct.Connection.html#method.set_session
#[inline]
- pub fn session(&self) -> Option<Vec<u8>> {
- self.session.clone()
+ pub fn session(&self) -> Option<&[u8]> {
+ self.session.as_deref()
}
/// Returns the source connection ID.
@@ -4180,14 +4631,14 @@ impl Connection {
/// Returns true if the connection is resumed.
#[inline]
pub fn is_resumed(&self) -> bool {
- self.handshake.lock().unwrap().is_resumed()
+ self.handshake.is_resumed()
}
/// Returns true if the connection has a pending handshake that has
/// progressed enough to send or receive early data.
#[inline]
pub fn is_in_early_data(&self) -> bool {
- self.handshake.lock().unwrap().is_in_early_data()
+ self.handshake.is_in_early_data()
}
/// Returns whether there is stream or DATAGRAM data available to read.
@@ -4222,21 +4673,38 @@ impl Connection {
self.closed
}
+ /// Returns true if the connection was closed due to the idle timeout.
+ #[inline]
+ pub fn is_timed_out(&self) -> bool {
+ self.timed_out
+ }
+
/// Returns the error received from the peer, if any.
///
- /// The values contained in the tuple are symmetric with the [`close()`]
- /// method.
- ///
/// Note that a `Some` return value does not necessarily imply
/// [`is_closed()`] or any other connection state.
///
- /// [`close()`]: struct.Connection.html#method.close
/// [`is_closed()`]: struct.Connection.html#method.is_closed
#[inline]
pub fn peer_error(&self) -> Option<&ConnectionError> {
self.peer_error.as_ref()
}
+ /// Returns the error [`close()`] was called with, or internally
+ /// created quiche errors, if any.
+ ///
+ /// Note that a `Some` return value does not necessarily imply
+ /// [`is_closed()`] or any other connection state.
+ /// `Some` also does not guarantee that the error has been sent to
+ /// or received by the peer.
+ ///
+ /// [`close()`]: struct.Connection.html#method.close
+ /// [`is_closed()`]: struct.Connection.html#method.is_closed
+ #[inline]
+ pub fn local_error(&self) -> Option<&ConnectionError> {
+ self.local_error.as_ref()
+ }
+
/// Collects and returns statistics about the connection.
#[inline]
pub fn stats(&self) -> Stats {
@@ -4244,9 +4712,48 @@ impl Connection {
recv: self.recv_count,
sent: self.sent_count,
lost: self.recovery.lost_count,
+ retrans: self.retrans_count,
cwnd: self.recovery.cwnd(),
rtt: self.recovery.rtt(),
+ sent_bytes: self.sent_bytes,
+ lost_bytes: self.recovery.bytes_lost,
+ recv_bytes: self.recv_bytes,
+ stream_retrans_bytes: self.stream_retrans_bytes,
+ pmtu: self.recovery.max_datagram_size(),
delivery_rate: self.recovery.delivery_rate(),
+ peer_max_idle_timeout: self.peer_transport_params.max_idle_timeout,
+ peer_max_udp_payload_size: self
+ .peer_transport_params
+ .max_udp_payload_size,
+ peer_initial_max_data: self.peer_transport_params.initial_max_data,
+ peer_initial_max_stream_data_bidi_local: self
+ .peer_transport_params
+ .initial_max_stream_data_bidi_local,
+ peer_initial_max_stream_data_bidi_remote: self
+ .peer_transport_params
+ .initial_max_stream_data_bidi_remote,
+ peer_initial_max_stream_data_uni: self
+ .peer_transport_params
+ .initial_max_stream_data_uni,
+ peer_initial_max_streams_bidi: self
+ .peer_transport_params
+ .initial_max_streams_bidi,
+ peer_initial_max_streams_uni: self
+ .peer_transport_params
+ .initial_max_streams_uni,
+ peer_ack_delay_exponent: self
+ .peer_transport_params
+ .ack_delay_exponent,
+ peer_max_ack_delay: self.peer_transport_params.max_ack_delay,
+ peer_disable_active_migration: self
+ .peer_transport_params
+ .disable_active_migration,
+ peer_active_conn_id_limit: self
+ .peer_transport_params
+ .active_conn_id_limit,
+ peer_max_datagram_frame_size: self
+ .peer_transport_params
+ .max_datagram_frame_size,
}
}
@@ -4259,10 +4766,7 @@ impl Connection {
&mut raw_params,
)?;
- self.handshake
- .lock()
- .unwrap()
- .set_quic_transport_params(raw_params)?;
+ self.handshake.set_quic_transport_params(raw_params)?;
Ok(())
}
@@ -4336,10 +4840,7 @@ impl Connection {
self.max_tx_data = peer_params.initial_max_data;
// Update send capacity.
- self.tx_cap = cmp::min(
- self.recovery.cwnd_available() as u64,
- self.max_tx_data - self.tx_data,
- ) as usize;
+ self.update_tx_cap();
self.streams
.update_peer_max_streams_bidi(peer_params.initial_max_streams_bidi);
@@ -4359,14 +4860,27 @@ impl Connection {
///
/// If the connection is already established, it does nothing.
fn do_handshake(&mut self) -> Result<()> {
- let handshake = self.handshake.lock().unwrap();
+ let mut ex_data = tls::ExData {
+ application_protos: &self.application_protos,
- // Handshake is already complete, nothing more to do.
- if handshake.is_completed() {
- return Ok(());
+ pkt_num_spaces: &mut self.pkt_num_spaces,
+
+ session: &mut self.session,
+
+ local_error: &mut self.local_error,
+
+ keylog: self.keylog.as_mut(),
+
+ trace_id: &self.trace_id,
+
+ is_server: self.is_server,
+ };
+
+ if self.handshake_completed {
+ return self.handshake.process_post_handshake(&mut ex_data);
}
- match handshake.do_handshake() {
+ match self.handshake.do_handshake(&mut ex_data) {
Ok(_) => (),
Err(Error::Done) => {
@@ -4376,14 +4890,11 @@ impl Connection {
// This is potentially dangerous as the handshake hasn't been
// completed yet, though it's required to be able to send data
// in 0.5 RTT.
- let raw_params = handshake.quic_transport_params();
+ let raw_params = self.handshake.quic_transport_params();
if !self.parsed_peer_transport_params && !raw_params.is_empty() {
let peer_params =
- TransportParams::decode(&raw_params, self.is_server)?;
-
- // Unlock handshake object.
- drop(handshake);
+ TransportParams::decode(raw_params, self.is_server)?;
self.parse_peer_transport_params(peer_params)?;
}
@@ -4394,23 +4905,15 @@ impl Connection {
Err(e) => return Err(e),
};
- self.handshake_completed = handshake.is_completed();
-
- self.alpn = handshake.alpn_protocol().to_vec();
+ self.handshake_completed = self.handshake.is_completed();
- let cipher = handshake.cipher();
- let curve = handshake.curve();
- let sigalg = handshake.sigalg();
- let is_resumed = handshake.is_resumed();
+ self.alpn = self.handshake.alpn_protocol().to_vec();
- let raw_params = handshake.quic_transport_params();
+ let raw_params = self.handshake.quic_transport_params();
if !self.parsed_peer_transport_params && !raw_params.is_empty() {
let peer_params =
- TransportParams::decode(&raw_params, self.is_server)?;
-
- // Unlock handshake object.
- drop(handshake);
+ TransportParams::decode(raw_params, self.is_server)?;
self.parse_peer_transport_params(peer_params)?;
}
@@ -4422,8 +4925,13 @@ impl Connection {
}
trace!("{} connection established: proto={:?} cipher={:?} curve={:?} sigalg={:?} resumed={} {:?}",
- &self.trace_id, std::str::from_utf8(self.application_proto()),
- cipher, curve, sigalg, is_resumed, self.peer_transport_params);
+ &self.trace_id,
+ std::str::from_utf8(self.application_proto()),
+ self.handshake.cipher(),
+ self.handshake.curve(),
+ self.handshake.sigalg(),
+ self.handshake.is_resumed(),
+ self.peer_transport_params);
Ok(())
}
@@ -4437,7 +4945,7 @@ impl Connection {
.as_ref()
.map_or(false, |conn_err| !conn_err.is_app)
{
- let epoch = match self.handshake.lock().unwrap().write_level() {
+ let epoch = match self.handshake.write_level() {
crypto::Level::Initial => packet::EPOCH_INITIAL,
crypto::Level::ZeroRTT => unreachable!(),
crypto::Level::Handshake => packet::EPOCH_HANDSHAKE,
@@ -4478,7 +4986,7 @@ impl Connection {
// If there are flushable, almost full or blocked streams, use the
// Application epoch.
if (self.is_established() || self.is_in_early_data()) &&
- ((self.is_server && !self.handshake_done_sent) ||
+ (self.should_send_handshake_done() ||
self.almost_full ||
self.blocked_limit.is_some() ||
self.dgram_send_queue.has_pending() ||
@@ -4493,7 +5001,8 @@ impl Connection {
self.streams.has_reset() ||
self.streams.has_stopped())
{
- if self.is_in_early_data() && !self.is_server {
+ // Only clients can send 0-RTT packets.
+ if !self.is_server && self.is_in_early_data() {
return Ok(packet::Type::ZeroRTT);
}
@@ -4528,7 +5037,9 @@ impl Connection {
frame::Frame::Ping => (),
- frame::Frame::ACK { ranges, ack_delay } => {
+ frame::Frame::ACK {
+ ranges, ack_delay, ..
+ } => {
let ack_delay = ack_delay
.checked_mul(2_u64.pow(
self.peer_transport_params.ack_delay_exponent as u32,
@@ -4547,6 +5058,10 @@ impl Connection {
self.handshake_confirmed = true;
}
+ if self.delivery_rate_check_if_app_limited() {
+ self.recovery.delivery_rate_update_app_limited(true);
+ }
+
self.recovery.on_ack_received(
&ranges,
ack_delay,
@@ -4564,8 +5079,8 @@ impl Connection {
frame::Frame::ResetStream {
stream_id,
+ error_code,
final_size,
- ..
} => {
// Peer can't send on our unidirectional streams.
if !stream::is_bidi(stream_id) &&
@@ -4574,6 +5089,8 @@ impl Connection {
return Err(Error::InvalidStreamState(stream_id));
}
+ let max_rx_data_left = self.max_rx_data() - self.rx_data;
+
// Get existing stream or create a new one, but if the stream
// has already been closed and collected, ignore the frame.
//
@@ -4592,11 +5109,20 @@ impl Connection {
Err(e) => return Err(e),
};
- self.rx_data += stream.recv.reset(final_size)? as u64;
+ let was_readable = stream.is_readable();
- if self.rx_data > self.max_rx_data {
+ let max_off_delta =
+ stream.recv.reset(error_code, final_size)? as u64;
+
+ if max_off_delta > max_rx_data_left {
return Err(Error::FlowControl);
}
+
+ if !was_readable && stream.is_readable() {
+ self.streams.mark_readable(stream_id, true);
+ }
+
+ self.rx_data += max_off_delta;
},
frame::Frame::StopSending {
@@ -4631,7 +5157,15 @@ impl Connection {
let was_writable = stream.is_writable();
// Try stopping the stream.
- if let Ok(final_size) = stream.send.stop(error_code) {
+ if let Ok((final_size, unsent)) = stream.send.stop(error_code) {
+ // Claw back some flow control allowance from data that was
+ // buffered but not actually sent before the stream was
+ // reset.
+ //
+ // Note that `tx_cap` will be updated later on, so no need
+ // to touch it here.
+ self.tx_data = self.tx_data.saturating_sub(unsent);
+
self.streams
.mark_reset(stream_id, true, error_code, final_size);
@@ -4655,17 +5189,10 @@ impl Connection {
while let Ok((read, _)) = stream.recv.emit(&mut crypto_buf) {
let recv_buf = &crypto_buf[..read];
- self.handshake
- .lock()
- .unwrap()
- .provide_data(level, &recv_buf)?;
+ self.handshake.provide_data(level, recv_buf)?;
}
- if self.is_established() {
- self.handshake.lock().unwrap().process_post_handshake()?;
- } else {
- self.do_handshake()?;
- }
+ self.do_handshake()?;
},
frame::Frame::CryptoHeader { .. } => unreachable!(),
@@ -4681,7 +5208,7 @@ impl Connection {
return Err(Error::InvalidStreamState(stream_id));
}
- let max_rx_data_left = self.max_rx_data - self.rx_data;
+ let max_rx_data_left = self.max_rx_data() - self.rx_data;
// Get existing stream or create a new one, but if the stream
// has already been closed and collected, ignore the frame.
@@ -4709,9 +5236,11 @@ impl Connection {
return Err(Error::FlowControl);
}
+ let was_readable = stream.is_readable();
+
stream.recv.write(data)?;
- if stream.is_readable() {
+ if !was_readable && stream.is_readable() {
self.streams.mark_readable(stream_id, true);
}
@@ -4858,8 +5387,10 @@ impl Connection {
self.dgram_recv_queue.pop();
}
- self.dgram_recv_queue.push(&data)?;
+ self.dgram_recv_queue.push(data)?;
},
+
+ frame::Frame::DatagramHeader { .. } => unreachable!(),
}
Ok(())
@@ -4889,8 +5420,22 @@ impl Connection {
/// This happens when the new max data limit is at least double the amount
/// of data that can be received before blocking.
fn should_update_max_data(&self) -> bool {
- self.max_rx_data_next != self.max_rx_data &&
- self.max_rx_data_next / 2 > self.max_rx_data - self.rx_data
+ self.flow_control.should_update_max_data()
+ }
+
+ /// Returns the connection level flow control limit.
+ fn max_rx_data(&self) -> u64 {
+ self.flow_control.max_data()
+ }
+
+ /// Returns the updated connection level flow control limit.
+ fn max_rx_data_next(&self) -> u64 {
+ self.flow_control.max_data_next()
+ }
+
+ /// Returns true if the HANDSHAKE_DONE frame needs to be sent.
+ fn should_send_handshake_done(&self) -> bool {
+ self.is_established() && !self.handshake_done_sent && self.is_server
}
/// Returns the idle timeout value.
@@ -4936,6 +5481,36 @@ impl Connection {
completed: self.is_established(),
}
}
+
+ /// Updates send capacity.
+ fn update_tx_cap(&mut self) {
+ self.tx_cap = cmp::min(
+ self.recovery.cwnd_available() as u64,
+ self.max_tx_data - self.tx_data,
+ ) as usize;
+ }
+
+ fn delivery_rate_check_if_app_limited(&self) -> bool {
+ // Enter the app-limited phase of delivery rate when these conditions
+ // are met:
+ //
+ // - The remaining capacity is higher than available bytes in cwnd (there
+ // is more room to send).
+ // - New data since the last send() is smaller than available bytes in
+ // cwnd (we queued less than what we can send).
+ // - There is room to send more data in cwnd.
+ //
+ // In application-limited phases the transmission rate is limited by the
+ // application rather than the congestion control algorithm.
+ //
+ // Note that this is equivalent to CheckIfApplicationLimited() from the
+ // delivery rate draft. This is also separate from `recovery.app_limited`
+ // and only applies to delivery rate calculation.
+ self.tx_cap >= self.recovery.cwnd_available() &&
+ (self.tx_data.saturating_sub(self.last_tx_data)) <
+ self.recovery.cwnd_available() as u64 &&
+ self.recovery.cwnd_available() > 0
+ }
}
/// Maps an `Error` to `Error::Done`, or itself.
@@ -4959,7 +5534,7 @@ impl Connection {
fn drop_pkt_on_err(
e: Error, recv_count: usize, is_server: bool, trace_id: &str,
) -> Error {
- // On the server, if no other packet has been successflully processed, abort
+ // On the server, if no other packet has been successfully processed, abort
// the connection to avoid keeping the connection open when only junk is
// received.
if is_server && recv_count == 0 {
@@ -4989,14 +5564,78 @@ pub struct Stats {
/// The number of QUIC packets that were lost.
pub lost: usize,
+ /// The number of sent QUIC packets with retransmitted data.
+ pub retrans: usize,
+
/// The estimated round-trip time of the connection.
pub rtt: time::Duration,
/// The size of the connection's congestion window in bytes.
pub cwnd: usize,
+ /// The number of sent bytes.
+ pub sent_bytes: u64,
+
+ /// The number of received bytes.
+ pub recv_bytes: u64,
+
+ /// The number of bytes lost.
+ pub lost_bytes: u64,
+
+ /// The number of stream bytes retransmitted.
+ pub stream_retrans_bytes: u64,
+
+ /// The current PMTU for the connection.
+ pub pmtu: usize,
+
/// The most recent data delivery rate estimate in bytes/s.
+ ///
+ /// Note that this value could be inaccurate if the application does not
+ /// respect pacing hints (see [`SendInfo.at`] and [Pacing] for more
+ /// details).
+ ///
+ /// [`SendInfo.at`]: struct.SendInfo.html#structfield.at
+ /// [Pacing]: index.html#pacing
pub delivery_rate: u64,
+
+ /// The maximum idle timeout.
+ pub peer_max_idle_timeout: u64,
+
+ /// The maximum UDP payload size.
+ pub peer_max_udp_payload_size: u64,
+
+ /// The initial flow control maximum data for the connection.
+ pub peer_initial_max_data: u64,
+
+ /// The initial flow control maximum data for local bidirectional streams.
+ pub peer_initial_max_stream_data_bidi_local: u64,
+
+ /// The initial flow control maximum data for remote bidirectional streams.
+ pub peer_initial_max_stream_data_bidi_remote: u64,
+
+ /// The initial flow control maximum data for unidirectional streams.
+ pub peer_initial_max_stream_data_uni: u64,
+
+ /// The initial maximum bidirectional streams.
+ pub peer_initial_max_streams_bidi: u64,
+
+ /// The initial maximum unidirectional streams.
+ pub peer_initial_max_streams_uni: u64,
+
+ /// The ACK delay exponent.
+ pub peer_ack_delay_exponent: u64,
+
+ /// The max ACK delay.
+ pub peer_max_ack_delay: u64,
+
+ /// Whether active migration is disabled.
+ pub peer_disable_active_migration: bool,
+
+ /// The active connection ID limit.
+ pub peer_active_conn_id_limit: u64,
+
+ /// DATAGRAM frame extension parameter, if any.
+ pub peer_max_datagram_frame_size: Option<u64>,
}
impl std::fmt::Debug for Stats {
@@ -5004,9 +5643,75 @@ impl std::fmt::Debug for Stats {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
- "recv={} sent={} lost={} rtt={:?} cwnd={}",
- self.recv, self.sent, self.lost, self.rtt, self.cwnd,
- )
+ "recv={} sent={} lost={} retrans={} rtt={:?} cwnd={}",
+ self.recv, self.sent, self.lost, self.retrans, self.rtt, self.cwnd,
+ )?;
+
+ write!(f, " peer_tps={{")?;
+
+ write!(f, " max_idle_timeout={},", self.peer_max_idle_timeout,)?;
+
+ write!(
+ f,
+ " max_udp_payload_size={},",
+ self.peer_max_udp_payload_size,
+ )?;
+
+ write!(f, " initial_max_data={},", self.peer_initial_max_data,)?;
+
+ write!(
+ f,
+ " initial_max_stream_data_bidi_local={},",
+ self.peer_initial_max_stream_data_bidi_local,
+ )?;
+
+ write!(
+ f,
+ " initial_max_stream_data_bidi_remote={},",
+ self.peer_initial_max_stream_data_bidi_remote,
+ )?;
+
+ write!(
+ f,
+ " initial_max_stream_data_uni={},",
+ self.peer_initial_max_stream_data_uni,
+ )?;
+
+ write!(
+ f,
+ " initial_max_streams_bidi={},",
+ self.peer_initial_max_streams_bidi,
+ )?;
+
+ write!(
+ f,
+ " initial_max_streams_uni={},",
+ self.peer_initial_max_streams_uni,
+ )?;
+
+ write!(f, " ack_delay_exponent={},", self.peer_ack_delay_exponent,)?;
+
+ write!(f, " max_ack_delay={},", self.peer_max_ack_delay,)?;
+
+ write!(
+ f,
+ " disable_active_migration={},",
+ self.peer_disable_active_migration,
+ )?;
+
+ write!(
+ f,
+ " active_conn_id_limit={},",
+ self.peer_active_conn_id_limit,
+ )?;
+
+ write!(
+ f,
+ " max_datagram_frame_size={:?}",
+ self.peer_max_datagram_frame_size,
+ )?;
+
+ write!(f, " }}")
}
}
@@ -5218,7 +5923,7 @@ impl TransportParams {
if is_server {
if let Some(ref odcid) = tp.original_destination_connection_id {
TransportParams::encode_param(&mut b, 0x0000, odcid.len())?;
- b.put_bytes(&odcid)?;
+ b.put_bytes(odcid)?;
}
};
@@ -5234,7 +5939,7 @@ impl TransportParams {
if is_server {
if let Some(ref token) = tp.stateless_reset_token {
TransportParams::encode_param(&mut b, 0x0002, token.len())?;
- b.put_bytes(&token)?;
+ b.put_bytes(token)?;
}
}
@@ -5336,13 +6041,13 @@ impl TransportParams {
if let Some(scid) = &tp.initial_source_connection_id {
TransportParams::encode_param(&mut b, 0x000f, scid.len())?;
- b.put_bytes(&scid)?;
+ b.put_bytes(scid)?;
}
if is_server {
if let Some(scid) = &tp.retry_source_connection_id {
TransportParams::encode_param(&mut b, 0x0010, scid.len())?;
- b.put_bytes(&scid)?;
+ b.put_bytes(scid)?;
}
}
@@ -5363,37 +6068,56 @@ impl TransportParams {
/// Creates a qlog event for connection transport parameters and TLS fields
#[cfg(feature = "qlog")]
pub fn to_qlog(
- &self, owner: qlog::TransportOwner, version: u32, alpn: &[u8],
- cipher: Option<crypto::Algorithm>,
- ) -> qlog::event::Event {
- let ocid = qlog::HexSlice::maybe_string(
+ &self, owner: TransportOwner, cipher: Option<crypto::Algorithm>,
+ ) -> EventData {
+ let original_destination_connection_id = qlog::HexSlice::maybe_string(
self.original_destination_connection_id.as_ref(),
);
- let stateless_reset_token =
- qlog::HexSlice::maybe_string(self.stateless_reset_token.as_ref());
-
- qlog::event::Event::transport_parameters_set(
- Some(owner),
- None, // resumption
- None, // early data
- String::from_utf8(alpn.to_vec()).ok(),
- Some(format!("{:x?}", version)),
- Some(format!("{:?}", cipher)),
- ocid,
- stateless_reset_token,
- Some(self.disable_active_migration),
- Some(self.max_idle_timeout),
- Some(self.max_udp_payload_size),
- Some(self.ack_delay_exponent),
- Some(self.max_ack_delay),
- Some(self.active_conn_id_limit),
- Some(self.initial_max_data.to_string()),
- Some(self.initial_max_stream_data_bidi_local.to_string()),
- Some(self.initial_max_stream_data_bidi_remote.to_string()),
- Some(self.initial_max_stream_data_uni.to_string()),
- Some(self.initial_max_streams_bidi.to_string()),
- Some(self.initial_max_streams_uni.to_string()),
- None, // preferred address
+
+ let stateless_reset_token = Some(qlog::Token {
+ ty: Some(qlog::TokenType::StatelessReset),
+ length: None,
+ data: qlog::HexSlice::maybe_string(
+ self.stateless_reset_token.as_ref(),
+ ),
+ details: None,
+ });
+
+ EventData::TransportParametersSet(
+ qlog::events::quic::TransportParametersSet {
+ owner: Some(owner),
+ resumption_allowed: None,
+ early_data_enabled: None,
+ tls_cipher: Some(format!("{:?}", cipher)),
+ aead_tag_length: None,
+ original_destination_connection_id,
+ initial_source_connection_id: None,
+ retry_source_connection_id: None,
+ stateless_reset_token,
+ disable_active_migration: Some(self.disable_active_migration),
+ max_idle_timeout: Some(self.max_idle_timeout),
+ max_udp_payload_size: Some(self.max_udp_payload_size as u32),
+ ack_delay_exponent: Some(self.ack_delay_exponent as u16),
+ max_ack_delay: Some(self.max_ack_delay as u16),
+ active_connection_id_limit: Some(
+ self.active_conn_id_limit as u32,
+ ),
+
+ initial_max_data: Some(self.initial_max_data),
+ initial_max_stream_data_bidi_local: Some(
+ self.initial_max_stream_data_bidi_local,
+ ),
+ initial_max_stream_data_bidi_remote: Some(
+ self.initial_max_stream_data_bidi_remote,
+ ),
+ initial_max_stream_data_uni: Some(
+ self.initial_max_stream_data_uni,
+ ),
+ initial_max_streams_bidi: Some(self.initial_max_streams_bidi),
+ initial_max_streams_uni: Some(self.initial_max_streams_uni),
+
+ preferred_address: None,
+ },
)
}
}
@@ -5403,8 +6127,8 @@ pub mod testing {
use super::*;
pub struct Pipe {
- pub client: Pin<Box<Connection>>,
- pub server: Pin<Box<Connection>>,
+ pub client: Connection,
+ pub server: Connection,
}
impl Pipe {
@@ -5421,7 +6145,7 @@ pub mod testing {
config.set_initial_max_streams_uni(3);
config.set_max_idle_timeout(180_000);
config.verify_peer(false);
- config.set_ack_delay_exponent(5);
+ config.set_ack_delay_exponent(8);
Pipe::with_config(&mut config)
}
@@ -5468,6 +6192,7 @@ pub mod testing {
config.set_initial_max_stream_data_bidi_remote(15);
config.set_initial_max_streams_bidi(3);
config.set_initial_max_streams_uni(3);
+ config.set_ack_delay_exponent(8);
Ok(Pipe {
client: connect(
@@ -5498,6 +6223,7 @@ pub mod testing {
config.set_initial_max_stream_data_bidi_remote(15);
config.set_initial_max_streams_bidi(3);
config.set_initial_max_streams_uni(3);
+ config.set_ack_delay_exponent(8);
Ok(Pipe {
client: connect(
@@ -5659,11 +6385,10 @@ pub mod testing {
hdr.to_bytes(&mut b)?;
- let payload_len = frames.iter().fold(0, |acc, x| acc + x.wire_len()) +
- space.crypto_overhead().unwrap();
+ let payload_len = frames.iter().fold(0, |acc, x| acc + x.wire_len());
if pkt_type != packet::Type::Short {
- let len = pn_len + payload_len;
+ let len = pn_len + payload_len + space.crypto_overhead().unwrap();
b.put_varint(len as u64)?;
}
@@ -5688,6 +6413,7 @@ pub mod testing {
pn_len,
payload_len,
payload_offset,
+ None,
aead,
)?;
@@ -5709,7 +6435,7 @@ pub mod testing {
let payload_len = b.cap();
- packet::decrypt_hdr(&mut b, &mut hdr, &aead).unwrap();
+ packet::decrypt_hdr(&mut b, &mut hdr, aead).unwrap();
let pn = packet::decode_pkt_num(
conn.pkt_num_spaces[epoch].largest_rx_pkt_num,
@@ -5918,6 +6644,8 @@ mod tests {
pipe.client.application_proto(),
pipe.server.application_proto()
);
+
+ assert_eq!(pipe.server.server_name(), Some("quic.tech"));
}
#[test]
@@ -5926,11 +6654,7 @@ mod tests {
// Disable session tickets on the server (SSL_OP_NO_TICKET) to avoid
// triggering 1-RTT packet send with a CRYPTO frame.
- pipe.server
- .handshake
- .lock()
- .unwrap()
- .set_options(0x0000_4000);
+ pipe.server.handshake.set_options(0x0000_4000);
assert_eq!(pipe.handshake(), Ok(()));
@@ -6534,7 +7258,7 @@ mod tests {
// Force server to send a single PING frame.
pipe.server.recovery.loss_probes[packet::EPOCH_INITIAL] = 1;
- // Artifically limit the amount of bytes the server can send.
+ // Artificially limit the amount of bytes the server can send.
pipe.server.max_send_bytes = 60;
assert_eq!(pipe.server.send(&mut buf), Err(Error::Done));
@@ -6647,7 +7371,7 @@ mod tests {
max: 30
})
);
- assert_eq!(iter.next(), Some(&frame::Frame::MaxData { max: 46 }));
+ assert_eq!(iter.next(), Some(&frame::Frame::MaxData { max: 61 }));
}
#[test]
@@ -6731,7 +7455,7 @@ mod tests {
let frames = [frame::Frame::Stream {
stream_id: 4,
- data: stream::RangeBuf::from(b"aaaaaaa", 0, false),
+ data: stream::RangeBuf::from(b"aaaaaaaaa", 0, false),
}];
let pkt_type = packet::Type::Short;
@@ -6742,7 +7466,7 @@ mod tests {
let frames = [frame::Frame::Stream {
stream_id: 4,
- data: stream::RangeBuf::from(b"a", 7, false),
+ data: stream::RangeBuf::from(b"a", 9, false),
}];
let len = pipe
@@ -6762,7 +7486,7 @@ mod tests {
iter.next(),
Some(&frame::Frame::MaxStreamData {
stream_id: 4,
- max: 22,
+ max: 24,
})
);
}
@@ -7066,6 +7790,136 @@ mod tests {
}
#[test]
+ /// Tests that receiving a valid RESET_STREAM frame when all data has
+ /// already been read, notifies the application.
+ fn reset_stream_data_recvd() {
+ let mut b = [0; 15];
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ // Client sends some data.
+ assert_eq!(pipe.client.stream_send(4, b"hello", false), Ok(5));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ // Server gets data and sends data back, closing stream.
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, false)));
+ assert!(!pipe.server.stream_finished(4));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.server.stream_send(4, b"", true), Ok(0));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ let mut r = pipe.client.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.client.stream_recv(4, &mut b), Ok((0, true)));
+ assert!(pipe.client.stream_finished(4));
+
+ // Client sends RESET_STREAM, closing stream.
+ let frames = [frame::Frame::ResetStream {
+ stream_id: 4,
+ error_code: 42,
+ final_size: 5,
+ }];
+
+ let pkt_type = packet::Type::Short;
+ assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39));
+
+ // Server is notified of stream readability, due to reset.
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(
+ pipe.server.stream_recv(4, &mut b),
+ Err(Error::StreamReset(42))
+ );
+
+ assert!(pipe.server.stream_finished(4));
+
+ // Sending RESET_STREAM again shouldn't make stream readable again.
+ assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), None);
+ }
+
+ #[test]
+ /// Tests that receiving a valid RESET_STREAM frame when all data has _not_
+ /// been read, discards all buffered data and notifies the application.
+ fn reset_stream_data_not_recvd() {
+ let mut b = [0; 15];
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ // Client sends some data.
+ assert_eq!(pipe.client.stream_send(4, b"h", false), Ok(1));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ // Server gets data and sends data back, closing stream.
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((1, false)));
+ assert!(!pipe.server.stream_finished(4));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.server.stream_send(4, b"", true), Ok(0));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ let mut r = pipe.client.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.client.stream_recv(4, &mut b), Ok((0, true)));
+ assert!(pipe.client.stream_finished(4));
+
+ // Client sends RESET_STREAM, closing stream.
+ let frames = [frame::Frame::ResetStream {
+ stream_id: 4,
+ error_code: 42,
+ final_size: 5,
+ }];
+
+ let pkt_type = packet::Type::Short;
+ assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39));
+
+ // Server is notified of stream readability, due to reset.
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(
+ pipe.server.stream_recv(4, &mut b),
+ Err(Error::StreamReset(42))
+ );
+
+ assert!(pipe.server.stream_finished(4));
+
+ // Sending RESET_STREAM again shouldn't make stream readable again.
+ assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), None);
+ }
+
+ #[test]
+ /// Tests that RESET_STREAM frames exceeding the connection-level flow
+ /// control limit cause an error.
fn reset_stream_flow_control() {
let mut buf = [0; 65535];
@@ -7100,15 +7954,41 @@ mod tests {
}
#[test]
+ /// Tests that RESET_STREAM frames exceeding the stream-level flow control
+ /// limit cause an error.
+ fn reset_stream_flow_control_stream() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ let frames = [
+ frame::Frame::Stream {
+ stream_id: 4,
+ data: stream::RangeBuf::from(b"a", 0, false),
+ },
+ frame::Frame::ResetStream {
+ stream_id: 4,
+ error_code: 0,
+ final_size: 16, // Past stream's flow control limit.
+ },
+ ];
+
+ let pkt_type = packet::Type::Short;
+ assert_eq!(
+ pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
+ Err(Error::FlowControl),
+ );
+ }
+
+ #[test]
fn path_challenge() {
let mut buf = [0; 65535];
let mut pipe = testing::Pipe::default().unwrap();
assert_eq!(pipe.handshake(), Ok(()));
- let frames = [frame::Frame::PathChallenge {
- data: vec![0xba; 8],
- }];
+ let frames = [frame::Frame::PathChallenge { data: [0xba; 8] }];
let pkt_type = packet::Type::Short;
@@ -7127,9 +8007,7 @@ mod tests {
assert_eq!(
iter.next(),
- Some(&frame::Frame::PathResponse {
- data: vec![0xba; 8],
- })
+ Some(&frame::Frame::PathResponse { data: [0xba; 8] })
);
}
@@ -7239,7 +8117,7 @@ mod tests {
assert_eq!(r.next(), None);
loop {
- if pipe.server.stream_send(4, b"world", false) == Ok(0) {
+ if pipe.server.stream_send(4, b"world", false) == Err(Error::Done) {
break;
}
@@ -7297,6 +8175,7 @@ mod tests {
let frames = [frame::Frame::ACK {
ack_delay: 15,
ranges,
+ ecn_counts: None,
}];
assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(0));
@@ -7353,11 +8232,15 @@ mod tests {
let mut r = pipe.server.readable();
assert_eq!(r.next(), None);
- // Server sends data, and closes stream.
+ // Server sends data...
let mut r = pipe.server.writable();
assert_eq!(r.next(), Some(4));
assert_eq!(r.next(), None);
+ assert_eq!(pipe.server.stream_send(4, b"world", false), Ok(5));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ // ...and buffers more, and closes stream.
assert_eq!(pipe.server.stream_send(4, b"world", true), Ok(5));
// Client sends STOP_SENDING before server flushes stream.
@@ -7394,6 +8277,82 @@ mod tests {
}
#[test]
+ /// Tests that resetting a stream restores flow control for unsent data.
+ fn stop_sending_unsent_tx_cap() {
+ let mut buf = [0; 65535];
+
+ let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap();
+ config
+ .load_cert_chain_from_pem_file("examples/cert.crt")
+ .unwrap();
+ config
+ .load_priv_key_from_pem_file("examples/cert.key")
+ .unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .unwrap();
+ config.set_initial_max_data(15);
+ config.set_initial_max_stream_data_bidi_local(30);
+ config.set_initial_max_stream_data_bidi_remote(30);
+ config.set_initial_max_stream_data_uni(30);
+ config.set_initial_max_streams_bidi(3);
+ config.set_initial_max_streams_uni(0);
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_config(&mut config).unwrap();
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ // Client sends some data.
+ assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ let mut b = [0; 15];
+ assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true)));
+
+ // Server sends some data.
+ assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ // Server buffers some data, until send capacity limit reached.
+ assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5));
+ assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5));
+ assert_eq!(
+ pipe.server.stream_send(4, b"hello", false),
+ Err(Error::Done)
+ );
+ assert_eq!(
+ pipe.server.stream_send(8, b"hello", false),
+ Err(Error::Done)
+ );
+
+ // Client sends STOP_SENDING.
+ let frames = [frame::Frame::StopSending {
+ stream_id: 4,
+ error_code: 42,
+ }];
+
+ let pkt_type = packet::Type::Short;
+ pipe.send_pkt_to_server(pkt_type, &frames, &mut buf)
+ .unwrap();
+
+ // Server can now send more data (on a different stream).
+ assert_eq!(pipe.client.stream_send(8, b"hello", true), Ok(5));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ assert_eq!(pipe.server.stream_send(8, b"hello", false), Ok(5));
+ assert_eq!(pipe.server.stream_send(8, b"hello", false), Ok(5));
+ assert_eq!(
+ pipe.server.stream_send(8, b"hello", false),
+ Err(Error::Done)
+ );
+ assert_eq!(pipe.advance(), Ok(()));
+ }
+
+ #[test]
fn stream_shutdown_read() {
let mut buf = [0; 65535];
@@ -7544,6 +8503,7 @@ mod tests {
// Server sends some data.
assert_eq!(pipe.server.stream_send(4, b"goodbye, world", false), Ok(14));
+ assert_eq!(pipe.advance(), Ok(()));
// Server shuts down stream.
assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Write, 42), Ok(()));
@@ -7589,8 +8549,18 @@ mod tests {
assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((15, true)));
+ // Client processes readable streams.
+ let mut r = pipe.client.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(
+ pipe.client.stream_recv(4, &mut buf),
+ Err(Error::StreamReset(42))
+ );
+
// Stream is collected on both sides.
- // TODO: assert_eq!(pipe.client.streams.len(), 0);
+ assert_eq!(pipe.client.streams.len(), 0);
assert_eq!(pipe.server.streams.len(), 0);
assert_eq!(
@@ -7600,6 +8570,77 @@ mod tests {
}
#[test]
+ /// Tests that shutting down a stream restores flow control for unsent data.
+ fn stream_shutdown_write_unsent_tx_cap() {
+ let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap();
+ config
+ .load_cert_chain_from_pem_file("examples/cert.crt")
+ .unwrap();
+ config
+ .load_priv_key_from_pem_file("examples/cert.key")
+ .unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .unwrap();
+ config.set_initial_max_data(15);
+ config.set_initial_max_stream_data_bidi_local(30);
+ config.set_initial_max_stream_data_bidi_remote(30);
+ config.set_initial_max_stream_data_uni(30);
+ config.set_initial_max_streams_bidi(3);
+ config.set_initial_max_streams_uni(0);
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_config(&mut config).unwrap();
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ // Client sends some data.
+ assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ let mut b = [0; 15];
+ assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true)));
+
+ // Server sends some data.
+ assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ // Server buffers some data, until send capacity limit reached.
+ assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5));
+ assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5));
+ assert_eq!(
+ pipe.server.stream_send(4, b"hello", false),
+ Err(Error::Done)
+ );
+ assert_eq!(
+ pipe.server.stream_send(8, b"hello", false),
+ Err(Error::Done)
+ );
+
+ // Client shouldn't update flow control.
+ assert_eq!(pipe.client.should_update_max_data(), false);
+
+ // Server shuts down stream.
+ assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Write, 42), Ok(()));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ // Server can now send more data (on a different stream).
+ assert_eq!(pipe.client.stream_send(8, b"hello", true), Ok(5));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ assert_eq!(pipe.server.stream_send(8, b"hello", false), Ok(5));
+ assert_eq!(pipe.server.stream_send(8, b"hello", false), Ok(5));
+ assert_eq!(
+ pipe.server.stream_send(8, b"hello", false),
+ Err(Error::Done)
+ );
+ assert_eq!(pipe.advance(), Ok(()));
+ }
+
+ #[test]
/// Tests that the order of flushable streams scheduled on the wire is the
/// same as the order of `stream_send()` calls done by the application.
fn stream_round_robin() {
@@ -7772,7 +8813,7 @@ mod tests {
assert_eq!(w.next(), Some(4));
assert_eq!(w.next(), None);
- // Server suts down stream.
+ // Server shuts down stream.
assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Write, 0), Ok(()));
let mut w = pipe.server.writable();
@@ -7819,7 +8860,7 @@ mod tests {
Ok(15)
);
assert_eq!(pipe.advance(), Ok(()));
- assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(0));
+ assert_eq!(pipe.client.stream_send(8, b"a", false), Err(Error::Done));
assert_eq!(pipe.advance(), Ok(()));
let mut r = pipe.server.readable();
@@ -7945,8 +8986,7 @@ mod tests {
let space = &mut pipe.client.pkt_num_spaces[epoch];
// Use correct payload length when encrypting the packet.
- let payload_len = frames.iter().fold(0, |acc, x| acc + x.wire_len()) +
- space.crypto_overhead().unwrap();
+ let payload_len = frames.iter().fold(0, |acc, x| acc + x.wire_len());
let aead = space.crypto_seal.as_ref().unwrap();
@@ -7956,6 +8996,7 @@ mod tests {
pn_len,
payload_len,
payload_offset,
+ None,
aead,
)
.unwrap();
@@ -8088,7 +9129,7 @@ mod tests {
}
#[test]
- /// Tests that the MAX_STREAMS frame is sent for unirectional streams.
+ /// Tests that the MAX_STREAMS frame is sent for unidirectional streams.
fn stream_limit_update_uni() {
let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap();
config
@@ -8256,6 +9297,25 @@ mod tests {
}
#[test]
+ /// Tests that the stream gets created with stream_send() even if there's
+ /// no data in the buffer and the fin flag is not set.
+ fn stream_zero_length_non_fin() {
+ let mut pipe = testing::Pipe::default().unwrap();
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(0, b"", false), Ok(0));
+
+ // The stream now should have been created.
+ assert_eq!(pipe.client.streams.len(), 1);
+ assert_eq!(pipe.advance(), Ok(()));
+
+ // Sending an empty non-fin should not change any stream state on the
+ // other side.
+ let mut r = pipe.server.readable();
+ assert!(r.next().is_none());
+ }
+
+ #[test]
/// Tests that completed streams are garbage collected.
fn collect_streams() {
let mut buf = [0; 65535];
@@ -8645,9 +9705,57 @@ mod tests {
assert_eq!(iter.next(), None);
- // Send again from blocked stream and make sure it is marked as blocked
- // again.
- assert_eq!(pipe.client.stream_send(0, b"aaaaaa", false), Ok(0));
+ // Send again from blocked stream and make sure it is not marked as
+ // blocked again.
+ assert_eq!(
+ pipe.client.stream_send(0, b"aaaaaa", false),
+ Err(Error::Done)
+ );
+ assert_eq!(pipe.client.streams.blocked().len(), 0);
+ assert_eq!(pipe.client.send(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn stream_data_blocked_unblocked_flow_control() {
+ let mut buf = [0; 65535];
+ let mut pipe = testing::Pipe::default().unwrap();
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ assert_eq!(
+ pipe.client.stream_send(0, b"aaaaaaaaaaaaaaah", false),
+ Ok(15)
+ );
+ assert_eq!(pipe.client.streams.blocked().len(), 1);
+ assert_eq!(pipe.advance(), Ok(()));
+ assert_eq!(pipe.client.streams.blocked().len(), 0);
+
+ // Send again on blocked stream. It's blocked at the same offset as
+ // previously, so it should not be marked as blocked again.
+ assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done));
+ assert_eq!(pipe.client.streams.blocked().len(), 0);
+
+ // No matter how many times we try to write stream data tried, no
+ // packets containing STREAM_BLOCKED should be emitted.
+ assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done));
+ assert_eq!(pipe.client.send(&mut buf), Err(Error::Done));
+
+ assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done));
+ assert_eq!(pipe.client.send(&mut buf), Err(Error::Done));
+
+ assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done));
+ assert_eq!(pipe.client.send(&mut buf), Err(Error::Done));
+
+ // Now read some data at the server to release flow control.
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(0));
+ assert_eq!(r.next(), None);
+
+ let mut b = [0; 10];
+ assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((10, false)));
+ assert_eq!(&b[..10], b"aaaaaaaaaa");
+ assert_eq!(pipe.advance(), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(0, b"hhhhhhhhhh!", false), Ok(10));
assert_eq!(pipe.client.streams.blocked().len(), 1);
let (len, _) = pipe.client.send(&mut buf).unwrap();
@@ -8662,13 +9770,15 @@ mod tests {
iter.next(),
Some(&frame::Frame::StreamDataBlocked {
stream_id: 0,
- limit: 15,
+ limit: 25,
})
);
- assert_eq!(iter.next(), Some(&frame::Frame::Padding { len: 1 }));
+ // don't care about remaining received frames
- assert_eq!(iter.next(), None);
+ assert_eq!(pipe.client.stream_send(0, b"!", false), Err(Error::Done));
+ assert_eq!(pipe.client.streams.blocked().len(), 0);
+ assert_eq!(pipe.client.send(&mut buf), Err(Error::Done));
}
#[test]
@@ -9416,6 +10526,7 @@ mod tests {
data: stream::RangeBuf::from(b"b", 0, false),
})
);
+ assert_eq!(pipe.client.stats().retrans, 1);
}
#[test]
@@ -10076,6 +11187,25 @@ mod tests {
}
#[test]
+ fn local_error() {
+ let mut pipe = testing::Pipe::default().unwrap();
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ assert_eq!(pipe.server.local_error(), None);
+
+ assert_eq!(pipe.server.close(true, 0x1234, b"hello!"), Ok(()));
+
+ assert_eq!(
+ pipe.server.local_error(),
+ Some(&ConnectionError {
+ is_app: true,
+ error_code: 0x1234u64,
+ reason: b"hello!".to_vec()
+ })
+ );
+ }
+
+ #[test]
fn update_max_datagram_size() {
let mut client_scid = [0; 16];
rand::rand_bytes(&mut client_scid[..]);
@@ -10189,11 +11319,140 @@ mod tests {
assert_eq!(pipe.server.stream_send(8, &buf[..5000], false), Ok(2000));
// No more connection send capacity.
- assert_eq!(pipe.server.stream_send(12, &buf[..5000], false), Ok(0));
+ assert_eq!(
+ pipe.server.stream_send(12, &buf[..5000], false),
+ Err(Error::Done)
+ );
assert_eq!(pipe.server.tx_cap, 0);
assert_eq!(pipe.advance(), Ok(()));
}
+
+ #[cfg(feature = "boringssl-boring-crate")]
+ #[test]
+ fn user_provided_boring_ctx() -> Result<()> {
+ // Manually construct boring ssl ctx for server
+ let server_tls_ctx = {
+ let mut builder = boring::ssl::SslContextBuilder::new(
+ boring::ssl::SslMethod::tls(),
+ )
+ .unwrap();
+ builder
+ .set_certificate_chain_file("examples/cert.crt")
+ .unwrap();
+ builder
+ .set_private_key_file(
+ "examples/cert.key",
+ boring::ssl::SslFiletype::PEM,
+ )
+ .unwrap();
+ builder.build()
+ };
+
+ let mut server_config =
+ Config::with_boring_ssl_ctx(crate::PROTOCOL_VERSION, server_tls_ctx)?;
+ let mut client_config = Config::new(crate::PROTOCOL_VERSION)?;
+ client_config.load_cert_chain_from_pem_file("examples/cert.crt")?;
+ client_config.load_priv_key_from_pem_file("examples/cert.key")?;
+
+ for config in [&mut client_config, &mut server_config] {
+ config.set_application_protos(b"\x06proto1\x06proto2")?;
+ config.set_initial_max_data(30);
+ config.set_initial_max_stream_data_bidi_local(15);
+ config.set_initial_max_stream_data_bidi_remote(15);
+ config.set_initial_max_stream_data_uni(10);
+ config.set_initial_max_streams_bidi(3);
+ config.set_initial_max_streams_uni(3);
+ config.set_max_idle_timeout(180_000);
+ config.verify_peer(false);
+ config.set_ack_delay_exponent(8);
+ }
+
+ let mut client_scid = [0; 16];
+ rand::rand_bytes(&mut client_scid[..]);
+ let client_scid = ConnectionId::from_ref(&client_scid);
+ let client_addr = "127.0.0.1:1234".parse().unwrap();
+
+ let mut server_scid = [0; 16];
+ rand::rand_bytes(&mut server_scid[..]);
+ let server_scid = ConnectionId::from_ref(&server_scid);
+ let server_addr = "127.0.0.1:4321".parse().unwrap();
+
+ let mut pipe = testing::Pipe {
+ client: connect(
+ Some("quic.tech"),
+ &client_scid,
+ client_addr,
+ &mut client_config,
+ )?,
+ server: accept(&server_scid, None, server_addr, &mut server_config)?,
+ };
+
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ Ok(())
+ }
+
+ #[test]
+ /// Tests that resetting a stream restores flow control for unsent data.
+ fn last_tx_data_larger_than_tx_data() {
+ let mut config = Config::new(PROTOCOL_VERSION).unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .unwrap();
+ config.set_initial_max_data(12000);
+ config.set_initial_max_stream_data_bidi_local(20000);
+ config.set_initial_max_stream_data_bidi_remote(20000);
+ config.set_max_recv_udp_payload_size(1200);
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap();
+ assert_eq!(pipe.handshake(), Ok(()));
+
+ // Client opens stream 4 and 8.
+ assert_eq!(pipe.client.stream_send(4, b"a", true), Ok(1));
+ assert_eq!(pipe.client.stream_send(8, b"b", true), Ok(1));
+ assert_eq!(pipe.advance(), Ok(()));
+
+ // Server reads stream data.
+ let mut b = [0; 15];
+ pipe.server.stream_recv(4, &mut b).unwrap();
+
+ // Server sends stream data close to cwnd (12000).
+ let buf = [0; 10000];
+ assert_eq!(pipe.server.stream_send(4, &buf, false), Ok(10000));
+
+ testing::emit_flight(&mut pipe.server).unwrap();
+
+ // Server buffers some data, until send capacity limit reached.
+ let mut buf = [0; 1200];
+ assert_eq!(pipe.server.stream_send(4, &buf, false), Ok(1200));
+ assert_eq!(pipe.server.stream_send(8, &buf, false), Ok(800));
+ assert_eq!(pipe.server.stream_send(4, &buf, false), Err(Error::Done));
+
+ // Wait for PTO to expire.
+ let timer = pipe.server.timeout().unwrap();
+ std::thread::sleep(timer + time::Duration::from_millis(1));
+
+ pipe.server.on_timeout();
+
+ // Server sends PTO probe (not limited to cwnd),
+ // to update last_tx_data.
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
+ assert_eq!(len, 1200);
+
+ // Client sends STOP_SENDING to decrease tx_data
+ // by unsent data. It will make last_tx_data > tx_data
+ // and trigger #1232 bug.
+ let frames = [frame::Frame::StopSending {
+ stream_id: 4,
+ error_code: 42,
+ }];
+
+ let pkt_type = packet::Type::Short;
+ pipe.send_pkt_to_server(pkt_type, &frames, &mut buf)
+ .unwrap();
+ }
}
pub use crate::packet::ConnectionId;
@@ -10208,10 +11467,10 @@ mod crypto;
mod dgram;
#[cfg(feature = "ffi")]
mod ffi;
+mod flowcontrol;
mod frame;
pub mod h3;
mod minmax;
-mod octets;
mod packet;
mod rand;
mod ranges;
diff --git a/src/minmax.rs b/src/minmax.rs
index a8a23fd..8d81c28 100644
--- a/src/minmax.rs
+++ b/src/minmax.rs
@@ -173,7 +173,7 @@ mod tests {
#[test]
fn reset_filter_rtt() {
- let mut f = Minmax::new(Duration::new(0, 0));
+ let mut f = Minmax::new(Duration::ZERO);
let now = Instant::now();
let rtt = Duration::from_millis(50);
@@ -211,7 +211,7 @@ mod tests {
#[test]
fn get_windowed_min_rtt() {
- let mut f = Minmax::new(Duration::new(0, 0));
+ let mut f = Minmax::new(Duration::ZERO);
let rtt_25 = Duration::from_millis(25);
let rtt_24 = Duration::from_millis(24);
let win = Duration::from_millis(500);
@@ -259,7 +259,7 @@ mod tests {
#[test]
fn get_windowed_max_rtt() {
- let mut f = Minmax::new(Duration::new(0, 0));
+ let mut f = Minmax::new(Duration::ZERO);
let rtt_25 = Duration::from_millis(25);
let rtt_24 = Duration::from_millis(24);
let win = Duration::from_millis(500);
@@ -307,7 +307,7 @@ mod tests {
#[test]
fn get_windowed_min_estimates_rtt() {
- let mut f = Minmax::new(Duration::new(0, 0));
+ let mut f = Minmax::new(Duration::ZERO);
let rtt_25 = Duration::from_millis(25);
let rtt_24 = Duration::from_millis(24);
let rtt_23 = Duration::from_millis(23);
@@ -371,7 +371,7 @@ mod tests {
#[test]
fn get_windowed_max_estimates_rtt() {
- let mut f = Minmax::new(Duration::new(0, 0));
+ let mut f = Minmax::new(Duration::ZERO);
let rtt_25 = Duration::from_millis(25);
let rtt_24 = Duration::from_millis(24);
let rtt_23 = Duration::from_millis(23);
diff --git a/src/octets.rs b/src/octets.rs
deleted file mode 100644
index 3983667..0000000
--- a/src/octets.rs
+++ /dev/null
@@ -1,1277 +0,0 @@
-// Copyright (C) 2018-2019, Cloudflare, Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// * Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#![allow(dead_code)]
-
-/// Zero-copy abstraction for parsing and constructing network packets.
-use std::mem;
-use std::ptr;
-
-/// A specialized [`Result`] type for [`OctetsMut`] operations.
-///
-/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
-/// [`OctetsMut`]: struct.OctetsMut.html
-pub type Result<T> = std::result::Result<T, BufferTooShortError>;
-
-/// An error indicating that the provided [`OctetsMut`] is not big enough.
-///
-/// [`OctetsMut`]: struct.OctetsMut.html
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub struct BufferTooShortError;
-
-impl std::fmt::Display for BufferTooShortError {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(f, "BufferTooShortError")
- }
-}
-
-impl std::error::Error for BufferTooShortError {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- None
- }
-}
-
-macro_rules! peek_u {
- ($b:expr, $ty:ty, $len:expr) => {{
- let len = $len;
- let src = &$b.buf[$b.off..];
-
- if src.len() < len {
- return Err(BufferTooShortError);
- }
-
- let mut out: $ty = 0;
- unsafe {
- let dst = &mut out as *mut $ty as *mut u8;
- let off = (mem::size_of::<$ty>() - len) as isize;
-
- ptr::copy_nonoverlapping(src.as_ptr(), dst.offset(off), len);
- };
-
- Ok(<$ty>::from_be(out))
- }};
-}
-
-macro_rules! get_u {
- ($b:expr, $ty:ty, $len:expr) => {{
- let out = peek_u!($b, $ty, $len);
-
- $b.off += $len;
-
- out
- }};
-}
-
-macro_rules! put_u {
- ($b:expr, $ty:ty, $v:expr, $len:expr) => {{
- let len = $len;
-
- if $b.buf.len() < $b.off + len {
- return Err(BufferTooShortError);
- }
-
- let v = $v;
-
- #[allow(clippy::range_plus_one)]
- let dst = &mut $b.buf[$b.off..($b.off + len)];
-
- unsafe {
- let src = &<$ty>::to_be(v) as *const $ty as *const u8;
- let off = (mem::size_of::<$ty>() - len) as isize;
-
- ptr::copy_nonoverlapping(src.offset(off), dst.as_mut_ptr(), len);
- }
-
- $b.off += $len;
-
- Ok(dst)
- }};
-}
-
-/// A zero-copy immutable byte buffer.
-///
-/// `Octets` wraps an in-memory buffer of bytes and provides utility functions
-/// for manipulating it. The underlying buffer is provided by the user and is
-/// not copied when creating an `Octets`. Operations are panic-free and will
-/// avoid indexing the buffer past its end.
-///
-/// Additionally, an offset (initially set to the start of the buffer) is
-/// incremented as bytes are read from / written to the buffer, to allow for
-/// sequential operations.
-#[derive(Debug, PartialEq)]
-pub struct Octets<'a> {
- buf: &'a [u8],
- off: usize,
-}
-
-impl<'a> Octets<'a> {
- /// Creates an `Octets` from the given slice, without copying.
- ///
- /// Since there's no copy, the input slice needs to be mutable to allow
- /// modifications.
- pub fn with_slice(buf: &'a [u8]) -> Self {
- Octets { buf, off: 0 }
- }
-
- /// Reads an unsigned 8-bit integer from the current offset and advances
- /// the buffer.
- pub fn get_u8(&mut self) -> Result<u8> {
- get_u!(self, u8, 1)
- }
-
- /// Reads an unsigned 8-bit integer from the current offset without
- /// advancing the buffer.
- pub fn peek_u8(&mut self) -> Result<u8> {
- peek_u!(self, u8, 1)
- }
-
- /// Reads an unsigned 16-bit integer in network byte-order from the current
- /// offset and advances the buffer.
- pub fn get_u16(&mut self) -> Result<u16> {
- get_u!(self, u16, 2)
- }
-
- /// Reads an unsigned 24-bit integer in network byte-order from the current
- /// offset and advances the buffer.
- pub fn get_u24(&mut self) -> Result<u32> {
- get_u!(self, u32, 3)
- }
-
- /// Reads an unsigned 32-bit integer in network byte-order from the current
- /// offset and advances the buffer.
- pub fn get_u32(&mut self) -> Result<u32> {
- get_u!(self, u32, 4)
- }
-
- /// Reads an unsigned 64-bit integer in network byte-order from the current
- /// offset and advances the buffer.
- pub fn get_u64(&mut self) -> Result<u64> {
- get_u!(self, u64, 8)
- }
-
- /// Reads an unsigned variable-length integer in network byte-order from
- /// the current offset and advances the buffer.
- pub fn get_varint(&mut self) -> Result<u64> {
- let first = self.peek_u8()?;
-
- let len = varint_parse_len(first);
-
- if len > self.cap() {
- return Err(BufferTooShortError);
- }
-
- let out = match len {
- 1 => u64::from(self.get_u8()?),
-
- 2 => u64::from(self.get_u16()? & 0x3fff),
-
- 4 => u64::from(self.get_u32()? & 0x3fffffff),
-
- 8 => self.get_u64()? & 0x3fffffffffffffff,
-
- _ => unreachable!(),
- };
-
- Ok(out)
- }
-
- /// Reads `len` bytes from the current offset without copying and advances
- /// the buffer.
- pub fn get_bytes(&mut self, len: usize) -> Result<Octets> {
- if self.cap() < len {
- return Err(BufferTooShortError);
- }
-
- let out = Octets {
- buf: &self.buf[self.off..self.off + len],
- off: 0,
- };
-
- self.off += len;
-
- Ok(out)
- }
-
- /// Reads `len` bytes from the current offset without copying and advances
- /// the buffer, where `len` is an unsigned 8-bit integer prefix.
- pub fn get_bytes_with_u8_length(&mut self) -> Result<Octets> {
- let len = self.get_u8()?;
- self.get_bytes(len as usize)
- }
-
- /// Reads `len` bytes from the current offset without copying and advances
- /// the buffer, where `len` is an unsigned 16-bit integer prefix in network
- /// byte-order.
- pub fn get_bytes_with_u16_length(&mut self) -> Result<Octets> {
- let len = self.get_u16()?;
- self.get_bytes(len as usize)
- }
-
- /// Reads `len` bytes from the current offset without copying and advances
- /// the buffer, where `len` is an unsigned variable-length integer prefix
- /// in network byte-order.
- pub fn get_bytes_with_varint_length(&mut self) -> Result<Octets> {
- let len = self.get_varint()?;
- self.get_bytes(len as usize)
- }
-
- /// Reads `len` bytes from the current offset without copying and without
- /// advancing the buffer.
- pub fn peek_bytes(&self, len: usize) -> Result<Octets> {
- if self.cap() < len {
- return Err(BufferTooShortError);
- }
-
- let out = Octets {
- buf: &self.buf[self.off..self.off + len],
- off: 0,
- };
-
- Ok(out)
- }
-
- /// Returns a slice of `len` elements from the current offset.
- pub fn slice(&'a self, len: usize) -> Result<&'a [u8]> {
- if len > self.cap() {
- return Err(BufferTooShortError);
- }
-
- Ok(&self.buf[self.off..self.off + len])
- }
-
- /// Returns a slice of `len` elements from the end of the buffer.
- pub fn slice_last(&'a self, len: usize) -> Result<&'a [u8]> {
- if len > self.cap() {
- return Err(BufferTooShortError);
- }
-
- let cap = self.cap();
- Ok(&self.buf[cap - len..])
- }
-
- /// Advances the buffer's offset.
- pub fn skip(&mut self, skip: usize) -> Result<()> {
- if skip > self.cap() {
- return Err(BufferTooShortError);
- }
-
- self.off += skip;
-
- Ok(())
- }
-
- /// Returns the remaining capacity in the buffer.
- pub fn cap(&self) -> usize {
- self.buf.len() - self.off
- }
-
- /// Returns the total length of the buffer.
- pub fn len(&self) -> usize {
- self.buf.len()
- }
-
- /// Returns the current offset of the buffer.
- pub fn off(&self) -> usize {
- self.off
- }
-
- /// Returns a reference to the internal buffer.
- pub fn buf(&self) -> &[u8] {
- self.buf
- }
-
- /// Copies the buffer from the current offset into a new `Vec<u8>`.
- pub fn to_vec(&self) -> Vec<u8> {
- self.as_ref().to_vec()
- }
-}
-
-impl<'a> AsRef<[u8]> for Octets<'a> {
- fn as_ref(&self) -> &[u8] {
- &self.buf[self.off..]
- }
-}
-
-/// A zero-copy mutable byte buffer.
-///
-/// Like `Octets` but mutable.
-#[derive(Debug, PartialEq)]
-pub struct OctetsMut<'a> {
- buf: &'a mut [u8],
- off: usize,
-}
-
-impl<'a> OctetsMut<'a> {
- /// Creates an `OctetsMut` from the given slice, without copying.
- ///
- /// Since there's no copy, the input slice needs to be mutable to allow
- /// modifications.
- pub fn with_slice(buf: &'a mut [u8]) -> Self {
- OctetsMut { buf, off: 0 }
- }
-
- /// Reads an unsigned 8-bit integer from the current offset and advances
- /// the buffer.
- pub fn get_u8(&mut self) -> Result<u8> {
- get_u!(self, u8, 1)
- }
-
- /// Reads an unsigned 8-bit integer from the current offset without
- /// advancing the buffer.
- pub fn peek_u8(&mut self) -> Result<u8> {
- peek_u!(self, u8, 1)
- }
-
- /// Writes an unsigned 8-bit integer at the current offset and advances
- /// the buffer.
- pub fn put_u8(&mut self, v: u8) -> Result<&mut [u8]> {
- put_u!(self, u8, v, 1)
- }
-
- /// Reads an unsigned 16-bit integer in network byte-order from the current
- /// offset and advances the buffer.
- pub fn get_u16(&mut self) -> Result<u16> {
- get_u!(self, u16, 2)
- }
-
- /// Writes an unsigned 16-bit integer in network byte-order at the current
- /// offset and advances the buffer.
- pub fn put_u16(&mut self, v: u16) -> Result<&mut [u8]> {
- put_u!(self, u16, v, 2)
- }
-
- /// Reads an unsigned 24-bit integer in network byte-order from the current
- /// offset and advances the buffer.
- pub fn get_u24(&mut self) -> Result<u32> {
- get_u!(self, u32, 3)
- }
-
- /// Writes an unsigned 24-bit integer in network byte-order at the current
- /// offset and advances the buffer.
- pub fn put_u24(&mut self, v: u32) -> Result<&mut [u8]> {
- put_u!(self, u32, v, 3)
- }
-
- /// Reads an unsigned 32-bit integer in network byte-order from the current
- /// offset and advances the buffer.
- pub fn get_u32(&mut self) -> Result<u32> {
- get_u!(self, u32, 4)
- }
-
- /// Writes an unsigned 32-bit integer in network byte-order at the current
- /// offset and advances the buffer.
- pub fn put_u32(&mut self, v: u32) -> Result<&mut [u8]> {
- put_u!(self, u32, v, 4)
- }
-
- /// Reads an unsigned 64-bit integer in network byte-order from the current
- /// offset and advances the buffer.
- pub fn get_u64(&mut self) -> Result<u64> {
- get_u!(self, u64, 8)
- }
-
- /// Writes an unsigned 64-bit integer in network byte-order at the current
- /// offset and advances the buffer.
- pub fn put_u64(&mut self, v: u64) -> Result<&mut [u8]> {
- put_u!(self, u64, v, 8)
- }
-
- /// Reads an unsigned variable-length integer in network byte-order from
- /// the current offset and advances the buffer.
- pub fn get_varint(&mut self) -> Result<u64> {
- let first = self.peek_u8()?;
-
- let len = varint_parse_len(first);
-
- if len > self.cap() {
- return Err(BufferTooShortError);
- }
-
- let out = match len {
- 1 => u64::from(self.get_u8()?),
-
- 2 => u64::from(self.get_u16()? & 0x3fff),
-
- 4 => u64::from(self.get_u32()? & 0x3fffffff),
-
- 8 => self.get_u64()? & 0x3fffffffffffffff,
-
- _ => unreachable!(),
- };
-
- Ok(out)
- }
-
- /// Writes an unsigned variable-length integer in network byte-order at the
- /// current offset and advances the buffer.
- pub fn put_varint(&mut self, v: u64) -> Result<&mut [u8]> {
- self.put_varint_with_len(v, varint_len(v))
- }
-
- /// Writes an unsigned variable-length integer of the specified length, in
- /// network byte-order at the current offset and advances the buffer.
- pub fn put_varint_with_len(
- &mut self, v: u64, len: usize,
- ) -> Result<&mut [u8]> {
- if self.cap() < len {
- return Err(BufferTooShortError);
- }
-
- let buf = match len {
- 1 => self.put_u8(v as u8)?,
-
- 2 => {
- let buf = self.put_u16(v as u16)?;
- buf[0] |= 0x40;
- buf
- },
-
- 4 => {
- let buf = self.put_u32(v as u32)?;
- buf[0] |= 0x80;
- buf
- },
-
- 8 => {
- let buf = self.put_u64(v)?;
- buf[0] |= 0xc0;
- buf
- },
-
- _ => panic!("value is too large for varint"),
- };
-
- Ok(buf)
- }
-
- /// Reads `len` bytes from the current offset without copying and advances
- /// the buffer.
- pub fn get_bytes(&mut self, len: usize) -> Result<Octets> {
- if self.cap() < len {
- return Err(BufferTooShortError);
- }
-
- let out = Octets {
- buf: &self.buf[self.off..self.off + len],
- off: 0,
- };
-
- self.off += len;
-
- Ok(out)
- }
-
- /// Reads `len` bytes from the current offset without copying and advances
- /// the buffer.
- pub fn get_bytes_mut(&mut self, len: usize) -> Result<OctetsMut> {
- if self.cap() < len {
- return Err(BufferTooShortError);
- }
-
- let out = OctetsMut {
- buf: &mut self.buf[self.off..self.off + len],
- off: 0,
- };
-
- self.off += len;
-
- Ok(out)
- }
-
- /// Reads `len` bytes from the current offset without copying and advances
- /// the buffer, where `len` is an unsigned 8-bit integer prefix.
- pub fn get_bytes_with_u8_length(&mut self) -> Result<Octets> {
- let len = self.get_u8()?;
- self.get_bytes(len as usize)
- }
-
- /// Reads `len` bytes from the current offset without copying and advances
- /// the buffer, where `len` is an unsigned 16-bit integer prefix in network
- /// byte-order.
- pub fn get_bytes_with_u16_length(&mut self) -> Result<Octets> {
- let len = self.get_u16()?;
- self.get_bytes(len as usize)
- }
-
- /// Reads `len` bytes from the current offset without copying and advances
- /// the buffer, where `len` is an unsigned variable-length integer prefix
- /// in network byte-order.
- pub fn get_bytes_with_varint_length(&mut self) -> Result<Octets> {
- let len = self.get_varint()?;
- self.get_bytes(len as usize)
- }
-
- /// Reads `len` bytes from the current offset without copying and without
- /// advancing the buffer.
- pub fn peek_bytes(&mut self, len: usize) -> Result<Octets> {
- if self.cap() < len {
- return Err(BufferTooShortError);
- }
-
- let out = Octets {
- buf: &self.buf[self.off..self.off + len],
- off: 0,
- };
-
- Ok(out)
- }
-
- /// Reads `len` bytes from the current offset without copying and without
- /// advancing the buffer.
- pub fn peek_bytes_mut(&mut self, len: usize) -> Result<OctetsMut> {
- if self.cap() < len {
- return Err(BufferTooShortError);
- }
-
- let out = OctetsMut {
- buf: &mut self.buf[self.off..self.off + len],
- off: 0,
- };
-
- Ok(out)
- }
-
- /// Writes `len` bytes from the current offset without copying and advances
- /// the buffer.
- pub fn put_bytes(&mut self, v: &[u8]) -> Result<()> {
- let len = v.len();
-
- if self.cap() < len {
- return Err(BufferTooShortError);
- }
-
- if len == 0 {
- return Ok(());
- }
-
- self.as_mut()[..len].copy_from_slice(v);
-
- self.off += len;
-
- Ok(())
- }
-
- /// Splits the buffer in two at the given absolute offset.
- pub fn split_at(&mut self, off: usize) -> Result<(OctetsMut, OctetsMut)> {
- if self.len() < off {
- return Err(BufferTooShortError);
- }
-
- let (left, right) = self.buf.split_at_mut(off);
-
- let first = OctetsMut { buf: left, off: 0 };
-
- let last = OctetsMut { buf: right, off: 0 };
-
- Ok((first, last))
- }
-
- /// Returns a slice of `len` elements from the current offset.
- pub fn slice(&'a mut self, len: usize) -> Result<&'a mut [u8]> {
- if len > self.cap() {
- return Err(BufferTooShortError);
- }
-
- Ok(&mut self.buf[self.off..self.off + len])
- }
-
- /// Returns a slice of `len` elements from the end of the buffer.
- pub fn slice_last(&'a mut self, len: usize) -> Result<&'a mut [u8]> {
- if len > self.cap() {
- return Err(BufferTooShortError);
- }
-
- let cap = self.cap();
- Ok(&mut self.buf[cap - len..])
- }
-
- /// Advances the buffer's offset.
- pub fn skip(&mut self, skip: usize) -> Result<()> {
- if skip > self.cap() {
- return Err(BufferTooShortError);
- }
-
- self.off += skip;
-
- Ok(())
- }
-
- /// Returns the remaining capacity in the buffer.
- pub fn cap(&self) -> usize {
- self.buf.len() - self.off
- }
-
- /// Returns the total length of the buffer.
- pub fn len(&self) -> usize {
- self.buf.len()
- }
-
- /// Returns the current offset of the buffer.
- pub fn off(&self) -> usize {
- self.off
- }
-
- /// Returns a reference to the internal buffer.
- pub fn buf(&self) -> &[u8] {
- self.buf
- }
-
- /// Copies the buffer from the current offset into a new `Vec<u8>`.
- pub fn to_vec(&self) -> Vec<u8> {
- self.as_ref().to_vec()
- }
-}
-
-impl<'a> AsRef<[u8]> for OctetsMut<'a> {
- fn as_ref(&self) -> &[u8] {
- &self.buf[self.off..]
- }
-}
-
-impl<'a> AsMut<[u8]> for OctetsMut<'a> {
- fn as_mut(&mut self) -> &mut [u8] {
- &mut self.buf[self.off..]
- }
-}
-
-/// Returns how many bytes it would take to encode `v` as a variable-length
-/// integer.
-pub fn varint_len(v: u64) -> usize {
- if v <= 63 {
- 1
- } else if v <= 16383 {
- 2
- } else if v <= 1_073_741_823 {
- 4
- } else if v <= 4_611_686_018_427_387_903 {
- 8
- } else {
- unreachable!()
- }
-}
-
-/// Returns how long the variable-length integer is, given its first byte.
-pub fn varint_parse_len(first: u8) -> usize {
- match first >> 6 {
- 0 => 1,
- 1 => 2,
- 2 => 4,
- 3 => 8,
- _ => unreachable!(),
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn get_u() {
- let d = [
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- ];
-
- let mut b = Octets::with_slice(&d);
- assert_eq!(b.cap(), 18);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.get_u8().unwrap(), 1);
- assert_eq!(b.cap(), 17);
- assert_eq!(b.off(), 1);
-
- assert_eq!(b.get_u16().unwrap(), 0x203);
- assert_eq!(b.cap(), 15);
- assert_eq!(b.off(), 3);
-
- assert_eq!(b.get_u24().unwrap(), 0x40506);
- assert_eq!(b.cap(), 12);
- assert_eq!(b.off(), 6);
-
- assert_eq!(b.get_u32().unwrap(), 0x0708090a);
- assert_eq!(b.cap(), 8);
- assert_eq!(b.off(), 10);
-
- assert_eq!(b.get_u64().unwrap(), 0x0b0c0d0e0f101112);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 18);
-
- assert!(b.get_u8().is_err());
- assert!(b.get_u16().is_err());
- assert!(b.get_u24().is_err());
- assert!(b.get_u32().is_err());
- assert!(b.get_u64().is_err());
- }
-
- #[test]
- fn get_u_mut() {
- let mut d = [
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- ];
-
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.cap(), 18);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.get_u8().unwrap(), 1);
- assert_eq!(b.cap(), 17);
- assert_eq!(b.off(), 1);
-
- assert_eq!(b.get_u16().unwrap(), 0x203);
- assert_eq!(b.cap(), 15);
- assert_eq!(b.off(), 3);
-
- assert_eq!(b.get_u24().unwrap(), 0x40506);
- assert_eq!(b.cap(), 12);
- assert_eq!(b.off(), 6);
-
- assert_eq!(b.get_u32().unwrap(), 0x0708090a);
- assert_eq!(b.cap(), 8);
- assert_eq!(b.off(), 10);
-
- assert_eq!(b.get_u64().unwrap(), 0x0b0c0d0e0f101112);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 18);
-
- assert!(b.get_u8().is_err());
- assert!(b.get_u16().is_err());
- assert!(b.get_u24().is_err());
- assert!(b.get_u32().is_err());
- assert!(b.get_u64().is_err());
- }
-
- #[test]
- fn peek_u() {
- let d = [1, 2];
-
- let mut b = Octets::with_slice(&d);
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.peek_u8().unwrap(), 1);
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.peek_u8().unwrap(), 1);
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 0);
-
- b.get_u16().unwrap();
-
- assert!(b.peek_u8().is_err());
- }
-
- #[test]
- fn peek_u_mut() {
- let mut d = [1, 2];
-
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.peek_u8().unwrap(), 1);
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.peek_u8().unwrap(), 1);
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 0);
-
- b.get_u16().unwrap();
-
- assert!(b.peek_u8().is_err());
- }
-
- #[test]
- fn get_bytes() {
- let d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
- let mut b = Octets::with_slice(&d);
- assert_eq!(b.cap(), 10);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.get_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
- assert_eq!(b.cap(), 5);
- assert_eq!(b.off(), 5);
-
- assert_eq!(b.get_bytes(3).unwrap().as_ref(), [6, 7, 8]);
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 8);
-
- assert!(b.get_bytes(3).is_err());
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 8);
-
- assert_eq!(b.get_bytes(2).unwrap().as_ref(), [9, 10]);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 10);
-
- assert!(b.get_bytes(2).is_err());
- }
-
- #[test]
- fn get_bytes_mut() {
- let mut d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.cap(), 10);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.get_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
- assert_eq!(b.cap(), 5);
- assert_eq!(b.off(), 5);
-
- assert_eq!(b.get_bytes(3).unwrap().as_ref(), [6, 7, 8]);
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 8);
-
- assert!(b.get_bytes(3).is_err());
- assert_eq!(b.cap(), 2);
- assert_eq!(b.off(), 8);
-
- assert_eq!(b.get_bytes(2).unwrap().as_ref(), [9, 10]);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 10);
-
- assert!(b.get_bytes(2).is_err());
- }
-
- #[test]
- fn peek_bytes() {
- let d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
- let mut b = Octets::with_slice(&d);
- assert_eq!(b.cap(), 10);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
- assert_eq!(b.cap(), 10);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
- assert_eq!(b.cap(), 10);
- assert_eq!(b.off(), 0);
-
- b.get_bytes(5).unwrap();
- }
-
- #[test]
- fn peek_bytes_mut() {
- let mut d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.cap(), 10);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
- assert_eq!(b.cap(), 10);
- assert_eq!(b.off(), 0);
-
- assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
- assert_eq!(b.cap(), 10);
- assert_eq!(b.off(), 0);
-
- b.get_bytes(5).unwrap();
- }
-
- #[test]
- fn get_varint() {
- let d = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c];
- let mut b = Octets::with_slice(&d);
- assert_eq!(b.get_varint().unwrap(), 151288809941952652);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 8);
-
- let d = [0x9d, 0x7f, 0x3e, 0x7d];
- let mut b = Octets::with_slice(&d);
- assert_eq!(b.get_varint().unwrap(), 494878333);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 4);
-
- let d = [0x7b, 0xbd];
- let mut b = Octets::with_slice(&d);
- assert_eq!(b.get_varint().unwrap(), 15293);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 2);
-
- let d = [0x40, 0x25];
- let mut b = Octets::with_slice(&d);
- assert_eq!(b.get_varint().unwrap(), 37);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 2);
-
- let d = [0x25];
- let mut b = Octets::with_slice(&d);
- assert_eq!(b.get_varint().unwrap(), 37);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 1);
- }
-
- #[test]
- fn get_varint_mut() {
- let mut d = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c];
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.get_varint().unwrap(), 151288809941952652);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 8);
-
- let mut d = [0x9d, 0x7f, 0x3e, 0x7d];
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.get_varint().unwrap(), 494878333);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 4);
-
- let mut d = [0x7b, 0xbd];
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.get_varint().unwrap(), 15293);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 2);
-
- let mut d = [0x40, 0x25];
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.get_varint().unwrap(), 37);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 2);
-
- let mut d = [0x25];
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.get_varint().unwrap(), 37);
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 1);
- }
-
- #[test]
- fn put_varint() {
- let mut d = [0; 8];
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert!(b.put_varint(151288809941952652).is_ok());
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 8);
- }
- let exp = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c];
- assert_eq!(&d, &exp);
-
- let mut d = [0; 4];
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert!(b.put_varint(494878333).is_ok());
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 4);
- }
- let exp = [0x9d, 0x7f, 0x3e, 0x7d];
- assert_eq!(&d, &exp);
-
- let mut d = [0; 2];
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert!(b.put_varint(15293).is_ok());
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 2);
- }
- let exp = [0x7b, 0xbd];
- assert_eq!(&d, &exp);
-
- let mut d = [0; 1];
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert!(b.put_varint(37).is_ok());
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 1);
- }
- let exp = [0x25];
- assert_eq!(&d, &exp);
-
- let mut d = [0; 3];
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert!(b.put_varint(151288809941952652).is_err());
- assert_eq!(b.cap(), 3);
- assert_eq!(b.off(), 0);
- }
- let exp = [0; 3];
- assert_eq!(&d, &exp);
- }
-
- #[test]
- #[should_panic]
- fn varint_too_large() {
- let mut d = [0; 3];
- let mut b = OctetsMut::with_slice(&mut d);
- assert!(b.put_varint(std::u64::MAX).is_err());
- }
-
- #[test]
- fn put_u() {
- let mut d = [0; 18];
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.cap(), 18);
- assert_eq!(b.off(), 0);
-
- assert!(b.put_u8(1).is_ok());
- assert_eq!(b.cap(), 17);
- assert_eq!(b.off(), 1);
-
- assert!(b.put_u16(0x203).is_ok());
- assert_eq!(b.cap(), 15);
- assert_eq!(b.off(), 3);
-
- assert!(b.put_u24(0x40506).is_ok());
- assert_eq!(b.cap(), 12);
- assert_eq!(b.off(), 6);
-
- assert!(b.put_u32(0x0708090a).is_ok());
- assert_eq!(b.cap(), 8);
- assert_eq!(b.off(), 10);
-
- assert!(b.put_u64(0x0b0c0d0e0f101112).is_ok());
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 18);
-
- assert!(b.put_u8(1).is_err());
- }
-
- let exp = [
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- ];
- assert_eq!(&d, &exp);
- }
-
- #[test]
- fn put_bytes() {
- let mut d = [0; 5];
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.cap(), 5);
- assert_eq!(b.off(), 0);
-
- let p = [0x0a, 0x0b, 0x0c, 0x0d, 0x0e];
- assert!(b.put_bytes(&p).is_ok());
- assert_eq!(b.cap(), 0);
- assert_eq!(b.off(), 5);
-
- assert!(b.put_u8(1).is_err());
- }
-
- let exp = [0xa, 0xb, 0xc, 0xd, 0xe];
- assert_eq!(&d, &exp);
- }
-
- #[test]
- fn split() {
- let mut d = b"helloworld".to_vec();
-
- let mut b = OctetsMut::with_slice(&mut d);
- assert_eq!(b.cap(), 10);
- assert_eq!(b.off(), 0);
- assert_eq!(b.as_ref(), b"helloworld");
-
- assert!(b.get_bytes(5).is_ok());
- assert_eq!(b.cap(), 5);
- assert_eq!(b.off(), 5);
- assert_eq!(b.as_ref(), b"world");
-
- let off = b.off();
-
- let (first, last) = b.split_at(off).unwrap();
- assert_eq!(first.cap(), 5);
- assert_eq!(first.off(), 0);
- assert_eq!(first.as_ref(), b"hello");
-
- assert_eq!(last.cap(), 5);
- assert_eq!(last.off(), 0);
- assert_eq!(last.as_ref(), b"world");
- }
-
- #[test]
- fn split_at() {
- let mut d = b"helloworld".to_vec();
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- let (first, second) = b.split_at(5).unwrap();
-
- let mut exp1 = b"hello".to_vec();
- assert_eq!(first.as_ref(), &mut exp1[..]);
-
- let mut exp2 = b"world".to_vec();
- assert_eq!(second.as_ref(), &mut exp2[..]);
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- let (first, second) = b.split_at(10).unwrap();
-
- let mut exp1 = b"helloworld".to_vec();
- assert_eq!(first.as_ref(), &mut exp1[..]);
-
- let mut exp2 = b"".to_vec();
- assert_eq!(second.as_ref(), &mut exp2[..]);
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- let (first, second) = b.split_at(9).unwrap();
-
- let mut exp1 = b"helloworl".to_vec();
- assert_eq!(first.as_ref(), &mut exp1[..]);
-
- let mut exp2 = b"d".to_vec();
- assert_eq!(second.as_ref(), &mut exp2[..]);
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert!(b.split_at(11).is_err());
- }
- }
-
- #[test]
- fn slice() {
- let d = b"helloworld".to_vec();
-
- {
- let b = Octets::with_slice(&d);
- let exp = b"hello".to_vec();
- assert_eq!(b.slice(5), Ok(&exp[..]));
- }
-
- {
- let b = Octets::with_slice(&d);
- let exp = b"".to_vec();
- assert_eq!(b.slice(0), Ok(&exp[..]));
- }
-
- {
- let mut b = Octets::with_slice(&d);
- b.get_bytes(5).unwrap();
-
- let exp = b"world".to_vec();
- assert_eq!(b.slice(5), Ok(&exp[..]));
- }
-
- {
- let b = Octets::with_slice(&d);
- assert!(b.slice(11).is_err());
- }
- }
-
- #[test]
- fn slice_mut() {
- let mut d = b"helloworld".to_vec();
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- let mut exp = b"hello".to_vec();
- assert_eq!(b.slice(5), Ok(&mut exp[..]));
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- let mut exp = b"".to_vec();
- assert_eq!(b.slice(0), Ok(&mut exp[..]));
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- b.get_bytes(5).unwrap();
-
- let mut exp = b"world".to_vec();
- assert_eq!(b.slice(5), Ok(&mut exp[..]));
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert!(b.slice(11).is_err());
- }
- }
-
- #[test]
- fn slice_last() {
- let d = b"helloworld".to_vec();
-
- {
- let b = Octets::with_slice(&d);
- let exp = b"orld".to_vec();
- assert_eq!(b.slice_last(4), Ok(&exp[..]));
- }
-
- {
- let b = Octets::with_slice(&d);
- let exp = b"d".to_vec();
- assert_eq!(b.slice_last(1), Ok(&exp[..]));
- }
-
- {
- let b = Octets::with_slice(&d);
- let exp = b"".to_vec();
- assert_eq!(b.slice_last(0), Ok(&exp[..]));
- }
-
- {
- let b = Octets::with_slice(&d);
- let exp = b"helloworld".to_vec();
- assert_eq!(b.slice_last(10), Ok(&exp[..]));
- }
-
- {
- let b = Octets::with_slice(&d);
- assert!(b.slice_last(11).is_err());
- }
- }
-
- #[test]
- fn slice_last_mut() {
- let mut d = b"helloworld".to_vec();
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- let mut exp = b"orld".to_vec();
- assert_eq!(b.slice_last(4), Ok(&mut exp[..]));
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- let mut exp = b"d".to_vec();
- assert_eq!(b.slice_last(1), Ok(&mut exp[..]));
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- let mut exp = b"".to_vec();
- assert_eq!(b.slice_last(0), Ok(&mut exp[..]));
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- let mut exp = b"helloworld".to_vec();
- assert_eq!(b.slice_last(10), Ok(&mut exp[..]));
- }
-
- {
- let mut b = OctetsMut::with_slice(&mut d);
- assert!(b.slice_last(11).is_err());
- }
- }
-}
diff --git a/src/packet.rs b/src/packet.rs
index e6180f2..cc06031 100644
--- a/src/packet.rs
+++ b/src/packet.rs
@@ -32,7 +32,6 @@ use crate::Error;
use crate::Result;
use crate::crypto;
-use crate::octets;
use crate::rand;
use crate::ranges;
use crate::stream;
@@ -112,19 +111,20 @@ impl Type {
}
#[cfg(feature = "qlog")]
- pub(crate) fn to_qlog(self) -> qlog::PacketType {
+ pub(crate) fn to_qlog(self) -> qlog::events::quic::PacketType {
match self {
- Type::Initial => qlog::PacketType::Initial,
+ Type::Initial => qlog::events::quic::PacketType::Initial,
- Type::Retry => qlog::PacketType::Retry,
+ Type::Retry => qlog::events::quic::PacketType::Retry,
- Type::Handshake => qlog::PacketType::Handshake,
+ Type::Handshake => qlog::events::quic::PacketType::Handshake,
- Type::ZeroRTT => qlog::PacketType::ZeroRtt,
+ Type::ZeroRTT => qlog::events::quic::PacketType::ZeroRtt,
- Type::VersionNegotiation => qlog::PacketType::VersionNegotiation,
+ Type::VersionNegotiation =>
+ qlog::events::quic::PacketType::VersionNegotiation,
- Type::Short => qlog::PacketType::OneRtt,
+ Type::Short => qlog::events::quic::PacketType::OneRtt,
}
}
}
@@ -649,17 +649,21 @@ pub fn encrypt_hdr(
pub fn encrypt_pkt(
b: &mut octets::OctetsMut, pn: u64, pn_len: usize, payload_len: usize,
- payload_offset: usize, aead: &crypto::Seal,
+ payload_offset: usize, extra_in: Option<&[u8]>, aead: &crypto::Seal,
) -> Result<usize> {
let (mut header, mut payload) = b.split_at(payload_offset)?;
- // Encrypt + authenticate payload.
- let ciphertext = payload.slice(payload_len)?;
- aead.seal_with_u64_counter(pn, header.as_ref(), ciphertext)?;
+ let ciphertext_len = aead.seal_with_u64_counter(
+ pn,
+ header.as_ref(),
+ payload.as_mut(),
+ payload_len,
+ extra_in,
+ )?;
- encrypt_hdr(&mut header, pn_len, ciphertext, aead)?;
+ encrypt_hdr(&mut header, pn_len, payload.as_ref(), aead)?;
- Ok(payload_offset + payload_len)
+ Ok(payload_offset + ciphertext_len)
}
pub fn encode_pkt_num(pn: u64, b: &mut octets::OctetsMut) -> Result<()> {
@@ -691,9 +695,9 @@ pub fn negotiate_version(
b.put_u32(0)?;
b.put_u8(scid.len() as u8)?;
- b.put_bytes(&scid)?;
+ b.put_bytes(scid)?;
b.put_u8(dcid.len() as u8)?;
- b.put_bytes(&dcid)?;
+ b.put_bytes(dcid)?;
b.put_u32(crate::PROTOCOL_VERSION_V1)?;
b.put_u32(crate::PROTOCOL_VERSION_DRAFT29)?;
b.put_u32(crate::PROTOCOL_VERSION_DRAFT28)?;
@@ -858,13 +862,19 @@ impl PktNumSpace {
std::u64::MAX,
true,
true,
+ stream::MAX_STREAM_WINDOW,
),
}
}
pub fn clear(&mut self) {
- self.crypto_stream =
- stream::Stream::new(std::u64::MAX, std::u64::MAX, true, true);
+ self.crypto_stream = stream::Stream::new(
+ std::u64::MAX,
+ std::u64::MAX,
+ true,
+ true,
+ stream::MAX_STREAM_WINDOW,
+ );
self.ack_elicited = false;
}
@@ -934,7 +944,6 @@ mod tests {
use super::*;
use crate::crypto;
- use crate::octets;
#[test]
fn retry() {
@@ -1848,17 +1857,22 @@ mod tests {
crypto::derive_initial_key_material(dcid, hdr.version, is_server)
.unwrap();
- let overhead = aead.alg().tag_len();
-
- let payload_len = frames.len() + overhead;
+ let payload_len = frames.len();
let payload_offset = b.off();
b.put_bytes(frames).unwrap();
- let written =
- encrypt_pkt(&mut b, pn, pn_len, payload_len, payload_offset, &aead)
- .unwrap();
+ let written = encrypt_pkt(
+ &mut b,
+ pn,
+ pn_len,
+ payload_len,
+ payload_offset,
+ None,
+ &aead,
+ )
+ .unwrap();
assert_eq!(written, expected_pkt.len());
assert_eq!(&out[..written], &expected_pkt[..]);
@@ -2744,17 +2758,22 @@ mod tests {
let frames = [01];
- let overhead = aead.alg().tag_len();
-
- let payload_len = frames.len() + overhead;
+ let payload_len = frames.len();
let payload_offset = b.off();
b.put_bytes(&frames).unwrap();
- let written =
- encrypt_pkt(&mut b, pn, pn_len, payload_len, payload_offset, &aead)
- .unwrap();
+ let written = encrypt_pkt(
+ &mut b,
+ pn,
+ pn_len,
+ payload_len,
+ payload_offset,
+ None,
+ &aead,
+ )
+ .unwrap();
assert_eq!(written, expected_pkt.len());
assert_eq!(&out[..written], &expected_pkt[..]);
@@ -2791,4 +2810,37 @@ mod tests {
Err(Error::InvalidPacket)
);
}
+
+ #[test]
+ fn decrypt_pkt_too_small() {
+ let mut buf = [0; 65535];
+ let mut b = octets::OctetsMut::with_slice(&mut buf);
+
+ let hdr = Header {
+ ty: Type::Initial,
+ version: crate::PROTOCOL_VERSION,
+ dcid: ConnectionId::default(),
+ scid: ConnectionId::default(),
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: None,
+ versions: None,
+ key_phase: false,
+ };
+
+ hdr.to_bytes(&mut b).unwrap();
+
+ b.put_bytes(&[0; 1]).unwrap();
+
+ // No space for decryption.
+ let payload_len = 1;
+
+ let (aead, _) =
+ crypto::derive_initial_key_material(b"", hdr.version, true).unwrap();
+
+ assert_eq!(
+ decrypt_pkt(&mut b, 0, 1, payload_len, &aead),
+ Err(Error::CryptoFail)
+ );
+ }
}
diff --git a/src/ranges.rs b/src/ranges.rs
index c390873..b10eb35 100644
--- a/src/ranges.rs
+++ b/src/ranges.rs
@@ -108,7 +108,6 @@ impl RangeSet {
}
pub fn push_item(&mut self, item: u64) {
- #[allow(clippy::range_plus_one)]
self.insert(item..item + 1);
}
diff --git a/src/recovery/cubic.rs b/src/recovery/cubic.rs
index 8b091c4..090a8f4 100644
--- a/src/recovery/cubic.rs
+++ b/src/recovery/cubic.rs
@@ -45,13 +45,15 @@ use crate::recovery::CongestionControlOps;
use crate::recovery::Recovery;
pub static CUBIC: CongestionControlOps = CongestionControlOps {
+ on_init,
on_packet_sent,
- on_packet_acked,
+ on_packets_acked,
congestion_event,
collapse_cwnd,
checkpoint,
rollback,
has_custom_pacing,
+ debug_fmt,
};
/// CUBIC Constants.
@@ -61,9 +63,12 @@ const BETA_CUBIC: f64 = 0.7;
const C: f64 = 0.4;
-/// The packet count threshold to restore to the prior state if the
-/// lost packet count since the last checkpoint is less than the threshold.
-const RESTORE_COUNT_THRESHOLD: usize = 10;
+/// Threshold for rolling back state, as percentage of lost packets relative to
+/// cwnd.
+const ROLLBACK_THRESHOLD_PERCENT: usize = 20;
+
+/// Minimum threshold for rolling back state, as number of packets.
+const MIN_ROLLBACK_THRESHOLD: usize = 2;
/// Default value of alpha_aimd in the beginning of congestion avoidance.
const ALPHA_AIMD: f64 = 3.0 * (1.0 - BETA_CUBIC) / (1.0 + BETA_CUBIC);
@@ -103,8 +108,6 @@ struct PriorState {
w_max: f64,
- w_last_max: f64,
-
k: f64,
epoch_start: Option<Instant>,
@@ -142,6 +145,8 @@ impl State {
}
}
+fn on_init(_r: &mut Recovery) {}
+
fn collapse_cwnd(r: &mut Recovery) {
let cubic = &mut r.cubic_state;
@@ -186,6 +191,14 @@ fn on_packet_sent(r: &mut Recovery, sent_bytes: usize, now: Instant) {
reno::on_packet_sent(r, sent_bytes, now);
}
+fn on_packets_acked(
+ r: &mut Recovery, packets: &[Acked], epoch: packet::Epoch, now: Instant,
+) {
+ for pkt in packets {
+ on_packet_acked(r, pkt, epoch, now);
+ }
+}
+
fn on_packet_acked(
r: &mut Recovery, packet: &Acked, epoch: packet::Epoch, now: Instant,
) {
@@ -194,6 +207,13 @@ fn on_packet_acked(
r.bytes_in_flight = r.bytes_in_flight.saturating_sub(packet.size);
if in_congestion_recovery {
+ r.prr.on_packet_acked(
+ packet.size,
+ r.bytes_in_flight,
+ r.ssthresh,
+ r.max_datagram_size,
+ );
+
return;
}
@@ -205,16 +225,21 @@ fn on_packet_acked(
// <https://tools.ietf.org/id/draft-ietf-tcpm-rfc8312bis-00.html#section-4.9>
//
// When the recovery episode ends with recovering
- // a few packets (less than RESTORE_COUNT_THRESHOLD), it's considered
- // as spurious and restore to the previous state.
+ // a few packets (less than cwnd / mss * ROLLBACK_THRESHOLD_PERCENT(%)), it's
+ // considered as spurious and restore to the previous state.
if r.congestion_recovery_start_time.is_some() {
let new_lost = r.lost_count - r.cubic_state.prior.lost_count;
+ let rollback_threshold = (r.congestion_window / r.max_datagram_size) *
+ ROLLBACK_THRESHOLD_PERCENT /
+ 100;
+ let rollback_threshold = rollback_threshold.max(MIN_ROLLBACK_THRESHOLD);
- if r.congestion_window < r.cubic_state.prior.congestion_window &&
- new_lost < RESTORE_COUNT_THRESHOLD
- {
- rollback(r);
- return;
+ if new_lost < rollback_threshold {
+ let did_rollback = rollback(r);
+
+ if did_rollback {
+ return;
+ }
}
}
@@ -224,31 +249,29 @@ fn on_packet_acked(
r.bytes_acked_sl += packet.size;
if r.bytes_acked_sl >= r.max_datagram_size {
- r.congestion_window += r.max_datagram_size;
+ if r.hystart.in_css(epoch) {
+ r.congestion_window +=
+ r.hystart.css_cwnd_inc(r.max_datagram_size);
+ } else {
+ r.congestion_window += r.max_datagram_size;
+ }
+
r.bytes_acked_sl -= r.max_datagram_size;
}
- if r.hystart.enabled() &&
- epoch == packet::EPOCH_APPLICATION &&
- r.hystart.try_enter_lss(
- packet,
- r.latest_rtt,
- r.congestion_window,
- now,
- r.max_datagram_size,
- )
- {
+ if r.hystart.on_packet_acked(epoch, packet, r.latest_rtt, now) {
+ // Exit to congestion avoidance if CSS ends.
r.ssthresh = r.congestion_window;
}
} else {
// Congestion avoidance.
let ca_start_time;
- // In LSS, use lss_start_time instead of congestion_recovery_start_time.
- if r.hystart.in_lss(epoch) {
- ca_start_time = r.hystart.lss_start_time().unwrap();
+ // In CSS, use css_start_time instead of congestion_recovery_start_time.
+ if r.hystart.in_css(epoch) {
+ ca_start_time = r.hystart.css_start_time().unwrap();
- // Reset w_max and k when LSS started.
+ // Reset w_max and k when CSS started.
if r.cubic_state.w_max == 0.0 {
r.cubic_state.w_max = r.congestion_window as f64;
r.cubic_state.k = 0.0;
@@ -274,7 +297,7 @@ fn on_packet_acked(
}
}
- let t = now - ca_start_time;
+ let t = now.saturating_duration_since(ca_start_time);
// target = w_cubic(t + rtt)
let target = r.cubic_state.w_cubic(t + r.min_rtt, r.max_datagram_size);
@@ -308,18 +331,6 @@ fn on_packet_acked(
cubic_cwnd += cubic_inc;
}
- // When in Limited Slow Start, take the max of CA cwnd and
- // LSS cwnd.
- if r.hystart.in_lss(epoch) {
- let lss_cwnd_inc = r.hystart.lss_cwnd_inc(
- packet.size,
- r.congestion_window,
- r.ssthresh,
- );
-
- cubic_cwnd = cmp::max(cubic_cwnd, r.congestion_window + lss_cwnd_inc);
- }
-
// Update the increment and increase cwnd by MSS.
r.cubic_state.cwnd_inc += cubic_cwnd - r.congestion_window;
@@ -331,7 +342,8 @@ fn on_packet_acked(
}
fn congestion_event(
- r: &mut Recovery, time_sent: Instant, epoch: packet::Epoch, now: Instant,
+ r: &mut Recovery, _lost_bytes: usize, time_sent: Instant,
+ epoch: packet::Epoch, now: Instant,
) {
let in_congestion_recovery = r.in_congestion_recovery(time_sent);
@@ -368,9 +380,11 @@ fn congestion_event(
r.cubic_state.w_est = r.congestion_window as f64;
r.cubic_state.alpha_aimd = ALPHA_AIMD;
- if r.hystart.in_lss(epoch) {
+ if r.hystart.in_css(epoch) {
r.hystart.congestion_event();
}
+
+ r.prr.congestion_event(r.bytes_in_flight);
}
}
@@ -383,18 +397,37 @@ fn checkpoint(r: &mut Recovery) {
r.cubic_state.prior.lost_count = r.lost_count;
}
-fn rollback(r: &mut Recovery) {
+fn rollback(r: &mut Recovery) -> bool {
+ // Don't go back to slow start.
+ if r.cubic_state.prior.congestion_window < r.cubic_state.prior.ssthresh {
+ return false;
+ }
+
+ if r.congestion_window >= r.cubic_state.prior.congestion_window {
+ return false;
+ }
+
r.congestion_window = r.cubic_state.prior.congestion_window;
r.ssthresh = r.cubic_state.prior.ssthresh;
r.cubic_state.w_max = r.cubic_state.prior.w_max;
r.cubic_state.k = r.cubic_state.prior.k;
r.congestion_recovery_start_time = r.cubic_state.prior.epoch_start;
+
+ true
}
fn has_custom_pacing() -> bool {
false
}
+fn debug_fmt(r: &Recovery, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(
+ f,
+ "cubic={{ k={} w_max={} }} ",
+ r.cubic_state.k, r.cubic_state.w_max
+ )
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -442,7 +475,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -458,6 +491,11 @@ mod tests {
pkt_num: p.pkt_num,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
@@ -485,7 +523,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -502,16 +540,31 @@ mod tests {
pkt_num: p.pkt_num,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
},
Acked {
pkt_num: p.pkt_num,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
},
Acked {
pkt_num: p.pkt_num,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
},
];
@@ -530,7 +583,12 @@ mod tests {
let now = Instant::now();
let prev_cwnd = r.cwnd();
- r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+ r.congestion_event(
+ r.max_datagram_size,
+ now,
+ packet::EPOCH_APPLICATION,
+ now,
+ );
// In CUBIC, after congestion event, cwnd will be reduced by (1 -
// CUBIC_BETA)
@@ -552,7 +610,12 @@ mod tests {
}
// Trigger congestion event to update ssthresh
- r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+ r.congestion_event(
+ r.max_datagram_size,
+ now,
+ packet::EPOCH_APPLICATION,
+ now,
+ );
// After congestion event, cwnd will be reduced.
let cur_cwnd = (prev_cwnd as f64 * BETA_CUBIC) as usize;
@@ -567,7 +630,7 @@ mod tests {
now += rtt;
// To avoid rollback
- r.lost_count += RESTORE_COUNT_THRESHOLD;
+ r.lost_count += MIN_ROLLBACK_THRESHOLD;
// During Congestion Avoidance, it will take
// 5 ACKs to increase cwnd by 1 MSS.
@@ -576,6 +639,11 @@ mod tests {
pkt_num: 0,
time_sent: now,
size: r.max_datagram_size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
@@ -597,7 +665,12 @@ mod tests {
r.on_packet_sent_cc(30000, now);
// Trigger congestion event to update ssthresh
- r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+ r.congestion_event(
+ r.max_datagram_size,
+ now,
+ packet::EPOCH_APPLICATION,
+ now,
+ );
// After persistent congestion, cwnd should be the minimum window
r.collapse_cwnd();
@@ -611,6 +684,11 @@ mod tests {
// To exit from recovery
time_sent: now + Duration::from_millis(1),
size: r.max_datagram_size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
@@ -623,14 +701,13 @@ mod tests {
}
#[test]
- fn cubic_hystart_limited_slow_start() {
+ fn cubic_hystart_css_to_ss() {
let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::CUBIC);
cfg.enable_hystart(true);
let mut r = Recovery::new(&cfg);
let now = Instant::now();
- let pkt_num = 0;
let epoch = packet::EPOCH_APPLICATION;
let p = recovery::Sent {
@@ -644,99 +721,272 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
// 1st round.
let n_rtt_sample = hystart::N_RTT_SAMPLE;
- let pkts_1st_round = n_rtt_sample as u64;
- r.hystart.start_round(pkt_num);
+ let mut send_pn = 0;
+ let mut ack_pn = 0;
- let rtt_1st = 50;
+ let rtt_1st = Duration::from_millis(50);
// Send 1st round packets.
for _ in 0..n_rtt_sample {
r.on_packet_sent_cc(p.size, now);
+ send_pn += 1;
}
+ r.hystart.start_round(send_pn - 1);
+
// Receving Acks.
- let now = now + Duration::from_millis(rtt_1st);
+ let now = now + rtt_1st;
for _ in 0..n_rtt_sample {
- r.update_rtt(
- Duration::from_millis(rtt_1st),
- Duration::from_millis(0),
- now,
- );
+ r.update_rtt(rtt_1st, Duration::from_millis(0), now);
let acked = vec![Acked {
- pkt_num: p.pkt_num,
+ pkt_num: ack_pn,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
r.on_packets_acked(acked, epoch, now);
+ ack_pn += 1;
}
- // Not in LSS yet.
- assert_eq!(r.hystart.lss_start_time().is_some(), false);
+ // Not in CSS yet.
+ assert_eq!(r.hystart.css_start_time().is_some(), false);
// 2nd round.
- r.hystart.start_round(pkts_1st_round * 2);
-
- let mut rtt_2nd = 100;
- let now = now + Duration::from_millis(rtt_2nd);
+ let mut rtt_2nd = Duration::from_millis(100);
+ let now = now + rtt_2nd;
// Send 2nd round packets.
for _ in 0..n_rtt_sample {
r.on_packet_sent_cc(p.size, now);
+ send_pn += 1;
}
+ r.hystart.start_round(send_pn - 1);
// Receving Acks.
- // Last ack will cause to exit to LSS.
+ // Last ack will cause to exit to CSS.
let mut cwnd_prev = r.cwnd();
for _ in 0..n_rtt_sample {
cwnd_prev = r.cwnd();
- r.update_rtt(
- Duration::from_millis(rtt_2nd),
- Duration::from_millis(0),
- now,
- );
+ r.update_rtt(rtt_2nd, Duration::from_millis(0), now);
let acked = vec![Acked {
- pkt_num: p.pkt_num,
+ pkt_num: ack_pn,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
r.on_packets_acked(acked, epoch, now);
+ ack_pn += 1;
- // Keep increasing RTT so that hystart exits to LSS.
- rtt_2nd += 4;
+ // Keep increasing RTT so that hystart exits to CSS.
+ rtt_2nd += rtt_2nd.saturating_add(Duration::from_millis(4));
}
- // Now we are in LSS.
- assert_eq!(r.hystart.lss_start_time().is_some(), true);
+ // Now we are in CSS.
+ assert_eq!(r.hystart.css_start_time().is_some(), true);
assert_eq!(r.cwnd(), cwnd_prev + r.max_datagram_size);
- // Send a full cwnd.
- r.on_packet_sent_cc(r.cwnd(), now);
-
- // Ack'ing 4 packets to increase cwnd by 1 MSS during LSS
+ // 3rd round, which RTT is less than previous round to
+ // trigger back to Slow Start.
+ let rtt_3rd = Duration::from_millis(80);
+ let now = now + rtt_3rd;
cwnd_prev = r.cwnd();
- for _ in 0..4 {
+
+ // Send 3nd round packets.
+ for _ in 0..n_rtt_sample {
+ r.on_packet_sent_cc(p.size, now);
+ send_pn += 1;
+ }
+ r.hystart.start_round(send_pn - 1);
+
+ // Receving Acks.
+ // Last ack will cause to exit to SS.
+ for _ in 0..n_rtt_sample {
+ r.update_rtt(rtt_3rd, Duration::from_millis(0), now);
+
let acked = vec![Acked {
- pkt_num: p.pkt_num,
+ pkt_num: ack_pn,
+ time_sent: p.time_sent,
+ size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
+ }];
+
+ r.on_packets_acked(acked, epoch, now);
+ ack_pn += 1;
+ }
+
+ // Now we are back in Slow Start.
+ assert_eq!(r.hystart.css_start_time().is_some(), false);
+ assert_eq!(
+ r.cwnd(),
+ cwnd_prev +
+ r.max_datagram_size / hystart::CSS_GROWTH_DIVISOR *
+ hystart::N_RTT_SAMPLE
+ );
+ }
+
+ #[test]
+ fn cubic_hystart_css_to_ca() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::CUBIC);
+ cfg.enable_hystart(true);
+
+ let mut r = Recovery::new(&cfg);
+ let now = Instant::now();
+ let epoch = packet::EPOCH_APPLICATION;
+
+ let p = recovery::Sent {
+ pkt_num: 0,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: r.max_datagram_size,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ // 1st round.
+ let n_rtt_sample = hystart::N_RTT_SAMPLE;
+ let mut send_pn = 0;
+ let mut ack_pn = 0;
+
+ let rtt_1st = Duration::from_millis(50);
+
+ // Send 1st round packets.
+ for _ in 0..n_rtt_sample {
+ r.on_packet_sent_cc(p.size, now);
+ send_pn += 1;
+ }
+
+ r.hystart.start_round(send_pn - 1);
+
+ // Receving Acks.
+ let now = now + rtt_1st;
+ for _ in 0..n_rtt_sample {
+ r.update_rtt(rtt_1st, Duration::from_millis(0), now);
+
+ let acked = vec![Acked {
+ pkt_num: ack_pn,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
+
r.on_packets_acked(acked, epoch, now);
+ ack_pn += 1;
}
- // During LSS cwnd will be increased less than usual slow start.
+ // Not in CSS yet.
+ assert_eq!(r.hystart.css_start_time().is_some(), false);
+
+ // 2nd round.
+ let mut rtt_2nd = Duration::from_millis(100);
+ let now = now + rtt_2nd;
+
+ // Send 2nd round packets.
+ for _ in 0..n_rtt_sample {
+ r.on_packet_sent_cc(p.size, now);
+ send_pn += 1;
+ }
+ r.hystart.start_round(send_pn - 1);
+
+ // Receving Acks.
+ // Last ack will cause to exit to CSS.
+ let mut cwnd_prev = r.cwnd();
+
+ for _ in 0..n_rtt_sample {
+ cwnd_prev = r.cwnd();
+ r.update_rtt(rtt_2nd, Duration::from_millis(0), now);
+
+ let acked = vec![Acked {
+ pkt_num: ack_pn,
+ time_sent: p.time_sent,
+ size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
+ }];
+
+ r.on_packets_acked(acked, epoch, now);
+ ack_pn += 1;
+
+ // Keep increasing RTT so that hystart exits to CSS.
+ rtt_2nd += rtt_2nd.saturating_add(Duration::from_millis(4));
+ }
+
+ // Now we are in CSS.
+ assert_eq!(r.hystart.css_start_time().is_some(), true);
assert_eq!(r.cwnd(), cwnd_prev + r.max_datagram_size);
+
+ // Run 5 (CSS_ROUNDS) in CSS, to exit to congestion avoidance.
+ let rtt_css = Duration::from_millis(100);
+ let now = now + rtt_css;
+
+ for _ in 0..hystart::CSS_ROUNDS {
+ // Send a round of packets.
+ for _ in 0..n_rtt_sample {
+ r.on_packet_sent_cc(p.size, now);
+ send_pn += 1;
+ }
+ r.hystart.start_round(send_pn - 1);
+
+ // Receving Acks.
+ for _ in 0..n_rtt_sample {
+ r.update_rtt(rtt_css, Duration::from_millis(0), now);
+
+ let acked = vec![Acked {
+ pkt_num: ack_pn,
+ time_sent: p.time_sent,
+ size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
+ }];
+
+ r.on_packets_acked(acked, epoch, now);
+ ack_pn += 1;
+ }
+ }
+
+ // Now we are in congestion avoidance.
+ assert_eq!(r.cwnd(), r.ssthresh);
}
#[test]
@@ -754,7 +1004,12 @@ mod tests {
}
// Trigger congestion event to update ssthresh
- r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+ r.congestion_event(
+ r.max_datagram_size,
+ now,
+ packet::EPOCH_APPLICATION,
+ now,
+ );
// After congestion event, cwnd will be reduced.
let cur_cwnd = (prev_cwnd as f64 * BETA_CUBIC) as usize;
@@ -767,6 +1022,11 @@ mod tests {
// To exit from recovery
time_sent: now + rtt,
size: r.max_datagram_size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
// Ack more than cwnd bytes with rtt=100ms
@@ -779,7 +1039,49 @@ mod tests {
now + rtt + Duration::from_millis(5),
);
- // cwnd is restored to the previous one.
+ // This is from slow start, no rollback.
+ assert_eq!(r.cwnd(), cur_cwnd);
+
+ let now = now + rtt;
+
+ // Trigger another congestion event.
+ let prev_cwnd = r.cwnd();
+ r.congestion_event(
+ r.max_datagram_size,
+ now,
+ packet::EPOCH_APPLICATION,
+ now,
+ );
+
+ // After congestion event, cwnd will be reduced.
+ let cur_cwnd = (cur_cwnd as f64 * BETA_CUBIC) as usize;
+ assert_eq!(r.cwnd(), cur_cwnd);
+
+ let rtt = Duration::from_millis(100);
+
+ let acked = vec![Acked {
+ pkt_num: 0,
+ // To exit from recovery
+ time_sent: now + rtt,
+ size: r.max_datagram_size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
+ }];
+
+ // Ack more than cwnd bytes with rtt=100ms.
+ r.update_rtt(rtt, Duration::from_millis(0), now);
+
+ // Trigger detecting sprurious congestion event.
+ r.on_packets_acked(
+ acked,
+ packet::EPOCH_APPLICATION,
+ now + rtt + Duration::from_millis(5),
+ );
+
+ // cwnd is rolled back to the previous one.
assert_eq!(r.cwnd(), prev_cwnd);
}
@@ -798,7 +1100,12 @@ mod tests {
}
// Trigger congestion event to update ssthresh
- r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+ r.congestion_event(
+ r.max_datagram_size,
+ now,
+ packet::EPOCH_APPLICATION,
+ now,
+ );
// After 1st congestion event, cwnd will be reduced.
let cur_cwnd = (prev_cwnd as f64 * BETA_CUBIC) as usize;
@@ -812,7 +1119,7 @@ mod tests {
now += rtt;
// To avoid rollback
- r.lost_count += RESTORE_COUNT_THRESHOLD;
+ r.lost_count += MIN_ROLLBACK_THRESHOLD;
// During Congestion Avoidance, it will take
// 5 ACKs to increase cwnd by 1 MSS.
@@ -821,6 +1128,11 @@ mod tests {
pkt_num: 0,
time_sent: now,
size: r.max_datagram_size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
@@ -834,7 +1146,12 @@ mod tests {
// Fast convergence: now there is 2nd congestion event and
// cwnd is not fully recovered to w_max, w_max will be
// further reduced.
- r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+ r.congestion_event(
+ r.max_datagram_size,
+ now,
+ packet::EPOCH_APPLICATION,
+ now,
+ );
// After 2nd congestion event, cwnd will be reduced.
let cur_cwnd = (prev_cwnd as f64 * BETA_CUBIC) as usize;
diff --git a/src/recovery/delivery_rate.rs b/src/recovery/delivery_rate.rs
index 97edeba..dcc3e48 100644
--- a/src/recovery/delivery_rate.rs
+++ b/src/recovery/delivery_rate.rs
@@ -1,4 +1,4 @@
-// Copyright (C) 2020, Cloudflare, Inc.
+// Copyright (C) 2020-2022, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -27,127 +27,164 @@
//! Delivery rate estimation.
//!
//! This implements the algorithm for estimating delivery rate as described in
-//! <https://tools.ietf.org/html/draft-cheng-iccrg-delivery-rate-estimation-00>
-
-use std::cmp;
+//! <https://tools.ietf.org/html/draft-cheng-iccrg-delivery-rate-estimation-01>
use std::time::Duration;
use std::time::Instant;
+use crate::recovery::Acked;
use crate::recovery::Sent;
-#[derive(Default)]
+#[derive(Debug)]
pub struct Rate {
delivered: usize,
- delivered_time: Option<Instant>,
+ delivered_time: Instant,
+
+ first_sent_time: Instant,
- recent_delivered_packet_sent_time: Option<Instant>,
+ // Packet number of the last sent packet with app limited.
+ end_of_app_limited: u64,
- app_limited_at_pkt: usize,
+ // Packet number of the last sent packet.
+ last_sent_packet: u64,
+ // Packet number of the largest acked packet.
+ largest_acked: u64,
+
+ // Sample of rate estimation.
rate_sample: RateSample,
}
-impl Rate {
- pub fn on_packet_sent(&mut self, pkt: &mut Sent, now: Instant) {
- if self.delivered_time.is_none() {
- self.delivered_time = Some(now);
+impl Default for Rate {
+ fn default() -> Self {
+ let now = Instant::now();
+
+ Rate {
+ delivered: 0,
+
+ delivered_time: now,
+
+ first_sent_time: now,
+
+ end_of_app_limited: 0,
+
+ last_sent_packet: 0,
+
+ largest_acked: 0,
+
+ rate_sample: RateSample::default(),
}
+ }
+}
- if self.recent_delivered_packet_sent_time.is_none() {
- self.recent_delivered_packet_sent_time = Some(now);
+impl Rate {
+ pub fn on_packet_sent(
+ &mut self, pkt: &mut Sent, bytes_in_flight: usize, now: Instant,
+ ) {
+ // No packets in flight yet?
+ if bytes_in_flight == 0 {
+ self.first_sent_time = now;
+ self.delivered_time = now;
}
+ pkt.first_sent_time = self.first_sent_time;
+ pkt.delivered_time = self.delivered_time;
pkt.delivered = self.delivered;
- pkt.delivered_time = self.delivered_time.unwrap();
-
- pkt.recent_delivered_packet_sent_time =
- self.recent_delivered_packet_sent_time.unwrap();
+ pkt.is_app_limited = self.app_limited();
- pkt.is_app_limited = self.app_limited_at_pkt > 0;
+ self.last_sent_packet = pkt.pkt_num;
}
- pub fn on_packet_acked(&mut self, pkt: &Sent, now: Instant) {
- self.rate_sample.prior_time = Some(pkt.delivered_time);
-
+ // Update the delivery rate sample when a packet is acked.
+ pub fn update_rate_sample(&mut self, pkt: &Acked, now: Instant) {
self.delivered += pkt.size;
- self.delivered_time = Some(now);
+ self.delivered_time = now;
- if pkt.delivered > self.rate_sample.prior_delivered {
+ // Update info using the newest packet. If rate_sample is not yet
+ // initialized, initialize with the first packet.
+ if self.rate_sample.prior_time.is_none() ||
+ pkt.delivered > self.rate_sample.prior_delivered
+ {
self.rate_sample.prior_delivered = pkt.delivered;
-
+ self.rate_sample.prior_time = Some(pkt.delivered_time);
+ self.rate_sample.is_app_limited = pkt.is_app_limited;
self.rate_sample.send_elapsed =
- pkt.time_sent - pkt.recent_delivered_packet_sent_time;
-
+ pkt.time_sent.saturating_duration_since(pkt.first_sent_time);
+ self.rate_sample.rtt = pkt.rtt;
self.rate_sample.ack_elapsed = self
.delivered_time
- .unwrap()
- .duration_since(pkt.delivered_time);
+ .saturating_duration_since(pkt.delivered_time);
- self.recent_delivered_packet_sent_time = Some(pkt.time_sent);
+ self.first_sent_time = pkt.time_sent;
}
- }
- pub fn estimate(&mut self) {
- if (self.app_limited_at_pkt > 0) &&
- (self.delivered > self.app_limited_at_pkt)
- {
- self.app_limited_at_pkt = 0;
- }
+ self.largest_acked = self.largest_acked.max(pkt.pkt_num);
+ }
- match self.rate_sample.prior_time {
- Some(_) => {
- self.rate_sample.delivered =
- self.delivered - self.rate_sample.prior_delivered;
-
- self.rate_sample.interval = cmp::max(
- self.rate_sample.send_elapsed,
- self.rate_sample.ack_elapsed,
- );
- },
- None => return,
+ pub fn generate_rate_sample(&mut self, min_rtt: Duration) {
+ // End app-limited phase if bubble is ACKed and gone.
+ if self.app_limited() && self.largest_acked > self.end_of_app_limited {
+ self.update_app_limited(false);
}
- if self.rate_sample.interval.as_secs_f64() > 0.0 {
- self.rate_sample.delivery_rate = (self.rate_sample.delivered as f64 /
- self.rate_sample.interval.as_secs_f64())
- as u64;
+ if self.rate_sample.prior_time.is_some() {
+ let interval = self
+ .rate_sample
+ .send_elapsed
+ .max(self.rate_sample.ack_elapsed);
+
+ self.rate_sample.delivered =
+ self.delivered - self.rate_sample.prior_delivered;
+ self.rate_sample.interval = interval;
+
+ if interval < min_rtt {
+ self.rate_sample.interval = Duration::ZERO;
+
+ // No reliable sample.
+ return;
+ }
+
+ if !interval.is_zero() {
+ // Fill in rate_sample with a rate sample.
+ self.rate_sample.delivery_rate =
+ (self.rate_sample.delivered as f64 / interval.as_secs_f64())
+ as u64;
+ }
}
}
- pub fn check_app_limited(&mut self, bytes_in_flight: usize) {
- let limited = self.delivered + bytes_in_flight;
- self.app_limited_at_pkt = if limited > 0 { limited } else { 1 };
+ pub fn update_app_limited(&mut self, v: bool) {
+ self.end_of_app_limited = if v { self.last_sent_packet.max(1) } else { 0 }
}
- pub fn delivery_rate(&self) -> u64 {
- self.rate_sample.delivery_rate
+ pub fn app_limited(&mut self) -> bool {
+ self.end_of_app_limited != 0
}
-}
-
-impl std::fmt::Debug for Rate {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(f, "delivered={:?} ", self.delivered)?;
- if let Some(t) = self.delivered_time {
- write!(f, "delivered_time={:?} ", t.elapsed())?;
- }
+ pub fn _delivered(&self) -> usize {
+ self.delivered
+ }
- if let Some(t) = self.recent_delivered_packet_sent_time {
- write!(f, "recent_delivered_packet_sent_time={:?} ", t.elapsed())?;
- }
+ pub fn sample_delivery_rate(&self) -> u64 {
+ self.rate_sample.delivery_rate
+ }
- write!(f, "app_limited_at_pkt={:?} ", self.app_limited_at_pkt)?;
+ pub fn _sample_rtt(&self) -> Duration {
+ self.rate_sample.rtt
+ }
- Ok(())
+ pub fn _sample_is_app_limited(&self) -> bool {
+ self.rate_sample.is_app_limited
}
}
-#[derive(Default)]
+#[derive(Default, Debug)]
struct RateSample {
delivery_rate: u64,
+ is_app_limited: bool,
+
interval: Duration,
delivered: usize,
@@ -159,22 +196,8 @@ struct RateSample {
send_elapsed: Duration,
ack_elapsed: Duration,
-}
-impl std::fmt::Debug for RateSample {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(f, "delivery_rate={:?} ", self.delivery_rate)?;
- write!(f, "interval={:?} ", self.interval)?;
- write!(f, "delivered={:?} ", self.delivered)?;
- write!(f, "prior_delivered={:?} ", self.prior_delivered)?;
- write!(f, "send_elapsed={:?} ", self.send_elapsed)?;
- if let Some(t) = self.prior_time {
- write!(f, "prior_time={:?} ", t.elapsed())?;
- }
- write!(f, "ack_elapsed={:?}", self.ack_elapsed)?;
-
- Ok(())
- }
+ rtt: Duration,
}
#[cfg(test)]
@@ -186,114 +209,163 @@ mod tests {
#[test]
fn rate_check() {
let config = Config::new(0xbabababa).unwrap();
- let mut recovery = Recovery::new(&config);
-
- let mut pkt_1 = Sent {
- pkt_num: 0,
- frames: vec![],
- time_sent: Instant::now(),
- time_acked: None,
- time_lost: None,
- size: 1200,
- ack_eliciting: true,
- in_flight: true,
- delivered: 0,
- delivered_time: Instant::now(),
- recent_delivered_packet_sent_time: Instant::now(),
- is_app_limited: false,
- has_data: false,
- };
-
- recovery
- .delivery_rate
- .on_packet_sent(&mut pkt_1, Instant::now());
- std::thread::sleep(Duration::from_millis(50));
- recovery
- .delivery_rate
- .on_packet_acked(&pkt_1, Instant::now());
-
- let mut pkt_2 = Sent {
- pkt_num: 1,
- frames: vec![],
- time_sent: Instant::now(),
- time_acked: None,
- time_lost: None,
- size: 1200,
- ack_eliciting: true,
- in_flight: true,
- delivered: 0,
- delivered_time: Instant::now(),
- recent_delivered_packet_sent_time: Instant::now(),
- is_app_limited: false,
- has_data: false,
- };
-
- recovery
- .delivery_rate
- .on_packet_sent(&mut pkt_2, Instant::now());
- std::thread::sleep(Duration::from_millis(50));
- recovery
- .delivery_rate
- .on_packet_acked(&pkt_2, Instant::now());
- recovery.delivery_rate.estimate();
-
- assert!(recovery.delivery_rate() > 0);
+ let mut r = Recovery::new(&config);
+
+ let now = Instant::now();
+ let mss = r.max_datagram_size();
+
+ // Send 2 packets.
+ for pn in 0..2 {
+ let pkt = Sent {
+ pkt_num: pn,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: mss,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ pkt,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ }
+
+ let rtt = Duration::from_millis(50);
+ let now = now + rtt;
+
+ // Ack 2 packets.
+ for pn in 0..2 {
+ let acked = Acked {
+ pkt_num: pn,
+ time_sent: now,
+ size: mss,
+ rtt,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now - rtt,
+ is_app_limited: false,
+ };
+
+ r.delivery_rate.update_rate_sample(&acked, now);
+ }
+
+ // Update rate sample after 1 rtt.
+ r.delivery_rate.generate_rate_sample(rtt);
+
+ // Bytes acked so far.
+ assert_eq!(r.delivery_rate._delivered(), 2400);
+
+ // Estimated delivery rate = (1200 x 2) / 0.05s = 48000.
+ assert_eq!(r.delivery_rate(), 48000);
+ }
+
+ #[test]
+ fn app_limited_cwnd_full() {
+ let config = Config::new(0xbabababa).unwrap();
+ let mut r = Recovery::new(&config);
+
+ let now = Instant::now();
+ let mss = r.max_datagram_size();
+
+ // Send 10 packets to fill cwnd.
+ for pn in 0..10 {
+ let pkt = Sent {
+ pkt_num: pn,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: mss,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ pkt,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ }
+
+ assert_eq!(r.app_limited(), false);
+ assert_eq!(r.delivery_rate._sample_is_app_limited(), false);
}
#[test]
fn app_limited_check() {
let config = Config::new(0xbabababa).unwrap();
- let mut recvry = Recovery::new(&config);
-
- let mut pkt_1 = Sent {
- pkt_num: 0,
- frames: vec![],
- time_sent: Instant::now(),
- time_acked: None,
- time_lost: None,
- size: 1200,
- ack_eliciting: true,
- in_flight: true,
- delivered: 0,
- delivered_time: Instant::now(),
- recent_delivered_packet_sent_time: Instant::now(),
- is_app_limited: false,
- has_data: false,
- };
-
- recvry
- .delivery_rate
- .on_packet_sent(&mut pkt_1, Instant::now());
- std::thread::sleep(Duration::from_millis(50));
- recvry.delivery_rate.on_packet_acked(&pkt_1, Instant::now());
-
- let mut pkt_2 = Sent {
- pkt_num: 1,
- frames: vec![],
- time_sent: Instant::now(),
- time_acked: None,
- time_lost: None,
- size: 1200,
- ack_eliciting: true,
- in_flight: true,
- delivered: 0,
- delivered_time: Instant::now(),
- recent_delivered_packet_sent_time: Instant::now(),
- is_app_limited: false,
- has_data: false,
- };
-
- recvry.app_limited = true;
- recvry
- .delivery_rate
- .check_app_limited(recvry.bytes_in_flight);
- recvry
- .delivery_rate
- .on_packet_sent(&mut pkt_2, Instant::now());
- std::thread::sleep(Duration::from_millis(50));
- recvry.delivery_rate.on_packet_acked(&pkt_2, Instant::now());
- recvry.delivery_rate.estimate();
-
- assert_eq!(recvry.delivery_rate.app_limited_at_pkt, 0);
+ let mut r = Recovery::new(&config);
+
+ let now = Instant::now();
+ let mss = r.max_datagram_size();
+
+ // Send 5 packets.
+ for pn in 0..5 {
+ let pkt = Sent {
+ pkt_num: pn,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: mss,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ pkt,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ }
+
+ let rtt = Duration::from_millis(50);
+ let now = now + rtt;
+
+ let mut acked = ranges::RangeSet::default();
+ acked.insert(0..5);
+
+ assert_eq!(
+ r.on_ack_received(
+ &acked,
+ 25,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ ),
+ Ok(()),
+ );
+
+ assert_eq!(r.app_limited(), true);
+
+ // Rate sample is not app limited (all acked).
+ assert_eq!(r.delivery_rate._sample_is_app_limited(), false);
+ assert_eq!(r.delivery_rate._sample_rtt(), rtt);
}
}
diff --git a/src/recovery/hystart.rs b/src/recovery/hystart.rs
index 6a275bc..2285951 100644
--- a/src/recovery/hystart.rs
+++ b/src/recovery/hystart.rs
@@ -28,7 +28,7 @@
//!
//! This implementation is based on the following I-D:
//!
-//! <https://tools.ietf.org/html/draft-balasubramanian-tcpm-hystartplusplus-03>
+//! <https://datatracker.ietf.org/doc/html/draft-ietf-tcpm-hystartplusplus-04>
use std::cmp;
use std::time::Duration;
@@ -38,29 +38,33 @@ use crate::packet;
use crate::recovery;
/// Constants from I-D.
-const LOW_CWND: usize = 16;
-
const MIN_RTT_THRESH: Duration = Duration::from_millis(4);
const MAX_RTT_THRESH: Duration = Duration::from_millis(16);
-pub const LSS_DIVISOR: f64 = 0.25;
-
pub const N_RTT_SAMPLE: usize = 8;
+pub const CSS_GROWTH_DIVISOR: usize = 4;
+
+pub const CSS_ROUNDS: usize = 5;
+
#[derive(Default)]
pub struct Hystart {
enabled: bool,
window_end: Option<u64>,
- last_round_min_rtt: Option<Duration>,
+ last_round_min_rtt: Duration,
+
+ current_round_min_rtt: Duration,
- current_round_min_rtt: Option<Duration>,
+ css_baseline_min_rtt: Duration,
rtt_sample_count: usize,
- lss_start_time: Option<Instant>,
+ css_start_time: Option<Instant>,
+
+ css_round_count: usize,
}
impl std::fmt::Debug for Hystart {
@@ -68,8 +72,10 @@ impl std::fmt::Debug for Hystart {
write!(f, "window_end={:?} ", self.window_end)?;
write!(f, "last_round_min_rtt={:?} ", self.last_round_min_rtt)?;
write!(f, "current_round_min_rtt={:?} ", self.current_round_min_rtt)?;
+ write!(f, "css_baseline_min_rtt={:?} ", self.css_baseline_min_rtt)?;
write!(f, "rtt_sample_count={:?} ", self.rtt_sample_count)?;
- write!(f, "lss_start_time={:?} ", self.lss_start_time)?;
+ write!(f, "css_start_time={:?} ", self.css_start_time)?;
+ write!(f, "css_round_count={:?}", self.css_round_count)?;
Ok(())
}
@@ -80,101 +86,124 @@ impl Hystart {
Self {
enabled,
+ last_round_min_rtt: Duration::MAX,
+
+ current_round_min_rtt: Duration::MAX,
+
+ css_baseline_min_rtt: Duration::MAX,
+
..Default::default()
}
}
+ pub fn reset(&mut self) {
+ *self = Self::new(self.enabled);
+ }
+
pub fn enabled(&self) -> bool {
self.enabled
}
- pub fn lss_start_time(&self) -> Option<Instant> {
- self.lss_start_time
+ pub fn css_start_time(&self) -> Option<Instant> {
+ self.css_start_time
}
- pub fn in_lss(&self, epoch: packet::Epoch) -> bool {
+ pub fn in_css(&self, epoch: packet::Epoch) -> bool {
self.enabled &&
epoch == packet::EPOCH_APPLICATION &&
- self.lss_start_time().is_some()
+ self.css_start_time().is_some()
}
pub fn start_round(&mut self, pkt_num: u64) {
if self.window_end.is_none() {
- *self = Hystart {
- enabled: self.enabled,
-
- window_end: Some(pkt_num),
+ self.window_end = Some(pkt_num);
- last_round_min_rtt: self.current_round_min_rtt,
+ self.last_round_min_rtt = self.current_round_min_rtt;
- current_round_min_rtt: None,
+ self.current_round_min_rtt = Duration::MAX;
- rtt_sample_count: 0,
-
- lss_start_time: None,
- };
+ self.rtt_sample_count = 0;
}
}
- // Returns true if LSS started.
- pub fn try_enter_lss(
- &mut self, packet: &recovery::Acked, rtt: Duration, cwnd: usize,
- now: Instant, max_datagram_size: usize,
+ // On receiving ACK. Returns true if need to enter Congestion Avoidance.
+ pub fn on_packet_acked(
+ &mut self, epoch: packet::Epoch, packet: &recovery::Acked, rtt: Duration,
+ now: Instant,
) -> bool {
- if self.lss_start_time().is_none() {
- if let Some(current_round_min_rtt) = self.current_round_min_rtt {
- self.current_round_min_rtt =
- Some(cmp::min(current_round_min_rtt, rtt));
- } else {
- self.current_round_min_rtt = Some(rtt);
- }
+ if !(self.enabled && epoch == packet::EPOCH_APPLICATION) {
+ return false;
+ }
- self.rtt_sample_count += 1;
+ self.current_round_min_rtt = cmp::min(self.current_round_min_rtt, rtt);
- if cwnd >= (LOW_CWND * max_datagram_size) &&
- self.rtt_sample_count >= N_RTT_SAMPLE &&
- self.current_round_min_rtt.is_some() &&
- self.last_round_min_rtt.is_some()
+ self.rtt_sample_count += 1;
+
+ // Slow Start.
+ if self.css_start_time().is_none() {
+ if self.rtt_sample_count >= N_RTT_SAMPLE &&
+ self.current_round_min_rtt != Duration::MAX &&
+ self.last_round_min_rtt != Duration::MAX
{
// clamp(min_rtt_thresh, last_round_min_rtt/8,
// max_rtt_thresh)
- let rtt_thresh = cmp::max(
- self.last_round_min_rtt.unwrap() / 8,
- MIN_RTT_THRESH,
- );
+ let rtt_thresh =
+ cmp::max(self.last_round_min_rtt / 8, MIN_RTT_THRESH);
let rtt_thresh = cmp::min(rtt_thresh, MAX_RTT_THRESH);
- // Check if we can exit to LSS.
- if self.current_round_min_rtt.unwrap() >=
- (self.last_round_min_rtt.unwrap() + rtt_thresh)
+ // Check if we can exit to CSS.
+ if self.current_round_min_rtt >=
+ self.last_round_min_rtt.saturating_add(rtt_thresh)
{
- self.lss_start_time = Some(now);
+ self.css_baseline_min_rtt = self.current_round_min_rtt;
+ self.css_start_time = Some(now);
+ }
+ }
+ } else {
+ // Conservative Slow Start.
+ if self.rtt_sample_count >= N_RTT_SAMPLE {
+ self.rtt_sample_count = 0;
+
+ if self.current_round_min_rtt < self.css_baseline_min_rtt {
+ self.css_baseline_min_rtt = Duration::MAX;
+
+ // Back to Slow Start.
+ self.css_start_time = None;
+ self.css_round_count = 0;
}
}
+ }
- // Check if we reached the end of the round.
- if let Some(end_pkt_num) = self.window_end {
- if packet.pkt_num >= end_pkt_num {
- // Start of a new round.
- self.window_end = None;
+ // Check if we reached the end of the round.
+ if let Some(end_pkt_num) = self.window_end {
+ if packet.pkt_num >= end_pkt_num {
+ // Start of a new round.
+ self.window_end = None;
+
+ if self.css_start_time().is_some() {
+ self.css_round_count += 1;
+
+ // End of CSS - exit to congestion avoidance.
+ if self.css_round_count >= CSS_ROUNDS {
+ self.css_round_count = 0;
+ return true;
+ }
}
}
}
- self.lss_start_time.is_some()
+ false
}
- // Return a cwnd increment during LSS (Limited Slow Start).
- pub fn lss_cwnd_inc(
- &self, pkt_size: usize, cwnd: usize, ssthresh: usize,
- ) -> usize {
- pkt_size / (cwnd as f64 / (LSS_DIVISOR * ssthresh as f64)) as usize
+ // Return a cwnd increment during CSS (Conservative Slow Start).
+ pub fn css_cwnd_inc(&self, pkt_size: usize) -> usize {
+ pkt_size / CSS_GROWTH_DIVISOR
}
// Exit HyStart++ when entering congestion avoidance.
pub fn congestion_event(&mut self) {
self.window_end = None;
- self.lss_start_time = None;
+ self.css_start_time = None;
}
}
@@ -190,20 +219,17 @@ mod tests {
hspp.start_round(pkt_num);
assert_eq!(hspp.window_end, Some(pkt_num));
- assert_eq!(hspp.current_round_min_rtt, None);
+ assert_eq!(hspp.current_round_min_rtt, Duration::MAX);
}
#[test]
- fn lss_cwnd_inc() {
+ fn css_cwnd_inc() {
let hspp = Hystart::default();
-
let datagram_size = 1200;
- let cwnd = 24000;
- let ssthresh = 24000;
- let lss_cwnd_inc = hspp.lss_cwnd_inc(datagram_size, cwnd, ssthresh);
+ let css_cwnd_inc = hspp.css_cwnd_inc(datagram_size);
- assert_eq!((datagram_size as f64 * LSS_DIVISOR) as usize, lss_cwnd_inc);
+ assert_eq!(datagram_size / CSS_GROWTH_DIVISOR, css_cwnd_inc);
}
#[test]
diff --git a/src/recovery/mod.rs b/src/recovery/mod.rs
index 2bffa79..7b9bce3 100644
--- a/src/recovery/mod.rs
+++ b/src/recovery/mod.rs
@@ -42,10 +42,15 @@ use crate::minmax;
use crate::packet;
use crate::ranges;
+#[cfg(feature = "qlog")]
+use qlog::events::EventData;
+
// Loss Recovery
-const PACKET_THRESHOLD: u64 = 3;
+const INITIAL_PACKET_THRESHOLD: u64 = 3;
+
+const MAX_PACKET_THRESHOLD: u64 = 20;
-const TIME_THRESHOLD: f64 = 9.0 / 8.0;
+const INITIAL_TIME_THRESHOLD: f64 = 9.0 / 8.0;
const GRANULARITY: Duration = Duration::from_millis(1);
@@ -64,6 +69,8 @@ const MINIMUM_WINDOW_PACKETS: usize = 2;
const LOSS_REDUCTION_FACTOR: f64 = 0.5;
+const PACING_MULTIPLIER: f64 = 1.25;
+
pub struct Recovery {
loss_detection_timer: Option<Instant>,
@@ -97,6 +104,8 @@ pub struct Recovery {
pub lost_count: usize,
+ pub lost_spurious_count: usize,
+
pub loss_probes: [usize; packet::EPOCH_COUNT],
in_flight_count: [usize; packet::EPOCH_COUNT],
@@ -105,6 +114,10 @@ pub struct Recovery {
delivery_rate: delivery_rate::Rate,
+ pkt_thresh: u64,
+
+ time_thresh: f64,
+
// Congestion control.
cc_ops: &'static CongestionControlOps,
@@ -120,6 +133,8 @@ pub struct Recovery {
bytes_sent: usize,
+ pub bytes_lost: u64,
+
congestion_recovery_start_time: Option<Instant>,
max_datagram_size: usize,
@@ -132,7 +147,17 @@ pub struct Recovery {
// Pacing.
pacing_rate: u64,
- last_packet_scheduled_time: Option<Instant>,
+ last_packet_scheduled_time: Instant,
+
+ // RFC6937 PRR.
+ prr: prr::PRR,
+
+ #[cfg(feature = "qlog")]
+ qlog_metrics: QlogMetrics,
+
+ // The maximum size of a data aggregate scheduled and
+ // transmitted together.
+ send_quantum: usize,
}
impl Recovery {
@@ -148,7 +173,7 @@ impl Recovery {
largest_sent_pkt: [0; packet::EPOCH_COUNT],
- latest_rtt: Duration::new(0, 0),
+ latest_rtt: Duration::ZERO,
// This field should be initialized to `INITIAL_RTT` for the initial
// PTO calculation, but it also needs to be an `Option` to track
@@ -156,13 +181,13 @@ impl Recovery {
// handled by the `rtt()` method instead.
smoothed_rtt: None,
- minmax_filter: minmax::Minmax::new(Duration::new(0, 0)),
+ minmax_filter: minmax::Minmax::new(Duration::ZERO),
- min_rtt: Duration::new(0, 0),
+ min_rtt: Duration::ZERO,
rttvar: INITIAL_RTT / 2,
- max_ack_delay: Duration::new(0, 0),
+ max_ack_delay: Duration::ZERO,
loss_time: [None; packet::EPOCH_COUNT],
@@ -173,6 +198,7 @@ impl Recovery {
acked: [Vec::new(), Vec::new(), Vec::new()],
lost_count: 0,
+ lost_spurious_count: 0,
loss_probes: [0; packet::EPOCH_COUNT],
@@ -181,6 +207,10 @@ impl Recovery {
congestion_window: config.max_send_udp_payload_size *
INITIAL_WINDOW_PACKETS,
+ pkt_thresh: INITIAL_PACKET_THRESHOLD,
+
+ time_thresh: INITIAL_TIME_THRESHOLD,
+
bytes_in_flight: 0,
ssthresh: std::usize::MAX,
@@ -191,6 +221,8 @@ impl Recovery {
bytes_sent: 0,
+ bytes_lost: 0,
+
congestion_recovery_start_time: None,
max_datagram_size: config.max_send_udp_payload_size,
@@ -207,10 +239,22 @@ impl Recovery {
pacing_rate: 0,
- last_packet_scheduled_time: None,
+ last_packet_scheduled_time: Instant::now(),
+
+ prr: prr::PRR::default(),
+
+ send_quantum: config.max_send_udp_payload_size *
+ INITIAL_WINDOW_PACKETS,
+
+ #[cfg(feature = "qlog")]
+ qlog_metrics: QlogMetrics::default(),
}
}
+ pub fn on_init(&mut self) {
+ (self.cc_ops.on_init)(self);
+ }
+
pub fn on_packet_sent(
&mut self, mut pkt: Sent, epoch: packet::Epoch,
handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
@@ -220,12 +264,11 @@ impl Recovery {
let sent_bytes = pkt.size;
let pkt_num = pkt.pkt_num;
- self.delivery_rate.on_packet_sent(&mut pkt, now);
-
self.largest_sent_pkt[epoch] =
cmp::max(self.largest_sent_pkt[epoch], pkt_num);
- self.sent[epoch].push_back(pkt);
+ self.delivery_rate
+ .on_packet_sent(&mut pkt, self.bytes_in_flight, now);
if in_flight {
if ack_eliciting {
@@ -234,11 +277,14 @@ impl Recovery {
self.in_flight_count[epoch] += 1;
- self.app_limited =
- (self.bytes_in_flight + sent_bytes) < self.congestion_window;
+ self.update_app_limited(
+ (self.bytes_in_flight + sent_bytes) < self.congestion_window,
+ );
self.on_packet_sent_cc(sent_bytes, now);
+ self.prr.on_packet_sent(sent_bytes);
+
self.set_loss_detection_timer(handshake_status, now);
}
@@ -253,14 +299,18 @@ impl Recovery {
// Pacing: Set the pacing rate if CC doesn't do its own.
if !(self.cc_ops.has_custom_pacing)() {
if let Some(srtt) = self.smoothed_rtt {
- let rate = (self.congestion_window as u64 * 1000000) /
- srtt.as_micros() as u64;
- self.set_pacing_rate(rate);
+ let rate = PACING_MULTIPLIER * self.congestion_window as f64 /
+ srtt.as_secs_f64();
+ self.set_pacing_rate(rate as u64);
}
}
self.schedule_next_packet(epoch, now, sent_bytes);
+ pkt.time_sent = self.get_packet_send_time();
+
+ self.sent[epoch].push_back(pkt);
+
self.bytes_sent += sent_bytes;
trace!("{} {:?}", trace_id, self);
}
@@ -275,7 +325,7 @@ impl Recovery {
}
}
- pub fn get_packet_send_time(&self) -> Option<Instant> {
+ pub fn get_packet_send_time(&self) -> Instant {
self.last_packet_scheduled_time
}
@@ -291,21 +341,17 @@ impl Recovery {
self.bytes_sent <= self.congestion_window ||
self.pacing_rate == 0
{
- self.last_packet_scheduled_time = Some(now);
+ self.last_packet_scheduled_time =
+ cmp::max(self.last_packet_scheduled_time, now);
+
return;
}
- self.last_packet_scheduled_time = match self.last_packet_scheduled_time {
- Some(last_scheduled_time) => {
- let interval: u64 =
- (packet_size as u64 * 1000000) / self.pacing_rate;
- let interval = Duration::from_micros(interval);
- let next_schedule_time = last_scheduled_time + interval;
- Some(cmp::max(now, next_schedule_time))
- },
+ let interval = packet_size as f64 / self.pacing_rate as f64;
+ let interval = Duration::from_secs_f64(interval);
+ let next_schedule_time = self.last_packet_scheduled_time + interval;
- None => Some(now),
- };
+ self.last_packet_scheduled_time = cmp::max(now, next_schedule_time);
}
pub fn on_ack_received(
@@ -340,24 +386,57 @@ impl Recovery {
let mut newly_acked = Vec::new();
+ let mut undo_cwnd = false;
+
+ let max_rtt = cmp::max(self.latest_rtt, self.rtt());
+
// Detect and mark acked packets, without removing them from the sent
// packets list.
for r in ranges.iter() {
- let lowest_acked = r.start;
- let largest_acked = r.end - 1;
+ let lowest_acked_in_block = r.start;
+ let largest_acked_in_block = r.end - 1;
let unacked_iter = self.sent[epoch]
.iter_mut()
// Skip packets that precede the lowest acked packet in the block.
- .skip_while(|p| p.pkt_num < lowest_acked)
+ .skip_while(|p| p.pkt_num < lowest_acked_in_block)
// Skip packets that follow the largest acked packet in the block.
- .take_while(|p| p.pkt_num <= largest_acked)
+ .take_while(|p| p.pkt_num <= largest_acked_in_block)
// Skip packets that have already been acked or lost.
- .filter(|p| p.time_acked.is_none() && p.time_lost.is_none());
+ .filter(|p| p.time_acked.is_none());
for unacked in unacked_iter {
unacked.time_acked = Some(now);
+ // Check if acked packet was already declared lost.
+ if unacked.time_lost.is_some() {
+ // Calculate new packet reordering threshold.
+ let pkt_thresh =
+ self.largest_acked_pkt[epoch] - unacked.pkt_num + 1;
+ let pkt_thresh = cmp::min(MAX_PACKET_THRESHOLD, pkt_thresh);
+
+ self.pkt_thresh = cmp::max(self.pkt_thresh, pkt_thresh);
+
+ // Calculate new time reordering threshold.
+ let loss_delay = max_rtt.mul_f64(self.time_thresh);
+
+ // unacked.time_sent can be in the future due to
+ // pacing.
+ if now.saturating_duration_since(unacked.time_sent) >
+ loss_delay
+ {
+ // TODO: do time threshold update
+ self.time_thresh = 5_f64 / 4_f64;
+ }
+
+ if unacked.in_flight {
+ undo_cwnd = true;
+ }
+
+ self.lost_spurious_count += 1;
+ continue;
+ }
+
if unacked.ack_eliciting {
has_ack_eliciting = true;
}
@@ -370,8 +449,6 @@ impl Recovery {
if unacked.in_flight {
self.in_flight_count[epoch] =
self.in_flight_count[epoch].saturating_sub(1);
-
- self.delivery_rate.on_packet_acked(&unacked, now);
}
newly_acked.push(Acked {
@@ -380,20 +457,36 @@ impl Recovery {
time_sent: unacked.time_sent,
size: unacked.size,
+
+ rtt: now.saturating_duration_since(unacked.time_sent),
+
+ delivered: unacked.delivered,
+
+ delivered_time: unacked.delivered_time,
+
+ first_sent_time: unacked.first_sent_time,
+
+ is_app_limited: unacked.is_app_limited,
});
trace!("{} packet newly acked {}", trace_id, unacked.pkt_num);
}
}
- self.delivery_rate.estimate();
+ // Undo congestion window update.
+ if undo_cwnd {
+ (self.cc_ops.rollback)(self);
+ }
if newly_acked.is_empty() {
return Ok(());
}
if largest_newly_acked_pkt_num == largest_acked && has_ack_eliciting {
- let latest_rtt = now - largest_newly_acked_sent_time;
+ // The packet's sent time could be in the future if pacing is used
+ // and the network has a very short RTT.
+ let latest_rtt =
+ now.saturating_duration_since(largest_newly_acked_sent_time);
let ack_delay = if epoch == packet::EPOCH_APPLICATION {
Duration::from_micros(ack_delay)
@@ -414,7 +507,7 @@ impl Recovery {
self.set_loss_detection_timer(handshake_status, now);
- self.drain_packets(epoch);
+ self.drain_packets(epoch, now);
Ok(())
}
@@ -521,7 +614,9 @@ impl Recovery {
return std::usize::MAX;
}
- self.congestion_window.saturating_sub(self.bytes_in_flight)
+ // Open more space (snd_cnt) for PRR when allowed.
+ self.congestion_window.saturating_sub(self.bytes_in_flight) +
+ self.prr.snd_cnt
}
pub fn rtt(&self) -> Duration {
@@ -533,7 +628,7 @@ impl Recovery {
}
pub fn delivery_rate(&self) -> u64 {
- self.delivery_rate.delivery_rate()
+ self.delivery_rate.sample_delivery_rate()
}
pub fn max_datagram_size(&self) -> usize {
@@ -597,7 +692,6 @@ impl Recovery {
let mut time = self.loss_time[epoch];
// Iterate over all packet number spaces starting from Handshake.
- #[allow(clippy::needless_range_loop)]
for e in packet::EPOCH_HANDSHAKE..packet::EPOCH_COUNT {
let new_time = self.loss_time[e];
@@ -684,7 +778,7 @@ impl Recovery {
self.loss_time[epoch] = None;
let loss_delay =
- cmp::max(self.latest_rtt, self.rtt()).mul_f64(TIME_THRESHOLD);
+ cmp::max(self.latest_rtt, self.rtt()).mul_f64(self.time_thresh);
// Minimum time of kGranularity before packets are deemed lost.
let loss_delay = cmp::max(loss_delay, GRANULARITY);
@@ -706,7 +800,7 @@ impl Recovery {
for unacked in unacked_iter {
// Mark packet as lost, or set time when it should be marked.
if unacked.time_sent <= lost_send_time ||
- largest_acked >= unacked.pkt_num + PACKET_THRESHOLD
+ largest_acked >= unacked.pkt_num + self.pkt_thresh
{
self.lost[epoch].append(&mut unacked.frames);
@@ -743,14 +837,16 @@ impl Recovery {
}
}
+ self.bytes_lost += lost_bytes as u64;
+
if let Some(pkt) = largest_lost_pkt {
self.on_packets_lost(lost_bytes, &pkt, epoch, now);
}
- self.drain_packets(epoch);
+ self.drain_packets(epoch, now);
}
- fn drain_packets(&mut self, epoch: packet::Epoch) {
+ fn drain_packets(&mut self, epoch: packet::Epoch, now: Instant) {
let mut lowest_non_expired_pkt_index = self.sent[epoch].len();
// In order to avoid removing elements from the middle of the list
@@ -764,6 +860,13 @@ impl Recovery {
// First, find the first element that is neither acked nor lost.
for (i, pkt) in self.sent[epoch].iter().enumerate() {
+ if let Some(time_lost) = pkt.time_lost {
+ if time_lost + self.rtt() > now {
+ lowest_non_expired_pkt_index = i;
+ break;
+ }
+ }
+
if pkt.time_acked.is_none() && pkt.time_lost.is_none() {
lowest_non_expired_pkt_index = i;
break;
@@ -777,9 +880,16 @@ impl Recovery {
fn on_packets_acked(
&mut self, acked: Vec<Acked>, epoch: packet::Epoch, now: Instant,
) {
- for pkt in acked {
- (self.cc_ops.on_packet_acked)(self, &pkt, epoch, now);
+ // Update delivery rate sample per acked packet.
+ for pkt in &acked {
+ self.delivery_rate.update_rate_sample(pkt, now);
}
+
+ // Fill in a rate sample.
+ self.delivery_rate.generate_rate_sample(self.min_rtt);
+
+ // Call congestion control hooks.
+ (self.cc_ops.on_packets_acked)(self, &acked, epoch, now);
}
fn in_congestion_recovery(&self, sent_time: Instant) -> bool {
@@ -804,7 +914,7 @@ impl Recovery {
) {
self.bytes_in_flight = self.bytes_in_flight.saturating_sub(lost_bytes);
- self.congestion_event(largest_lost_pkt.time_sent, epoch, now);
+ self.congestion_event(lost_bytes, largest_lost_pkt.time_sent, epoch, now);
if self.in_persistent_congestion(largest_lost_pkt.pkt_num) {
self.collapse_cwnd();
@@ -812,25 +922,20 @@ impl Recovery {
}
fn congestion_event(
- &mut self, time_sent: Instant, epoch: packet::Epoch, now: Instant,
+ &mut self, lost_bytes: usize, time_sent: Instant, epoch: packet::Epoch,
+ now: Instant,
) {
if !self.in_congestion_recovery(time_sent) {
(self.cc_ops.checkpoint)(self);
}
- (self.cc_ops.congestion_event)(self, time_sent, epoch, now);
+ (self.cc_ops.congestion_event)(self, lost_bytes, time_sent, epoch, now);
}
fn collapse_cwnd(&mut self) {
(self.cc_ops.collapse_cwnd)(self);
}
- pub fn rate_check_app_limited(&mut self) {
- if self.app_limited {
- self.delivery_rate.check_app_limited(self.bytes_in_flight)
- }
- }
-
pub fn update_app_limited(&mut self, v: bool) {
self.app_limited = v;
}
@@ -839,23 +944,27 @@ impl Recovery {
self.app_limited
}
+ pub fn delivery_rate_update_app_limited(&mut self, v: bool) {
+ self.delivery_rate.update_app_limited(v);
+ }
+
#[cfg(feature = "qlog")]
- pub fn to_qlog(&self) -> qlog::event::Event {
- // QVis can't use all these fields and they can be large.
- qlog::event::Event::metrics_updated(
- Some(self.min_rtt.as_millis() as u64),
- Some(self.rtt().as_millis() as u64),
- Some(self.latest_rtt.as_millis() as u64),
- Some(self.rttvar.as_millis() as u64),
- None, // delay
- None, // probe_count
- Some(self.cwnd() as u64),
- Some(self.bytes_in_flight as u64),
- None, // ssthresh
- None, // packets_in_flight
- None, // in_recovery
- None, // pacing_rate
- )
+ pub fn maybe_qlog(&mut self) -> Option<EventData> {
+ let qlog_metrics = QlogMetrics {
+ min_rtt: self.min_rtt,
+ smoothed_rtt: self.rtt(),
+ latest_rtt: self.latest_rtt,
+ rttvar: self.rttvar,
+ cwnd: self.cwnd() as u64,
+ bytes_in_flight: self.bytes_in_flight as u64,
+ ssthresh: self.ssthresh as u64,
+ };
+
+ self.qlog_metrics.maybe_update(qlog_metrics)
+ }
+
+ pub fn send_quantum(&self) -> usize {
+ self.send_quantum
}
}
@@ -889,13 +998,20 @@ impl FromStr for CongestionControlAlgorithm {
}
pub struct CongestionControlOps {
+ pub on_init: fn(r: &mut Recovery),
+
pub on_packet_sent: fn(r: &mut Recovery, sent_bytes: usize, now: Instant),
- pub on_packet_acked:
- fn(r: &mut Recovery, packet: &Acked, epoch: packet::Epoch, now: Instant),
+ pub on_packets_acked: fn(
+ r: &mut Recovery,
+ packets: &[Acked],
+ epoch: packet::Epoch,
+ now: Instant,
+ ),
pub congestion_event: fn(
r: &mut Recovery,
+ lost_bytes: usize,
time_sent: Instant,
epoch: packet::Epoch,
now: Instant,
@@ -905,9 +1021,12 @@ pub struct CongestionControlOps {
pub checkpoint: fn(r: &mut Recovery),
- pub rollback: fn(r: &mut Recovery),
+ pub rollback: fn(r: &mut Recovery) -> bool,
pub has_custom_pacing: fn() -> bool,
+
+ pub debug_fmt:
+ fn(r: &Recovery, formatter: &mut std::fmt::Formatter) -> std::fmt::Result,
}
impl From<CongestionControlAlgorithm> for &'static CongestionControlOps {
@@ -965,6 +1084,9 @@ impl std::fmt::Debug for Recovery {
write!(f, "hystart={:?} ", self.hystart)?;
}
+ // CC-specific debug info
+ (self.cc_ops.debug_fmt)(self, f)?;
+
Ok(())
}
}
@@ -991,7 +1113,7 @@ pub struct Sent {
pub delivered_time: Instant,
- pub recent_delivered_packet_sent_time: Instant,
+ pub first_sent_time: Instant,
pub is_app_limited: bool,
@@ -1005,11 +1127,7 @@ impl std::fmt::Debug for Sent {
write!(f, "pkt_size={:?} ", self.size)?;
write!(f, "delivered={:?} ", self.delivered)?;
write!(f, "delivered_time={:?} ", self.delivered_time.elapsed())?;
- write!(
- f,
- "recent_delivered_packet_sent_time={:?} ",
- self.recent_delivered_packet_sent_time.elapsed()
- )?;
+ write!(f, "first_sent_time={:?} ", self.first_sent_time.elapsed())?;
write!(f, "is_app_limited={} ", self.is_app_limited)?;
write!(f, "has_data={} ", self.has_data)?;
@@ -1024,6 +1142,16 @@ pub struct Acked {
pub time_sent: Instant,
pub size: usize,
+
+ pub rtt: Duration,
+
+ pub delivered: usize,
+
+ pub delivered_time: Instant,
+
+ pub first_sent_time: Instant,
+
+ pub is_app_limited: bool,
}
#[derive(Clone, Copy, Debug)]
@@ -1056,6 +1184,111 @@ fn sub_abs(lhs: Duration, rhs: Duration) -> Duration {
}
}
+// We don't need to log all qlog metrics every time there is a recovery event.
+// Instead, we can log only the MetricsUpdated event data fields that we care
+// about, only when they change. To support this, the QLogMetrics structure
+// keeps a running picture of the fields.
+#[derive(Default)]
+#[cfg(feature = "qlog")]
+struct QlogMetrics {
+ min_rtt: Duration,
+ smoothed_rtt: Duration,
+ latest_rtt: Duration,
+ rttvar: Duration,
+ cwnd: u64,
+ bytes_in_flight: u64,
+ ssthresh: u64,
+}
+
+#[cfg(feature = "qlog")]
+impl QlogMetrics {
+ // Make a qlog event if the latest instance of QlogMetrics is different.
+ //
+ // This function diffs each of the fields. A qlog MetricsUpdated event is
+ // only generated if at least one field is different. Where fields are
+ // different, the qlog event contains the latest value.
+ fn maybe_update(&mut self, latest: Self) -> Option<EventData> {
+ let mut emit_event = false;
+
+ let new_min_rtt = if self.min_rtt != latest.min_rtt {
+ self.min_rtt = latest.min_rtt;
+ emit_event = true;
+ Some(latest.min_rtt.as_secs_f32() * 1000.0)
+ } else {
+ None
+ };
+
+ let new_smoothed_rtt = if self.smoothed_rtt != latest.smoothed_rtt {
+ self.smoothed_rtt = latest.smoothed_rtt;
+ emit_event = true;
+ Some(latest.smoothed_rtt.as_secs_f32() * 1000.0)
+ } else {
+ None
+ };
+
+ let new_latest_rtt = if self.latest_rtt != latest.latest_rtt {
+ self.latest_rtt = latest.latest_rtt;
+ emit_event = true;
+ Some(latest.latest_rtt.as_secs_f32() * 1000.0)
+ } else {
+ None
+ };
+
+ let new_rttvar = if self.rttvar != latest.rttvar {
+ self.rttvar = latest.rttvar;
+ emit_event = true;
+ Some(latest.rttvar.as_secs_f32() * 1000.0)
+ } else {
+ None
+ };
+
+ let new_cwnd = if self.cwnd != latest.cwnd {
+ self.cwnd = latest.cwnd;
+ emit_event = true;
+ Some(latest.cwnd)
+ } else {
+ None
+ };
+
+ let new_bytes_in_flight =
+ if self.bytes_in_flight != latest.bytes_in_flight {
+ self.bytes_in_flight = latest.bytes_in_flight;
+ emit_event = true;
+ Some(latest.bytes_in_flight)
+ } else {
+ None
+ };
+
+ let new_ssthresh = if self.ssthresh != latest.ssthresh {
+ self.ssthresh = latest.ssthresh;
+ emit_event = true;
+ Some(latest.ssthresh)
+ } else {
+ None
+ };
+
+ if emit_event {
+ // QVis can't use all these fields and they can be large.
+ return Some(EventData::MetricsUpdated(
+ qlog::events::quic::MetricsUpdated {
+ min_rtt: new_min_rtt,
+ smoothed_rtt: new_smoothed_rtt,
+ latest_rtt: new_latest_rtt,
+ rtt_variance: new_rttvar,
+ pto_count: None,
+ congestion_window: new_cwnd,
+ bytes_in_flight: new_bytes_in_flight,
+ ssthresh: new_ssthresh,
+ packets_in_flight: None,
+ pacing_rate: None,
+ },
+ ));
+ }
+
+ None
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -1109,7 +1342,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1135,7 +1368,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1161,7 +1394,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1187,7 +1420,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1245,7 +1478,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1271,7 +1504,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1306,10 +1539,17 @@ mod tests {
Ok(())
);
- assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 4);
assert_eq!(r.bytes_in_flight, 0);
assert_eq!(r.lost_count, 2);
+
+ // Wait 1 RTT.
+ now += r.rtt();
+
+ r.detect_lost_packets(packet::EPOCH_APPLICATION, now, "");
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
}
#[test]
@@ -1335,7 +1575,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1361,7 +1601,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1387,7 +1627,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1413,7 +1653,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1459,10 +1699,17 @@ mod tests {
r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
assert_eq!(r.loss_probes[packet::EPOCH_APPLICATION], 0);
- assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 2);
assert_eq!(r.bytes_in_flight, 0);
assert_eq!(r.lost_count, 1);
+
+ // Wait 1 RTT.
+ now += r.rtt();
+
+ r.detect_lost_packets(packet::EPOCH_APPLICATION, now, "");
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
}
#[test]
@@ -1488,7 +1735,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1514,7 +1761,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1540,7 +1787,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1566,7 +1813,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1605,6 +1852,8 @@ mod tests {
let mut acked = ranges::RangeSet::default();
acked.insert(0..2);
+ assert_eq!(r.pkt_thresh, INITIAL_PACKET_THRESHOLD);
+
assert_eq!(
r.on_ack_received(
&acked,
@@ -1617,11 +1866,22 @@ mod tests {
Ok(())
);
- assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 4);
assert_eq!(r.bytes_in_flight, 0);
// Spurious loss.
assert_eq!(r.lost_count, 1);
+ assert_eq!(r.lost_spurious_count, 1);
+
+ // Packet threshold was increased.
+ assert_eq!(r.pkt_thresh, 4);
+
+ // Wait 1 RTT.
+ now += r.rtt();
+
+ r.detect_lost_packets(packet::EPOCH_APPLICATION, now, "");
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
}
#[test]
@@ -1647,7 +1907,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1665,7 +1925,7 @@ mod tests {
// First packet will be sent out immidiately.
assert_eq!(r.pacing_rate, 0);
- assert_eq!(r.get_packet_send_time().unwrap(), now);
+ assert_eq!(r.get_packet_send_time(), now);
// Wait 50ms for ACK.
now += Duration::from_millis(50);
@@ -1701,7 +1961,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1718,7 +1978,7 @@ mod tests {
assert_eq!(r.bytes_in_flight, 6500);
// Pacing is not done during intial phase of connection.
- assert_eq!(r.get_packet_send_time().unwrap(), now);
+ assert_eq!(r.get_packet_send_time(), now);
// Send the third packet out.
let p = Sent {
@@ -1732,7 +1992,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: now,
- recent_delivered_packet_sent_time: now,
+ first_sent_time: now,
is_app_limited: false,
has_data: false,
};
@@ -1751,12 +2011,11 @@ mod tests {
// We pace this outgoing packet. as all conditions for pacing
// are passed.
- assert_eq!(r.pacing_rate, (12000.0 / 0.05) as u64);
+ let pacing_rate = (12000.0 * PACING_MULTIPLIER / 0.05) as u64;
+ assert_eq!(r.pacing_rate, pacing_rate);
assert_eq!(
- r.get_packet_send_time().unwrap(),
- now + Duration::from_micros(
- (6500 * 1000000) / (12000.0 / 0.05) as u64
- )
+ r.get_packet_send_time(),
+ now + Duration::from_secs_f64(6500.0 / pacing_rate as f64)
);
}
}
@@ -1764,4 +2023,5 @@ mod tests {
mod cubic;
mod delivery_rate;
mod hystart;
+mod prr;
mod reno;
diff --git a/src/recovery/prr.rs b/src/recovery/prr.rs
new file mode 100644
index 0000000..312b260
--- /dev/null
+++ b/src/recovery/prr.rs
@@ -0,0 +1,238 @@
+// Copyright (C) 2021, Cloudflare, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//! Proportional Rate Reduction
+//!
+//! This implementation is based on the following RFC:
+//!
+//! <https://datatracker.ietf.org/doc/html/rfc6937>
+
+use std::cmp;
+
+#[derive(Default, Debug)]
+pub struct PRR {
+ // Total bytes delivered during recovery.
+ prr_delivered: usize,
+
+ // FlightSize at the start of recovery.
+ recoverfs: usize,
+
+ // Total bytes sent during recovery.
+ prr_out: usize,
+
+ // Total additional bytes can be sent for retransmit during recovery.
+ pub snd_cnt: usize,
+}
+
+impl PRR {
+ pub fn on_packet_sent(&mut self, sent_bytes: usize) {
+ self.prr_out += sent_bytes;
+
+ self.snd_cnt = self.snd_cnt.saturating_sub(sent_bytes);
+ }
+
+ pub fn congestion_event(&mut self, bytes_in_flight: usize) {
+ self.prr_delivered = 0;
+
+ self.recoverfs = bytes_in_flight;
+
+ self.prr_out = 0;
+
+ self.snd_cnt = 0;
+ }
+
+ pub fn on_packet_acked(
+ &mut self, delivered_data: usize, pipe: usize, ssthresh: usize,
+ max_datagram_size: usize,
+ ) {
+ self.prr_delivered += delivered_data;
+
+ self.snd_cnt = if pipe > ssthresh {
+ // Proportional Rate Reduction.
+ if self.recoverfs > 0 {
+ ((self.prr_delivered * ssthresh + self.recoverfs - 1) /
+ self.recoverfs)
+ .saturating_sub(self.prr_out)
+ } else {
+ 0
+ }
+ } else {
+ // PRR-SSRB.
+ let limit = cmp::max(
+ self.prr_delivered.saturating_sub(self.prr_out),
+ delivered_data,
+ ) + max_datagram_size;
+
+ // Attempt to catch up, as permitted by limit
+ cmp::min(ssthresh - pipe, limit)
+ };
+
+ // snd_cnt should be a positive number.
+ self.snd_cnt = cmp::max(self.snd_cnt, 0);
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn congestion_event() {
+ let mut prr = PRR::default();
+ let bytes_in_flight = 1000;
+
+ prr.congestion_event(bytes_in_flight);
+
+ assert_eq!(prr.recoverfs, bytes_in_flight);
+ assert_eq!(prr.snd_cnt, 0);
+ }
+
+ #[test]
+ fn on_packet_sent() {
+ let mut prr = PRR::default();
+ let bytes_in_flight = 1000;
+ let bytes_sent = 500;
+
+ prr.congestion_event(bytes_in_flight);
+
+ prr.on_packet_sent(bytes_sent);
+
+ assert_eq!(prr.prr_out, bytes_sent);
+ assert_eq!(prr.snd_cnt, 0);
+ }
+
+ #[test]
+ fn on_packet_acked_prr() {
+ let mut prr = PRR::default();
+ let max_datagram_size = 1000;
+ let bytes_in_flight = max_datagram_size * 10;
+ let ssthresh = bytes_in_flight / 2;
+ let acked = 1000;
+
+ prr.congestion_event(bytes_in_flight);
+
+ // pipe > ssthresh uses PRR algorithm.
+ let pipe = bytes_in_flight;
+
+ prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
+
+ assert_eq!(prr.snd_cnt, 500);
+
+ let snd_cnt = prr.snd_cnt;
+
+ // send one more allowed by snd_cnt
+ prr.on_packet_sent(snd_cnt);
+
+ prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
+
+ assert_eq!(prr.snd_cnt, 500);
+ }
+
+ #[test]
+ fn on_packet_acked_prr_overflow() {
+ let mut prr = PRR::default();
+ let max_datagram_size = 1000;
+ let bytes_in_flight = max_datagram_size * 10;
+ let ssthresh = bytes_in_flight / 2;
+ let acked = 1000;
+
+ prr.congestion_event(bytes_in_flight);
+
+ prr.on_packet_sent(max_datagram_size);
+
+ // pipe > ssthresh uses PRR algorithm.
+ let pipe = bytes_in_flight + max_datagram_size;
+
+ prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
+
+ assert_eq!(prr.snd_cnt, 0);
+ }
+
+ #[test]
+ fn on_packet_acked_prr_zero_in_flight() {
+ let mut prr = PRR::default();
+ let max_datagram_size = 1000;
+ let bytes_in_flight = 0;
+ let ssthresh = 3000;
+ let acked = 1000;
+
+ prr.congestion_event(bytes_in_flight);
+
+ // pipe > ssthresh uses PRR algorithm.
+ let pipe = ssthresh + 1000;
+
+ prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
+
+ assert_eq!(prr.snd_cnt, 0);
+ }
+
+ #[test]
+ fn on_packet_acked_prr_ssrb() {
+ let mut prr = PRR::default();
+ let max_datagram_size = 1000;
+ let bytes_in_flight = max_datagram_size * 10;
+ let ssthresh = bytes_in_flight / 2;
+ let acked = 1000;
+
+ prr.congestion_event(bytes_in_flight);
+
+ // pipe <= ssthresh uses PRR-SSRB algorithm.
+ let pipe = max_datagram_size;
+
+ prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
+
+ assert_eq!(prr.snd_cnt, 2000);
+
+ let snd_cnt = prr.snd_cnt;
+
+ // send one more allowed by snd_cnt
+ prr.on_packet_sent(snd_cnt);
+
+ prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
+
+ assert_eq!(prr.snd_cnt, 2000);
+ }
+
+ #[test]
+ fn on_packet_acked_prr_ssrb_overflow() {
+ let mut prr = PRR::default();
+ let max_datagram_size = 1000;
+ let bytes_in_flight = max_datagram_size * 10;
+ let ssthresh = bytes_in_flight / 2;
+ let acked = 500;
+
+ prr.congestion_event(bytes_in_flight);
+
+ // pipe <= ssthresh uses PRR-SSRB algorithm.
+ let pipe = max_datagram_size;
+
+ prr.on_packet_sent(max_datagram_size);
+
+ prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
+
+ assert_eq!(prr.snd_cnt, 1500);
+ }
+}
diff --git a/src/recovery/reno.rs b/src/recovery/reno.rs
index 404b63f..eb8942b 100644
--- a/src/recovery/reno.rs
+++ b/src/recovery/reno.rs
@@ -39,19 +39,31 @@ use crate::recovery::CongestionControlOps;
use crate::recovery::Recovery;
pub static RENO: CongestionControlOps = CongestionControlOps {
+ on_init,
on_packet_sent,
- on_packet_acked,
+ on_packets_acked,
congestion_event,
collapse_cwnd,
checkpoint,
rollback,
has_custom_pacing,
+ debug_fmt,
};
+pub fn on_init(_r: &mut Recovery) {}
+
pub fn on_packet_sent(r: &mut Recovery, sent_bytes: usize, _now: Instant) {
r.bytes_in_flight += sent_bytes;
}
+fn on_packets_acked(
+ r: &mut Recovery, packets: &[Acked], epoch: packet::Epoch, now: Instant,
+) {
+ for pkt in packets {
+ on_packet_acked(r, pkt, epoch, now);
+ }
+}
+
fn on_packet_acked(
r: &mut Recovery, packet: &Acked, epoch: packet::Epoch, now: Instant,
) {
@@ -70,53 +82,30 @@ fn on_packet_acked(
// acknowledged bytes.
r.bytes_acked_sl += packet.size;
- if r.bytes_acked_sl >= r.max_datagram_size {
+ if r.hystart.in_css(epoch) {
+ r.congestion_window += r.hystart.css_cwnd_inc(r.max_datagram_size);
+ } else {
r.congestion_window += r.max_datagram_size;
- r.bytes_acked_sl -= r.max_datagram_size;
}
- if r.hystart.enabled() &&
- epoch == packet::EPOCH_APPLICATION &&
- r.hystart.try_enter_lss(
- packet,
- r.latest_rtt,
- r.congestion_window,
- now,
- r.max_datagram_size,
- )
- {
+ if r.hystart.on_packet_acked(epoch, packet, r.latest_rtt, now) {
+ // Exit to congestion avoidance if CSS ends.
r.ssthresh = r.congestion_window;
}
} else {
// Congestion avoidance.
- let mut reno_cwnd = r.congestion_window;
-
r.bytes_acked_ca += packet.size;
if r.bytes_acked_ca >= r.congestion_window {
r.bytes_acked_ca -= r.congestion_window;
- reno_cwnd += r.max_datagram_size;
- }
-
- // When in Limited Slow Start, take the max of CA cwnd and
- // LSS cwnd.
- if r.hystart.in_lss(epoch) {
- let lss_cwnd_inc = r.hystart.lss_cwnd_inc(
- packet.size,
- r.congestion_window,
- r.ssthresh,
- );
-
- r.congestion_window =
- cmp::max(reno_cwnd, r.congestion_window + lss_cwnd_inc);
- } else {
- r.congestion_window = reno_cwnd;
+ r.congestion_window += r.max_datagram_size;
}
}
}
fn congestion_event(
- r: &mut Recovery, time_sent: Instant, epoch: packet::Epoch, now: Instant,
+ r: &mut Recovery, _lost_bytes: usize, time_sent: Instant,
+ epoch: packet::Epoch, now: Instant,
) {
// Start a new congestion event if packet was sent after the
// start of the previous congestion recovery period.
@@ -137,7 +126,7 @@ fn congestion_event(
r.ssthresh = r.congestion_window;
- if r.hystart.in_lss(epoch) {
+ if r.hystart.in_css(epoch) {
r.hystart.congestion_event();
}
}
@@ -147,16 +136,26 @@ pub fn collapse_cwnd(r: &mut Recovery) {
r.congestion_window = r.max_datagram_size * recovery::MINIMUM_WINDOW_PACKETS;
r.bytes_acked_sl = 0;
r.bytes_acked_ca = 0;
+
+ if r.hystart.enabled() {
+ r.hystart.reset();
+ }
}
fn checkpoint(_r: &mut Recovery) {}
-fn rollback(_r: &mut Recovery) {}
+fn rollback(_r: &mut Recovery) -> bool {
+ true
+}
fn has_custom_pacing() -> bool {
false
}
+fn debug_fmt(_r: &Recovery, _f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ Ok(())
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -208,7 +207,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: std::time::Instant::now(),
- recent_delivered_packet_sent_time: std::time::Instant::now(),
+ first_sent_time: std::time::Instant::now(),
is_app_limited: false,
has_data: false,
};
@@ -224,6 +223,11 @@ mod tests {
pkt_num: p.pkt_num,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
@@ -252,7 +256,7 @@ mod tests {
in_flight: true,
delivered: 0,
delivered_time: std::time::Instant::now(),
- recent_delivered_packet_sent_time: std::time::Instant::now(),
+ first_sent_time: std::time::Instant::now(),
is_app_limited: false,
has_data: false,
};
@@ -269,16 +273,31 @@ mod tests {
pkt_num: p.pkt_num,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
},
Acked {
pkt_num: p.pkt_num,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
},
Acked {
pkt_num: p.pkt_num,
time_sent: p.time_sent,
size: p.size,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
},
];
@@ -299,7 +318,12 @@ mod tests {
let now = Instant::now();
- r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+ r.congestion_event(
+ r.max_datagram_size,
+ now,
+ packet::EPOCH_APPLICATION,
+ now,
+ );
// In Reno, after congestion event, cwnd will be cut in half.
assert_eq!(prev_cwnd / 2, r.cwnd());
@@ -318,7 +342,12 @@ mod tests {
r.on_packet_sent_cc(20000, now);
// Trigger congestion event to update ssthresh
- r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+ r.congestion_event(
+ r.max_datagram_size,
+ now,
+ packet::EPOCH_APPLICATION,
+ now,
+ );
// After congestion event, cwnd will be reduced.
let cur_cwnd =
@@ -333,6 +362,11 @@ mod tests {
time_sent: now + rtt,
// More than cur_cwnd to increase cwnd
size: 8000,
+ delivered: 0,
+ delivered_time: now,
+ first_sent_time: now,
+ is_app_limited: false,
+ rtt: Duration::ZERO,
}];
// Ack more than cwnd bytes with rtt=100ms
diff --git a/src/stream.rs b/src/stream.rs
index dfb9b0d..80e174f 100644
--- a/src/stream.rs
+++ b/src/stream.rs
@@ -36,9 +36,12 @@ use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
+use std::time;
+
use crate::Error;
use crate::Result;
+use crate::flowcontrol;
use crate::ranges;
const DEFAULT_URGENCY: u8 = 127;
@@ -49,18 +52,57 @@ const SEND_BUFFER_SIZE: usize = 5;
#[cfg(not(test))]
const SEND_BUFFER_SIZE: usize = 4096;
+// The default size of the receiver stream flow control window.
+const DEFAULT_STREAM_WINDOW: u64 = 32 * 1024;
+
+/// The maximum size of the receiver stream flow control window.
+pub const MAX_STREAM_WINDOW: u64 = 16 * 1024 * 1024;
+
+/// A simple no-op hasher for Stream IDs.
+///
+/// The QUIC protocol and quiche library guarantees stream ID uniqueness, so
+/// we can save effort by avoiding using a more complicated algorithm.
+#[derive(Default)]
+pub struct StreamIdHasher {
+ id: u64,
+}
+
+impl std::hash::Hasher for StreamIdHasher {
+ #[inline]
+ fn finish(&self) -> u64 {
+ self.id
+ }
+
+ #[inline]
+ fn write_u64(&mut self, id: u64) {
+ self.id = id;
+ }
+
+ #[inline]
+ fn write(&mut self, _: &[u8]) {
+ // We need a default write() for the trait but stream IDs will always
+ // be a u64 so we just delegate to write_u64.
+ unimplemented!()
+ }
+}
+
+type BuildStreamIdHasher = std::hash::BuildHasherDefault<StreamIdHasher>;
+
+pub type StreamIdHashMap<V> = HashMap<u64, V, BuildStreamIdHasher>;
+pub type StreamIdHashSet = HashSet<u64, BuildStreamIdHasher>;
+
/// Keeps track of QUIC streams and enforces stream limits.
#[derive(Default)]
pub struct StreamMap {
/// Map of streams indexed by stream ID.
- streams: HashMap<u64, Stream>,
+ streams: StreamIdHashMap<Stream>,
/// Set of streams that were completed and garbage collected.
///
/// Instead of keeping the full stream state forever, we collect completed
/// streams to save memory, but we still need to keep track of previously
/// created streams, to prevent peers from re-creating them.
- collected: HashSet<u64>,
+ collected: StreamIdHashSet,
/// Peer's maximum bidirectional stream count limit.
peer_max_streams_bidi: u64,
@@ -104,38 +146,43 @@ pub struct StreamMap {
/// Set of stream IDs corresponding to streams that have outstanding data
/// to read. This is used to generate a `StreamIter` of streams without
/// having to iterate over the full list of streams.
- readable: HashSet<u64>,
+ readable: StreamIdHashSet,
/// Set of stream IDs corresponding to streams that have enough flow control
/// capacity to be written to, and is not finished. This is used to generate
/// a `StreamIter` of streams without having to iterate over the full list
/// of streams.
- writable: HashSet<u64>,
+ writable: StreamIdHashSet,
/// Set of stream IDs corresponding to streams that are almost out of flow
/// control credit and need to send MAX_STREAM_DATA. This is used to
/// generate a `StreamIter` of streams without having to iterate over the
/// full list of streams.
- almost_full: HashSet<u64>,
+ almost_full: StreamIdHashSet,
/// Set of stream IDs corresponding to streams that are blocked. The value
/// of the map elements represents the offset of the stream at which the
/// blocking occurred.
- blocked: HashMap<u64, u64>,
+ blocked: StreamIdHashMap<u64>,
/// Set of stream IDs corresponding to streams that are reset. The value
/// of the map elements is a tuple of the error code and final size values
/// to include in the RESET_STREAM frame.
- reset: HashMap<u64, (u64, u64)>,
+ reset: StreamIdHashMap<(u64, u64)>,
/// Set of stream IDs corresponding to streams that are shutdown on the
/// receive side, and need to send a STOP_SENDING frame. The value of the
/// map elements is the error code to include in the STOP_SENDING frame.
- stopped: HashMap<u64, u64>,
+ stopped: StreamIdHashMap<u64>,
+
+ /// The maximum size of a stream window.
+ max_stream_window: u64,
}
impl StreamMap {
- pub fn new(max_streams_bidi: u64, max_streams_uni: u64) -> StreamMap {
+ pub fn new(
+ max_streams_bidi: u64, max_streams_uni: u64, max_stream_window: u64,
+ ) -> StreamMap {
StreamMap {
local_max_streams_bidi: max_streams_bidi,
local_max_streams_bidi_next: max_streams_bidi,
@@ -143,6 +190,8 @@ impl StreamMap {
local_max_streams_uni: max_streams_uni,
local_max_streams_uni_next: max_streams_uni,
+ max_stream_window,
+
..StreamMap::default()
}
}
@@ -248,7 +297,13 @@ impl StreamMap {
},
};
- let s = Stream::new(max_rx_data, max_tx_data, is_bidi(id), local);
+ let s = Stream::new(
+ max_rx_data,
+ max_tx_data,
+ is_bidi(id),
+ local,
+ self.max_stream_window,
+ );
v.insert(s)
},
@@ -417,6 +472,11 @@ impl StreamMap {
self.local_max_streams_bidi = self.local_max_streams_bidi_next;
}
+ /// Returns the current max_streams_bidi limit.
+ pub fn max_streams_bidi(&self) -> u64 {
+ self.local_max_streams_bidi
+ }
+
/// Returns the new max_streams_bidi limit.
pub fn max_streams_bidi_next(&mut self) -> u64 {
self.local_max_streams_bidi_next
@@ -495,6 +555,11 @@ impl StreamMap {
self.stopped.iter()
}
+ /// Returns true if the stream has been collected.
+ pub fn is_collected(&self, stream_id: u64) -> bool {
+ self.collected.contains(&stream_id)
+ }
+
/// Returns true if there are any streams that have data to write.
pub fn has_flushable(&self) -> bool {
!self.flushable.is_empty()
@@ -578,9 +643,10 @@ impl Stream {
/// Creates a new stream with the given flow control limits.
pub fn new(
max_rx_data: u64, max_tx_data: u64, bidi: bool, local: bool,
+ max_window: u64,
) -> Stream {
Stream {
- recv: RecvBuf::new(max_rx_data),
+ recv: RecvBuf::new(max_rx_data, max_window),
send: SendBuf::new(max_tx_data),
bidi,
local,
@@ -653,7 +719,7 @@ pub struct StreamIter {
impl StreamIter {
#[inline]
- fn from(streams: &HashSet<u64>) -> Self {
+ fn from(streams: &StreamIdHashSet) -> Self {
StreamIter {
streams: streams.iter().copied().collect(),
}
@@ -693,25 +759,28 @@ pub struct RecvBuf {
/// The total length of data received on this stream.
len: u64,
- /// The maximum offset the peer is allowed to send us.
- max_data: u64,
-
- /// The updated maximum offset the peer is allowed to send us.
- max_data_next: u64,
+ /// Receiver flow controller.
+ flow_control: flowcontrol::FlowControl,
/// The final stream offset received from the peer, if any.
fin_off: Option<u64>,
+ /// The error code received via RESET_STREAM.
+ error: Option<u64>,
+
/// Whether incoming data is validated but not buffered.
drain: bool,
}
impl RecvBuf {
/// Creates a new receive buffer.
- fn new(max_data: u64) -> RecvBuf {
+ fn new(max_data: u64, max_window: u64) -> RecvBuf {
RecvBuf {
- max_data,
- max_data_next: max_data,
+ flow_control: flowcontrol::FlowControl::new(
+ max_data,
+ cmp::min(max_data, DEFAULT_STREAM_WINDOW),
+ max_window,
+ ),
..RecvBuf::default()
}
}
@@ -722,7 +791,7 @@ impl RecvBuf {
/// as handling incoming data that overlaps data that is already in the
/// buffer.
pub fn write(&mut self, buf: RangeBuf) -> Result<()> {
- if buf.max_off() > self.max_data {
+ if buf.max_off() > self.max_data() {
return Err(Error::FlowControl);
}
@@ -777,34 +846,43 @@ impl RecvBuf {
}
}
- let mut tmp_buf = Some(buf);
-
- while let Some(mut buf) = tmp_buf {
- tmp_buf = None;
+ let mut tmp_bufs = VecDeque::with_capacity(2);
+ tmp_bufs.push_back(buf);
+ 'tmp: while let Some(mut buf) = tmp_bufs.pop_front() {
// Discard incoming data below current stream offset. Bytes up to
// `self.off` have already been received so we should not buffer
// them again. This is also important to make sure `ready()` doesn't
// get stuck when a buffer with lower offset than the stream's is
// buffered.
- if self.off > buf.off() {
- buf = buf.split_off((self.off - buf.off()) as usize);
+ if self.off_front() > buf.off() {
+ buf = buf.split_off((self.off_front() - buf.off()) as usize);
}
- for b in &self.data {
- // New buffer is fully contained in existing buffer.
- if buf.off() >= b.off() && buf.max_off() <= b.max_off() {
- return Ok(());
- }
-
- // New buffer's start overlaps existing buffer.
- if buf.off() >= b.off() && buf.off() < b.max_off() {
- buf = buf.split_off((b.max_off() - buf.off()) as usize);
- }
-
- // New buffer's end overlaps existing buffer.
- if buf.off() < b.off() && buf.max_off() > b.off() {
- tmp_buf = Some(buf.split_off((b.off() - buf.off()) as usize));
+ // Handle overlapping data. If the incoming data's starting offset
+ // is above the previous maximum received offset, there is clearly
+ // no overlap so this logic can be skipped. However do still try to
+ // merge an empty final buffer (i.e. an empty buffer with the fin
+ // flag set, which is the only kind of empty buffer that should
+ // reach this point).
+ if buf.off() < self.max_off() || buf.is_empty() {
+ for b in &self.data {
+ // New buffer is fully contained in existing buffer.
+ if buf.off() >= b.off() && buf.max_off() <= b.max_off() {
+ continue 'tmp;
+ }
+
+ // New buffer's start overlaps existing buffer.
+ if buf.off() >= b.off() && buf.off() < b.max_off() {
+ buf = buf.split_off((b.max_off() - buf.off()) as usize);
+ }
+
+ // New buffer's end overlaps existing buffer.
+ if buf.off() < b.off() && buf.max_off() > b.off() {
+ tmp_bufs.push_back(
+ buf.split_off((b.off() - buf.off()) as usize),
+ );
+ }
}
}
@@ -835,6 +913,11 @@ impl RecvBuf {
return Err(Error::Done);
}
+ // The stream was reset, so return the error code instead.
+ if let Some(e) = self.error {
+ return Err(Error::StreamReset(e));
+ }
+
while cap > 0 && self.ready() {
let mut buf = match self.data.peek_mut() {
Some(v) => v,
@@ -861,13 +944,14 @@ impl RecvBuf {
std::collections::binary_heap::PeekMut::pop(buf);
}
- self.max_data_next = self.max_data_next.saturating_add(len as u64);
+ // Update consumed bytes for flow control.
+ self.flow_control.add_consumed(len as u64);
Ok((len, self.is_fin()))
}
/// Resets the stream at the given offset.
- pub fn reset(&mut self, final_size: u64) -> Result<usize> {
+ pub fn reset(&mut self, error_code: u64, final_size: u64) -> Result<usize> {
// Stream's size is already known, forbid changing it.
if let Some(fin_off) = self.fin_off {
if fin_off != final_size {
@@ -880,21 +964,52 @@ impl RecvBuf {
return Err(Error::FinalSize);
}
- self.fin_off = Some(final_size);
-
- // Return how many bytes need to be removed from the connection flow
+ // Calculate how many bytes need to be removed from the connection flow
// control.
- Ok((final_size - self.len) as usize)
+ let max_data_delta = final_size - self.len;
+
+ if self.error.is_some() {
+ return Ok(max_data_delta as usize);
+ }
+
+ self.error = Some(error_code);
+
+ // Clear all data already buffered.
+ self.off = final_size;
+
+ self.data.clear();
+
+ // In order to ensure the application is notified when the stream is
+ // reset, enqueue a zero-length buffer at the final size offset.
+ let buf = RangeBuf::from(b"", final_size, true);
+ self.write(buf)?;
+
+ Ok(max_data_delta as usize)
}
/// Commits the new max_data limit.
- pub fn update_max_data(&mut self) {
- self.max_data = self.max_data_next;
+ pub fn update_max_data(&mut self, now: time::Instant) {
+ self.flow_control.update_max_data(now);
}
/// Return the new max_data limit.
pub fn max_data_next(&mut self) -> u64 {
- self.max_data_next
+ self.flow_control.max_data_next()
+ }
+
+ /// Return the current flow control limit.
+ fn max_data(&self) -> u64 {
+ self.flow_control.max_data()
+ }
+
+ /// Return the current window.
+ pub fn window(&self) -> u64 {
+ self.flow_control.window()
+ }
+
+ /// Autotune the window size.
+ pub fn autotune_window(&mut self, now: time::Instant, rtt: time::Duration) {
+ self.flow_control.autotune_window(now, rtt);
}
/// Shuts down receiving data.
@@ -913,18 +1028,13 @@ impl RecvBuf {
}
/// Returns the lowest offset of data buffered.
- #[allow(dead_code)]
pub fn off_front(&self) -> u64 {
self.off
}
/// Returns true if we need to update the local flow control limit.
pub fn almost_full(&self) -> bool {
- // Send MAX_STREAM_DATA when the new limit is at least double the
- // amount of data that can be received before blocking.
- self.fin_off.is_none() &&
- self.max_data_next != self.max_data &&
- self.max_data_next / 2 > self.max_data - self.len
+ self.fin_off.is_none() && self.flow_control.should_update_max_data()
}
/// Returns the largest offset ever received.
@@ -982,6 +1092,9 @@ pub struct SendBuf {
/// The maximum offset we are allowed to send to the peer.
max_data: u64,
+ /// The last offset the stream was blocked at, if any.
+ blocked_at: Option<u64>,
+
/// The final stream offset written to the stream, if any.
fin_off: Option<u64>,
@@ -1097,6 +1210,7 @@ impl SendBuf {
}
let buf_len = cmp::min(buf.len(), out_len);
+ let partial = buf_len < buf.len();
// Copy data to the output buffer.
let out_pos = (next_off - out_off) as usize;
@@ -1109,15 +1223,13 @@ impl SendBuf {
next_off = buf.off() + buf_len as u64;
- if !buf.is_empty() && buf_len < buf.len() {
- buf.consume(buf_len);
+ buf.consume(buf_len);
+ if partial {
// We reached the maximum capacity, so end here.
break;
}
- buf.consume(buf_len);
-
self.pos += 1;
}
@@ -1137,6 +1249,16 @@ impl SendBuf {
self.max_data = cmp::max(self.max_data, max_data);
}
+ /// Updates the last offset the stream was blocked at, if any.
+ pub fn update_blocked_at(&mut self, blocked_at: Option<u64>) {
+ self.blocked_at = blocked_at;
+ }
+
+ /// The last offset the stream was blocked at, if any.
+ pub fn blocked_at(&self) -> Option<u64> {
+ self.blocked_at
+ }
+
/// Increments the acked data offset.
pub fn ack(&mut self, off: u64, len: usize) {
self.acked.insert(off..off + len as u64);
@@ -1235,8 +1357,11 @@ impl SendBuf {
}
/// Resets the stream at the current offset and clears all buffered data.
- pub fn reset(&mut self) -> Result<u64> {
- self.write(b"", true)?;
+ pub fn reset(&mut self) -> Result<(u64, u64)> {
+ let unsent_off = self.off_front();
+ let unsent_len = self.off_back() - unsent_off;
+
+ self.fin_off = Some(unsent_off);
// Drop all buffered data.
self.data.clear();
@@ -1246,27 +1371,28 @@ impl SendBuf {
self.pos = 0;
self.len = 0;
+ self.off = unsent_off;
- Ok(self.fin_off.unwrap())
+ Ok((self.fin_off.unwrap(), unsent_len))
}
/// Resets the streams and records the received error code.
///
/// Calling this again after the first time has no effect.
- pub fn stop(&mut self, error_code: u64) -> Result<u64> {
+ pub fn stop(&mut self, error_code: u64) -> Result<(u64, u64)> {
if self.error.is_some() {
return Err(Error::Done);
}
- let fin_off = self.reset()?;
+ let (fin_off, unsent) = self.reset()?;
self.error = Some(error_code);
- Ok(fin_off)
+ Ok((fin_off, unsent))
}
/// Shuts down sending data.
- pub fn shutdown(&mut self) -> Result<u64> {
+ pub fn shutdown(&mut self) -> Result<(u64, u64)> {
if self.shutdown {
return Err(Error::Done);
}
@@ -1277,7 +1403,6 @@ impl SendBuf {
}
/// Returns the largest offset of data buffered.
- #[allow(dead_code)]
pub fn off_back(&self) -> u64 {
self.off
}
@@ -1305,7 +1430,7 @@ impl SendBuf {
/// Returns true if all data in the stream has been sent.
///
- /// This happens when the stream's send final size is knwon, and the
+ /// This happens when the stream's send final size is known, and the
/// application has already written data up to that point.
pub fn is_fin(&self) -> bool {
if self.fin_off == Some(self.off) {
@@ -1379,7 +1504,7 @@ impl SendBuf {
pub struct RangeBuf {
/// The internal buffer holding the data.
///
- /// To avoid neeless allocations when a RangeBuf is split, this field is
+ /// To avoid needless allocations when a RangeBuf is split, this field is
/// reference-counted and can be shared between multiple RangeBuf objects,
/// and sliced using the `start` and `len` values.
data: Arc<Vec<u8>>,
@@ -1445,12 +1570,12 @@ impl RangeBuf {
/// Splits the buffer into two at the given index.
pub fn split_off(&mut self, at: usize) -> RangeBuf {
- if at > self.len {
- panic!(
- "`at` split index (is {}) should be <= len (is {})",
- at, self.len
- );
- }
+ assert!(
+ at <= self.len,
+ "`at` split index (is {}) should be <= len (is {})",
+ at,
+ self.len
+ );
let buf = RangeBuf {
data: self.data.clone(),
@@ -1502,7 +1627,7 @@ mod tests {
#[test]
fn empty_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1512,7 +1637,7 @@ mod tests {
#[test]
fn empty_stream_frame() {
- let mut recv = RecvBuf::new(15);
+ let mut recv = RecvBuf::new(15, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let buf = RangeBuf::from(b"hello", 0, false);
@@ -1568,7 +1693,7 @@ mod tests {
#[test]
fn ordered_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1605,7 +1730,7 @@ mod tests {
#[test]
fn split_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1645,7 +1770,7 @@ mod tests {
#[test]
fn incomplete_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1673,7 +1798,7 @@ mod tests {
#[test]
fn zero_len_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1701,7 +1826,7 @@ mod tests {
#[test]
fn past_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1740,7 +1865,7 @@ mod tests {
#[test]
fn fully_overlapping_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1771,7 +1896,7 @@ mod tests {
#[test]
fn fully_overlapping_read2() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1802,7 +1927,7 @@ mod tests {
#[test]
fn fully_overlapping_read3() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1833,7 +1958,7 @@ mod tests {
#[test]
fn fully_overlapping_read_multi() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1870,7 +1995,7 @@ mod tests {
#[test]
fn overlapping_start_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1900,7 +2025,7 @@ mod tests {
#[test]
fn overlapping_end_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1929,8 +2054,92 @@ mod tests {
}
#[test]
+ fn overlapping_end_twice_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"he", 0, false);
+ let second = RangeBuf::from(b"ow", 4, false);
+ let third = RangeBuf::from(b"rl", 7, false);
+ let fourth = RangeBuf::from(b"helloworld", 0, true);
+
+ assert!(recv.write(third).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.write(second).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 2);
+
+ assert!(recv.write(first).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 3);
+
+ assert!(recv.write(fourth).is_ok());
+ assert_eq!(recv.len, 10);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 6);
+
+ let (len, fin) = recv.emit(&mut buf).unwrap();
+ assert_eq!(len, 10);
+ assert_eq!(fin, true);
+ assert_eq!(&buf[..len], b"helloworld");
+ assert_eq!(recv.len, 10);
+ assert_eq!(recv.off, 10);
+
+ assert_eq!(recv.emit(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn overlapping_end_twice_and_contained_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"hellow", 0, false);
+ let second = RangeBuf::from(b"barfoo", 10, true);
+ let third = RangeBuf::from(b"rl", 7, false);
+ let fourth = RangeBuf::from(b"elloworldbarfoo", 1, true);
+
+ assert!(recv.write(third).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.write(second).is_ok());
+ assert_eq!(recv.len, 16);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 2);
+
+ assert!(recv.write(first).is_ok());
+ assert_eq!(recv.len, 16);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 3);
+
+ assert!(recv.write(fourth).is_ok());
+ assert_eq!(recv.len, 16);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 5);
+
+ let (len, fin) = recv.emit(&mut buf).unwrap();
+ assert_eq!(len, 16);
+ assert_eq!(fin, true);
+ assert_eq!(&buf[..len], b"helloworldbarfoo");
+ assert_eq!(recv.len, 16);
+ assert_eq!(recv.off, 16);
+
+ assert_eq!(recv.emit(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
fn partially_multi_overlapping_reordered_read() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1967,7 +2176,7 @@ mod tests {
#[test]
fn partially_multi_overlapping_reordered_read2() {
- let mut recv = RecvBuf::new(std::u64::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX, DEFAULT_STREAM_WINDOW);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -2257,7 +2466,7 @@ mod tests {
#[test]
fn recv_flow_control() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let mut buf = [0; 32];
@@ -2278,7 +2487,7 @@ mod tests {
assert!(stream.recv.almost_full());
- stream.recv.update_max_data();
+ stream.recv.update_max_data(time::Instant::now());
assert_eq!(stream.recv.max_data_next(), 25);
assert!(!stream.recv.almost_full());
@@ -2288,7 +2497,7 @@ mod tests {
#[test]
fn recv_past_fin() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
@@ -2300,7 +2509,7 @@ mod tests {
#[test]
fn recv_fin_dup() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
@@ -2318,7 +2527,7 @@ mod tests {
#[test]
fn recv_fin_change() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
@@ -2330,7 +2539,7 @@ mod tests {
#[test]
fn recv_fin_lower_than_received() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
@@ -2342,7 +2551,7 @@ mod tests {
#[test]
fn recv_fin_flow_control() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let mut buf = [0; 32];
@@ -2362,55 +2571,55 @@ mod tests {
#[test]
fn recv_fin_reset_mismatch() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
assert_eq!(stream.recv.write(first), Ok(()));
- assert_eq!(stream.recv.reset(10), Err(Error::FinalSize));
+ assert_eq!(stream.recv.reset(0, 10), Err(Error::FinalSize));
}
#[test]
fn recv_reset_dup() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, false);
assert_eq!(stream.recv.write(first), Ok(()));
- assert_eq!(stream.recv.reset(5), Ok(0));
- assert_eq!(stream.recv.reset(5), Ok(0));
+ assert_eq!(stream.recv.reset(0, 5), Ok(0));
+ assert_eq!(stream.recv.reset(0, 5), Ok(0));
}
#[test]
fn recv_reset_change() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, false);
assert_eq!(stream.recv.write(first), Ok(()));
- assert_eq!(stream.recv.reset(5), Ok(0));
- assert_eq!(stream.recv.reset(10), Err(Error::FinalSize));
+ assert_eq!(stream.recv.reset(0, 5), Ok(0));
+ assert_eq!(stream.recv.reset(0, 10), Err(Error::FinalSize));
}
#[test]
fn recv_reset_lower_than_received() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, false);
assert_eq!(stream.recv.write(first), Ok(()));
- assert_eq!(stream.recv.reset(4), Err(Error::FinalSize));
+ assert_eq!(stream.recv.reset(0, 4), Err(Error::FinalSize));
}
#[test]
fn send_flow_control() {
let mut buf = [0; 25];
- let mut stream = Stream::new(0, 15, true, true);
+ let mut stream = Stream::new(0, 15, true, true, DEFAULT_STREAM_WINDOW);
let first = b"hello";
let second = b"world";
@@ -2453,7 +2662,7 @@ mod tests {
#[test]
fn send_past_fin() {
- let mut stream = Stream::new(0, 15, true, true);
+ let mut stream = Stream::new(0, 15, true, true, DEFAULT_STREAM_WINDOW);
let first = b"hello";
let second = b"world";
@@ -2469,7 +2678,7 @@ mod tests {
#[test]
fn send_fin_dup() {
- let mut stream = Stream::new(0, 15, true, true);
+ let mut stream = Stream::new(0, 15, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", true), Ok(5));
assert!(stream.send.is_fin());
@@ -2480,7 +2689,7 @@ mod tests {
#[test]
fn send_undo_fin() {
- let mut stream = Stream::new(0, 15, true, true);
+ let mut stream = Stream::new(0, 15, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", true), Ok(5));
assert!(stream.send.is_fin());
@@ -2495,7 +2704,7 @@ mod tests {
fn send_fin_max_data_match() {
let mut buf = [0; 15];
- let mut stream = Stream::new(0, 15, true, true);
+ let mut stream = Stream::new(0, 15, true, true, DEFAULT_STREAM_WINDOW);
let slice = b"hellohellohello";
@@ -2511,7 +2720,7 @@ mod tests {
fn send_fin_zero_length() {
let mut buf = [0; 5];
- let mut stream = Stream::new(0, 15, true, true);
+ let mut stream = Stream::new(0, 15, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", false), Ok(5));
assert_eq!(stream.send.write(b"", true), Ok(0));
@@ -2527,7 +2736,7 @@ mod tests {
fn send_ack() {
let mut buf = [0; 5];
- let mut stream = Stream::new(0, 15, true, true);
+ let mut stream = Stream::new(0, 15, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", false), Ok(5));
assert_eq!(stream.send.write(b"world", false), Ok(5));
@@ -2557,7 +2766,7 @@ mod tests {
fn send_ack_reordering() {
let mut buf = [0; 5];
- let mut stream = Stream::new(0, 15, true, true);
+ let mut stream = Stream::new(0, 15, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", false), Ok(5));
assert_eq!(stream.send.write(b"world", false), Ok(5));
@@ -2594,7 +2803,7 @@ mod tests {
#[test]
fn recv_data_below_off() {
- let mut stream = Stream::new(15, 0, true, true);
+ let mut stream = Stream::new(15, 0, true, true, DEFAULT_STREAM_WINDOW);
let first = RangeBuf::from(b"hello", 0, false);
@@ -2616,7 +2825,7 @@ mod tests {
#[test]
fn stream_complete() {
- let mut stream = Stream::new(30, 30, true, true);
+ let mut stream = Stream::new(30, 30, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", false), Ok(5));
assert_eq!(stream.send.write(b"world", false), Ok(5));
@@ -2659,7 +2868,7 @@ mod tests {
fn send_fin_zero_length_output() {
let mut buf = [0; 5];
- let mut stream = Stream::new(0, 15, true, true);
+ let mut stream = Stream::new(0, 15, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", false), Ok(5));
assert_eq!(stream.send.off_front(), 0);
@@ -2684,7 +2893,7 @@ mod tests {
fn send_emit() {
let mut buf = [0; 5];
- let mut stream = Stream::new(0, 20, true, true);
+ let mut stream = Stream::new(0, 20, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", false), Ok(5));
assert_eq!(stream.send.write(b"world", false), Ok(5));
@@ -2736,7 +2945,7 @@ mod tests {
fn send_emit_ack() {
let mut buf = [0; 5];
- let mut stream = Stream::new(0, 20, true, true);
+ let mut stream = Stream::new(0, 20, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", false), Ok(5));
assert_eq!(stream.send.write(b"world", false), Ok(5));
@@ -2803,7 +3012,7 @@ mod tests {
fn send_emit_retransmit() {
let mut buf = [0; 5];
- let mut stream = Stream::new(0, 20, true, true);
+ let mut stream = Stream::new(0, 20, true, true, DEFAULT_STREAM_WINDOW);
assert_eq!(stream.send.write(b"hello", false), Ok(5));
assert_eq!(stream.send.write(b"world", false), Ok(5));
diff --git a/src/tls.rs b/src/tls.rs
index ed7a5bf..0031eee 100644
--- a/src/tls.rs
+++ b/src/tls.rs
@@ -43,7 +43,6 @@ use crate::Connection;
use crate::ConnectionError;
use crate::crypto;
-use crate::octets;
use crate::packet;
const TLS1_3_VERSION: u16 = 0x0304;
@@ -124,7 +123,8 @@ struct SSL_QUIC_METHOD {
}
lazy_static::lazy_static! {
- static ref QUICHE_EX_DATA_INDEX: c_int = unsafe {
+ /// BoringSSL Extra Data Index for Quiche Connections
+ pub static ref QUICHE_EX_DATA_INDEX: c_int = unsafe {
SSL_get_ex_new_index(0, ptr::null(), ptr::null(), ptr::null(), ptr::null())
};
}
@@ -154,9 +154,19 @@ impl Context {
}
}
+ #[cfg(feature = "boringssl-boring-crate")]
+ pub fn from_boring(ssl_ctx: boring::ssl::SslContext) -> Context {
+ use foreign_types_shared::ForeignType;
+
+ let mut ctx = Context(ssl_ctx.into_ptr() as _);
+ ctx.set_session_callback();
+
+ ctx
+ }
+
pub fn new_handshake(&mut self) -> Result<Handshake> {
unsafe {
- let ssl = SSL_new(self.as_ptr());
+ let ssl = SSL_new(self.as_mut_ptr());
Ok(Handshake(ssl))
}
}
@@ -165,7 +175,7 @@ impl Context {
let file = ffi::CString::new(file).map_err(|_| Error::TlsFail)?;
map_result(unsafe {
SSL_CTX_load_verify_locations(
- self.as_ptr(),
+ self.as_mut_ptr(),
file.as_ptr(),
std::ptr::null(),
)
@@ -178,7 +188,7 @@ impl Context {
let path = ffi::CString::new(path).map_err(|_| Error::TlsFail)?;
map_result(unsafe {
SSL_CTX_load_verify_locations(
- self.as_ptr(),
+ self.as_mut_ptr(),
std::ptr::null(),
path.as_ptr(),
)
@@ -188,20 +198,20 @@ impl Context {
pub fn use_certificate_chain_file(&mut self, file: &str) -> Result<()> {
let cstr = ffi::CString::new(file).map_err(|_| Error::TlsFail)?;
map_result(unsafe {
- SSL_CTX_use_certificate_chain_file(self.as_ptr(), cstr.as_ptr())
+ SSL_CTX_use_certificate_chain_file(self.as_mut_ptr(), cstr.as_ptr())
})
}
pub fn use_privkey_file(&mut self, file: &str) -> Result<()> {
let cstr = ffi::CString::new(file).map_err(|_| Error::TlsFail)?;
map_result(unsafe {
- SSL_CTX_use_PrivateKey_file(self.as_ptr(), cstr.as_ptr(), 1)
+ SSL_CTX_use_PrivateKey_file(self.as_mut_ptr(), cstr.as_ptr(), 1)
})
}
#[cfg(not(windows))]
fn load_ca_certs(&mut self) -> Result<()> {
- unsafe { map_result(SSL_CTX_set_default_verify_paths(self.as_ptr())) }
+ unsafe { map_result(SSL_CTX_set_default_verify_paths(self.as_mut_ptr())) }
}
#[cfg(windows)]
@@ -216,7 +226,7 @@ impl Context {
return Err(Error::TlsFail);
}
- let ctx_store = SSL_CTX_get_cert_store(self.as_ptr());
+ let ctx_store = SSL_CTX_get_cert_store(self.as_mut_ptr());
if ctx_store.is_null() {
return Err(Error::TlsFail);
}
@@ -258,11 +268,11 @@ impl Context {
// This is needed to enable the session callback on the client. On
// the server it doesn't do anything.
SSL_CTX_set_session_cache_mode(
- self.as_ptr(),
+ self.as_mut_ptr(),
0x0001, // SSL_SESS_CACHE_CLIENT
);
- SSL_CTX_sess_set_new_cb(self.as_ptr(), new_session);
+ SSL_CTX_sess_set_new_cb(self.as_mut_ptr(), new_session);
};
}
@@ -274,13 +284,13 @@ impl Context {
};
unsafe {
- SSL_CTX_set_verify(self.as_ptr(), mode, ptr::null());
+ SSL_CTX_set_verify(self.as_mut_ptr(), mode, ptr::null());
}
}
pub fn enable_keylog(&mut self) {
unsafe {
- SSL_CTX_set_keylog_callback(self.as_ptr(), keylog);
+ SSL_CTX_set_keylog_callback(self.as_mut_ptr(), keylog);
}
}
@@ -295,7 +305,7 @@ impl Context {
// Configure ALPN for servers.
unsafe {
SSL_CTX_set_alpn_select_cb(
- self.as_ptr(),
+ self.as_mut_ptr(),
select_alpn,
ptr::null_mut(),
);
@@ -303,13 +313,21 @@ impl Context {
// Configure ALPN for clients.
map_result_zero_is_success(unsafe {
- SSL_CTX_set_alpn_protos(self.as_ptr(), protos.as_ptr(), protos.len())
+ SSL_CTX_set_alpn_protos(
+ self.as_mut_ptr(),
+ protos.as_ptr(),
+ protos.len(),
+ )
})
}
pub fn set_ticket_key(&mut self, key: &[u8]) -> Result<()> {
map_result(unsafe {
- SSL_CTX_set_tlsext_ticket_keys(self.as_ptr(), key.as_ptr(), key.len())
+ SSL_CTX_set_tlsext_ticket_keys(
+ self.as_mut_ptr(),
+ key.as_ptr(),
+ key.len(),
+ )
})
}
@@ -317,20 +335,26 @@ impl Context {
let enabled = if enabled { 1 } else { 0 };
unsafe {
- SSL_CTX_set_early_data_enabled(self.as_ptr(), enabled);
+ SSL_CTX_set_early_data_enabled(self.as_mut_ptr(), enabled);
}
}
- fn as_ptr(&self) -> *mut SSL_CTX {
+ fn as_mut_ptr(&mut self) -> *mut SSL_CTX {
self.0
}
}
+// NOTE: These traits are not automatically implemented for Context due to the
+// raw pointer it wraps. However, the underlying data is not aliased (as Context
+// should be its only owner), and there is no interior mutability, as the
+// pointer is not accessed directly outside of this module, and the Context
+// object API should preserve Rust's borrowing guarantees.
unsafe impl std::marker::Send for Context {}
+unsafe impl std::marker::Sync for Context {}
impl Drop for Context {
fn drop(&mut self) {
- unsafe { SSL_CTX_free(self.as_ptr()) }
+ unsafe { SSL_CTX_free(self.as_mut_ptr()) }
}
}
@@ -347,10 +371,8 @@ impl Handshake {
unsafe { SSL_get_error(self.as_ptr(), ret_code) }
}
- pub fn init(&self, conn: &Connection) -> Result<()> {
- self.set_state(conn.is_server);
-
- self.set_ex_data(*QUICHE_EX_DATA_INDEX, conn)?;
+ pub fn init(&mut self, is_server: bool) -> Result<()> {
+ self.set_state(is_server);
self.set_min_proto_version(TLS1_3_VERSION);
self.set_max_proto_version(TLS1_3_VERSION);
@@ -366,80 +388,90 @@ impl Handshake {
Ok(())
}
- pub fn use_legacy_codepoint(&self, use_legacy: bool) {
+ pub fn use_legacy_codepoint(&mut self, use_legacy: bool) {
unsafe {
- SSL_set_quic_use_legacy_codepoint(self.as_ptr(), use_legacy as c_int);
+ SSL_set_quic_use_legacy_codepoint(
+ self.as_mut_ptr(),
+ use_legacy as c_int,
+ );
}
}
- pub fn set_state(&self, is_server: bool) {
+ pub fn set_state(&mut self, is_server: bool) {
unsafe {
if is_server {
- SSL_set_accept_state(self.as_ptr());
+ SSL_set_accept_state(self.as_mut_ptr());
} else {
- SSL_set_connect_state(self.as_ptr());
+ SSL_set_connect_state(self.as_mut_ptr());
}
}
}
- pub fn set_ex_data<T>(&self, idx: c_int, data: &T) -> Result<()> {
+ pub fn set_ex_data<T>(&mut self, idx: c_int, data: *const T) -> Result<()> {
map_result(unsafe {
- let ptr = data as *const T as *const c_void;
- SSL_set_ex_data(self.as_ptr(), idx, ptr)
+ let ptr = data as *const c_void;
+ SSL_set_ex_data(self.as_mut_ptr(), idx, ptr)
})
}
- pub fn set_quic_method(&self) -> Result<()> {
+ pub fn set_quic_method(&mut self) -> Result<()> {
map_result(unsafe {
- SSL_set_quic_method(self.as_ptr(), &QUICHE_STREAM_METHOD)
+ SSL_set_quic_method(self.as_mut_ptr(), &QUICHE_STREAM_METHOD)
})
}
- pub fn set_quic_early_data_context(&self, context: &[u8]) -> Result<()> {
+ pub fn set_quic_early_data_context(&mut self, context: &[u8]) -> Result<()> {
map_result(unsafe {
SSL_set_quic_early_data_context(
- self.as_ptr(),
+ self.as_mut_ptr(),
context.as_ptr(),
context.len(),
)
})
}
- pub fn set_min_proto_version(&self, version: u16) {
- unsafe { SSL_set_min_proto_version(self.as_ptr(), version) }
+ pub fn set_min_proto_version(&mut self, version: u16) {
+ unsafe { SSL_set_min_proto_version(self.as_mut_ptr(), version) }
}
- pub fn set_max_proto_version(&self, version: u16) {
- unsafe { SSL_set_max_proto_version(self.as_ptr(), version) }
+ pub fn set_max_proto_version(&mut self, version: u16) {
+ unsafe { SSL_set_max_proto_version(self.as_mut_ptr(), version) }
}
- pub fn set_quiet_shutdown(&self, mode: bool) {
- unsafe { SSL_set_quiet_shutdown(self.as_ptr(), if mode { 1 } else { 0 }) }
+ pub fn set_quiet_shutdown(&mut self, mode: bool) {
+ unsafe {
+ SSL_set_quiet_shutdown(self.as_mut_ptr(), if mode { 1 } else { 0 })
+ }
}
- pub fn set_host_name(&self, name: &str) -> Result<()> {
+ pub fn set_host_name(&mut self, name: &str) -> Result<()> {
let cstr = ffi::CString::new(name).map_err(|_| Error::TlsFail)?;
- map_result_ssl(self, unsafe {
- SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr())
- })?;
+ let rc =
+ unsafe { SSL_set_tlsext_host_name(self.as_mut_ptr(), cstr.as_ptr()) };
+ map_result_ssl(self, rc)?;
- let param = unsafe { SSL_get0_param(self.as_ptr()) };
+ let param = unsafe { SSL_get0_param(self.as_mut_ptr()) };
map_result(unsafe {
X509_VERIFY_PARAM_set1_host(param, cstr.as_ptr(), name.len())
})
}
- pub fn set_quic_transport_params(&self, buf: &[u8]) -> Result<()> {
- map_result_ssl(self, unsafe {
- SSL_set_quic_transport_params(self.as_ptr(), buf.as_ptr(), buf.len())
- })
+ pub fn set_quic_transport_params(&mut self, buf: &[u8]) -> Result<()> {
+ let rc = unsafe {
+ SSL_set_quic_transport_params(
+ self.as_mut_ptr(),
+ buf.as_ptr(),
+ buf.len(),
+ )
+ };
+ map_result_ssl(self, rc)
}
#[cfg(test)]
pub fn set_options(&mut self, opts: u32) {
unsafe {
- SSL_set_options(self.as_ptr(), opts);
+ SSL_set_options(self.as_mut_ptr(), opts);
}
}
@@ -473,7 +505,24 @@ impl Handshake {
unsafe { slice::from_raw_parts(ptr, len as usize) }
}
- pub fn set_session(&self, session: &[u8]) -> Result<()> {
+ pub fn server_name(&self) -> Option<&str> {
+ let s = unsafe {
+ let ptr = SSL_get_servername(
+ self.as_ptr(),
+ 0, // TLSEXT_NAMETYPE_host_name
+ );
+
+ if ptr.is_null() {
+ return None;
+ }
+
+ ffi::CStr::from_ptr(ptr)
+ };
+
+ s.to_str().ok()
+ }
+
+ pub fn set_session(&mut self, session: &[u8]) -> Result<()> {
unsafe {
let ctx = SSL_get_SSL_CTX(self.as_ptr());
@@ -488,31 +537,45 @@ impl Handshake {
return Err(Error::TlsFail);
}
- let rc = SSL_set_session(self.as_ptr(), session);
+ let rc = SSL_set_session(self.as_mut_ptr(), session);
SSL_SESSION_free(session);
map_result(rc)
}
}
- pub fn provide_data(&self, level: crypto::Level, buf: &[u8]) -> Result<()> {
- map_result_ssl(self, unsafe {
- SSL_provide_quic_data(self.as_ptr(), level, buf.as_ptr(), buf.len())
- })
+ pub fn provide_data(
+ &mut self, level: crypto::Level, buf: &[u8],
+ ) -> Result<()> {
+ let rc = unsafe {
+ SSL_provide_quic_data(
+ self.as_mut_ptr(),
+ level,
+ buf.as_ptr(),
+ buf.len(),
+ )
+ };
+ map_result_ssl(self, rc)
}
- pub fn do_handshake(&self) -> Result<()> {
- map_result_ssl(self, unsafe { SSL_do_handshake(self.as_ptr()) })
+ pub fn do_handshake(&mut self, ex_data: &mut ExData) -> Result<()> {
+ self.set_ex_data(*QUICHE_EX_DATA_INDEX, ex_data)?;
+ let rc = unsafe { SSL_do_handshake(self.as_mut_ptr()) };
+ self.set_ex_data::<Connection>(*QUICHE_EX_DATA_INDEX, std::ptr::null())?;
+
+ map_result_ssl(self, rc)
}
- pub fn process_post_handshake(&self) -> Result<()> {
- map_result_ssl(self, unsafe {
- SSL_process_quic_post_handshake(self.as_ptr())
- })
+ pub fn process_post_handshake(&mut self, ex_data: &mut ExData) -> Result<()> {
+ self.set_ex_data(*QUICHE_EX_DATA_INDEX, ex_data)?;
+ let rc = unsafe { SSL_process_quic_post_handshake(self.as_mut_ptr()) };
+ self.set_ex_data::<Connection>(*QUICHE_EX_DATA_INDEX, std::ptr::null())?;
+
+ map_result_ssl(self, rc)
}
- pub fn reset_early_data_reject(&self) {
- unsafe { SSL_reset_early_data_reject(self.as_ptr()) };
+ pub fn reset_early_data_reject(&mut self) {
+ unsafe { SSL_reset_early_data_reject(self.as_mut_ptr()) };
}
pub fn write_level(&self) -> crypto::Level {
@@ -534,7 +597,7 @@ impl Handshake {
}
let curve_name = SSL_get_curve_name(curve_id);
- match std::ffi::CStr::from_ptr(curve_name).to_str() {
+ match ffi::CStr::from_ptr(curve_name).to_str() {
Ok(v) => v,
Err(_) => return None,
@@ -552,7 +615,7 @@ impl Handshake {
}
let sigalg_name = SSL_get_signature_algorithm_name(sigalg_id, 1);
- match std::ffi::CStr::from_ptr(sigalg_name).to_str() {
+ match ffi::CStr::from_ptr(sigalg_name).to_str() {
Ok(v) => v,
Err(_) => return None,
@@ -562,7 +625,7 @@ impl Handshake {
Some(sigalg.to_string())
}
- pub fn peer_cert(&self) -> Option<Vec<u8>> {
+ pub fn peer_cert(&self) -> Option<&[u8]> {
let peer_cert = unsafe {
let chain =
map_result_ptr(SSL_get0_peer_certificates(self.as_ptr())).ok()?;
@@ -573,14 +636,14 @@ impl Handshake {
let buffer =
map_result_ptr(sk_value(chain, 0) as *const CRYPTO_BUFFER)
.ok()?;
+
let out_len = CRYPTO_BUFFER_len(buffer);
if out_len == 0 {
return None;
}
let out = CRYPTO_BUFFER_data(buffer);
- let der = slice::from_raw_parts(out, out_len as usize);
- der.to_vec()
+ slice::from_raw_parts(out, out_len as usize)
};
Some(peer_cert)
@@ -599,22 +662,49 @@ impl Handshake {
}
pub fn clear(&mut self) -> Result<()> {
- map_result_ssl(self, unsafe { SSL_clear(self.as_ptr()) })
+ let rc = unsafe { SSL_clear(self.as_mut_ptr()) };
+ map_result_ssl(self, rc)
+ }
+
+ fn as_ptr(&self) -> *const SSL {
+ self.0
}
- fn as_ptr(&self) -> *mut SSL {
+ fn as_mut_ptr(&mut self) -> *mut SSL {
self.0
}
}
+// NOTE: These traits are not automatically implemented for Handshake due to the
+// raw pointer it wraps. However, the underlying data is not aliased (as
+// Handshake should be its only owner), and there is no interior mutability, as
+// the pointer is not accessed directly outside of this module, and the
+// Handshake object API should preserve Rust's borrowing guarantees.
unsafe impl std::marker::Send for Handshake {}
+unsafe impl std::marker::Sync for Handshake {}
impl Drop for Handshake {
fn drop(&mut self) {
- unsafe { SSL_free(self.as_ptr()) }
+ unsafe { SSL_free(self.as_mut_ptr()) }
}
}
+pub struct ExData<'a> {
+ pub application_protos: &'a Vec<Vec<u8>>,
+
+ pub pkt_num_spaces: &'a mut [packet::PktNumSpace; packet::EPOCH_COUNT],
+
+ pub session: &'a mut Option<Vec<u8>>,
+
+ pub local_error: &'a mut Option<super::ConnectionError>,
+
+ pub keylog: Option<&'a mut Box<dyn std::io::Write + Send + Sync>>,
+
+ pub trace_id: &'a str,
+
+ pub is_server: bool,
+}
+
fn get_ex_data_from_ptr<'a, T>(ptr: *mut SSL, idx: c_int) -> Option<&'a mut T> {
unsafe {
let data = SSL_get_ex_data(ptr, idx) as *mut T;
@@ -639,23 +729,24 @@ extern fn set_read_secret(
ssl: *mut SSL, level: crypto::Level, cipher: *const SSL_CIPHER,
secret: *const u8, secret_len: usize,
) -> c_int {
- let conn =
- match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
- Some(v) => v,
+ let ex_data = match get_ex_data_from_ptr::<ExData>(ssl, *QUICHE_EX_DATA_INDEX)
+ {
+ Some(v) => v,
- None => return 0,
- };
+ None => return 0,
+ };
- trace!("{} set read secret lvl={:?}", conn.trace_id, level);
+ trace!("{} set read secret lvl={:?}", ex_data.trace_id, level);
let space = match level {
- crypto::Level::Initial => &mut conn.pkt_num_spaces[packet::EPOCH_INITIAL],
+ crypto::Level::Initial =>
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_INITIAL],
crypto::Level::ZeroRTT =>
- &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_APPLICATION],
crypto::Level::Handshake =>
- &mut conn.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
crypto::Level::OneRTT =>
- &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_APPLICATION],
};
let aead = match get_cipher_from_ptr(cipher) {
@@ -665,10 +756,10 @@ extern fn set_read_secret(
};
// 0-RTT read secrets are present only on the server.
- if level != crypto::Level::ZeroRTT || conn.is_server {
+ if level != crypto::Level::ZeroRTT || ex_data.is_server {
let secret = unsafe { slice::from_raw_parts(secret, secret_len) };
- let open = match crypto::Open::from_secret(aead, &secret) {
+ let open = match crypto::Open::from_secret(aead, secret) {
Ok(v) => v,
Err(_) => return 0,
@@ -689,23 +780,24 @@ extern fn set_write_secret(
ssl: *mut SSL, level: crypto::Level, cipher: *const SSL_CIPHER,
secret: *const u8, secret_len: usize,
) -> c_int {
- let conn =
- match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
- Some(v) => v,
+ let ex_data = match get_ex_data_from_ptr::<ExData>(ssl, *QUICHE_EX_DATA_INDEX)
+ {
+ Some(v) => v,
- None => return 0,
- };
+ None => return 0,
+ };
- trace!("{} set write secret lvl={:?}", conn.trace_id, level);
+ trace!("{} set write secret lvl={:?}", ex_data.trace_id, level);
let space = match level {
- crypto::Level::Initial => &mut conn.pkt_num_spaces[packet::EPOCH_INITIAL],
+ crypto::Level::Initial =>
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_INITIAL],
crypto::Level::ZeroRTT =>
- &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_APPLICATION],
crypto::Level::Handshake =>
- &mut conn.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
crypto::Level::OneRTT =>
- &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_APPLICATION],
};
let aead = match get_cipher_from_ptr(cipher) {
@@ -715,10 +807,10 @@ extern fn set_write_secret(
};
// 0-RTT write secrets are present only on the client.
- if level != crypto::Level::ZeroRTT || !conn.is_server {
+ if level != crypto::Level::ZeroRTT || !ex_data.is_server {
let secret = unsafe { slice::from_raw_parts(secret, secret_len) };
- let seal = match crypto::Seal::from_secret(aead, &secret) {
+ let seal = match crypto::Seal::from_secret(aead, secret) {
Ok(v) => v,
Err(_) => return 0,
@@ -733,16 +825,16 @@ extern fn set_write_secret(
extern fn add_handshake_data(
ssl: *mut SSL, level: crypto::Level, data: *const u8, len: usize,
) -> c_int {
- let conn =
- match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
- Some(v) => v,
+ let ex_data = match get_ex_data_from_ptr::<ExData>(ssl, *QUICHE_EX_DATA_INDEX)
+ {
+ Some(v) => v,
- None => return 0,
- };
+ None => return 0,
+ };
trace!(
"{} write message lvl={:?} len={}",
- conn.trace_id,
+ ex_data.trace_id,
level,
len
);
@@ -750,12 +842,13 @@ extern fn add_handshake_data(
let buf = unsafe { slice::from_raw_parts(data, len) };
let space = match level {
- crypto::Level::Initial => &mut conn.pkt_num_spaces[packet::EPOCH_INITIAL],
+ crypto::Level::Initial =>
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_INITIAL],
crypto::Level::ZeroRTT => unreachable!(),
crypto::Level::Handshake =>
- &mut conn.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
crypto::Level::OneRTT =>
- &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ &mut ex_data.pkt_num_spaces[packet::EPOCH_APPLICATION],
};
if space.crypto_stream.send.write(buf, false).is_err() {
@@ -773,22 +866,22 @@ extern fn flush_flight(_ssl: *mut SSL) -> c_int {
}
extern fn send_alert(ssl: *mut SSL, level: crypto::Level, alert: u8) -> c_int {
- let conn =
- match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
- Some(v) => v,
+ let ex_data = match get_ex_data_from_ptr::<ExData>(ssl, *QUICHE_EX_DATA_INDEX)
+ {
+ Some(v) => v,
- None => return 0,
- };
+ None => return 0,
+ };
trace!(
"{} send alert lvl={:?} alert={:x}",
- conn.trace_id,
+ ex_data.trace_id,
level,
alert
);
let error: u64 = TLS_ALERT_ERROR + u64::from(alert);
- conn.local_error = Some(ConnectionError {
+ *ex_data.local_error = Some(ConnectionError {
is_app: false,
error_code: error,
reason: Vec::new(),
@@ -798,14 +891,14 @@ extern fn send_alert(ssl: *mut SSL, level: crypto::Level, alert: u8) -> c_int {
}
extern fn keylog(ssl: *mut SSL, line: *const c_char) {
- let conn =
- match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
- Some(v) => v,
+ let ex_data = match get_ex_data_from_ptr::<ExData>(ssl, *QUICHE_EX_DATA_INDEX)
+ {
+ Some(v) => v,
- None => return,
- };
+ None => return,
+ };
- if let Some(keylog) = &mut conn.keylog {
+ if let Some(keylog) = &mut ex_data.keylog {
let data = unsafe { ffi::CStr::from_ptr(line).to_bytes() };
let mut full_line = Vec::with_capacity(data.len() + 1);
@@ -820,14 +913,14 @@ extern fn select_alpn(
ssl: *mut SSL, out: *mut *const u8, out_len: *mut u8, inp: *mut u8,
in_len: c_uint, _arg: *mut c_void,
) -> c_int {
- let conn =
- match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
- Some(v) => v,
+ let ex_data = match get_ex_data_from_ptr::<ExData>(ssl, *QUICHE_EX_DATA_INDEX)
+ {
+ Some(v) => v,
- None => return 3, // SSL_TLSEXT_ERR_NOACK
- };
+ None => return 3, // SSL_TLSEXT_ERR_NOACK
+ };
- if conn.application_protos.is_empty() {
+ if ex_data.application_protos.is_empty() {
return 3; // SSL_TLSEXT_ERR_NOACK
}
@@ -836,7 +929,7 @@ extern fn select_alpn(
});
while let Ok(proto) = protos.get_bytes_with_u8_length() {
- let found = conn.application_protos.iter().any(|expected| {
+ let found = ex_data.application_protos.iter().any(|expected| {
trace!(
"checking peer ALPN {:?} against {:?}",
std::str::from_utf8(proto.as_ref()),
@@ -865,14 +958,13 @@ extern fn select_alpn(
3 // SSL_TLSEXT_ERR_NOACK
}
-#[no_mangle]
extern fn new_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int {
- let conn =
- match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
- Some(v) => v,
+ let ex_data = match get_ex_data_from_ptr::<ExData>(ssl, *QUICHE_EX_DATA_INDEX)
+ {
+ Some(v) => v,
- None => return 0,
- };
+ None => return 0,
+ };
let handshake = Handshake(ssl);
let peer_params = handshake.quic_transport_params();
@@ -914,12 +1006,12 @@ extern fn new_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int {
return 0;
}
- if buffer.write(&peer_params).is_err() {
+ if buffer.write(peer_params).is_err() {
std::mem::forget(handshake);
return 0;
}
- conn.session = Some(buffer);
+ *ex_data.session = Some(buffer);
// Prevent handshake from being freed, as we still need it.
std::mem::forget(handshake);
@@ -948,7 +1040,7 @@ fn map_result_ptr<'a, T>(bssl_result: *const T) -> Result<&'a T> {
}
}
-fn map_result_ssl(ssl: &Handshake, bssl_result: c_int) -> Result<()> {
+fn map_result_ssl(ssl: &mut Handshake, bssl_result: c_int) -> Result<()> {
match bssl_result {
1 => Ok(()),
@@ -1082,7 +1174,7 @@ extern {
fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL;
- fn SSL_get_error(ssl: *mut SSL, ret_code: c_int) -> c_int;
+ fn SSL_get_error(ssl: *const SSL, ret_code: c_int) -> c_int;
fn SSL_set_accept_state(ssl: *mut SSL);
fn SSL_set_connect_state(ssl: *mut SSL);
@@ -1092,21 +1184,21 @@ extern {
fn SSL_set_ex_data(ssl: *mut SSL, idx: c_int, ptr: *const c_void) -> c_int;
fn SSL_get_ex_data(ssl: *mut SSL, idx: c_int) -> *mut c_void;
- fn SSL_get_current_cipher(ssl: *mut SSL) -> *const SSL_CIPHER;
+ fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER;
- fn SSL_get_curve_id(ssl: *mut SSL) -> u16;
+ fn SSL_get_curve_id(ssl: *const SSL) -> u16;
fn SSL_get_curve_name(curve: u16) -> *const c_char;
- fn SSL_get_peer_signature_algorithm(ssl: *mut SSL) -> u16;
+ fn SSL_get_peer_signature_algorithm(ssl: *const SSL) -> u16;
fn SSL_get_signature_algorithm_name(
sigalg: u16, include_curve: i32,
) -> *const c_char;
fn SSL_set_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int;
- fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX;
+ fn SSL_get_SSL_CTX(ssl: *const SSL) -> *mut SSL_CTX;
- fn SSL_get0_peer_certificates(ssl: *mut SSL) -> *const STACK_OF;
+ fn SSL_get0_peer_certificates(ssl: *const SSL) -> *const STACK_OF;
fn SSL_set_min_proto_version(ssl: *mut SSL, version: u16);
fn SSL_set_max_proto_version(ssl: *mut SSL, version: u16);
@@ -1133,13 +1225,15 @@ extern {
) -> c_int;
fn SSL_get_peer_quic_transport_params(
- ssl: *mut SSL, out_params: *mut *const u8, out_params_len: *mut usize,
+ ssl: *const SSL, out_params: *mut *const u8, out_params_len: *mut usize,
);
fn SSL_get0_alpn_selected(
- ssl: *mut SSL, out: *mut *const u8, out_len: *mut u32,
+ ssl: *const SSL, out: *mut *const u8, out_len: *mut u32,
);
+ fn SSL_get_servername(ssl: *const SSL, ty: c_int) -> *const c_char;
+
fn SSL_provide_quic_data(
ssl: *mut SSL, level: crypto::Level, data: *const u8, len: usize,
) -> c_int;
@@ -1150,13 +1244,13 @@ extern {
fn SSL_do_handshake(ssl: *mut SSL) -> c_int;
- fn SSL_quic_write_level(ssl: *mut SSL) -> crypto::Level;
+ fn SSL_quic_write_level(ssl: *const SSL) -> crypto::Level;
- fn SSL_session_reused(ssl: *mut SSL) -> c_int;
+ fn SSL_session_reused(ssl: *const SSL) -> c_int;
- fn SSL_in_init(ssl: *mut SSL) -> c_int;
+ fn SSL_in_init(ssl: *const SSL) -> c_int;
- fn SSL_in_early_data(ssl: *mut SSL) -> c_int;
+ fn SSL_in_early_data(ssl: *const SSL) -> c_int;
fn SSL_clear(ssl: *mut SSL) -> c_int;