X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Ftls-gnu.c;h=ace59633a565f36e7b15a30e7877e6abadd060df;hb=2b4a568dfa3d79a9a968984cf5b23829c084a951;hp=5600d6bb8e4c2aa3db52f8546432cb64ec7a4f5f;hpb=52f93eed9f96e1630b181857289d5f2423f55cd7;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 5600d6bb8..ace59633a 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2013 */ +/* Copyright (c) University of Cambridge 1995 - 2014 */ /* See the file NOTICE for conditions of use and distribution. */ /* Copyright (c) Phil Pennock 2012 */ @@ -43,6 +43,9 @@ require current GnuTLS, then we'll drop support for the ancient libraries). #if GNUTLS_VERSION_NUMBER >= 0x020c00 # include #endif +#ifdef EXPERIMENTAL_OCSP +# include +#endif /* GnuTLS 2 vs 3 @@ -658,7 +661,7 @@ uschar *saved_tls_crl = NULL; int cert_count; /* We check for tls_sni *before* expansion. */ -if (!state->host) +if (!host) /* server */ { if (!state->received_sni) { @@ -700,7 +703,7 @@ if (!expand_check_tlsvar(tls_certificate)) if ((state->exp_tls_certificate == NULL) || (*state->exp_tls_certificate == '\0')) { - if (state->host == NULL) + if (!host) return tls_error(US"no TLS server certificate is specified", NULL, NULL); else DEBUG(D_tls) debug_printf("TLS: no client certificate specified; okay\n"); @@ -745,6 +748,30 @@ if (state->exp_tls_certificate && *state->exp_tls_certificate) DEBUG(D_tls) debug_printf("TLS: cert/key registered\n"); } /* tls_certificate */ + +/* Set the OCSP stapling server info */ + +#ifdef EXPERIMENTAL_OCSP +if ( !host /* server */ + && tls_ocsp_file + ) + { + uschar * expanded; + int rc; + + if (!expand_check(tls_ocsp_file, US"tls_ocsp_file", &expanded)) + return DEFER; + + /* Lazy way; would like callback to emit debug on actual response */ + + rc = gnutls_certificate_set_ocsp_status_request_file(state->x509_cred, + expanded, 0); + exim_gnutls_err_check(US"gnutls_certificate_set_ocsp_status_request_file"); + DEBUG(D_tls) debug_printf("Set OCSP response file %s\n", expanded); + } +#endif + + /* Set the trusted CAs file if one is provided, and then add the CRL if one is provided. Experiment shows that, if the certificate file is empty, an unhelpful error message is provided. However, if we just refrain from setting anything up @@ -1228,25 +1255,23 @@ unsigned int verify; *error = NULL; -rc = peer_status(state); -if (rc != OK) +if ((rc = peer_status(state)) != OK) { verify = GNUTLS_CERT_INVALID; - *error = "not supplied"; + *error = "certificate not supplied"; } else - { rc = gnutls_certificate_verify_peers2(state->session, &verify); - } /* Handle the result of verification. INVALID seems to be set as well as REVOKED, but leave the test for both. */ -if ((rc < 0) || (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) != 0) +if (rc < 0 || verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) { state->peer_cert_verified = FALSE; - if (*error == NULL) - *error = ((verify & GNUTLS_CERT_REVOKED) != 0) ? "revoked" : "invalid"; + if (!*error) + *error = verify & GNUTLS_CERT_REVOKED + ? "certificate revoked" : "certificate invalid"; DEBUG(D_tls) debug_printf("TLS certificate verification failed (%s): peerdn=%s\n", @@ -1561,10 +1586,11 @@ Arguments: verify_certs file for certificate verify verify_crl CRL for verify require_ciphers list of allowed ciphers or NULL + hosts_require_ocsp hosts for which to request certificate-status (OCSP) dh_min_bits minimum number of bits acceptable in server's DH prime timeout startup timeout - verify_hosts mandatory client verification - try_verify_hosts optional client verification + verify_hosts mandatory client verification + try_verify_hosts optional client verification Returns: OK/DEFER/FAIL (because using common functions), but for a client, DEFER and FAIL have the same meaning @@ -1577,7 +1603,7 @@ tls_client_start(int fd, host_item *host, uschar *verify_certs, uschar *verify_crl, uschar *require_ciphers, #ifdef EXPERIMENTAL_OCSP - uschar *require_ocsp ARG_UNUSED, + uschar *hosts_require_ocsp, #endif int dh_min_bits, int timeout, uschar *verify_hosts, uschar *try_verify_hosts) @@ -1585,12 +1611,16 @@ tls_client_start(int fd, host_item *host, int rc; const char *error; exim_gnutls_state_st *state = NULL; +#ifdef EXPERIMENTAL_OCSP +BOOL require_ocsp = verify_check_this_host(&hosts_require_ocsp, + NULL, host->name, host->address, NULL) == OK; +#endif DEBUG(D_tls) debug_printf("initialising GnuTLS as a client on fd %d\n", fd); -rc = tls_init(host, certificate, privatekey, - sni, verify_certs, verify_crl, require_ciphers, &state); -if (rc != OK) return rc; +if ((rc = tls_init(host, certificate, privatekey, + sni, verify_certs, verify_crl, require_ciphers, &state)) != OK) + return rc; if (dh_min_bits < EXIM_CLIENT_DH_MIN_MIN_BITS) { @@ -1604,11 +1634,17 @@ DEBUG(D_tls) debug_printf("Setting D-H prime minimum acceptable bits to %d\n", dh_min_bits); gnutls_dh_set_prime_bits(state->session, dh_min_bits); -/* stick to the old behaviour for compatibility if tls_verify_certificates is - set but both tls_verify_hosts and tls_try_verify_hosts is not set. Check only - the specified host patterns if one of them is defined */ -if (((state->exp_tls_verify_certificates != NULL) && (verify_hosts == NULL) && (try_verify_hosts == NULL)) || - (verify_check_host(&verify_hosts) == OK)) +/* Stick to the old behaviour for compatibility if tls_verify_certificates is +set but both tls_verify_hosts and tls_try_verify_hosts are unset. Check only +the specified host patterns if one of them is defined */ + +if (( state->exp_tls_verify_certificates + && !verify_hosts + && !try_verify_hosts + ) + || + verify_check_host(&verify_hosts) == OK + ) { DEBUG(D_tls) debug_printf("TLS: server certificate verification required.\n"); state->verify_requirement = VERIFY_REQUIRED; @@ -1627,6 +1663,13 @@ else gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE); } +#ifdef EXPERIMENTAL_OCSP /* since GnuTLS 3.1.3 */ +if (require_ocsp && + (rc = gnutls_ocsp_status_request_enable_client(state->session, NULL, 0, NULL)) + != OK) + return tls_error(US"cert-status-req", gnutls_strerror(rc), state->host); +#endif + gnutls_transport_set_ptr(state->session, (gnutls_transport_ptr)fd); state->fd_in = fd; state->fd_out = fd; @@ -1654,10 +1697,38 @@ if (state->verify_requirement != VERIFY_NONE && !verify_certificate(state, &error)) return tls_error(US"certificate verification failed", error, state->host); +#ifdef EXPERIMENTAL_OCSP +if (require_ocsp) + { + DEBUG(D_tls) + { + gnutls_datum_t stapling; + gnutls_ocsp_resp_t resp; + gnutls_datum_t printed; + if ( (rc= gnutls_ocsp_status_request_get(state->session, &stapling)) == 0 + && (rc= gnutls_ocsp_resp_init(&resp)) == 0 + && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0 + && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0 + ) + { + fprintf(stderr, "%.4096s", printed.data); + gnutls_free(printed.data); + } + else + (void) tls_error(US"ocsp decode", gnutls_strerror(rc), state->host); + } + + fprintf(stderr, "%s: checking ocsp\n", __FUNCTION__); + if (gnutls_ocsp_status_request_is_checked(state->session, 0) == 0) + return tls_error(US"certificate status check failed", NULL, state->host); + DEBUG(D_tls) debug_printf("Passed OCSP checking\n"); + } +#endif + /* Figure out peer DN, and if authenticated, etc. */ -rc = peer_status(state); -if (rc != OK) return rc; +if ((rc = peer_status(state)) != OK) + return rc; /* Sets various Exim expansion variables; may need to adjust for ACL callouts */ @@ -2043,4 +2114,6 @@ fprintf(f, "Library version: GnuTLS: Compile: %s\n" gnutls_check_version(NULL)); } +/* vi: aw ai sw=2 +*/ /* End of tls-gnu.c */