On Tue, 2019-10-15 at 12:03 +0100, David Woodhouse wrote: > > Something like this... and instead of calling SSL_set1_host(ssl, host) > your own code now has to call > SSL_set_ex_data(ssl, ssl_target_idx, strdup(host)); Here's how I tested that in the OpenSSL tree in userspace, FWIW... diff --git a/demos/bio/sconnect.c b/demos/bio/sconnect.c index 7e46bf0ad8..1fd2829a79 100644 --- a/demos/bio/sconnect.c +++ b/demos/bio/sconnect.c @@ -25,11 +25,40 @@ #define HOSTPORT "localhost:4433" #define CAFILE "root.pem" +static int ssl_target_idx; + +void ssl_target_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int idx, long argl, void *argp) +{ + printf("Freeing %s\n", ptr); + free(ptr); +} + +int ssl_target_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from, + void *from_d, int idx, long argl, void *argp) +{ + /* strdup it */ + return 0; +} + +int app_verify_callback(X509_STORE_CTX *ctx, void *dummy) +{ + SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + char *hostname = SSL_get_ex_data(ssl, ssl_target_idx); + X509_VERIFY_PARAM *vpm = X509_STORE_CTX_get0_param(ctx); + + printf("Setting %s\n", hostname); + if (hostname && !X509_VERIFY_PARAM_set1_ip_asc(vpm, hostname)) + X509_VERIFY_PARAM_set1_host(vpm, hostname, 0); + + return X509_verify_cert(ctx); +} + int main(int argc, char *argv[]) { const char *hostport = HOSTPORT; const char *CAfile = CAFILE; - char *hostname; + const char *hostname; char *cp; BIO *out = NULL; char buf[1024 * 10], *p; @@ -43,10 +72,6 @@ int main(int argc, char *argv[]) if (argc > 2) CAfile = argv[2]; - hostname = OPENSSL_strdup(hostport); - if ((cp = strchr(hostname, ':')) != NULL) - *cp = 0; - #ifdef WATT32 dbug_init(); sock_init(); @@ -54,6 +79,8 @@ int main(int argc, char *argv[]) ssl_ctx = SSL_CTX_new(TLS_client_method()); + SSL_CTX_set_cert_verify_callback(ssl_ctx, app_verify_callback, NULL); + /* Enable trust chain verification */ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); SSL_CTX_load_verify_locations(ssl_ctx, CAfile, NULL); @@ -62,9 +89,6 @@ int main(int argc, char *argv[]) ssl = SSL_new(ssl_ctx); SSL_set_connect_state(ssl); - /* Enable peername verification */ - if (SSL_set1_host(ssl, hostname) <= 0) - goto err; /* Use it inside an SSL BIO */ ssl_bio = BIO_new(BIO_f_ssl()); @@ -73,6 +97,13 @@ int main(int argc, char *argv[]) /* Lets use a connect BIO under the SSL BIO */ out = BIO_new(BIO_s_connect()); BIO_set_conn_hostname(out, hostport); + + /* The BIO has parsed the host:port and even IPv6 literals in [] */ + hostname = BIO_get_conn_hostname(out); + + if (hostname) + SSL_set_ex_data(ssl, ssl_target_idx, strdup(hostname)); + BIO_set_nbio(out, 1); out = BIO_push(ssl_bio, out);