1 /* tls.c --- TLSv1 functions
2 Copyright (C) 2000 Kenichi Okada <okada@opaopa.org>
4 Author: Kenichi Okada <okada@opaopa.org>
11 [RFC 2246] "The TLS Protocol Version 1.0"
12 by Christopher Allen <callen@certicom.com> and
13 Tim Dierks <tdierks@certicom.com> (1999/01)
15 [RFC 2595] "Using TLS with IMAP, POP3 and ACAP"
16 by Chris Newman <chris.newman@innosoft.com> (1999/06)
20 #include <sys/types.h>
37 /* outside the ifdef so `make depend` works even ifndef HAVE_SSL */
39 #include "sasl_config.h"
43 /* We must keep some of the info available */
44 static const char hexcodes[] = "0123456789ABCDEF";
46 static bool tls_initialized = false;
48 static int verify_depth;
49 static int verify_error = X509_V_OK;
50 static int do_dump = 0;
51 static SSL_CTX *CTX = NULL;
54 #define CCERT_BUFSIZ 256
56 int tls_serverengine = 0;
57 int tls_serveractive = 0; /* available or not */
58 char *tls_peer_subject = NULL;
59 char *tls_peer_issuer = NULL;
60 char *tls_peer_fingerprint = NULL;
62 int tls_clientactive = 0; /* available or not */
63 char *tls_peer_CN = NULL;
64 char *tls_issuer_CN = NULL;
66 const char *tls_protocol = NULL;
67 const char *tls_cipher_name = NULL;
68 int tls_cipher_usebits = 0;
69 int tls_cipher_algbits = 0;
75 /* taken from OpenSSL apps/s_cb.c
76 * tim - this seems to just be giving logging messages
79 static void apps_ssl_info_callback(SSL * s, int where, int ret)
84 if (tls_loglevel==0) return;
86 w = where & ~SSL_ST_MASK;
88 if (w & SSL_ST_CONNECT)
90 else if (w & SSL_ST_ACCEPT)
95 if (where & SSL_CB_LOOP) {
96 if (tls_serverengine && (tls_loglevel >= 2))
97 Printf("%s:%s", str, SSL_state_string_long(s));
98 } else if (where & SSL_CB_ALERT) {
99 str = (where & SSL_CB_READ) ? "read" : "write";
100 if ((tls_serverengine && (tls_loglevel >= 2)) ||
101 ((ret & 0xff) != SSL3_AD_CLOSE_NOTIFY))
102 Printf("SSL3 alert %s:%s:%s", str,
103 SSL_alert_type_string_long(ret),
104 SSL_alert_desc_string_long(ret));
105 } else if (where & SSL_CB_EXIT) {
107 Printf("%s:failed in %s",
108 str, SSL_state_string_long(s));
110 Printf("%s:error in %s",
111 str, SSL_state_string_long(s));
118 * Hardcoded DH parameter files, from OpenSSL.
119 * For information on how these files were generated, see
120 * "Assigned Number for SKIP Protocols"
121 * (http://www.skip-vpn.org/spec/numbers.html.
123 static const char file_dh512[] =
124 "-----BEGIN DH PARAMETERS-----\n\
125 MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak\n\
126 XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC\n\
127 -----END DH PARAMETERS-----\n";
129 static const char file_dh1024[] =
130 "-----BEGIN DH PARAMETERS-----\n\
131 MIGHAoGBAPSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsY\n\
132 jY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6\n\
133 ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpL3jHAgEC\n\
134 -----END DH PARAMETERS-----\n";
136 static const char file_dh2048[] =
137 "-----BEGIN DH PARAMETERS-----\n\
138 MIIBCAKCAQEA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV\n\
139 89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50\n\
140 T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknb\n\
141 zSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdX\n\
142 Q6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbT\n\
143 CD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwIBAg==\n\
144 -----END DH PARAMETERS-----\n";
146 static const char file_dh4096[] =
147 "-----BEGIN DH PARAMETERS-----\n\
148 MIICCAKCAgEA+hRyUsFN4VpJ1O8JLcCo/VWr19k3BCgJ4uk+d+KhehjdRqNDNyOQ\n\
149 l/MOyQNQfWXPeGKmOmIig6Ev/nm6Nf9Z2B1h3R4hExf+zTiHnvVPeRBhjdQi81rt\n\
150 Xeoh6TNrSBIKIHfUJWBh3va0TxxjQIs6IZOLeVNRLMqzeylWqMf49HsIXqbcokUS\n\
151 Vt1BkvLdW48j8PPv5DsKRN3tloTxqDJGo9tKvj1Fuk74A+Xda1kNhB7KFlqMyN98\n\
152 VETEJ6c7KpfOo30mnK30wqw3S8OtaIR/maYX72tGOno2ehFDkq3pnPtEbD2CScxc\n\
153 alJC+EL7RPk5c/tgeTvCngvc1KZn92Y//EI7G9tPZtylj2b56sHtMftIoYJ9+ODM\n\
154 sccD5Piz/rejE3Ome8EOOceUSCYAhXn8b3qvxVI1ddd1pED6FHRhFvLrZxFvBEM9\n\
155 ERRMp5QqOaHJkM+Dxv8Cj6MqrCbfC4u+ZErxodzuusgDgvZiLF22uxMZbobFWyte\n\
156 OvOzKGtwcTqO/1wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH\n\
157 AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL\n\
158 KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\
159 -----END DH PARAMETERS-----\n";
162 * Load hardcoded DH parameters.
165 load_dh_buffer (const char *buffer, size_t len)
170 bio = BIO_new_mem_buf((char *) buffer, len);
173 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
174 /* if (dh == NULL) log error */
181 * Generate empheral DH key. Because this can take a long
182 * time to compute, we use precomputed parameters of the
185 * These values can be static (once loaded or computed) since
186 * the OpenSSL library can effectively generate random keys
187 * from the information provided.
189 * EDH keying is slightly less efficient than static RSA keying,
190 * but it offers Perfect Forward Secrecy (PFS).
192 * FIXME: support user-specified files, to eliminate risk of
193 * "small group" attacks.
195 static DH *tmp_dh_cb(SSL *s UNUSED, int export UNUSED, int keylength)
198 static DH *dh = NULL;
199 static DH *dh512 = NULL;
200 static DH *dh1024 = NULL;
201 static DH *dh2048 = NULL;
202 static DH *dh4096 = NULL;
208 dh512 = load_dh_buffer(file_dh512, sizeof file_dh512);
213 dh1024 = load_dh_buffer(file_dh1024, sizeof file_dh1024);
218 dh2048 = load_dh_buffer(file_dh2048, sizeof file_dh2048);
223 dh4096 = load_dh_buffer(file_dh4096, sizeof file_dh4096);
227 /* we should check current keylength vs. requested keylength */
228 /* also, this is an extremely expensive operation! */
229 dh = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL);
236 /* taken from OpenSSL apps/s_cb.c */
238 static int verify_callback(int ok, X509_STORE_CTX * ctx)
245 syslog(L_NOTICE,"Doing a peer verify");
247 err_cert = X509_STORE_CTX_get_current_cert(ctx);
248 err = X509_STORE_CTX_get_error(ctx);
249 depth = X509_STORE_CTX_get_error_depth(ctx);
251 X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
252 if ((tls_serveractive) && (tls_loglevel >= 1))
253 Printf("Peer cert verify depth=%d %s", depth, buf);
256 syslog(L_NOTICE, "verify error:num=%d:%s", err,
257 X509_verify_cert_error_string(err));
259 if (verify_depth >= depth) {
261 verify_error = X509_V_OK;
264 verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
267 switch (ctx->error) {
268 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
269 X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
270 syslog(L_NOTICE, "issuer= %s", buf);
272 case X509_V_ERR_CERT_NOT_YET_VALID:
273 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
274 syslog(L_NOTICE, "cert not yet valid");
276 case X509_V_ERR_CERT_HAS_EXPIRED:
277 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
278 syslog(L_NOTICE, "cert has expired");
281 if ((tls_serveractive) && (tls_loglevel >= 1))
282 Printf("verify return:%d", ok);
289 * taken from OpenSSL crypto/bio/b_dump.c, modified to save a lot of strcpy
290 * and strcat by Matti Aarnio.
294 #define DUMP_WIDTH 16
296 static int tls_dump(const char *s, int len)
311 for (; (len > 0) && ((s[len - 1] == ' ') || (s[len - 1] == '\0')); len--)
315 rows = (len / DUMP_WIDTH);
316 if ((rows * DUMP_WIDTH) < len)
319 for (i = 0; i < rows; i++) {
320 buf[0] = '\0'; /* start with empty string */
323 sprintf(ss, "%04x ", i * DUMP_WIDTH);
325 for (j = 0; j < DUMP_WIDTH; j++) {
326 if (((i * DUMP_WIDTH) + j) >= len) {
329 ch = ((unsigned char) *((const char *)(s) + i * DUMP_WIDTH + j))
331 sprintf(ss, "%02x%c", ch, j == 7 ? '|' : ' ');
337 for (j = 0; j < DUMP_WIDTH; j++) {
338 if (((i * DUMP_WIDTH) + j) >= len)
340 ch = ((unsigned char) *((const char *)(s) + i * DUMP_WIDTH + j))
342 *ss+= (((ch >= ' ') && (ch <= '~')) ? ch : '.');
343 if (j == 7) *ss+= ' ';
347 * if this is the last call then update the ddt_dump thing so that
348 * we will move the selection point in the debug window
356 snprintf(buf, sizeof(buf), "%04x - <SPACES/NULS>\n", len+ trunc);
366 * Set up the cert things on the server side. We do need both the
367 * private key (in key_file) and the cert (in cert_file).
368 * Both files may be identical.
370 * This function is taken from OpenSSL apps/s_cb.c
373 static int set_cert_stuff(SSL_CTX * ctx, char *cert_file, char *key_file)
377 if (cert_file != NULL) {
378 if (SSL_CTX_use_certificate_file(ctx, cert_file,
379 SSL_FILETYPE_PEM) <= 0) {
380 syslog(L_ERROR, "unable to get certificate from '%s'", cert_file);
383 if (key_file == NULL)
384 key_file = cert_file;
386 /* check ownership and permissions of key file */
387 if (lstat(key_file, &buf) == -1) {
388 syslog(L_ERROR, "unable to stat private key '%s'", key_file);
391 if (!S_ISREG(buf.st_mode) || (buf.st_mode & 0077) != 0 ||
392 buf.st_uid != getuid()) {
393 syslog(L_ERROR, "bad ownership or permissions on private key"
394 " '%s': private key must be mode 600 and owned by "
395 NEWSUSER, cert_file);
399 if (SSL_CTX_use_PrivateKey_file(ctx, key_file,
400 SSL_FILETYPE_PEM) <= 0) {
401 syslog(L_ERROR, "unable to get private key from '%s'", key_file);
404 /* Now we know that a key and cert have been set against
406 if (!SSL_CTX_check_private_key(ctx)) {
407 syslog(L_ERROR, "Private key does not match the certificate public key");
417 * This is the setup routine for the SSL server. As smtpd might be called
418 * more than once, we only want to do the initialization one time.
420 * The skeleton of this function is taken from OpenSSL apps/s_server.c.
422 * returns -1 on error
425 int tls_init_serverengine(int verifydepth,
435 int verify_flags = SSL_VERIFY_NONE;
442 if (tls_serverengine)
443 return (0); /* already running */
445 if (tls_loglevel >= 2)
446 Printf("starting TLS engine");
448 SSL_load_error_strings();
449 SSLeay_add_ssl_algorithms();
451 CTX = SSL_CTX_new(SSLv23_server_method());
456 off |= SSL_OP_ALL; /* Work around all known bugs */
457 SSL_CTX_set_options(CTX, off);
458 SSL_CTX_set_info_callback(CTX, apps_ssl_info_callback);
459 SSL_CTX_sess_set_cache_size(CTX, 128);
461 if (strlen(tls_CAfile) == 0)
465 if (strlen(tls_CApath) == 0)
470 if ((!SSL_CTX_load_verify_locations(CTX, CAfile, CApath)) ||
471 (!SSL_CTX_set_default_verify_paths(CTX))) {
472 if (tls_loglevel >= 2)
473 Printf("TLS engine: cannot load CA data\n");
477 if (strlen(tls_cert_file) == 0)
480 s_cert_file = tls_cert_file;
481 if (strlen(tls_key_file) == 0)
484 s_key_file = tls_key_file;
486 if (!set_cert_stuff(CTX, s_cert_file, s_key_file)) {
487 if (tls_loglevel >= 2)
488 Printf("TLS engine: cannot load cert/key data\n");
492 /* load some randomization data from /dev/urandom, if it exists */
493 /* FIXME: should also check for ".rand" file, update it on exit */
494 if (stat("/dev/urandom", &buf) == 0)
495 RAND_load_file("/dev/urandom", 16 * 1024);
497 SSL_CTX_set_tmp_dh_callback(CTX, tmp_dh_cb);
498 SSL_CTX_set_options(CTX, SSL_OP_SINGLE_DH_USE);
500 verify_depth = verifydepth;
502 verify_flags |= SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
504 verify_flags |= SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
505 | SSL_VERIFY_CLIENT_ONCE;
506 SSL_CTX_set_verify(CTX, verify_flags, verify_callback);
508 SSL_CTX_set_client_CA_list(CTX, SSL_load_client_CA_file(CAfile));
510 tls_serverengine = 1;
516 ** The function called by nnrpd to initialize the TLS support. Calls
517 ** tls_init_server_engine and checks the result. On any sort of failure,
528 ssl_result = tls_init_serverengine(5, /* depth to verify */
529 0, /* can client auth? */
530 0, /* required client to auth? */
531 (char *)sasl_config_getstring("tls_ca_file", ""),
532 (char *)sasl_config_getstring("tls_ca_path", ""),
533 (char *)sasl_config_getstring("tls_cert_file", ""),
534 (char *)sasl_config_getstring("tls_key_file", ""));
535 if (ssl_result == -1) {
536 Reply("%d Error initializing TLS\r\n", NNTP_STARTTLS_BAD_VAL);
537 syslog(L_ERROR, "error initializing TLS: "
538 "[CA_file: %s] [CA_path: %s] [cert_file: %s] [key_file: %s]",
539 sasl_config_getstring("tls_ca_file", ""),
540 sasl_config_getstring("tls_ca_path", ""),
541 sasl_config_getstring("tls_cert_file", ""),
542 sasl_config_getstring("tls_key_file", ""));
543 ExitWithStats(1, false);
545 tls_initialized = true;
549 /* taken from OpenSSL apps/s_cb.c */
551 static long bio_dump_cb(BIO * bio, int cmd, const char *argp, int argi,
552 long argl UNUSED, long ret)
557 if (cmd == (BIO_CB_READ | BIO_CB_RETURN)) {
558 Printf("read from %08X [%08lX] (%d bytes => %ld (0x%X))", (unsigned int) bio, (long unsigned int) argp,
559 argi, ret, (unsigned int) ret);
560 tls_dump(argp, (int) ret);
562 } else if (cmd == (BIO_CB_WRITE | BIO_CB_RETURN)) {
563 Printf("write to %08X [%08lX] (%d bytes => %ld (0x%X))", (unsigned int) bio, (long unsigned int)argp,
564 argi, ret, (unsigned int) ret);
565 tls_dump(argp, (int) ret);
571 * This is the actual startup routine for the connection. We expect
572 * that the buffers are flushed and the "220 Ready to start TLS" was
573 * send to the client, so that we can immediately can start the TLS
576 * layerbits and authid are filled in on sucess. authid is only
577 * filled in if the client authenticated
580 int tls_start_servertls(int readfd, int writefd)
584 SSL_SESSION *session;
587 if (!tls_serverengine)
589 /* should never happen */
590 syslog(L_ERROR, "tls_engine not running");
593 if (tls_loglevel >= 1)
594 Printf("setting up TLS connection");
596 if (tls_conn == NULL)
598 tls_conn = (SSL *) SSL_new(CTX);
600 if (tls_conn == NULL)
606 #if defined(SOL_SOCKET) && defined(SO_KEEPALIVE)
607 /* Set KEEPALIVE to catch broken socket connections. */
609 if (setsockopt(readfd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) < 0)
610 syslog(L_ERROR, "fd %d can't setsockopt(KEEPALIVE) %m", readfd);
611 if (setsockopt(writefd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) < 0)
612 syslog(L_ERROR, "fd %d can't setsockopt(KEEPALIVE) %m", writefd);
613 #endif /* SOL_SOCKET && SO_KEEPALIVE */
615 /* set the file descriptors for SSL to use */
616 if (SSL_set_rfd(tls_conn, readfd)==0)
621 if (SSL_set_wfd(tls_conn, writefd)==0)
627 * This is the actual handshake routine. It will do all the negotiations
628 * and will check the client cert etc.
630 SSL_set_accept_state(tls_conn);
633 * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called?
634 * Well there is a BIO below the SSL routines that is automatically
635 * created for us, so we can use it for debugging purposes.
637 if (tls_loglevel >= 3)
638 BIO_set_callback(SSL_get_rbio(tls_conn), bio_dump_cb);
640 /* Dump the negotiation for loglevels 3 and 4*/
641 if (tls_loglevel >= 3)
644 if ((sts = SSL_accept(tls_conn)) <= 0) { /* xxx <= 0 */
645 session = SSL_get_session(tls_conn);
648 SSL_CTX_remove_session(CTX, session);
655 /* Only loglevel==4 dumps everything */
656 if (tls_loglevel < 4)
659 tls_protocol = SSL_get_version(tls_conn);
660 cipher = SSL_get_current_cipher(tls_conn);
662 tls_cipher_name = SSL_CIPHER_get_name(cipher);
663 tls_cipher_usebits = SSL_CIPHER_get_bits(cipher,
664 &tls_cipher_algbits);
665 tls_serveractive = 1;
667 syslog(L_NOTICE, "starttls: %s with cipher %s (%d/%d bits) no authentication", tls_protocol, tls_cipher_name,
668 tls_cipher_usebits, tls_cipher_algbits);
674 SSL_writev (ssl, vector, count)
676 const struct iovec *vector;
679 static char *buffer = NULL;
680 static size_t allocsize = 0;
682 size_t bytes, to_copy;
684 /* Find the total number of bytes to be written. */
686 for (i = 0; i < count; ++i)
687 bytes += vector[i].iov_len;
688 /* Allocate a buffer to hold the data. */
689 if (NULL == buffer) {
690 buffer = (char *) xmalloc(bytes);
692 } else if (bytes > allocsize) {
693 buffer = (char *) xrealloc (buffer, bytes);
696 /* Copy the data into BUFFER. */
699 for (i = 0; i < count; ++i)
701 #define min(a, b) ((a) > (b) ? (b) : (a))
702 size_t copy = min (vector[i].iov_len, to_copy);
703 memcpy (bp, vector[i].iov_base, copy);
709 return SSL_write (ssl, buffer, bytes);
713 #endif /* HAVE_SSL */