Merge pull request #360 from h2o/kazuho/client-cert-verify
`-V` option for specifying cert store, use verify params of the cert store
diff --git a/lib/openssl.c b/lib/openssl.c
index c63ba86..a1866b0 100644
--- a/lib/openssl.c
+++ b/lib/openssl.c
@@ -63,6 +63,7 @@
#define EVP_PKEY_up_ref(p) CRYPTO_add(&(p)->references, 1, CRYPTO_LOCK_EVP_PKEY)
#define X509_STORE_up_ref(p) CRYPTO_add(&(p)->references, 1, CRYPTO_LOCK_X509_STORE)
+#define X509_STORE_get0_param(p) ((p)->param)
static HMAC_CTX *HMAC_CTX_new(void)
{
@@ -1219,8 +1220,6 @@
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;
@@ -1231,15 +1230,13 @@
goto Exit;
}
- {
- X509_VERIFY_PARAM *params;
- if ((params = X509_VERIFY_PARAM_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
+ { /* setup verify params */
+ X509_VERIFY_PARAM *params = X509_STORE_CTX_get0_param(verify_ctx);
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) {
+ /* when _acting_ as client, set the server name */
+ if (!is_server) {
+ assert(server_name != NULL && "ptls_set_server_name MUST be called");
if (ptls_server_name_is_ipaddr(server_name)) {
X509_VERIFY_PARAM_set1_ip_asc(params, server_name);
} else {
@@ -1247,7 +1244,6 @@
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 */
}
if (X509_verify_cert(verify_ctx) != 1) {
diff --git a/t/cli.c b/t/cli.c
index db6bf82..5c540dc 100644
--- a/t/cli.c
+++ b/t/cli.c
@@ -365,6 +365,7 @@
" 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 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 @@
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 3890737..0dbbed7 100644
--- a/t/util.h
+++ b/t/util.h
@@ -124,10 +124,32 @@
}
}
-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;
}