+ tls_out.ocsp = OCSP_FAILED;
+ if (LOGGING(tls_cipher))
+ log_write(0, LOG_MAIN, "Received TLS cert status response, itself unverifiable");
+ BIO_printf(bp, "OCSP response verify failure\n");
+ ERR_print_errors(bp);
+ goto failed;
+ }
+
+ BIO_printf(bp, "OCSP response well-formed and signed OK\n");
+
+ /*XXX So we have a good stapled OCSP status. How do we know
+ it is for the cert of interest? OpenSSL 1.1.0 has a routine
+ OCSP_resp_find_status() which matches on a cert id, which presumably
+ we should use. Making an id needs OCSP_cert_id_new(), which takes
+ issuerName, issuerKey, serialNumber. Are they all in the cert?
+
+ For now, carry on blindly accepting the resp. */
+
+ {
+ OCSP_SINGLERESP * single;
+
+#ifdef EXIM_HAVE_OCSP_RESP_COUNT
+ if (OCSP_resp_count(bs) != 1)
+#else
+ STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses;
+ if (sk_OCSP_SINGLERESP_num(sresp) != 1)
+#endif
+ {
+ tls_out.ocsp = OCSP_FAILED;
+ log_write(0, LOG_MAIN, "OCSP stapling "
+ "with multiple responses not handled");
+ goto failed;
+ }
+ single = OCSP_resp_get0(bs, 0);
+ status = OCSP_single_get0_status(single, &reason, &rev,
+ &thisupd, &nextupd);
+ }
+
+ DEBUG(D_tls) time_print(bp, "This OCSP Update", thisupd);
+ DEBUG(D_tls) if(nextupd) time_print(bp, "Next OCSP Update", nextupd);
+ if (!OCSP_check_validity(thisupd, nextupd,
+ EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
+ {
+ tls_out.ocsp = OCSP_FAILED;
+ DEBUG(D_tls) ERR_print_errors(bp);
+ log_write(0, LOG_MAIN, "Server OSCP dates invalid");
+ }
+ else
+ {
+ DEBUG(D_tls) BIO_printf(bp, "Certificate status: %s\n",
+ OCSP_cert_status_str(status));
+ switch(status)
+ {
+ case V_OCSP_CERTSTATUS_GOOD:
+ tls_out.ocsp = OCSP_VFIED;
+ i = 1;
+ goto good;
+ case V_OCSP_CERTSTATUS_REVOKED:
+ tls_out.ocsp = OCSP_FAILED;
+ log_write(0, LOG_MAIN, "Server certificate revoked%s%s",
+ reason != -1 ? "; reason: " : "",
+ reason != -1 ? OCSP_crl_reason_str(reason) : "");
+ DEBUG(D_tls) time_print(bp, "Revocation Time", rev);
+ break;
+ default:
+ tls_out.ocsp = OCSP_FAILED;
+ log_write(0, LOG_MAIN,
+ "Server certificate status unknown, in OCSP stapling");
+ break;
+ }
+ }
+ failed:
+ i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
+ good:
+ BIO_free(bp);
+ }
+
+OCSP_RESPONSE_free(rsp);
+return i;
+}
+#endif /*!DISABLE_OCSP*/
+
+
+/*************************************************
+* Initialize for TLS *
+*************************************************/
+
+/* Called from both server and client code, to do preliminary initialization
+of the library. We allocate and return a context structure.
+
+Arguments:
+ ctxp returned SSL context
+ host connected host, if client; NULL if server
+ dhparam DH parameter file
+ certificate certificate file
+ privatekey private key
+ ocsp_file file of stapling info (server); flag for require ocsp (client)
+ addr address if client; NULL if server (for some randomness)
+ cbp place to put allocated callback context
+
+Returns: OK/DEFER/FAIL
+*/
+
+static int
+tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate,
+ uschar *privatekey,
+#ifndef DISABLE_OCSP
+ uschar *ocsp_file,
+#endif
+ address_item *addr, tls_ext_ctx_cb ** cbp)
+{
+long init_options;
+int rc;
+BOOL okay;
+tls_ext_ctx_cb * cbinfo;
+
+cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
+cbinfo->certificate = certificate;
+cbinfo->privatekey = privatekey;
+#ifndef DISABLE_OCSP
+if ((cbinfo->is_server = host==NULL))
+ {
+ cbinfo->u_ocsp.server.file = ocsp_file;
+ cbinfo->u_ocsp.server.file_expanded = NULL;
+ cbinfo->u_ocsp.server.response = NULL;
+ }
+else
+ cbinfo->u_ocsp.client.verify_store = NULL;
+#endif
+cbinfo->dhparam = dhparam;
+cbinfo->server_cipher_list = NULL;
+cbinfo->host = host;
+#ifndef DISABLE_EVENT
+cbinfo->event_action = NULL;
+#endif
+
+SSL_load_error_strings(); /* basic set up */
+OpenSSL_add_ssl_algorithms();
+
+#ifdef EXIM_HAVE_SHA256
+/* SHA256 is becoming ever more popular. This makes sure it gets added to the
+list of available digests. */
+EVP_add_digest(EVP_sha256());
+#endif
+
+/* Create a context.
+The OpenSSL docs in 1.0.1b have not been updated to clarify TLS variant
+negotiation in the different methods; as far as I can tell, the only
+*_{server,client}_method which allows negotiation is SSLv23, which exists even
+when OpenSSL is built without SSLv2 support.
+By disabling with openssl_options, we can let admins re-enable with the
+existing knob. */
+
+*ctxp = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method());
+
+if (!*ctxp) return tls_error(US"SSL_CTX_new", host, NULL);
+
+/* It turns out that we need to seed the random number generator this early in
+order to get the full complement of ciphers to work. It took me roughly a day
+of work to discover this by experiment.
+
+On systems that have /dev/urandom, SSL may automatically seed itself from
+there. Otherwise, we have to make something up as best we can. Double check
+afterwards. */
+
+if (!RAND_status())
+ {
+ randstuff r;
+ gettimeofday(&r.tv, NULL);
+ r.p = getpid();
+
+ RAND_seed((uschar *)(&r), sizeof(r));
+ RAND_seed((uschar *)big_buffer, big_buffer_size);
+ if (addr != NULL) RAND_seed((uschar *)addr, sizeof(addr));
+
+ if (!RAND_status())
+ return tls_error(US"RAND_status", host,
+ US"unable to seed random number generator");
+ }
+
+/* Set up the information callback, which outputs if debugging is at a suitable
+level. */
+
+DEBUG(D_tls) SSL_CTX_set_info_callback(*ctxp, (void (*)())info_callback);
+
+/* Automatically re-try reads/writes after renegotiation. */
+(void) SSL_CTX_set_mode(*ctxp, SSL_MODE_AUTO_RETRY);
+
+/* Apply administrator-supplied work-arounds.
+Historically we applied just one requested option,
+SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS, but when bug 994 requested a second, we
+moved to an administrator-controlled list of options to specify and
+grandfathered in the first one as the default value for "openssl_options".
+
+No OpenSSL version number checks: the options we accept depend upon the
+availability of the option value macros from OpenSSL. */
+
+okay = tls_openssl_options_parse(openssl_options, &init_options);
+if (!okay)
+ return tls_error(US"openssl_options parsing failed", host, NULL);
+
+if (init_options)
+ {
+ DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options);
+ if (!(SSL_CTX_set_options(*ctxp, init_options)))
+ return tls_error(string_sprintf(
+ "SSL_CTX_set_option(%#lx)", init_options), host, NULL);
+ }
+else
+ DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
+
+/* Initialize with DH parameters if supplied */
+/* Initialize ECDH temp key parameter selection */
+
+if ( !init_dh(*ctxp, dhparam, host)
+ || !init_ecdh(*ctxp, host)
+ )
+ return DEFER;
+
+/* Set up certificate and key (and perhaps OCSP info) */
+
+if ((rc = tls_expand_session_files(*ctxp, cbinfo)) != OK)
+ return rc;
+
+/* If we need to handle SNI, do so */
+#ifdef EXIM_HAVE_OPENSSL_TLSEXT
+if (host == NULL) /* server */
+ {
+# ifndef DISABLE_OCSP
+ /* We check u_ocsp.server.file, not server.response, because we care about if
+ the option exists, not what the current expansion might be, as SNI might
+ change the certificate and OCSP file in use between now and the time the
+ callback is invoked. */
+ if (cbinfo->u_ocsp.server.file)
+ {
+ SSL_CTX_set_tlsext_status_cb(server_ctx, tls_server_stapling_cb);
+ SSL_CTX_set_tlsext_status_arg(server_ctx, cbinfo);
+ }
+# endif
+ /* We always do this, so that $tls_sni is available even if not used in
+ tls_certificate */
+ SSL_CTX_set_tlsext_servername_callback(*ctxp, tls_servername_cb);
+ SSL_CTX_set_tlsext_servername_arg(*ctxp, cbinfo);
+ }
+# ifndef DISABLE_OCSP
+else /* client */
+ if(ocsp_file) /* wanting stapling */
+ {
+ if (!(cbinfo->u_ocsp.client.verify_store = X509_STORE_new()))
+ {
+ DEBUG(D_tls) debug_printf("failed to create store for stapling verify\n");
+ return FAIL;
+ }
+ SSL_CTX_set_tlsext_status_cb(*ctxp, tls_client_stapling_cb);
+ SSL_CTX_set_tlsext_status_arg(*ctxp, cbinfo);
+ }
+# endif
+#endif
+
+cbinfo->verify_cert_hostnames = NULL;
+
+#ifdef EXIM_HAVE_EPHEM_RSA_KEX
+/* Set up the RSA callback */
+SSL_CTX_set_tmp_rsa_callback(*ctxp, rsa_callback);
+#endif
+
+/* Finally, set the timeout, and we are done */
+
+SSL_CTX_set_timeout(*ctxp, ssl_session_timeout);
+DEBUG(D_tls) debug_printf("Initialized TLS\n");
+
+*cbp = cbinfo;
+
+return OK;
+}
+
+
+
+
+/*************************************************
+* Get name of cipher in use *
+*************************************************/
+
+/*
+Argument: pointer to an SSL structure for the connection
+ buffer to use for answer
+ size of buffer
+ pointer to number of bits for cipher
+Returns: nothing
+*/
+
+static void
+construct_cipher_name(SSL *ssl, uschar *cipherbuf, int bsize, int *bits)
+{
+/* With OpenSSL 1.0.0a, this needs to be const but the documentation doesn't
+yet reflect that. It should be a safe change anyway, even 0.9.8 versions have
+the accessor functions use const in the prototype. */
+const SSL_CIPHER *c;
+const uschar *ver;
+
+ver = (const uschar *)SSL_get_version(ssl);
+
+c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl);
+SSL_CIPHER_get_bits(c, bits);
+
+string_format(cipherbuf, bsize, "%s:%s:%u", ver,
+ SSL_CIPHER_get_name(c), *bits);
+
+DEBUG(D_tls) debug_printf("Cipher: %s\n", cipherbuf);
+}
+
+
+static void
+peer_cert(SSL * ssl, tls_support * tlsp, uschar * peerdn, unsigned bsize)
+{
+/*XXX we might consider a list-of-certs variable for the cert chain.
+SSL_get_peer_cert_chain(SSL*). We'd need a new variable type and support
+in list-handling functions, also consider the difference between the entire
+chain and the elements sent by the peer. */
+
+/* Will have already noted peercert on a verify fail; possibly not the leaf */
+if (!tlsp->peercert)
+ tlsp->peercert = SSL_get_peer_certificate(ssl);
+/* Beware anonymous ciphers which lead to server_cert being NULL */
+if (tlsp->peercert)
+ {
+ X509_NAME_oneline(X509_get_subject_name(tlsp->peercert), CS peerdn, bsize);
+ peerdn[bsize-1] = '\0';
+ tlsp->peerdn = peerdn; /*XXX a static buffer... */
+ }
+else
+ tlsp->peerdn = NULL;
+}
+
+
+
+
+
+/*************************************************
+* Set up for verifying certificates *
+*************************************************/
+
+/* Called by both client and server startup
+
+Arguments:
+ sctx SSL_CTX* to initialise
+ certs certs file or NULL
+ crl CRL file or NULL
+ host NULL in a server; the remote host in a client
+ optional TRUE if called from a server for a host in tls_try_verify_hosts;
+ otherwise passed as FALSE
+ cert_vfy_cb Callback function for certificate verification
+
+Returns: OK/DEFER/FAIL
+*/
+
+static int
+setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional,
+ int (*cert_vfy_cb)(int, X509_STORE_CTX *) )
+{
+uschar *expcerts, *expcrl;
+
+if (!expand_check(certs, US"tls_verify_certificates", &expcerts))
+ return DEFER;
+
+if (expcerts && *expcerts)
+ {
+ /* Tell the library to use its compiled-in location for the system default
+ CA bundle. Then add the ones specified in the config, if any. */
+
+ if (!SSL_CTX_set_default_verify_paths(sctx))
+ return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL);
+
+ if (Ustrcmp(expcerts, "system") != 0)
+ {
+ struct stat statbuf;
+
+ if (Ustat(expcerts, &statbuf) < 0)
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "failed to stat %s for certificates", expcerts);
+ return DEFER;
+ }
+ else
+ {
+ uschar *file, *dir;
+ if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+ { file = NULL; dir = expcerts; }
+ else
+ { file = expcerts; dir = NULL; }
+
+ /* If a certificate file is empty, the next function fails with an
+ unhelpful error message. If we skip it, we get the correct behaviour (no
+ certificates are recognized, but the error message is still misleading (it
+ says no certificate was supplied.) But this is better. */
+
+ if ( (!file || statbuf.st_size > 0)
+ && !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
+ return tls_error(US"SSL_CTX_load_verify_locations", host, NULL);
+
+ /* Load the list of CAs for which we will accept certs, for sending
+ to the client. This is only for the one-file tls_verify_certificates
+ variant.
+ If a list isn't loaded into the server, but
+ some verify locations are set, the server end appears to make
+ a wildcard reqest for client certs.
+ Meanwhile, the client library as default behaviour *ignores* the list
+ we send over the wire - see man SSL_CTX_set_client_cert_cb.
+ Because of this, and that the dir variant is likely only used for
+ the public-CA bundle (not for a private CA), not worth fixing.
+ */
+ if (file)
+ {
+ STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file);
+
+ DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n",
+ sk_X509_NAME_num(names));
+ SSL_CTX_set_client_CA_list(sctx, names);
+ }