diff --git a/lib/openssl.c b/lib/openssl.c index c63ba8627..2d077cc2f 100644 --- a/lib/openssl.c +++ b/lib/openssl.c @@ -1219,8 +1219,6 @@ static int verify_cert_chain(X509_STORE *store, X509 *cert, STACK_OF(X509) * cha X509_STORE_CTX *verify_ctx; int ret; - assert(server_name != NULL && "ptls_set_server_name MUST be called"); - /* verify certificate chain */ if ((verify_ctx = X509_STORE_CTX_new()) == NULL) { ret = PTLS_ERROR_NO_MEMORY; @@ -1239,12 +1237,16 @@ static int verify_cert_chain(X509_STORE *store, X509 *cert, STACK_OF(X509) * cha } X509_VERIFY_PARAM_set_purpose(params, is_server ? X509_PURPOSE_SSL_SERVER : X509_PURPOSE_SSL_CLIENT); X509_VERIFY_PARAM_set_depth(params, 98); /* use the default of OpenSSL 1.0.2 and above; see `man SSL_CTX_set_verify` */ - if (server_name != NULL) { - if (ptls_server_name_is_ipaddr(server_name)) { - X509_VERIFY_PARAM_set1_ip_asc(params, server_name); - } else { - X509_VERIFY_PARAM_set1_host(params, server_name, 0); - X509_VERIFY_PARAM_set_hostflags(params, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + X509_VERIFY_PARAM_set_flags(params, X509_V_FLAG_PARTIAL_CHAIN); + if (!is_server) { + assert(server_name != NULL && "ptls_set_server_name MUST be called"); + if (server_name != NULL) { + if (ptls_server_name_is_ipaddr(server_name)) { + X509_VERIFY_PARAM_set1_ip_asc(params, server_name); + } else { + X509_VERIFY_PARAM_set1_host(params, server_name, 0); + X509_VERIFY_PARAM_set_hostflags(params, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + } } } X509_STORE_CTX_set0_param(verify_ctx, params); /* params will be freed alongside verify_ctx */ diff --git a/t/cli.c b/t/cli.c index db6bf822c..5c540dc0b 100644 --- a/t/cli.c +++ b/t/cli.c @@ -365,6 +365,7 @@ static void usage(const char *cmd) " argument is ignored.\n" " -u update the traffic key when handshake is complete\n" " -v verify peer using the default certificates\n" + " -V CA-root-file verify peer using the CA Root File\n" " -y cipher-suite cipher-suite to be used, e.g., aes128gcmsha256 (default:\n" " all)\n" " -h print this help\n" @@ -422,7 +423,7 @@ int main(int argc, char **argv) int family = 0; const char *raw_pub_key_file = NULL, *cert_location = NULL; - while ((ch = getopt(argc, argv, "46abBC:c:i:Ik:nN:es:Sr:E:K:l:y:vh")) != -1) { + while ((ch = getopt(argc, argv, "46abBC:c:i:Ik:nN:es:Sr:E:K:l:y:vV:h")) != -1) { switch (ch) { case '4': family = AF_INET; @@ -503,7 +504,10 @@ int main(int argc, char **argv) setup_log_event(&ctx, optarg); break; case 'v': - setup_verify_certificate(&ctx); + setup_verify_certificate(&ctx, NULL); + break; + case 'V': + setup_verify_certificate(&ctx, optarg); break; case 'N': { ptls_key_exchange_algorithm_t *algo = NULL; diff --git a/t/util.h b/t/util.h index 3890737dd..0dbbed792 100644 --- a/t/util.h +++ b/t/util.h @@ -124,10 +124,32 @@ static inline void setup_session_file(ptls_context_t *ctx, ptls_handshake_proper } } -static inline void setup_verify_certificate(ptls_context_t *ctx) +static inline X509_STORE* init_cert_store(char const *crt_file) +{ + int ret = 0; + X509_STORE *store = X509_STORE_new(); + + if (store != NULL) { + X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + ret = X509_LOOKUP_load_file(lookup, crt_file, X509_FILETYPE_PEM); + if (ret != 1) { + fprintf(stderr, "Cannot load store (%s), ret = %d\n", + crt_file, ret); + X509_STORE_free(store); + exit(1); + } + } else { + fprintf(stderr, "Cannot get a new X509 store\n"); + exit(1); + } + + return store; +} + +static inline void setup_verify_certificate(ptls_context_t *ctx, const char *ca_file) { static ptls_openssl_verify_certificate_t vc; - ptls_openssl_init_verify_certificate(&vc, NULL); + ptls_openssl_init_verify_certificate(&vc, ca_file != NULL ? init_cert_store(ca_file) : NULL); ctx->verify_certificate = &vc.super; }