diff options
author | Viktor Dukhovni <openssl-users@dukhovni.org> | 2015-12-29 13:28:28 -0500 |
---|---|---|
committer | Viktor Dukhovni <openssl-users@dukhovni.org> | 2016-01-05 19:31:49 -0500 |
commit | 919ba009429b3617e975933f37a23be996a33b8d (patch) | |
tree | ffe91f4f27fd4d8b3d3401f1e860212f15c8b993 | |
parent | e29c73c93b88a4b7f492c7c8c7343223e7548612 (diff) | |
download | openssl-919ba009429b3617e975933f37a23be996a33b8d.tar.gz |
DANE support structures, constructructors and accessors
Also tweak some of the code in demos/bio, to enable interactive
testing of BIO_s_accept's use of SSL_dup. Changed the sconnect
client to authenticate the server, which now exercises the new
SSL_set1_host() function.
Reviewed-by: Richard Levitte <levitte@openssl.org>
-rw-r--r-- | crypto/x509/x509_vfy.c | 7 | ||||
-rw-r--r-- | crypto/x509/x509_vpm.c | 18 | ||||
-rw-r--r-- | demos/bio/client-arg.c | 3 | ||||
-rw-r--r-- | demos/bio/client-conf.c | 3 | ||||
-rw-r--r-- | demos/bio/saccept.c | 29 | ||||
-rw-r--r-- | demos/bio/sconnect.c | 33 | ||||
-rw-r--r-- | demos/bio/server.pem | 64 | ||||
-rw-r--r-- | doc/crypto/X509_VERIFY_PARAM_set_flags.pod | 2 | ||||
-rw-r--r-- | doc/ssl/SSL_CTX_dane_enable.pod | 278 | ||||
-rw-r--r-- | doc/ssl/SSL_set1_host.pod | 115 | ||||
-rw-r--r-- | doc/ssl/ssl.pod | 19 | ||||
-rw-r--r-- | include/internal/dane.h | 147 | ||||
-rw-r--r-- | include/openssl/safestack.h | 23 | ||||
-rw-r--r-- | include/openssl/ssl.h | 40 | ||||
-rw-r--r-- | include/openssl/x509_vfy.h | 8 | ||||
-rw-r--r-- | ssl/record/rec_layer_s3.c | 9 | ||||
-rw-r--r-- | ssl/record/record.h | 1 | ||||
-rw-r--r-- | ssl/ssl_cert.c | 15 | ||||
-rw-r--r-- | ssl/ssl_err.c | 22 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 517 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 8 |
21 files changed, 1284 insertions, 77 deletions
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 57fcf91b30..1c509a9961 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -70,6 +70,7 @@ #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/objects.h> +#include <internal/dane.h> #include <internal/x509_int.h> #include "x509_lcl.h" @@ -2072,6 +2073,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, ctx->current_reasons = 0; ctx->tree = NULL; ctx->parent = NULL; + ctx->dane = NULL; /* Zero ex_data to make sure we're cleanup-safe */ memset(&ctx->ex_data, 0, sizeof(ctx->ex_data)); @@ -2263,6 +2265,11 @@ void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param) ctx->param = param; } +void X509_STORE_CTX_set0_dane(X509_STORE_CTX *ctx, struct dane_st *dane) +{ + ctx->dane = dane; +} + static int build_chain(X509_STORE_CTX *ctx) { int (*cb) (int, X509_STORE_CTX *) = ctx->verify_cb; diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c index 2a15f82ea1..827360d622 100644 --- a/crypto/x509/x509_vpm.c +++ b/crypto/x509/x509_vpm.c @@ -444,6 +444,24 @@ char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param) return param->peername; } +/* + * Move peername from one param structure to another, freeing any name present + * at the target. If the source is a NULL parameter structure, free and zero + * the target peername. + */ +void X509_VERIFY_PARAM_move_peername(X509_VERIFY_PARAM *to, + X509_VERIFY_PARAM *from) +{ + char *peername = (from != NULL) ? from->peername : NULL; + + if (to->peername != peername) { + OPENSSL_free(to->peername); + to->peername = peername; + } + if (from) + from->peername = NULL; +} + int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, const char *email, size_t emaillen) { diff --git a/demos/bio/client-arg.c b/demos/bio/client-arg.c index 99ebff1f2a..630b166779 100644 --- a/demos/bio/client-arg.c +++ b/demos/bio/client-arg.c @@ -1,3 +1,4 @@ +#include <string.h> #include <openssl/err.h> #include <openssl/ssl.h> @@ -56,7 +57,7 @@ int main(int argc, char **argv) if (!SSL_CONF_CTX_finish(cctx)) { fprintf(stderr, "Finish error\n"); ERR_print_errors_fp(stderr); - goto err; + goto end; } /* diff --git a/demos/bio/client-conf.c b/demos/bio/client-conf.c index 2a78315165..4e4d4bc8df 100644 --- a/demos/bio/client-conf.c +++ b/demos/bio/client-conf.c @@ -1,3 +1,4 @@ +#include <string.h> #include <openssl/err.h> #include <openssl/ssl.h> #include <openssl/conf.h> @@ -64,7 +65,7 @@ int main(int argc, char **argv) if (!SSL_CONF_CTX_finish(cctx)) { fprintf(stderr, "Finish error\n"); ERR_print_errors_fp(stderr); - goto err; + goto end; } /* diff --git a/demos/bio/saccept.c b/demos/bio/saccept.c index 0d173aa039..b6d0361a9c 100644 --- a/demos/bio/saccept.c +++ b/demos/bio/saccept.c @@ -18,16 +18,30 @@ #define CERT_FILE "server.pem" -BIO *in = NULL; +static int done = 0; -void close_up() +void interrupt() { - BIO_free(in); + done = 1; +} + +void sigsetup(void) +{ + struct sigaction sa; + + /* + * Catch at most once, and don't restart the accept system call. + */ + sa.sa_flags = SA_RESETHAND; + sa.sa_handler = interrupt; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); } int main(int argc, char *argv[]) { char *port = NULL; + BIO *in = NULL; BIO *ssl_bio, *tmp; SSL_CTX *ctx; char buf[512]; @@ -38,15 +52,13 @@ int main(int argc, char *argv[]) else port = argv[1]; - signal(SIGINT, close_up); - SSL_load_error_strings(); /* Add ciphers and message digests */ OpenSSL_add_ssl_algorithms(); ctx = SSL_CTX_new(TLS_server_method()); - if (!SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM)) + if (!SSL_CTX_use_certificate_chain_file(ctx, CERT_FILE)) goto err; if (!SSL_CTX_use_PrivateKey_file(ctx, CERT_FILE, SSL_FILETYPE_PEM)) goto err; @@ -66,6 +78,9 @@ int main(int argc, char *argv[]) */ BIO_set_accept_bios(in, ssl_bio); + /* Arrange to leave server loop on interrupt */ + sigsetup(); + again: /* * The first call will setup the accept socket, and the second will get a @@ -76,7 +91,7 @@ int main(int argc, char *argv[]) if (BIO_do_accept(in) <= 0) goto err; - for (;;) { + while (!done) { i = BIO_read(in, buf, 512); if (i == 0) { /* diff --git a/demos/bio/sconnect.c b/demos/bio/sconnect.c index 865d503956..2b610cc8b5 100644 --- a/demos/bio/sconnect.c +++ b/demos/bio/sconnect.c @@ -11,27 +11,38 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <string.h> #include <openssl/err.h> #include <openssl/ssl.h> +#define HOSTPORT "localhost:4433" +#define CAFILE "root.pem" + extern int errno; int main(argc, argv) int argc; char *argv[]; { - char *host; - BIO *out; + const char *hostport = HOSTPORT; + const char *CAfile = CAFILE; + char *hostname; + char *cp; + BIO *out = NULL; char buf[1024 * 10], *p; SSL_CTX *ssl_ctx = NULL; SSL *ssl; BIO *ssl_bio; int i, len, off, ret = 1; - if (argc <= 1) - host = "localhost:4433"; - else - host = argv[1]; + if (argc > 1) + hostport = argv[1]; + if (argc > 2) + CAfile = argv[2]; + + hostname = OPENSSL_strdup(hostport); + if ((cp = strchr(hostname, ':')) != NULL) + *cp = 0; #ifdef WATT32 dbug_init(); @@ -45,17 +56,25 @@ char *argv[]; OpenSSL_add_ssl_algorithms(); ssl_ctx = SSL_CTX_new(TLS_client_method()); + /* Enable trust chain verification */ + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + SSL_CTX_load_verify_locations(ssl_ctx, CAfile, NULL); + /* Lets make a SSL structure */ 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()); BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE); /* Lets use a connect BIO under the SSL BIO */ out = BIO_new(BIO_s_connect()); - BIO_set_conn_hostname(out, host); + BIO_set_conn_hostname(out, hostport); BIO_set_nbio(out, 1); out = BIO_push(ssl_bio, out); diff --git a/demos/bio/server.pem b/demos/bio/server.pem index ef0d22a67b..8a4a51f9f0 100644 --- a/demos/bio/server.pem +++ b/demos/bio/server.pem @@ -1,26 +1,52 @@ subject= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = Test Server Cert issuer= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = OpenSSL Test Intermediate CA -----BEGIN CERTIFICATE----- -MIIDpTCCAo2gAwIBAgIJAK8ArbvjIOQlMA0GCSqGSIb3DQEBCwUAMHAxCzAJBgNV +MIIDyTCCArGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVSzEW +MBQGA1UECgwNT3BlblNTTCBHcm91cDEiMCAGA1UECwwZRk9SIFRFU1RJTkcgUFVS +UE9TRVMgT05MWTElMCMGA1UEAwwcT3BlblNTTCBUZXN0IEludGVybWVkaWF0ZSBD +QTAgFw0xNjAxMDQwODU0NDZaGA8yMTE2MDEwNTA4NTQ0NlowZDELMAkGA1UEBhMC +VUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBURVNUSU5H +IFBVUlBPU0VTIE9OTFkxGTAXBgNVBAMMEFRlc3QgU2VydmVyIENlcnQwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDzhPOSNtyyRspmeuUpxfNJKCLTuf7g +3uQ4zu4iHOmRO5TQci+HhVlLZrHF9XqFXcIP0y4pWDbMSGuiorUmzmfiR7bfSdI/ ++qIQt8KXRH6HNG1t8ou0VSvWId5TS5Dq/er5ODUr9OaaDva7EquHIcMvvPQGuI+O +EAcnleVCy9HVEIySrO4P3CNIicnGkwwiAud05yUAq/gPXBC1hTtmlPD7TVcGVSEi +Jdvzqqlgv02qedGrkki6GY4S7GjZxrrf7Foc2EP+51LJzwLQx3/JfrCU41NEWAsu +/Sl0tQabXESN+zJ1pDqoZ3uHMgpQjeGiE0olr+YcsSW/tJmiU9OiAr8RAgMBAAGj +eDB2MB0GA1UdDgQWBBSCvM8AABPR9zklmifnr9LvIBturDAfBgNVHSMEGDAWgBQ2 +w2yI55X+sL3szj49hqshgYfa2jAJBgNVHRMEAjAAMBMGA1UdJQQMMAoGCCsGAQUF +BwMBMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAC78R +sAr4uvkYOu/pSwQ3MYOFqZ0BnPuP0/AZW2zF7TLNy8g36GyH9rKxz2ffQEHRmPQN +Z11Ohg3z03jw/sVzkgt2U5Ipv923sSeCZcu0nuNex3v9/x72ldYikZNhQOsw+2kr +hx3OvE9R7xl9eyjz7BknsbY7PC3kiUY8SDdc5Fr/XMkHm3ge65oWYOHBjC5tAr5K +FGCEjM3syxS+Li5X6yfDGiVSjOU4gJuZDCYbl7cEQexU2deds8EmpJJrrI7s4JcQ +rraHI8+Hu8X9VLpZE1jl/fKJw3D0i53PoN2WhukIOg1Zv+ajMKQ4ubVfISH2ebox ++ybAZO8hxL6/I08/GQ== +-----END CERTIFICATE----- +subject= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = OpenSSL Test Intermediate CA +issuer= C = UK, O = OpenSSL Group, OU = FOR TESTING PURPOSES ONLY, CN = OpenSSL Test Root CA +-----BEGIN CERTIFICATE----- +MIIDvjCCAqagAwIBAgIJAPzCy4CUW9/qMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVT -VElORyBQVVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJt -ZWRpYXRlIENBMB4XDTE1MDcxNDEzMjIwNVoXDTI1MDUyMjEzMjIwNVowZDELMAkG -A1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxIjAgBgNVBAsMGUZPUiBU -RVNUSU5HIFBVUlBPU0VTIE9OTFkxGTAXBgNVBAMMEFRlc3QgU2VydmVyIENlcnQw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDzhPOSNtyyRspmeuUpxfNJ -KCLTuf7g3uQ4zu4iHOmRO5TQci+HhVlLZrHF9XqFXcIP0y4pWDbMSGuiorUmzmfi -R7bfSdI/+qIQt8KXRH6HNG1t8ou0VSvWId5TS5Dq/er5ODUr9OaaDva7EquHIcMv -vPQGuI+OEAcnleVCy9HVEIySrO4P3CNIicnGkwwiAud05yUAq/gPXBC1hTtmlPD7 -TVcGVSEiJdvzqqlgv02qedGrkki6GY4S7GjZxrrf7Foc2EP+51LJzwLQx3/JfrCU -41NEWAsu/Sl0tQabXESN+zJ1pDqoZ3uHMgpQjeGiE0olr+YcsSW/tJmiU9OiAr8R -AgMBAAGjTjBMMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXgMCwGCWCGSAGG -+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0B -AQsFAAOCAQEAq8v8dvU3Xskb7q5LKbLXxTIF6owFs5uLk2k2msEAQzX7SrYFZwdE -5e33S71rpDbXiJjyD4Yj0Av5yeRlW0YVFlBZAwgPn29CDCD6+DeQ7AwtXvJhcq9e -llTLpB1EuXC5UCerQmq99wmfTrK0q4hgK7/5c7mcoD7V1iOEvxI2kmG6ukIupbKi -P1TNVVET1kPhRG1dFP9rge7j2ssY3/H+j3jlAJnwQQoYg+YCZ6g0atjOrqvywAy3 -5E2d9LPF3TKw2mf4mAxjU6hPDOk0tiMS6g1xdHyeTftPXfN8Gli0T0LpNpy5a24B -dLPqZEpj0kXT8gTYEROX7tq9gYwpe6FVKw== +VElORyBQVVJQT1NFUyBPTkxZMR0wGwYDVQQDDBRPcGVuU1NMIFRlc3QgUm9vdCBD +QTAeFw0xNTA3MTQxMzIyMDVaFw0yNTA2MjExMzIyMDVaMHAxCzAJBgNVBAYTAlVL +MRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMSIwIAYDVQQLDBlGT1IgVEVTVElORyBQ +VVJQT1NFUyBPTkxZMSUwIwYDVQQDDBxPcGVuU1NMIFRlc3QgSW50ZXJtZWRpYXRl +IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsErw75CmLYD6pkrG +W/YhAl/K8L5wJYxDjqu2FghxjD8K308W3EHq4uBxEwR1OHXaM1+6ZZw7/r2I37VL +IdurBEAIEUdbzx0so74FPawgz5EW2CTqoJnK8F71/vo5Kj1VPwW46CxwxUR3cfvJ +GNXND2ip0TcyTSPLROXOyQakcVfIGJmdSa1wHKi+c2gMA4emADudZUOYLrg80gr2 +ldePm07ynbVsKKzCcStw8MdmoW9Qt3fLnPJn2TFUUBNWj+4kvL+88edWCVQXKNds +ysD/CDrH4W/hjyPDStVsM6XpiNU0+L2ZY6fcj3OP8d0goOx45xotMn9m8hNkCGsr +VXx9IwIDAQABo2MwYTAdBgNVHQ4EFgQUNsNsiOeV/rC97M4+PYarIYGH2towHwYD +VR0jBBgwFoAUjBkP10IxdwUG4dOxn+s5+3hxOkUwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAANQT0pDWBQoT/RY76xz +audadGz/dfYnwvSwT0RMFcXLcMVVRNqP0HeR8OP8qLaP7onRbNnEXNfos9pxXYlg +j+/WjWTBLVcr3pX2Xtmcaqw3CGN9qbQI8B3JkYeijZmc5+3r5MzK/9R0w8Y/T9Xt +CXEiQhtWHpPrFEfrExeVy2kjJNRctEfq3OTd1bjgX64zvTU7eR+MHFYKPoyMqwIR +gjoVKinvovEwWoZe5kfMQwJNA3IgoJexX9BXbS8efAYF/ku3tS0laoZS/q6V/o5I +RvG0OqnNgxhul+96PE5ujSaprsyvBswIUKt+e/BCxGaS6f2AJ8RmtoPOSfT4b9qN +thI= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA84TzkjbcskbKZnrlKcXzSSgi07n+4N7kOM7uIhzpkTuU0HIv diff --git a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod b/doc/crypto/X509_VERIFY_PARAM_set_flags.pod index df5766cdef..a2219d2aae 100644 --- a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod +++ b/doc/crypto/X509_VERIFY_PARAM_set_flags.pod @@ -127,7 +127,7 @@ IPv6. The condensed "::" notation is supported for IPv6 addresses. X509_VERIFY_PARAM_set_flags(), X509_VERIFY_PARAM_clear_flags(), X509_VERIFY_PARAM_set_purpose(), X509_VERIFY_PARAM_set_trust(), X509_VERIFY_PARAM_add0_policy() X509_VERIFY_PARAM_set1_policies(), -X509_VERIFY_PARAM_set1_host(), X509_VERIFY_PARAM_set_hostflags(), +X509_VERIFY_PARAM_set1_host(), X509_VERIFY_PARAM_add1_host(), X509_VERIFY_PARAM_set1_email(), X509_VERIFY_PARAM_set1_ip() and X509_VERIFY_PARAM_set1_ip_asc() return 1 for success and 0 for failure. diff --git a/doc/ssl/SSL_CTX_dane_enable.pod b/doc/ssl/SSL_CTX_dane_enable.pod new file mode 100644 index 0000000000..66eb1b3d8d --- /dev/null +++ b/doc/ssl/SSL_CTX_dane_enable.pod @@ -0,0 +1,278 @@ +=pod + +=head1 NAME + +SSL_CTX_dane_enable, SSL_CTX_dane_mtype_set, SSL_dane_enable, +SSL_dane_tlsa_add, SSL_get0_dane_authority, SSL_get0_dane_tlsa - +enable DANE TLS authentication of the remote TLS server in the local +TLS client + +=head1 SYNOPSIS + + #include <openssl/ssl.h> + + int SSL_CTX_dane_enable(SSL_CTX *ctx); + int SSL_CTX_dane_mtype_set(SSL_CTX *ctx, const EVP_MD *md, + uint8_t mtype, uint8_t ord); + int SSL_dane_enable(SSL *s, const char *basedomain); + int SSL_dane_tlsa_add(SSL *s, uint8_t usage, uint8_t selector, + uint8_t mtype, unsigned char *data, size_t dlen); + int SSL_get0_dane_authority(SSL *s, X509 **mcert, EVP_PKEY **mspki); + int SSL_get0_dane_tlsa(SSL *s, uint8_t *usage, uint8_t *selector, + uint8_t *mtype, unsigned const char **data, + size_t *dlen); + +=head1 DESCRIPTION + +These functions implement support for DANE TLSA (RFC6698 and RFC7671) +peer authentication. + +SSL_CTX_dane_enable() must be called first to initialize the +shared state required for DANE support. Individual connections +associated with the context can then enable per-connection DANE +support as appropriate. DANE authentication is implemented in the +L<X509_verify_cert(3)> function, and applications that override +L<X509_verify_cert(3)> via L<SSL_CTX_set_cert_verify_callback(3)> +are responsible to authenticate the peer chain in whatever manner +they see fit. + +SSL_CTX_dane_mtype_set() may then be called zero or more times to +to adjust the supported digest algorithms. This must be done before +any SSL handles are created for the context. + +The B<mtype> argument specifies a DANE TLSA matching type and the +the B<md> argument specifies the associated digest algorithm handle. +The B<ord> argument specifies a strength ordinal. Algorithms with +a larger strength ordinal are considered more secure. Strength +ordinals are used to implement RFC7671 digest algorithm agility. +Specifying a B<NULL> digest algorithm for a matching type disables +support for that matching type. Matching type Full(0) cannot be +modified or disabled. + +By default, matching type C<SHA2-256(1)> (see RFC7218 for definitions +of the DANE TLSA parameter acronyms) is mapped to C<EVP_sha256()> +with a strength ordinal of C<1> and matching type C<SHA2-512(2)> +is mapped to C<EVP_sha512()> with a strength ordinal of C<2>. + +SSL_dane_enable() may be called before the SSL handshake is +initiated with L<SSL_connect(3)> to enable DANE for that connection. +(The connection must be associated with a DANE-enabled SSL context). +The B<basedomain> argument specifies the RFC7671 TLSA base domain, +which will be the primary peer reference identifier for certificate +name checks. Additional server names can be specified via +L<SSL_add1_host(3)>. The B<basedomain> is used as the default SNI +hint if none has yet been specified via L<SSL_set_tlsext_host_name(3)>. + +SSL_dane_tlsa_add() may then be called one or more times, to +load each of the TLSA records that apply to the remote TLS peer. +(This too must be done prior to the beginning of the SSL handshake). +The arguments specify the fields of the TLSA record. The B<data> +field is provided in binary (wire RDATA) form, not the hexadecimal ASCII +presentation form, with an explicit length passed via B<dlen>. +A return value of 0 indicates that "unusable" TLSA records +(with invalid or unsupported parameters) were provided, a negative +return value indicates an internal error in processing the records. +If DANE authentication is enabled, but no TLSA records are added +successfully, authentication will fail, and the handshake may not +complete, depending on the B<mode> argument of L<SSL_set_verify(3)> +and any verification callback. + +SSL_get0_dane_authority() can be used to get more detailed information +about the matched DANE trust-anchor after successful connection +completion. The return value is negative if DANE verification +failed (or was not enabled), 0 if an EE TLSA record directly matched +the leaf certificate, or a positive number indicating the depth at +which a TA record matched an issuer certificate. + +If the B<mcert> argument is not B<NULL> and a TLSA record matched +a chain certificate, a pointer to the matching certificate is +returned via B<mcert>. The returned address is a short-term internal +reference to the certificate and must not be freed by the application. +Applications that want to retain access to the certificate can call +L<X509_up_ref(3)> to obtain a long-term reference which must then +be freed via L<X509_free(3)> once no longer needed. + +If no TLSA records directly matched any elements of the certificate +chain, but a DANE-TA(2) SPKI(1) Full(0) record provided the public +key that signed an element of the chain, then that key is returned +via B<mspki> argument (if not NULL). In this case the return value +is the depth of the top-most element of the validated certificate +chain. As with B<mcert> this is a short-term internal reference, +and L<EVP_PKEY_up_ref(3)> and L<EVP_PKEY_free(3)> can be used to +acquire and release long-term references respectively. + +SSL_get0_dane_tlsa() can be used to retrieve the fields of the +TLSA record that matched the peer certificate chain. The return +value indicates the match depth or failure to match just as with +SSL_get0_dane_authority(). When the return value is non-negative, +the storage pointed to by the B<usage>, B<selector>, B<mtype> and +B<data> parameters is updated to the corresponding TLSA record +fields. The B<data> field is in binary wire form, and is therefore +not NUL-terminated, its length is returned via the B<dlen> parameter. +If any of these parameters is NULL, the corresponding field +is not returned. The B<data> parameter is set to a short-term +internal-copy of the associated data field and must not be freed +by the application. Applications that need long-term access to +this field need to copy the content. + +=head1 RETURN VALUES + +The functions SSL_CTX_dane_enable(), SSL_CTX_dane_mtype_set(), +SSL_dane_enable() and SSL_dane_tlsa_add() return a positive value +on success. Negative return values indicate resource problems (out +of memory, etc.) in the SSL library, while a return value of B<0> +indicates incorrect usage or invalid input, such as an unsupported +TLSA record certificate usage, selector or matching type. Invalid +input also includes malformed data, either a digest length that +does not match the digest algorithm, or a C<Full(0)> (binary ASN.1 +DER form) certificate or a public key that fails to parse. + +The functions SSL_get0_dane_authority() and SSL_get0_dane_tlsa() +return a negative value when DANE authentication failed or was not +enabled, a non-negative value indicates the chain depth at which +the TLSA record matched a chain certificate, or the depth of the +top-most certificate, when the TLSA record is a full public key +that is its signer. + +=head1 EXAMPLE + +Suppose "smtp.example.com" is the MX host of the domain "example.com", +and has DNSSEC-validated TLSA records. The calls below will perform +DANE authentication and arrange to match either the MX hostname or +the destination domain name in the SMTP server certificate. Wildcards +are supported, but must match the entire label. The actual name +matched in the certificate (which might be a wildcard) is retrieved, +and must be copied by the application if it is to be retained beyond +the lifetime of the SSL connection. + + SSL_CTX *ctx; + SSL *ssl; + int num_usable = 0; + const char *nexthop_domain = "example.com"; + const char *dane_tlsa_domain = "smtp.example.com"; + uint8_t usage, selector, mtype; + + if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL) + /* handle error */ + if (SSL_CTX_dane_enable(ctx) <= 0) + /* handle error */ + + if ((ssl = SSL_new(ctx)) == NULL) + /* handle error */ + + if (SSL_dane_enable(ssl, dane_tlsa_domain) <= 0) + /* handle error */ + if (!SSL_add1_host(ssl, nexthop_domain)) + /* handle error */ + SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + + for (... each TLSA record ...) { + unsigned char *data; + size_t len; + int ret; + + /* set usage, selector, mtype, data, len */ + + /* Opportunistic DANE TLS clients treat usages 0, 1 as unusable. */ + switch (usage) { + case 0: /* PKIX-TA(0) */ + case 1: /* PKIX-EE(1) */ + continue; + } + + ret = SSL_dane_tlsa_add(ssl, usage, selector, mtype, data, len); + /* free data as approriate */ + + if (ret < 0) + /* handle SSL library internal error */ + else if (ret == 0) + /* handle unusable TLSA record */ + else + ++num_usable; + } + + /* + * Opportunistic DANE clients use unauthenticated TLS when all TLSA records + * are unusable, so continue the handshake even if authentication fails. + */ + if (num_usable == 0) { + int (*cb)(int ok, X509_STORE_CTX *sctx) = NULL; + + /* Log all records unusable? */ + /* Set cb to a non-NULL callback of your choice? */ + + SSL_set_verify(ssl, SSL_VERIFY_NONE, cb); + } + + /* Perform SSL_connect() handshake and handle errors here */ + + if (SSL_get_verify_result(ssl) == X509_V_OK) { + const char *peername = SSL_get0_peername(ssl); + EVP_PKEY *mspki = NULL; + + int depth = SSL_get0_dane_authority(s, NULL, &mspki); + if (depth >= 0) { + (void) SSL_get0_dane_tlsa(s, &usage, &selector, &mtype, NULL, NULL); + printf("DANE TLSA %d %d %d %s at depth %d\n", usage, selector, mtype, + (mspki != NULL) ? "TA public key verified certificate" : + depth ? "matched TA certificate" : "matched EE certificate", + depth); + } + if (peername != NULL) { + /* Name checks were in scope and matched the peername */ + printf(bio, "Verified peername: %s\n", peername); + } + } else { + /* + * Not authenticated, presumably all TLSA rrs unusable, but possibly a + * callback suppressed connection termination despite presence of TLSA + * usable RRs none of which matched. Do whatever is appropriate for + * unauthenticated connections. + */ + } + +=head1 NOTES + +It is expected that the majority of clients employing DANE TLS will +be doing "opportunistic DANE TLS" in the sense of RFC7672 and +RFC7435. That is, they will use DANE authentication when +DNSSEC-validated TLSA records are published for a given peer, and +otherwise will use unauthenticated TLS or even cleartext. + +Such applications should generally treat any TLSA records published +by the peer with usages PKIX-TA(0) and PKIX-EE(1) as "unusable", +and should not include them among the TLSA records used to authenticate +peer connections. In addition, some TLSA records with supported +usages may be "unusable" as a result of invalid or unsupported +parameters. + +When a peer has TLSA records, but none are "usable", an opportunistic +application must avoid cleartext, but cannot authenticate the peer, +and so should generally proceed with an unauthenticated connection. +Opportunistic applications need to note the return value of each +call to SSL_dane_tlsa_add(), and if all return 0 (due to invalid +or unsupported parameters) disable peer authentication by calling +L<SSL_set_verify(3)> with B<mode> equal to B<SSL_VERIFY_NONE>. + +=head1 SEE ALSO + +L<SSL_new(3)>, +L<SSL_add1_host(3)>, +L<SSL_set_hostflags(3)>, +L<SSL_set_tlsext_host_name(3)>, +L<SSL_set_verify(3)>, +L<SSL_CTX_set_cert_verify_callback(3)>, +L<X509_verify_cert(3)>, +L<SSL_connect(3)>, +L<SSL_get0_peername(3)>, +L<EVP_get_digestbyname(3)>, +L<X509_up_ref(3)>, +L<X509_free(3)>, +L<EVP_PKEY_up_ref(3)>, +L<EVP_PKEY_free(3)> + +=head1 HISTORY + +These functions were first added to OpenSSL 1.1.0. + +=cut diff --git a/doc/ssl/SSL_set1_host.pod b/doc/ssl/SSL_set1_host.pod new file mode 100644 index 0000000000..b008a5ff6e --- /dev/null +++ b/doc/ssl/SSL_set1_host.pod @@ -0,0 +1,115 @@ +=pod + +=head1 NAME + + SSL_set1_host, SSL_add1_host, SSL_set_hostflags, SSL_get0_peername - + SSL server verification parameters + +=head1 SYNOPSIS + + #include <openssl/ssl.h> + #include <openssl/x509_vfy.h> + + int SSL_set1_host(SSL *s, const char *hostname); + int SSL_add1_host(SSL *s, const char *hostname); + void SSL_set_hostflags(SSL *s, unsigned int flags); + const char *SSL_get0_peername(SSL *s); + +=head1 DESCRIPTION + +These functions configure server hostname checks in the SSL client. + +SSL_set1_host() sets the expected DNS hostname to B<name> clearing +any previously specified host name or names. If B<name> is NULL, +or the empty string the list of hostnames is cleared, and name +checks are not performed on the peer certificate. When a non-empty +B<name> is specified, certificate verification automatically checks +the peer hostname via L<X509_check_host(3)> with B<flags> as specified +via SSL_set_hostflags(). Clients that enable DANE TLSA authentication +via L<SSL_dane_enable(3)> should leave it to that function to set +the primary reference identifier of the peer, and should not call +SSL_set1_host(). + +SSL_add1_host() adds B<name> as an additional reference identifier +that can match the peer's certificate. Any previous names set via +SSL_set1_host() or SSL_add1_host() are retained, no change is made +if B<name> is NULL or empty. When multiple names are configured, +the peer is considered verified when any name matches. This function +is required for DANE TLA in the presence of service name indirection +via CNAME, MX or SRV records as specified in RFC7671, RFC7672 or +RFC7673. + +SSL_set_hostflags() sets the B<flags> that will be passed to +L<X509_check_host(3)> when name checks are applicable, by default +the B<flags> value is 0. See L<X509_check_host(3)> for the list +of available flags and their meaning. + +SSL_get0_peername() returns the DNS hostname or subject CommonName +from the peer certificate that matched one of the reference +identifiers. When wildcard matching is not disabled, the name +matched in the peer certificate may be a wildcard name. When one +of the reference identifiers configured via SSL_set1_host() or +SSL_add1_host() starts with ".", which indicates a parent domain prefix +rather than a fixed name, the matched peer name may be a sub-domain +of the reference identifier. The returned string is allocated by +the library and is no longer valid once the associated B<ssl> handle +is cleared or freed, or a renegotiation takes place. Applications +must not free the return value. + +SSL clients are advised to use these functions in preference to +explicitly calling L<X509_check_host(3)>. Hostname checks are out +of scope with the RFC7671 DANE-EE(3) certificate usage, and the +internal check will be suppressed as appropriate when DANE is +enabled. + +=head1 RETURN VALUES + +SSL_set1_host() and SSL_add1_host() return 1 for success and 0 for +failure. + +SSL_get0_peername() returns NULL if peername verification is not +applicable (as with RFC7671 DANE-EE(3)), or no trusted peername was +matched. Otherwise, it returns the matched peername. To determine +whether verification succeeded call L<SSL_get_verify_result(3)>. + +=head1 NOTES + +=head1 EXAMPLE + +Suppose "smtp.example.com" is the MX host of the domain "example.com". +The calls below will arrange to match either the MX hostname or the +destination domain name in the SMTP server certificate. Wildcards +are supported, but must match the entire label. The actual name +matched in the certificate (which might be a wildcard) is retrieved, +and must be copied by the application if it is to be retained beyond +the lifetime of the SSL connection. + + SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + if (!SSL_set1_host(ssl, "smtp.example.com")) { + /* handle error */ + } + if (!SSL_add1_host(ssl, "example.com")) { + /* handle error */ + } + + /* XXX: Perform SSL_connect() handshake and handle errors here */ + + if (SSL_get_verify_result(ssl) == X509_V_OK) { + const char *peername = SSL_get0_peername(ssl); + + if (peername != NULL) { + /* Name checks were in scope and matched the peername */ + } + } + +=head1 SEE ALSO + +L<X509_check_host(3)>, +L<SSL_get_verify_result(3)>. +L<SSL_dane_enable(3)>. + +=head1 HISTORY + +These functions were first added to OpenSSL 1.1.0. + +=cut diff --git a/doc/ssl/ssl.pod b/doc/ssl/ssl.pod index adcec5ffa9..bb3bc94809 100644 --- a/doc/ssl/ssl.pod +++ b/doc/ssl/ssl.pod @@ -447,6 +447,25 @@ success or 0 on failure. =item SSL *B<SSL_dup>(SSL *ssl); +SSL_dup() allows applications to configure an SSL handle for use +in multiple SSL connections, and then duplicate it prior to initiating +each connection with the duplicated handle. +Use of SSL_dup() avoids the need to repeat the configuration of the +handles for each connection. +This is used internally by L<BIO_s_accept(3)> to construct +per-connection SSL handles after L<accept(2)>. + +For SSL_dup() to work, the connection MUST be in its initial state +and MUST NOT have not yet have started the SSL handshake. +For connections that are not in their initial state SSL_dup() just +increments an internal reference count and returns the I<same> +handle. +It may be possible to use L<SSL_clear(3)> to recycle an SSL handle +that is not in its initial state for re-use, but this is best +avoided. +Instead, save and restore the session, if desired, and construct a +fresh handle for each connection. + =item STACK *B<SSL_dup_CA_list>(STACK *sk); =item void B<SSL_free>(SSL *ssl); diff --git a/include/internal/dane.h b/include/internal/dane.h new file mode 100644 index 0000000000..cbe33f3e48 --- /dev/null +++ b/include/internal/dane.h @@ -0,0 +1,147 @@ +/* dane.h */ +/* + * Written by Viktor Dukhovni (viktor@openssl.org) for the OpenSSL project + * 2015. + */ +/* ==================================================================== + * Copyright (c) 2015 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). + * + */ +#ifndef HEADER_INTERNAL_DANE_H +#define HEADER_INTERNAL_DANE_H + +#include <openssl/safestack.h> + +/*- + * Certificate usages: + * https://tools.ietf.org/html/rfc6698#section-2.1.1 + */ +#define DANETLS_USAGE_PKIX_TA 0 +#define DANETLS_USAGE_PKIX_EE 1 +#define DANETLS_USAGE_DANE_TA 2 +#define DANETLS_USAGE_DANE_EE 3 +#define DANETLS_USAGE_LAST DANETLS_USAGE_DANE_EE + +/*- + * Selectors: + * https://tools.ietf.org/html/rfc6698#section-2.1.2 + */ +#define DANETLS_SELECTOR_CERT 0 +#define DANETLS_SELECTOR_SPKI 1 +#define DANETLS_SELECTOR_LAST DANETLS_SELECTOR_SPKI + +/*- + * Matching types: + * https://tools.ietf.org/html/rfc6698#section-2.1.3 + */ +#define DANETLS_MATCHING_FULL 0 +#define DANETLS_MATCHING_2256 1 +#define DANETLS_MATCHING_2512 2 +#define DANETLS_MATCHING_LAST DANETLS_MATCHING_2512 + +typedef struct danetls_record_st { + uint8_t usage; + uint8_t selector; + uint8_t mtype; + unsigned char *data; + size_t dlen; + EVP_PKEY *spki; +} danetls_record; + +/* + * Shared DANE context + */ +struct dane_ctx_st { + const EVP_MD **mdevp; /* mtype -> digest */ + uint8_t *mdord; /* mtype -> preference */ + uint8_t mdmax; /* highest supported mtype */ +}; + +/* + * Per connection DANE state + */ +struct dane_st { + struct dane_ctx_st *dctx; + STACK_OF(danetls_record) *trecs; + STACK_OF(X509) *certs; /* DANE-TA(2) Cert(0) Full(0) certs */ + danetls_record *mtlsa; /* Matching TLSA record */ + X509 *mcert; /* DANE matched cert */ + uint32_t umask; /* Usages present */ + int mdpth; /* Depth of matched cert */ + int pdpth; /* Depth of PKIX trust */ +}; + +#define DANETLS_ENABLED(dane) ((dane) && ((dane)->trecs != NULL)) + +#define DANETLS_USAGE_BIT(u) (((uint32_t)1) << u) + +#define DANETLS_PKIX_TA_MASK (DANETLS_USAGE_BIT(DANETLS_USAGE_PKIX_TA)) +#define DANETLS_PKIX_EE_MASK (DANETLS_USAGE_BIT(DANETLS_USAGE_PKIX_EE)) +#define DANETLS_DANE_TA_MASK (DANETLS_USAGE_BIT(DANETLS_USAGE_DANE_TA)) +#define DANETLS_DANE_EE_MASK (DANETLS_USAGE_BIT(DANETLS_USAGE_DANE_EE)) + +#define DANETLS_PKIX_MASK (DANETLS_PKIX_TA_MASK | DANETLS_PKIX_EE_MASK) +#define DANETLS_DANE_MASK (DANETLS_DANE_TA_MASK | DANETLS_DANE_EE_MASK) +#define DANETLS_TA_MASK (DANETLS_PKIX_TA_MASK | DANETLS_DANE_TA_MASK) +#define DANETLS_EE_MASK (DANETLS_PKIX_EE_MASK | DANETLS_DANE_EE_MASK) + +#define DANETLS_HAS_PKIX(dane) ((dane) && ((dane)->umask & DANETLS_PKIX_MASK)) +#define DANETLS_HAS_DANE(dane) ((dane) && ((dane)->umask & DANETLS_DANE_MASK)) +#define DANETLS_HAS_TA(dane) ((dane) && ((dane)->umask & DANETLS_TA_MASK)) +#define DANETLS_HAS_EE(dane) ((dane) && ((dane)->umask & DANETLS_EE_MASK)) + +#define DANETLS_HAS_PKIX_TA(dane) ((dane)&&((dane)->umask & DANETLS_PKIX_TA_MASK)) +#define DANETLS_HAS_PKIX_EE(dane) ((dane)&&((dane)->umask & DANETLS_PKIX_EE_MASK)) +#define DANETLS_HAS_DANE_TA(dane) ((dane)&&((dane)->umask & DANETLS_DANE_TA_MASK)) +#define DANETLS_HAS_DANE_EE(dane) ((dane)&&((dane)->umask & DANETLS_DANE_EE_MASK)) + +#endif /* HEADER_INTERNAL_DANE_H */ diff --git a/include/openssl/safestack.h b/include/openssl/safestack.h index cce3afd630..94b8af4cca 100644 --- a/include/openssl/safestack.h +++ b/include/openssl/safestack.h @@ -2045,6 +2045,29 @@ DECLARE_SPECIAL_STACK_OF(OPENSSL_BLOCK, void) # define sk_X509_VERIFY_PARAM_sort(st) SKM_sk_sort(X509_VERIFY_PARAM, (st)) # define sk_X509_VERIFY_PARAM_is_sorted(st) SKM_sk_is_sorted(X509_VERIFY_PARAM, (st)) +# define sk_danetls_record_new(cmp) SKM_sk_new(danetls_record, (cmp)) +# define sk_danetls_record_new_null() SKM_sk_new_null(danetls_record) +# define sk_danetls_record_free(st) SKM_sk_free(danetls_record, (st)) +# define sk_danetls_record_num(st) SKM_sk_num(danetls_record, (st)) +# define sk_danetls_record_value(st, i) SKM_sk_value(danetls_record, (st), (i)) +# define sk_danetls_record_set(st, i, val) SKM_sk_set(danetls_record, (st), (i), (val)) +# define sk_danetls_record_zero(st) SKM_sk_zero(danetls_record, (st)) +# define sk_danetls_record_push(st, val) SKM_sk_push(danetls_record, (st), (val)) +# define sk_danetls_record_unshift(st, val) SKM_sk_unshift(danetls_record, (st), (val)) +# define sk_danetls_record_find(st, val) SKM_sk_find(danetls_record, (st), (val)) +# define sk_danetls_record_find_ex(st, val) SKM_sk_find_ex(danetls_record, (st), (val)) +# define sk_danetls_record_delete(st, i) SKM_sk_delete(danetls_record, (st), (i)) +# define sk_danetls_record_delete_ptr(st, ptr) SKM_sk_delete_ptr(danetls_record, (st), (ptr)) +# define sk_danetls_record_insert(st, val, i) SKM_sk_insert(danetls_record, (st), (val), (i)) +# define sk_danetls_record_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(danetls_record, (st), (cmp)) +# define sk_danetls_record_dup(st) SKM_sk_dup(danetls_record, st) +# define sk_danetls_record_pop_free(st, free_func) SKM_sk_pop_free(danetls_record, (st), (free_func)) +# define sk_danetls_record_deep_copy(st, copy_func, free_func) SKM_sk_deep_copy(danetls_record, (st), (copy_func), (free_func)) +# define sk_danetls_record_shift(st) SKM_sk_shift(danetls_record, (st)) +# define sk_danetls_record_pop(st) SKM_sk_pop(danetls_record, (st)) +# define sk_danetls_record_sort(st) SKM_sk_sort(danetls_record, (st)) +# define sk_danetls_record_is_sorted(st) SKM_sk_is_sorted(danetls_record, (st)) + # define sk_nid_triple_new(cmp) SKM_sk_new(nid_triple, (cmp)) # define sk_nid_triple_new_null() SKM_sk_new_null(nid_triple) # define sk_nid_triple_free(st) SKM_sk_free(nid_triple, (st)) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 0d22ab7716..e6342946dd 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -327,6 +327,8 @@ typedef struct ssl_conf_ctx_st SSL_CONF_CTX; DECLARE_STACK_OF(SSL_CIPHER) +DECLARE_STACK_OF(danetls_record) + /* SRTP protection profiles for use with the use_srtp extension (RFC 5764)*/ typedef struct srtp_protection_profile_st { const char *name; @@ -1533,6 +1535,27 @@ __owur int SSL_set_purpose(SSL *s, int purpose); __owur int SSL_CTX_set_trust(SSL_CTX *s, int trust); __owur int SSL_set_trust(SSL *s, int trust); +__owur int SSL_set1_host(SSL *s, const char *hostname); +__owur int SSL_add1_host(SSL *s, const char *hostname); +__owur const char *SSL_get0_peername(SSL *s); +void SSL_set_hostflags(SSL *s, unsigned int flags); + +__owur int SSL_CTX_dane_enable(SSL_CTX *ctx); +__owur int SSL_CTX_dane_mtype_set(SSL_CTX *ctx, const EVP_MD *md, + uint8_t mtype, uint8_t ord); +__owur int SSL_dane_enable(SSL *s, const char *basedomain); +__owur int SSL_dane_tlsa_add(SSL *s, uint8_t usage, uint8_t selector, + uint8_t mtype, unsigned char *data, size_t dlen); +__owur int SSL_get0_dane_authority(SSL *s, X509 **mcert, EVP_PKEY **mspki); +__owur int SSL_get0_dane_tlsa(SSL *s, uint8_t *usage, uint8_t *selector, + uint8_t *mtype, unsigned const char **data, + size_t *dlen); +/* + * Bridge opacity barrier between libcrypt and libssl, also needed to support + * offline testing in test/danetest.c + */ +struct dane_st *SSL_get0_dane(SSL *ssl); + __owur int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm); __owur int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm); @@ -1919,6 +1942,9 @@ void ERR_load_SSL_strings(void); /* Function codes. */ # define SSL_F_CHECK_SUITEB_CIPHER_LIST 331 # define SSL_F_D2I_SSL_SESSION 103 +# define SSL_F_DANE_CTX_ENABLE 347 +# define SSL_F_DANE_MTYPE_SET 393 +# define SSL_F_DANE_TLSA_ADD 394 # define SSL_F_DO_DTLS1_WRITE 245 # define SSL_F_DO_SSL3_WRITE 104 # define SSL_F_DTLS1_ACCEPT 246 @@ -2059,6 +2085,7 @@ void ERR_load_SSL_strings(void); # define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE 179 # define SSL_F_SSL_CTX_USE_SERVERINFO 336 # define SSL_F_SSL_CTX_USE_SERVERINFO_FILE 337 +# define SSL_F_SSL_DANE_ENABLE 395 # define SSL_F_SSL_DO_CONFIG 391 # define SSL_F_SSL_DO_HANDSHAKE 180 # define SSL_F_SSL_GET_NEW_SESSION 181 @@ -2232,8 +2259,20 @@ void ERR_load_SSL_strings(void); # define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307 # define SSL_R_COMPRESSION_LIBRARY_ERROR 142 # define SSL_R_CONNECTION_TYPE_NOT_SET 144 +# define SSL_R_CONTEXT_NOT_DANE_ENABLED 167 # define SSL_R_COOKIE_GEN_CALLBACK_FAILURE 400 # define SSL_R_COOKIE_MISMATCH 308 +# define SSL_R_DANE_ALREADY_ENABLED 172 +# define SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL 173 +# define SSL_R_DANE_NOT_ENABLED 175 +# define SSL_R_DANE_TLSA_BAD_CERTIFICATE 180 +# define SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE 184 +# define SSL_R_DANE_TLSA_BAD_DATA_LENGTH 189 +# define SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH 192 +# define SSL_R_DANE_TLSA_BAD_MATCHING_TYPE 200 +# define SSL_R_DANE_TLSA_BAD_PUBLIC_KEY 201 +# define SSL_R_DANE_TLSA_BAD_SELECTOR 202 +# define SSL_R_DANE_TLSA_NULL_DATA 203 # define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145 # define SSL_R_DATA_LENGTH_TOO_LONG 146 # define SSL_R_DECRYPTION_FAILED 147 @@ -2253,6 +2292,7 @@ void ERR_load_SSL_strings(void); # define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 354 # define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150 # define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151 +# define SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN 204 # define SSL_R_EXCESSIVE_MESSAGE_SIZE 152 # define SSL_R_EXTRA_DATA_IN_MESSAGE 153 # define SSL_R_FAILED_TO_INIT_ASYNC 405 diff --git a/include/openssl/x509_vfy.h b/include/openssl/x509_vfy.h index 5e65998b35..e37c2f7f60 100644 --- a/include/openssl/x509_vfy.h +++ b/include/openssl/x509_vfy.h @@ -263,6 +263,7 @@ struct x509_store_ctx_st { /* X509_STORE_CTX */ /* For CRL path validation: parent context */ X509_STORE_CTX *parent; CRYPTO_EX_DATA ex_data; + struct dane_st *dane; } /* X509_STORE_CTX */ ; void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); @@ -528,6 +529,12 @@ X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx); void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param); int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name); +/* + * Bridge opacity barrier between libcrypt and libssl, also needed to support + * offline testing in test/danetest.c + */ +void X509_STORE_CTX_set0_dane(X509_STORE_CTX *ctx, struct dane_st *dane); + /* X509_VERIFY_PARAM functions */ X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void); @@ -558,6 +565,7 @@ int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, unsigned int flags); char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *); +void X509_VERIFY_PARAM_move_peername(X509_VERIFY_PARAM *, X509_VERIFY_PARAM *); int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, const char *email, size_t emaillen); int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index ae31f5dd66..53989125d6 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -208,15 +208,6 @@ int RECORD_LAYER_set_data(RECORD_LAYER *rl, const unsigned char *buf, int len) return 1; } -void RECORD_LAYER_dup(RECORD_LAYER *dst, RECORD_LAYER *src) -{ - /* - * Currently only called from SSL_dup...which only seems to expect the - * rstate to be duplicated and nothing else from the RECORD_LAYER??? - */ - dst->rstate = src->rstate; -} - void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl) { memset(rl->read_sequence, 0, sizeof(rl->read_sequence)); diff --git a/ssl/record/record.h b/ssl/record/record.h index 96370710c4..af10166a88 100644 --- a/ssl/record/record.h +++ b/ssl/record/record.h @@ -321,7 +321,6 @@ void RECORD_LAYER_release(RECORD_LAYER *rl); int RECORD_LAYER_read_pending(RECORD_LAYER *rl); int RECORD_LAYER_write_pending(RECORD_LAYER *rl); int RECORD_LAYER_set_data(RECORD_LAYER *rl, const unsigned char *buf, int len); -void RECORD_LAYER_dup(RECORD_LAYER *dst, RECORD_LAYER *src); void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl); void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl); int RECORD_LAYER_setup_comp_buffer(RECORD_LAYER *rl); diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 597de0ad6c..7f01bcc641 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -486,6 +486,7 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) int i; X509_STORE *verify_store; X509_STORE_CTX ctx; + X509_VERIFY_PARAM *param; if (s->cert->verify_store) verify_store = s->cert->verify_store; @@ -500,10 +501,16 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, ERR_R_X509_LIB); return (0); } + param = X509_STORE_CTX_get0_param(&ctx); + /* Set suite B flags if needed */ X509_STORE_CTX_set_flags(&ctx, tls1_suiteb(s)); X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), s); + /* Verify via DANE if enabled */ + if (DANETLS_ENABLED(&s->dane)) + X509_STORE_CTX_set0_dane(&ctx, &s->dane); + /* * 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 @@ -512,9 +519,9 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) X509_STORE_CTX_set_default(&ctx, s->server ? "ssl_client" : "ssl_server"); /* - * Anything non-default in "param" should overwrite anything in the ctx. + * Anything non-default in "s->param" should overwrite anything in the ctx. */ - X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param); + X509_VERIFY_PARAM_set1(param, s->param); if (s->verify_callback) X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback); @@ -534,6 +541,10 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) } s->verify_result = ctx.error; + + /* Move peername from the store context params to the SSL handle's */ + X509_VERIFY_PARAM_move_peername(s->param, param); + X509_STORE_CTX_cleanup(&ctx); return (i); diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index d9dbf99391..cfa4179a40 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -72,6 +72,9 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "check_suiteb_cipher_list"}, {ERR_FUNC(SSL_F_D2I_SSL_SESSION), "d2i_SSL_SESSION"}, + {ERR_FUNC(SSL_F_DANE_CTX_ENABLE), "dane_ctx_enable"}, + {ERR_FUNC(SSL_F_DANE_MTYPE_SET), "dane_mtype_set"}, + {ERR_FUNC(SSL_F_DANE_TLSA_ADD), "dane_tlsa_add"}, {ERR_FUNC(SSL_F_DO_DTLS1_WRITE), "do_dtls1_write"}, {ERR_FUNC(SSL_F_DO_SSL3_WRITE), "DO_SSL3_WRITE"}, {ERR_FUNC(SSL_F_DTLS1_ACCEPT), "dtls1_accept"}, @@ -262,6 +265,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_SSL_CTX_USE_SERVERINFO), "SSL_CTX_use_serverinfo"}, {ERR_FUNC(SSL_F_SSL_CTX_USE_SERVERINFO_FILE), "SSL_CTX_use_serverinfo_file"}, + {ERR_FUNC(SSL_F_SSL_DANE_ENABLE), "SSL_dane_enable"}, {ERR_FUNC(SSL_F_SSL_DO_CONFIG), "ssl_do_config"}, {ERR_FUNC(SSL_F_SSL_DO_HANDSHAKE), "SSL_do_handshake"}, {ERR_FUNC(SSL_F_SSL_GET_NEW_SESSION), "ssl_get_new_session"}, @@ -491,9 +495,25 @@ static ERR_STRING_DATA SSL_str_reasons[] = { {ERR_REASON(SSL_R_COMPRESSION_LIBRARY_ERROR), "compression library error"}, {ERR_REASON(SSL_R_CONNECTION_TYPE_NOT_SET), "connection type not set"}, + {ERR_REASON(SSL_R_CONTEXT_NOT_DANE_ENABLED), "context not dane enabled"}, {ERR_REASON(SSL_R_COOKIE_GEN_CALLBACK_FAILURE), "cookie gen callback failure"}, {ERR_REASON(SSL_R_COOKIE_MISMATCH), "cookie mismatch"}, + {ERR_REASON(SSL_R_DANE_ALREADY_ENABLED), "dane already enabled"}, + {ERR_REASON(SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL), + "dane cannot override mtype full"}, + {ERR_REASON(SSL_R_DANE_NOT_ENABLED), "dane not enabled"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_CERTIFICATE), "dane tlsa bad certificate"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE), + "dane tlsa bad certificate usage"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_DATA_LENGTH), "dane tlsa bad data length"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH), + "dane tlsa bad digest length"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_MATCHING_TYPE), + "dane tlsa bad matching type"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_PUBLIC_KEY), "dane tlsa bad public key"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_SELECTOR), "dane tlsa bad selector"}, + {ERR_REASON(SSL_R_DANE_TLSA_NULL_DATA), "dane tlsa null data"}, {ERR_REASON(SSL_R_DATA_BETWEEN_CCS_AND_FINISHED), "data between ccs and finished"}, {ERR_REASON(SSL_R_DATA_LENGTH_TOO_LONG), "data length too long"}, @@ -524,6 +544,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = { "encrypted length too long"}, {ERR_REASON(SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST), "error in received cipher list"}, + {ERR_REASON(SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN), + "error setting tlsa base domain"}, {ERR_REASON(SSL_R_EXCESSIVE_MESSAGE_SIZE), "excessive message size"}, {ERR_REASON(SSL_R_EXTRA_DATA_IN_MESSAGE), "extra data in message"}, {ERR_REASON(SSL_R_FAILED_TO_INIT_ASYNC), "failed to init async"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 760014d739..f0f1264cdf 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -197,6 +197,333 @@ struct ssl_async_args { } f; }; +static const struct { + uint8_t mtype; + uint8_t ord; + int nid; +} dane_mds[] = { + { DANETLS_MATCHING_FULL, 0, NID_undef }, + { DANETLS_MATCHING_2256, 1, NID_sha256 }, + { DANETLS_MATCHING_2512, 2, NID_sha512 }, +}; + +static int dane_ctx_enable(struct dane_ctx_st *dctx) +{ + const EVP_MD **mdevp; + uint8_t *mdord; + uint8_t mdmax = DANETLS_MATCHING_LAST; + int n = ((int) mdmax) + 1; /* int to handle PrivMatch(255) */ + size_t i; + + mdevp = OPENSSL_zalloc(n * sizeof(*mdevp)); + mdord = OPENSSL_zalloc(n * sizeof(*mdord)); + + if (mdord == NULL || mdevp == NULL) { + OPENSSL_free(mdevp); + SSLerr(SSL_F_DANE_CTX_ENABLE, ERR_R_MALLOC_FAILURE); + return 0; + } + + /* Install default entries */ + for (i = 0; i < OSSL_NELEM(dane_mds); ++i) { + const EVP_MD *md; + + if (dane_mds[i].nid == NID_undef || + (md = EVP_get_digestbynid(dane_mds[i].nid)) == NULL) + continue; + mdevp[dane_mds[i].mtype] = md; + mdord[dane_mds[i].mtype] = dane_mds[i].ord; + } + + dctx->mdevp = mdevp; + dctx->mdord = mdord; + dctx->mdmax = mdmax; + + return 1; +} + +static void dane_ctx_final(struct dane_ctx_st *dctx) +{ + OPENSSL_free(dctx->mdevp); + dctx->mdevp = NULL; + + OPENSSL_free(dctx->mdord); + dctx->mdord = NULL; + dctx->mdmax = 0; +} + +static void tlsa_free(danetls_record *t) +{ + if (t == NULL) + return; + OPENSSL_free(t->data); + EVP_PKEY_free(t->spki); + OPENSSL_free(t); +} + +static void dane_final(struct dane_st *dane) +{ + sk_danetls_record_pop_free(dane->trecs, tlsa_free); + dane->trecs = NULL; + + sk_X509_pop_free(dane->certs, X509_free); + dane->certs = NULL; + + X509_free(dane->mcert); + dane->mcert = NULL; + dane->mtlsa = NULL; + dane->mdpth = -1; + dane->pdpth = -1; +} + +/* + * dane_copy - Copy dane configuration, sans verification state. + */ +static int ssl_dane_dup(SSL *to, SSL *from) +{ + int num; + int i; + + if (!DANETLS_ENABLED(&from->dane)) + return 1; + + dane_final(&to->dane); + + num = sk_danetls_record_num(from->dane.trecs); + for (i = 0; i < num; ++i) { + danetls_record *t = sk_danetls_record_value(from->dane.trecs, i); + if (SSL_dane_tlsa_add(to, t->usage, t->selector, t->mtype, + t->data, t->dlen) <= 0) + return 0; + } + return 1; +} + +static int dane_mtype_set( + struct dane_ctx_st *dctx, + const EVP_MD *md, + uint8_t mtype, + uint8_t ord) +{ + int i; + + if (mtype == DANETLS_MATCHING_FULL && md != NULL) { + SSLerr(SSL_F_DANE_MTYPE_SET, + SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL); + return 0; + } + + if (mtype > dctx->mdmax) { + const EVP_MD **mdevp; + uint8_t *mdord; + int n = ((int) mtype) + 1; + + mdevp = OPENSSL_realloc(dctx->mdevp, n * sizeof(*mdevp)); + if (mdevp == NULL) { + SSLerr(SSL_F_DANE_MTYPE_SET, ERR_R_MALLOC_FAILURE); + return -1; + } + dctx->mdevp = mdevp; + + mdord = OPENSSL_realloc(dctx->mdord, n * sizeof(*mdord)); + if (mdord == NULL) { + SSLerr(SSL_F_DANE_MTYPE_SET, ERR_R_MALLOC_FAILURE); + return -1; + } + dctx->mdord = mdord; + + /* Zero-fill any gaps */ + for (i = dctx->mdmax+1; i < mtype; ++i) { + mdevp[i] = NULL; + mdord[i] = 0; + } + + dctx->mdmax = mtype; + } + + dctx->mdevp[mtype] = md; + /* Coerce ordinal of disabled matching types to 0 */ + dctx->mdord[mtype] = (md == NULL) ? 0 : ord; + + return 1; +} + +static const EVP_MD *tlsa_md_get(struct dane_st *dane, uint8_t mtype) +{ + if (mtype > dane->dctx->mdmax) + return NULL; + return dane->dctx->mdevp[mtype]; +} + +static int dane_tlsa_add( + struct dane_st *dane, + uint8_t usage, + uint8_t selector, + uint8_t mtype, + unsigned char *data, + size_t dlen) +{ + danetls_record *t; + const EVP_MD *md = NULL; + int ilen = (int)dlen; + int i; + + if (dane->trecs == NULL) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_NOT_ENABLED); + return -1; + } + + if (ilen < 0 || dlen != (size_t)ilen) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_DATA_LENGTH); + return 0; + } + + if (usage > DANETLS_USAGE_LAST) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE); + return 0; + } + + if (selector > DANETLS_SELECTOR_LAST) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_SELECTOR); + return 0; + } + + if (mtype != DANETLS_MATCHING_FULL) { + md = tlsa_md_get(dane, mtype); + if (md == NULL) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_MATCHING_TYPE); + return 0; + } + } + + if (md != NULL && dlen != (size_t)EVP_MD_size(md)) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH); + return 0; + } + if (!data) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_NULL_DATA); + return 0; + } + + if ((t = OPENSSL_zalloc(sizeof(*t))) == NULL) { + SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE); + return -1; + } + + t->usage = usage; + t->selector = selector; + t->mtype = mtype; + t->data = OPENSSL_malloc(ilen); + if (t->data == NULL) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE); + return -1; + } + memcpy(t->data, data, ilen); + t->dlen = ilen; + + /* Validate and cache full certificate or public key */ + if (mtype == DANETLS_MATCHING_FULL) { + const unsigned char *p = data; + X509 *cert = NULL; + EVP_PKEY *pkey = NULL; + + switch (selector) { + case DANETLS_SELECTOR_CERT: + if (!d2i_X509(&cert, &p, dlen) || p < data || + dlen != (size_t)(p - data)) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE); + return 0; + } + if (X509_get0_pubkey(cert) == NULL) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE); + return 0; + } + + if ((DANETLS_USAGE_BIT(usage) & DANETLS_TA_MASK) == 0) { + X509_free(cert); + break; + } + + /* + * For usage DANE-TA(2), we support authentication via "2 0 0" TLSA + * records that contain full certificates of trust-anchors that are + * not present in the wire chain. For usage PKIX-TA(0), we augment + * the chain with untrusted Full(0) certificates from DNS, in case + * they are missing from the chain. + */ + if ((dane->certs == NULL && + (dane->certs = sk_X509_new_null()) == NULL) || + !sk_X509_push(dane->certs, cert)) { + SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE); + X509_free(cert); + tlsa_free(t); + return -1; + } + break; + + case DANETLS_SELECTOR_SPKI: + if (!d2i_PUBKEY(&pkey, &p, dlen) || p < data || + dlen != (size_t)(p - data)) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY); + return 0; + } + + /* + * For usage DANE-TA(2), we support authentication via "2 1 0" TLSA + * records that contain full bare keys of trust-anchors that are + * not present in the wire chain. + */ + if (usage == DANETLS_USAGE_DANE_TA) + t->spki = pkey; + else + EVP_PKEY_free(pkey); + break; + } + } + + /*- + * Find the right insertion point for the new record. + * + * See crypto/x509/x509_vfy.c. We sort DANE-EE(3) records first, so that + * they can be processed first, as they require no chain building, and no + * expiration or hostname checks. Because DANE-EE(3) is numerically + * largest, this is accomplished via descending sort by "usage". + * + * We also sort in descending order by matching ordinal to simplify + * the implementation of digest agility in the verification code. + * + * The choice of order for the selector is not significant, so we + * use the same descending order for consistency. + */ + for (i = 0; i < sk_danetls_record_num(dane->trecs); ++i) { + danetls_record *rec = sk_danetls_record_value(dane->trecs, i); + if (rec->usage > usage) + continue; + if (rec->usage < usage) + break; + if (rec->selector > selector) + continue; + if (rec->selector < selector) + break; + if (dane->dctx->mdord[rec->mtype] > dane->dctx->mdord[mtype]) + continue; + break; + } + + if (!sk_danetls_record_insert(dane->trecs, t, i)) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE); + return -1; + } + dane->umask |= DANETLS_USAGE_BIT(usage); + + return 1; +} + static void clear_ciphers(SSL *s) { /* clear the current cipher */ @@ -237,6 +564,16 @@ int SSL_clear(SSL *s) clear_ciphers(s); s->first_packet = 0; + /* Reset DANE verification result state */ + s->dane.mdpth = -1; + s->dane.pdpth = -1; + X509_free(s->dane.mcert); + s->dane.mcert = NULL; + s->dane.mtlsa = NULL; + + /* Clear the verification result peername */ + X509_VERIFY_PARAM_move_peername(s->param, NULL); + /* * Check to see if we were changed into a different method, if so, revert * back if we are not doing session-id reuse. @@ -497,6 +834,121 @@ int SSL_set_trust(SSL *s, int trust) return X509_VERIFY_PARAM_set_trust(s->param, trust); } +int SSL_set1_host(SSL *s, const char *hostname) +{ + return X509_VERIFY_PARAM_set1_host(s->param, hostname, 0); +} + +int SSL_add1_host(SSL *s, const char *hostname) +{ + return X509_VERIFY_PARAM_add1_host(s->param, hostname, 0); +} + +void SSL_set_hostflags(SSL *s, unsigned int flags) +{ + X509_VERIFY_PARAM_set_hostflags(s->param, flags); +} + +const char *SSL_get0_peername(SSL *s) +{ + return X509_VERIFY_PARAM_get0_peername(s->param); +} + +int SSL_CTX_dane_enable(SSL_CTX *ctx) +{ + return dane_ctx_enable(&ctx->dane); +} + +int SSL_dane_enable(SSL *s, const char *basedomain) +{ + struct dane_st *dane = &s->dane; + + if (s->ctx->dane.mdmax == 0) { + SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_CONTEXT_NOT_DANE_ENABLED); + return 0; + } + if (dane->trecs != NULL) { + SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_DANE_ALREADY_ENABLED); + return 0; + } + + /* Primary RFC6125 reference identifier */ + if (!X509_VERIFY_PARAM_set1_host(s->param, basedomain, 0)) { + SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN); + return -1; + } + + /* Default SNI name */ + if (s->tlsext_hostname == NULL) { + if (!SSL_set_tlsext_host_name(s, basedomain)) + return -1; + } + + dane->mdpth = -1; + dane->pdpth = -1; + dane->dctx = &s->ctx->dane; + dane->trecs = sk_danetls_record_new_null(); + + if (dane->trecs == NULL) { + SSLerr(SSL_F_SSL_DANE_ENABLE, ERR_R_MALLOC_FAILURE); + return -1; + } + return 1; +} + +int SSL_get0_dane_authority(SSL *s, X509 **mcert, EVP_PKEY **mspki) +{ + struct dane_st *dane = &s->dane; + + if (!DANETLS_ENABLED(dane)) + return -1; + if (dane->mtlsa) { + if (mcert) + *mcert = dane->mcert; + if (mspki) + *mspki = (dane->mcert == NULL) ? dane->mtlsa->spki : NULL; + } + return dane->mdpth; +} + +int SSL_get0_dane_tlsa(SSL *s, uint8_t *usage, uint8_t *selector, + uint8_t *mtype, unsigned const char **data, size_t *dlen) +{ + struct dane_st *dane = &s->dane; + + if (!DANETLS_ENABLED(dane)) + return -1; + if (dane->mtlsa) { + if (usage) + *usage = dane->mtlsa->usage; + if (selector) + *selector = dane->mtlsa->selector; + if (mtype) + *mtype = dane->mtlsa->mtype; + if (data) + *data = dane->mtlsa->data; + if (dlen) + *dlen = dane->mtlsa->dlen; + } + return dane->mdpth; +} + +struct dane_st *SSL_get0_dane(SSL *s) +{ + return &s->dane; +} + +int SSL_dane_tlsa_add(SSL *s, uint8_t usage, uint8_t selector, + uint8_t mtype, unsigned char *data, size_t dlen) +{ + return dane_tlsa_add(&s->dane, usage, selector, mtype, data, dlen); +} + +int SSL_CTX_dane_mtype_set(SSL_CTX *ctx, const EVP_MD *md, uint8_t mtype, uint8_t ord) +{ + return dane_mtype_set(&ctx->dane, md, mtype, ord); +} + int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm) { return X509_VERIFY_PARAM_set1(ctx->param, vpm); @@ -543,6 +995,7 @@ void SSL_free(SSL *s) #endif X509_VERIFY_PARAM_free(s->param); + dane_final(&s->dane); CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data); if (s->bbio != NULL) { @@ -877,9 +1330,10 @@ int SSL_copy_session_id(SSL *t, const SSL *f) * what if we are setup for one protocol version but want to talk another */ if (t->method != f->method) { - t->method->ssl_free(t); /* cleanup current */ - t->method = f->method; /* change method */ - t->method->ssl_new(t); /* setup new */ + t->method->ssl_free(t); + t->method = f->method; + if (t->method->ssl_new(t) == 0) + return 0; } CRYPTO_add(&f->cert->references, 1, CRYPTO_LOCK_SSL_CERT); @@ -1922,6 +2376,7 @@ void SSL_CTX_free(SSL_CTX *a) #endif X509_VERIFY_PARAM_free(a->param); + dane_ctx_final(&a->dane); /* * Free internal session cache. However: the remove_cb() may reference @@ -2346,24 +2801,23 @@ const SSL_METHOD *SSL_get_ssl_method(SSL *s) int SSL_set_ssl_method(SSL *s, const SSL_METHOD *meth) { - int conn = -1; int ret = 1; if (s->method != meth) { - if (s->handshake_func != NULL) - conn = (s->handshake_func == s->method->ssl_connect); + const SSL_METHOD *sm = s->method; + int (*hf)(SSL *) = s->handshake_func; - if (s->method->version == meth->version) + if (sm->version == meth->version) s->method = meth; else { - s->method->ssl_free(s); + sm->ssl_free(s); s->method = meth; ret = s->method->ssl_new(s); } - if (conn == 1) + if (hf == sm->ssl_connect) s->handshake_func = meth->ssl_connect; - else if (conn == 0) + else if (hf == sm->ssl_accept) s->handshake_func = meth->ssl_accept; } return (ret); @@ -2554,14 +3008,23 @@ SSL *SSL_dup(SSL *s) SSL *ret; int i; + /* If we're not quiescent, just up_ref! */ + if (!SSL_in_init(s) || !SSL_in_before(s)) { + CRYPTO_add(&s->references, 1, CRYPTO_LOCK_SSL); + return s; + } + + /* + * Otherwise, copy configuration state, and session if set. + */ if ((ret = SSL_new(SSL_get_SSL_CTX(s))) == NULL) return (NULL); - ret->version = s->version; - ret->method = s->method; - if (s->session != NULL) { - /* This copies session-id, SSL_METHOD, sid_ctx, and 'cert' */ + /* + * Arranges to share the same session via up_ref. This "copies" + * session-id, SSL_METHOD, sid_ctx, and 'cert' + */ if (!SSL_copy_session_id(ret, s)) goto err; } else { @@ -2571,10 +3034,8 @@ SSL *SSL_dup(SSL *s) * point to the same object, and thus we can't use * SSL_copy_session_id. */ - - ret->method->ssl_free(ret); - ret->method = s->method; - ret->method->ssl_new(ret); + if (!SSL_set_ssl_method(ret, s->method)) + goto err; if (s->cert != NULL) { ssl_cert_free(ret->cert); @@ -2587,6 +3048,8 @@ SSL *SSL_dup(SSL *s) goto err; } + ssl_dane_dup(ret, s); + ret->version = s->version; ret->options = s->options; ret->mode = s->mode; SSL_set_max_cert_list(ret, SSL_get_max_cert_list(s)); @@ -2617,19 +3080,15 @@ SSL *SSL_dup(SSL *s) } else ret->wbio = ret->rbio; } - ret->rwstate = s->rwstate; - ret->handshake_func = s->handshake_func; + ret->server = s->server; - ret->renegotiate = s->renegotiate; - ret->new_session = s->new_session; - ret->quiet_shutdown = s->quiet_shutdown; + if (s->handshake_func) { + if (s->server) + SSL_set_accept_state(ret); + else + SSL_set_connect_state(ret); + } ret->shutdown = s->shutdown; - ret->statem = s->statem; /* SSL_dup does not really work at any state, - * though */ - RECORD_LAYER_dup(&ret->rlayer, &s->rlayer); - ret->init_num = 0; /* would have to copy ret->init_buf, - * ret->init_msg, ret->init_num, - * ret->init_off */ ret->hit = s->hit; ret->default_passwd_callback = s->default_passwd_callback; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 7e07297f2f..fee7fa6f15 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -169,6 +169,7 @@ #include "record/record.h" #include "statem/statem.h" #include "packet_locl.h" +#include "internal/dane.h" # ifdef OPENSSL_BUILD_SHLIBSSL # undef OPENSSL_EXTERN @@ -925,6 +926,9 @@ struct ssl_ctx_st { unsigned char *alpn_client_proto_list; unsigned alpn_client_proto_list_len; + /* Shared DANE context */ + struct dane_ctx_st dane; + /* SRTP profiles we are willing to do from RFC 5764 */ STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; /* @@ -1007,6 +1011,10 @@ struct ssl_st { void *msg_callback_arg; int hit; /* reusing a previous session */ X509_VERIFY_PARAM *param; + + /* Per connection DANE state */ + struct dane_st dane; + /* crypto */ STACK_OF(SSL_CIPHER) *cipher_list; STACK_OF(SSL_CIPHER) *cipher_list_by_id; |