Rewrite bssl_shim command-line parser.

The command-line parser is slightly showing its age: first, it is hard
to add new integral types, such as uint16_t, which is getting in the way
of fixing some of the -Wformat-signedness errors. Second, the parameter
extraction logic and skipping logic is duplicated in every type.

While I'm here, use a binary search to look up the flag, since we have
rather a lot of them. With more C++ template tricks, we could avoid the
std::function, but that seemed more trouble than was worth it,
especially since, prior to C++17, it's a little hard to convince
template argument deduction to infer one of the parameters.

Change-Id: I208f89d46371b31fc8b44487725296bcd9d7c8e7
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/50769
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
fips-20220613
David Benjamin 3 years ago committed by Boringssl LUCI CQ
parent 066469055f
commit 8ed06e0fd0
  1. 737
      ssl/test/test_config.cc

@ -15,15 +15,22 @@
#include "test_config.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <functional>
#include <limits>
#include <memory>
#include <type_traits>
#include <openssl/base64.h>
#include <openssl/hpke.h>
#include <openssl/rand.h>
#include <openssl/span.h>
#include <openssl/ssl.h>
#include "../../crypto/internal.h"
@ -34,235 +41,88 @@
namespace {
template <typename T>
struct Flag {
const char *flag;
T TestConfig::*member;
const char *name;
bool has_param;
// If |has_param| is false, |param| will be nullptr.
std::function<bool(TestConfig *config, const char *param)> set_param;
};
// FindField looks for the flag in |flags| that matches |flag|. If one is found,
// it returns a pointer to the corresponding field in |config|. Otherwise, it
// returns NULL.
template<typename T, size_t N>
T *FindField(TestConfig *config, const Flag<T> (&flags)[N], const char *flag) {
for (size_t i = 0; i < N; i++) {
if (strcmp(flag, flags[i].flag) == 0) {
return &(config->*(flags[i].member));
}
}
return NULL;
Flag BoolFlag(const char *name, bool TestConfig::*field) {
return Flag{name, false, [=](TestConfig *config, const char *) -> bool {
config->*field = true;
return true;
}};
}
const Flag<bool> kBoolFlags[] = {
{"-server", &TestConfig::is_server},
{"-dtls", &TestConfig::is_dtls},
{"-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},
{"-async", &TestConfig::async},
{"-write-different-record-sizes",
&TestConfig::write_different_record_sizes},
{"-cbc-record-splitting", &TestConfig::cbc_record_splitting},
{"-partial-write", &TestConfig::partial_write},
{"-no-tls13", &TestConfig::no_tls13},
{"-no-tls12", &TestConfig::no_tls12},
{"-no-tls11", &TestConfig::no_tls11},
{"-no-tls1", &TestConfig::no_tls1},
{"-no-ticket", &TestConfig::no_ticket},
{"-enable-channel-id", &TestConfig::enable_channel_id},
{"-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",
&TestConfig::expect_extended_master_secret},
{"-enable-ocsp-stapling", &TestConfig::enable_ocsp_stapling},
{"-enable-signed-cert-timestamps",
&TestConfig::enable_signed_cert_timestamps},
{"-implicit-handshake", &TestConfig::implicit_handshake},
{"-use-early-callback", &TestConfig::use_early_callback},
{"-fail-early-callback", &TestConfig::fail_early_callback},
{"-install-ddos-callback", &TestConfig::install_ddos_callback},
{"-fail-ddos-callback", &TestConfig::fail_ddos_callback},
{"-fail-cert-callback", &TestConfig::fail_cert_callback},
{"-handshake-never-done", &TestConfig::handshake_never_done},
{"-use-export-context", &TestConfig::use_export_context},
{"-tls-unique", &TestConfig::tls_unique},
{"-expect-ticket-renewal", &TestConfig::expect_ticket_renewal},
{"-expect-no-session", &TestConfig::expect_no_session},
{"-expect-ticket-supports-early-data",
&TestConfig::expect_ticket_supports_early_data},
{"-use-ticket-callback", &TestConfig::use_ticket_callback},
{"-renew-ticket", &TestConfig::renew_ticket},
{"-enable-early-data", &TestConfig::enable_early_data},
{"-check-close-notify", &TestConfig::check_close_notify},
{"-shim-shuts-down", &TestConfig::shim_shuts_down},
{"-verify-fail", &TestConfig::verify_fail},
{"-verify-peer", &TestConfig::verify_peer},
{"-verify-peer-if-no-obc", &TestConfig::verify_peer_if_no_obc},
{"-expect-verify-result", &TestConfig::expect_verify_result},
{"-renegotiate-once", &TestConfig::renegotiate_once},
{"-renegotiate-freely", &TestConfig::renegotiate_freely},
{"-renegotiate-ignore", &TestConfig::renegotiate_ignore},
{"-renegotiate-explicit", &TestConfig::renegotiate_explicit},
{"-forbid-renegotiation-after-handshake",
&TestConfig::forbid_renegotiation_after_handshake},
{"-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},
{"-expect-sha256-client-cert", &TestConfig::expect_sha256_client_cert},
{"-read-with-unfinished-write", &TestConfig::read_with_unfinished_write},
{"-expect-secure-renegotiation", &TestConfig::expect_secure_renegotiation},
{"-expect-no-secure-renegotiation",
&TestConfig::expect_no_secure_renegotiation},
{"-expect-session-id", &TestConfig::expect_session_id},
{"-expect-no-session-id", &TestConfig::expect_no_session_id},
{"-expect-accept-early-data", &TestConfig::expect_accept_early_data},
{"-expect-reject-early-data", &TestConfig::expect_reject_early_data},
{"-expect-no-offer-early-data", &TestConfig::expect_no_offer_early_data},
{"-no-op-extra-handshake", &TestConfig::no_op_extra_handshake},
{"-handshake-twice", &TestConfig::handshake_twice},
{"-allow-unknown-alpn-protos", &TestConfig::allow_unknown_alpn_protos},
{"-use-custom-verify-callback", &TestConfig::use_custom_verify_callback},
{"-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},
{"-fail-ocsp-callback", &TestConfig::fail_ocsp_callback},
{"-install-cert-compression-algs",
&TestConfig::install_cert_compression_algs},
{"-is-handshaker-supported", &TestConfig::is_handshaker_supported},
{"-handshaker-resume", &TestConfig::handshaker_resume},
{"-reverify-on-resume", &TestConfig::reverify_on_resume},
{"-enforce-rsa-key-usage", &TestConfig::enforce_rsa_key_usage},
{"-jdk11-workaround", &TestConfig::jdk11_workaround},
{"-server-preference", &TestConfig::server_preference},
{"-export-traffic-secrets", &TestConfig::export_traffic_secrets},
{"-key-update", &TestConfig::key_update},
{"-expect-delegated-credential-used",
&TestConfig::expect_delegated_credential_used},
{"-expect-hrr", &TestConfig::expect_hrr},
{"-expect-no-hrr", &TestConfig::expect_no_hrr},
{"-wait-for-debugger", &TestConfig::wait_for_debugger},
};
const Flag<std::string> kStringFlags[] = {
{"-write-settings", &TestConfig::write_settings},
{"-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},
{"-send-channel-id", &TestConfig::send_channel_id},
{"-host-name", &TestConfig::host_name},
{"-advertise-alpn", &TestConfig::advertise_alpn},
{"-expect-alpn", &TestConfig::expect_alpn},
{"-expect-late-alpn", &TestConfig::expect_late_alpn},
{"-expect-advertised-alpn", &TestConfig::expect_advertised_alpn},
{"-select-alpn", &TestConfig::select_alpn},
{"-psk", &TestConfig::psk},
{"-psk-identity", &TestConfig::psk_identity},
{"-srtp-profiles", &TestConfig::srtp_profiles},
{"-cipher", &TestConfig::cipher},
{"-export-label", &TestConfig::export_label},
{"-export-context", &TestConfig::export_context},
{"-expect-peer-cert-file", &TestConfig::expect_peer_cert_file},
{"-use-client-ca-list", &TestConfig::use_client_ca_list},
{"-expect-client-ca-list", &TestConfig::expect_client_ca_list},
{"-expect-msg-callback", &TestConfig::expect_msg_callback},
{"-handshaker-path", &TestConfig::handshaker_path},
{"-delegated-credential", &TestConfig::delegated_credential},
{"-expect-early-data-reason", &TestConfig::expect_early_data_reason},
{"-quic-early-data-context", &TestConfig::quic_early_data_context},
};
template <typename T>
bool StringToInt(T *out, const char *str) {
static_assert(std::is_integral<T>::value, "not an integral type");
static_assert(sizeof(T) <= sizeof(long long), "type too large for long long");
// |strtoull| allows leading '-' with wraparound. Additionally, both
// functions accept empty strings and leading whitespace.
if (!isdigit(static_cast<unsigned char>(*str)) &&
(!std::is_signed<T>::value || *str != '-')) {
return false;
}
// TODO(davidben): When we can depend on C++17 or Abseil, switch this to
// std::optional or absl::optional.
const Flag<std::unique_ptr<std::string>> kOptionalStringFlags[] = {
{"-expect-peer-application-settings",
&TestConfig::expect_peer_application_settings},
};
errno = 0;
char *end;
if (std::is_signed<T>::value) {
long long value = strtoll(str, &end, 10);
if (value < std::numeric_limits<T>::min() ||
value > std::numeric_limits<T>::max()) {
return false;
}
*out = static_cast<T>(value);
} else {
unsigned long long value = strtoull(str, &end, 10);
if (value > std::numeric_limits<T>::max()) {
return false;
}
*out = static_cast<T>(value);
}
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},
{"-expect-ocsp-response", &TestConfig::expect_ocsp_response},
{"-expect-signed-cert-timestamps",
&TestConfig::expect_signed_cert_timestamps},
{"-ocsp-response", &TestConfig::ocsp_response},
{"-signed-cert-timestamps", &TestConfig::signed_cert_timestamps},
{"-ticket-key", &TestConfig::ticket_key},
{"-quic-transport-params", &TestConfig::quic_transport_params},
{"-expect-quic-transport-params",
&TestConfig::expect_quic_transport_params},
};
// Check for overflow and that the whole input was consumed.
return errno != ERANGE && *end == '\0';
}
const Flag<int> kIntFlags[] = {
{"-port", &TestConfig::port},
{"-resume-count", &TestConfig::resume_count},
{"-min-version", &TestConfig::min_version},
{"-max-version", &TestConfig::max_version},
{"-expect-version", &TestConfig::expect_version},
{"-mtu", &TestConfig::mtu},
{"-export-keying-material", &TestConfig::export_keying_material},
{"-expect-total-renegotiations", &TestConfig::expect_total_renegotiations},
{"-expect-peer-signature-algorithm",
&TestConfig::expect_peer_signature_algorithm},
{"-expect-curve-id", &TestConfig::expect_curve_id},
{"-initial-timeout-duration-ms", &TestConfig::initial_timeout_duration_ms},
{"-max-cert-list", &TestConfig::max_cert_list},
{"-expect-cipher-aes", &TestConfig::expect_cipher_aes},
{"-expect-cipher-no-aes", &TestConfig::expect_cipher_no_aes},
{"-expect-cipher", &TestConfig::expect_cipher},
{"-resumption-delay", &TestConfig::resumption_delay},
{"-max-send-fragment", &TestConfig::max_send_fragment},
{"-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},
};
template <typename T>
Flag IntFlag(const char *name, T TestConfig::*field) {
return Flag{name, true, [=](TestConfig *config, const char *param) -> bool {
return StringToInt(&(config->*field), param);
}};
}
const Flag<std::vector<int>> kIntVectorFlags[] = {
{"-signing-prefs", &TestConfig::signing_prefs},
{"-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},
};
template <typename T>
Flag IntVectorFlag(const char *name, std::vector<T> TestConfig::*field) {
return Flag{name, true, [=](TestConfig *config, const char *param) -> bool {
T value;
if (!StringToInt(&value, param)) {
return false;
}
(config->*field).push_back(value);
return true;
}};
}
const Flag<std::vector<std::string>> kBase64VectorFlags[] = {
{"-ech-server-config", &TestConfig::ech_server_configs},
{"-ech-server-key", &TestConfig::ech_server_keys},
};
Flag StringFlag(const char *name, std::string TestConfig::*field) {
return Flag{name, true, [=](TestConfig *config, const char *param) -> bool {
config->*field = param;
return true;
}};
}
const Flag<std::vector<std::pair<std::string, std::string>>>
kStringPairVectorFlags[] = {
{"-application-settings", &TestConfig::application_settings},
};
// TODO(davidben): When we can depend on C++17 or Abseil, switch this to
// std::optional or absl::optional.
Flag OptionalStringFlag(const char *name,
std::unique_ptr<std::string> TestConfig::*field) {
return Flag{name, true, [=](TestConfig *config, const char *param) -> bool {
(config->*field).reset(new std::string(param));
return true;
}};
}
bool DecodeBase64(std::string *out, const std::string &in) {
size_t len;
@ -281,134 +141,268 @@ bool DecodeBase64(std::string *out, const std::string &in) {
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) {
if (!skip) {
*bool_field = true;
}
return true;
}
std::string *string_field = FindField(out_config, kStringFlags, flag);
if (string_field != NULL) {
*i = *i + 1;
if (*i >= argc) {
fprintf(stderr, "Missing parameter.\n");
return false;
}
if (!skip) {
string_field->assign(argv[*i]);
}
return true;
}
std::unique_ptr<std::string> *optional_string_field =
FindField(out_config, kOptionalStringFlags, flag);
if (optional_string_field != NULL) {
*i = *i + 1;
if (*i >= argc) {
fprintf(stderr, "Missing parameter.\n");
return false;
}
if (!skip) {
optional_string_field->reset(new std::string(argv[*i]));
}
return true;
}
std::string *base64_field = FindField(out_config, kBase64Flags, flag);
if (base64_field != NULL) {
*i = *i + 1;
if (*i >= argc) {
fprintf(stderr, "Missing parameter.\n");
return false;
}
std::string value;
if (!DecodeBase64(&value, argv[*i])) {
return false;
}
if (!skip) {
*base64_field = std::move(value);
}
return true;
}
int *int_field = FindField(out_config, kIntFlags, flag);
if (int_field) {
*i = *i + 1;
if (*i >= argc) {
fprintf(stderr, "Missing parameter.\n");
return false;
}
if (!skip) {
*int_field = atoi(argv[*i]);
}
return true;
}
Flag Base64Flag(const char *name, std::string TestConfig::*field) {
return Flag{name, true, [=](TestConfig *config, const char *param) -> bool {
return DecodeBase64(&(config->*field), param);
}};
}
std::vector<int> *int_vector_field =
FindField(out_config, kIntVectorFlags, flag);
if (int_vector_field) {
*i = *i + 1;
if (*i >= argc) {
fprintf(stderr, "Missing parameter.\n");
return false;
}
Flag Base64VectorFlag(const char *name,
std::vector<std::string> TestConfig::*field) {
return Flag{name, true, [=](TestConfig *config, const char *param) -> bool {
std::string value;
if (!DecodeBase64(&value, param)) {
return false;
}
(config->*field).push_back(std::move(value));
return true;
}};
}
// Each instance of the flag adds to the list.
if (!skip) {
int_vector_field->push_back(atoi(argv[*i]));
}
return true;
}
Flag StringPairVectorFlag(
const char *name,
std::vector<std::pair<std::string, std::string>> TestConfig::*field) {
return Flag{name, true, [=](TestConfig *config, const char *param) -> bool {
const char *comma = strchr(param, ',');
if (!comma) {
return false;
}
(config->*field)
.push_back(std::make_pair(std::string(param, comma - param),
std::string(comma + 1)));
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<Flag> SortedFlags() {
// TODO(davidben): Reorder these to match the struct.
std::vector<Flag> flags = {
BoolFlag("-server", &TestConfig::is_server),
BoolFlag("-dtls", &TestConfig::is_dtls),
BoolFlag("-quic", &TestConfig::is_quic),
BoolFlag("-fallback-scsv", &TestConfig::fallback_scsv),
BoolFlag("-enable-ech-grease", &TestConfig::enable_ech_grease),
BoolFlag("-expect-ech-accept", &TestConfig::expect_ech_accept),
BoolFlag("-expect-no-ech-name-override",
&TestConfig::expect_no_ech_name_override),
BoolFlag("-expect-no-ech-retry-configs",
&TestConfig::expect_no_ech_retry_configs),
BoolFlag("-require-any-client-certificate",
&TestConfig::require_any_client_certificate),
BoolFlag("-false-start", &TestConfig::false_start),
BoolFlag("-async", &TestConfig::async),
BoolFlag("-write-different-record-sizes",
&TestConfig::write_different_record_sizes),
BoolFlag("-cbc-record-splitting", &TestConfig::cbc_record_splitting),
BoolFlag("-partial-write", &TestConfig::partial_write),
BoolFlag("-no-tls13", &TestConfig::no_tls13),
BoolFlag("-no-tls12", &TestConfig::no_tls12),
BoolFlag("-no-tls11", &TestConfig::no_tls11),
BoolFlag("-no-tls1", &TestConfig::no_tls1),
BoolFlag("-no-ticket", &TestConfig::no_ticket),
BoolFlag("-enable-channel-id", &TestConfig::enable_channel_id),
BoolFlag("-shim-writes-first", &TestConfig::shim_writes_first),
BoolFlag("-expect-session-miss", &TestConfig::expect_session_miss),
BoolFlag("-decline-alpn", &TestConfig::decline_alpn),
BoolFlag("-reject-alpn", &TestConfig::reject_alpn),
BoolFlag("-select-empty-alpn", &TestConfig::select_empty_alpn),
BoolFlag("-defer-alps", &TestConfig::defer_alps),
BoolFlag("-expect-extended-master-secret",
&TestConfig::expect_extended_master_secret),
BoolFlag("-enable-ocsp-stapling", &TestConfig::enable_ocsp_stapling),
BoolFlag("-enable-signed-cert-timestamps",
&TestConfig::enable_signed_cert_timestamps),
BoolFlag("-implicit-handshake", &TestConfig::implicit_handshake),
BoolFlag("-use-early-callback", &TestConfig::use_early_callback),
BoolFlag("-fail-early-callback", &TestConfig::fail_early_callback),
BoolFlag("-install-ddos-callback", &TestConfig::install_ddos_callback),
BoolFlag("-fail-ddos-callback", &TestConfig::fail_ddos_callback),
BoolFlag("-fail-cert-callback", &TestConfig::fail_cert_callback),
BoolFlag("-handshake-never-done", &TestConfig::handshake_never_done),
BoolFlag("-use-export-context", &TestConfig::use_export_context),
BoolFlag("-tls-unique", &TestConfig::tls_unique),
BoolFlag("-expect-ticket-renewal", &TestConfig::expect_ticket_renewal),
BoolFlag("-expect-no-session", &TestConfig::expect_no_session),
BoolFlag("-expect-ticket-supports-early-data",
&TestConfig::expect_ticket_supports_early_data),
BoolFlag("-use-ticket-callback", &TestConfig::use_ticket_callback),
BoolFlag("-renew-ticket", &TestConfig::renew_ticket),
BoolFlag("-enable-early-data", &TestConfig::enable_early_data),
BoolFlag("-check-close-notify", &TestConfig::check_close_notify),
BoolFlag("-shim-shuts-down", &TestConfig::shim_shuts_down),
BoolFlag("-verify-fail", &TestConfig::verify_fail),
BoolFlag("-verify-peer", &TestConfig::verify_peer),
BoolFlag("-verify-peer-if-no-obc", &TestConfig::verify_peer_if_no_obc),
BoolFlag("-expect-verify-result", &TestConfig::expect_verify_result),
BoolFlag("-renegotiate-once", &TestConfig::renegotiate_once),
BoolFlag("-renegotiate-freely", &TestConfig::renegotiate_freely),
BoolFlag("-renegotiate-ignore", &TestConfig::renegotiate_ignore),
BoolFlag("-renegotiate-explicit", &TestConfig::renegotiate_explicit),
BoolFlag("-forbid-renegotiation-after-handshake",
&TestConfig::forbid_renegotiation_after_handshake),
BoolFlag("-use-old-client-cert-callback",
&TestConfig::use_old_client_cert_callback),
BoolFlag("-send-alert", &TestConfig::send_alert),
BoolFlag("-peek-then-read", &TestConfig::peek_then_read),
BoolFlag("-enable-grease", &TestConfig::enable_grease),
BoolFlag("-permute-extensions", &TestConfig::permute_extensions),
BoolFlag("-use-exporter-between-reads",
&TestConfig::use_exporter_between_reads),
BoolFlag("-retain-only-sha256-client-cert",
&TestConfig::retain_only_sha256_client_cert),
BoolFlag("-expect-sha256-client-cert",
&TestConfig::expect_sha256_client_cert),
BoolFlag("-read-with-unfinished-write",
&TestConfig::read_with_unfinished_write),
BoolFlag("-expect-secure-renegotiation",
&TestConfig::expect_secure_renegotiation),
BoolFlag("-expect-no-secure-renegotiation",
&TestConfig::expect_no_secure_renegotiation),
BoolFlag("-expect-session-id", &TestConfig::expect_session_id),
BoolFlag("-expect-no-session-id", &TestConfig::expect_no_session_id),
BoolFlag("-expect-accept-early-data",
&TestConfig::expect_accept_early_data),
BoolFlag("-expect-reject-early-data",
&TestConfig::expect_reject_early_data),
BoolFlag("-expect-no-offer-early-data",
&TestConfig::expect_no_offer_early_data),
BoolFlag("-no-op-extra-handshake", &TestConfig::no_op_extra_handshake),
BoolFlag("-handshake-twice", &TestConfig::handshake_twice),
BoolFlag("-allow-unknown-alpn-protos",
&TestConfig::allow_unknown_alpn_protos),
BoolFlag("-use-custom-verify-callback",
&TestConfig::use_custom_verify_callback),
BoolFlag("-allow-false-start-without-alpn",
&TestConfig::allow_false_start_without_alpn),
BoolFlag("-handoff", &TestConfig::handoff),
BoolFlag("-handshake-hints", &TestConfig::handshake_hints),
BoolFlag("-allow-hint-mismatch", &TestConfig::allow_hint_mismatch),
BoolFlag("-use-ocsp-callback", &TestConfig::use_ocsp_callback),
BoolFlag("-set-ocsp-in-callback", &TestConfig::set_ocsp_in_callback),
BoolFlag("-decline-ocsp-callback", &TestConfig::decline_ocsp_callback),
BoolFlag("-fail-ocsp-callback", &TestConfig::fail_ocsp_callback),
BoolFlag("-install-cert-compression-algs",
&TestConfig::install_cert_compression_algs),
BoolFlag("-is-handshaker-supported",
&TestConfig::is_handshaker_supported),
BoolFlag("-handshaker-resume", &TestConfig::handshaker_resume),
BoolFlag("-reverify-on-resume", &TestConfig::reverify_on_resume),
BoolFlag("-enforce-rsa-key-usage", &TestConfig::enforce_rsa_key_usage),
BoolFlag("-jdk11-workaround", &TestConfig::jdk11_workaround),
BoolFlag("-server-preference", &TestConfig::server_preference),
BoolFlag("-export-traffic-secrets", &TestConfig::export_traffic_secrets),
BoolFlag("-key-update", &TestConfig::key_update),
BoolFlag("-expect-delegated-credential-used",
&TestConfig::expect_delegated_credential_used),
BoolFlag("-expect-hrr", &TestConfig::expect_hrr),
BoolFlag("-expect-no-hrr", &TestConfig::expect_no_hrr),
BoolFlag("-wait-for-debugger", &TestConfig::wait_for_debugger),
StringFlag("-write-settings", &TestConfig::write_settings),
StringFlag("-key-file", &TestConfig::key_file),
StringFlag("-cert-file", &TestConfig::cert_file),
StringFlag("-expect-server-name", &TestConfig::expect_server_name),
StringFlag("-expect-ech-name-override",
&TestConfig::expect_ech_name_override),
StringFlag("-advertise-npn", &TestConfig::advertise_npn),
StringFlag("-expect-next-proto", &TestConfig::expect_next_proto),
StringFlag("-select-next-proto", &TestConfig::select_next_proto),
StringFlag("-send-channel-id", &TestConfig::send_channel_id),
StringFlag("-host-name", &TestConfig::host_name),
StringFlag("-advertise-alpn", &TestConfig::advertise_alpn),
StringFlag("-expect-alpn", &TestConfig::expect_alpn),
StringFlag("-expect-late-alpn", &TestConfig::expect_late_alpn),
StringFlag("-expect-advertised-alpn",
&TestConfig::expect_advertised_alpn),
StringFlag("-select-alpn", &TestConfig::select_alpn),
StringFlag("-psk", &TestConfig::psk),
StringFlag("-psk-identity", &TestConfig::psk_identity),
StringFlag("-srtp-profiles", &TestConfig::srtp_profiles),
StringFlag("-cipher", &TestConfig::cipher),
StringFlag("-export-label", &TestConfig::export_label),
StringFlag("-export-context", &TestConfig::export_context),
StringFlag("-expect-peer-cert-file", &TestConfig::expect_peer_cert_file),
StringFlag("-use-client-ca-list", &TestConfig::use_client_ca_list),
StringFlag("-expect-client-ca-list", &TestConfig::expect_client_ca_list),
StringFlag("-expect-msg-callback", &TestConfig::expect_msg_callback),
StringFlag("-handshaker-path", &TestConfig::handshaker_path),
StringFlag("-delegated-credential", &TestConfig::delegated_credential),
StringFlag("-expect-early-data-reason",
&TestConfig::expect_early_data_reason),
StringFlag("-quic-early-data-context",
&TestConfig::quic_early_data_context),
OptionalStringFlag("-expect-peer-application-settings",
&TestConfig::expect_peer_application_settings),
Base64Flag("-expect-ech-retry-configs",
&TestConfig::expect_ech_retry_configs),
Base64Flag("-ech-config-list", &TestConfig::ech_config_list),
Base64Flag("-expect-certificate-types",
&TestConfig::expect_certificate_types),
Base64Flag("-expect-channel-id", &TestConfig::expect_channel_id),
Base64Flag("-expect-ocsp-response", &TestConfig::expect_ocsp_response),
Base64Flag("-expect-signed-cert-timestamps",
&TestConfig::expect_signed_cert_timestamps),
Base64Flag("-ocsp-response", &TestConfig::ocsp_response),
Base64Flag("-signed-cert-timestamps",
&TestConfig::signed_cert_timestamps),
Base64Flag("-ticket-key", &TestConfig::ticket_key),
Base64Flag("-quic-transport-params", &TestConfig::quic_transport_params),
Base64Flag("-expect-quic-transport-params",
&TestConfig::expect_quic_transport_params),
IntFlag("-port", &TestConfig::port),
IntFlag("-resume-count", &TestConfig::resume_count),
IntFlag("-min-version", &TestConfig::min_version),
IntFlag("-max-version", &TestConfig::max_version),
IntFlag("-expect-version", &TestConfig::expect_version),
IntFlag("-mtu", &TestConfig::mtu),
IntFlag("-export-keying-material", &TestConfig::export_keying_material),
IntFlag("-expect-total-renegotiations",
&TestConfig::expect_total_renegotiations),
IntFlag("-expect-peer-signature-algorithm",
&TestConfig::expect_peer_signature_algorithm),
IntFlag("-expect-curve-id", &TestConfig::expect_curve_id),
IntFlag("-initial-timeout-duration-ms",
&TestConfig::initial_timeout_duration_ms),
IntFlag("-max-cert-list", &TestConfig::max_cert_list),
IntFlag("-expect-cipher-aes", &TestConfig::expect_cipher_aes),
IntFlag("-expect-cipher-no-aes", &TestConfig::expect_cipher_no_aes),
IntFlag("-expect-cipher", &TestConfig::expect_cipher),
IntFlag("-resumption-delay", &TestConfig::resumption_delay),
IntFlag("-max-send-fragment", &TestConfig::max_send_fragment),
IntFlag("-read-size", &TestConfig::read_size),
IntFlag("-expect-ticket-age-skew", &TestConfig::expect_ticket_age_skew),
IntFlag("-quic-use-legacy-codepoint",
&TestConfig::quic_use_legacy_codepoint),
IntFlag("-install-one-cert-compression-alg",
&TestConfig::install_one_cert_compression_alg),
IntFlag("-early-write-after-message",
&TestConfig::early_write_after_message),
IntVectorFlag("-signing-prefs", &TestConfig::signing_prefs),
IntVectorFlag("-verify-prefs", &TestConfig::verify_prefs),
IntVectorFlag("-expect-peer-verify-pref",
&TestConfig::expect_peer_verify_prefs),
IntVectorFlag("-curves", &TestConfig::curves),
IntVectorFlag("-ech-is-retry-config", &TestConfig::ech_is_retry_config),
Base64VectorFlag("-ech-server-config", &TestConfig::ech_server_configs),
Base64VectorFlag("-ech-server-key", &TestConfig::ech_server_keys),
StringPairVectorFlag("-application-settings",
&TestConfig::application_settings),
};
std::sort(flags.begin(), flags.end(), [](const Flag &a, const Flag &b) {
return strcmp(a.name, b.name) < 0;
});
return flags;
}
std::vector<std::pair<std::string, std::string>> *string_pair_vector_field =
FindField(out_config, kStringPairVectorFlags, flag);
if (string_pair_vector_field) {
*i = *i + 1;
if (*i >= argc) {
fprintf(stderr, "Missing parameter.\n");
return false;
}
const char *comma = strchr(argv[*i], ',');
if (!comma) {
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.
if (!skip) {
string_pair_vector_field->push_back(std::make_pair(
std::string(argv[*i], comma - argv[*i]), std::string(comma + 1)));
}
return true;
const Flag *FindFlag(const char *name) {
static const std::vector<Flag> kSortedFlags = SortedFlags();
auto iter = std::lower_bound(kSortedFlags.begin(), kSortedFlags.end(), name,
[](const Flag &flag, const char *key) {
return strcmp(flag.name, key) < 0;
});
if (iter == kSortedFlags.end() || strcmp(iter->name, name) != 0) {
return nullptr;
}
fprintf(stderr, "Unknown argument: %s.\n", flag);
return false;
return &*iter;
}
// RemovePrefix checks if |*str| begins with |prefix| + "-". If so, it advances
@ -433,15 +427,15 @@ bool ParseConfig(int argc, char **argv, bool is_shim,
out_initial->argv = out_resume->argv = out_retry->argv = argv;
for (int i = 0; i < argc; i++) {
bool skip = false;
const char *flag = argv[i];
const char *name = argv[i];
// -on-shim and -on-handshaker prefixes enable flags only on the shim or
// handshaker.
if (RemovePrefix(&flag, "-on-shim")) {
if (RemovePrefix(&name, "-on-shim")) {
if (!is_shim) {
skip = true;
}
} else if (RemovePrefix(&flag, "-on-handshaker")) {
} else if (RemovePrefix(&name, "-on-handshaker")) {
if (is_shim) {
skip = true;
}
@ -449,26 +443,45 @@ bool ParseConfig(int argc, char **argv, bool is_shim,
// 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 (RemovePrefix(&flag, "-on-resume")) {
if (!ParseFlag(flag, argc, argv, &i, skip, out_resume)) {
return false;
}
} else if (RemovePrefix(&flag, "-on-retry")) {
if (!ParseFlag(flag, argc, argv, &i, skip, out_retry)) {
TestConfig *out = nullptr;
if (RemovePrefix(&name, "-on-initial")) {
out = out_initial;
} else if (RemovePrefix(&name, "-on-resume")) {
out = out_resume;
} else if (RemovePrefix(&name, "-on-retry")) {
out = out_retry;
}
const Flag *flag = FindFlag(name);
if (flag == nullptr) {
fprintf(stderr, "Unrecognized flag: %s\n", name);
return false;
}
const char *param = nullptr;
if (flag->has_param) {
if (i >= argc) {
fprintf(stderr, "Missing parameter for %s\n", name);
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) ||
!ParseFlag(flag, argc, argv, &i_resume, skip, out_resume) ||
!ParseFlag(flag, argc, argv, &i, skip, out_retry)) {
return false;
i++;
param = argv[i];
}
if (!skip) {
if (out != nullptr) {
if (!flag->set_param(out, param)) {
fprintf(stderr, "Invalid parameter for %s: %s\n", name, param);
return false;
}
} else {
// Unprefixed flags apply to all three.
if (!flag->set_param(out_initial, param) ||
!flag->set_param(out_resume, param) ||
!flag->set_param(out_retry, param)) {
fprintf(stderr, "Invalid parameter for %s: %s\n", name, param);
return false;
}
}
}
}

Loading…
Cancel
Save