/* * tls.c: * TLS stuff for tpop3d. * * Copyright (c) 2002 Chris Lightfoot. All rights reserved. * Email: chris@ex-parrot.com; WWW: http://www.ex-parrot.com/~chris/ * */ #include "configuration.h" #ifdef USE_TLS static const char rcsid[] = "$Id: tls.c,v 1.8 2003/09/07 15:41:24 chris Exp $"; #include #include #include #include #include #include #include #include "config.h" #include "tls.h" #include "util.h" #define tls_errorstr() ERR_reason_error_string(ERR_get_error()) /* Normally, tpop3d will not read a pass phrase for a certificate from the * terminal. This is to prevent it from blocking during the boot phase, waiting * for the user to type something in. Reading of pass phrases can be enabled * using the -P switch to tpop3d. */ int noreadpassphrase = 1; /* tls_getpassphrase: * Obtain a pass phrase from the user. */ static int tls_getpass(char *buf, int size, int rwflag, void *userdata) { char *prompt, *s; memset(buf, 0, size); if (noreadpassphrase) return 0; prompt = xmalloc(strlen((char*)userdata) + 40); sprintf(prompt, "Enter pass phrase for `%s': ", (char*)userdata); /* XXX some systems have unreasonable limits on the length of strings * returned by getpass(3). */ s = getpass(prompt); xfree(prompt); strncpy(buf, s, size - 1); memset(s, 0, strlen(s)); /* paranoia */ return strlen(buf); } /* tls_init * Global TLS initialisation. */ static int tls_init_called; int tls_init(void) { if (tls_init_called) return 1; SSL_load_error_strings(); SSL_library_init(); tls_init_called = 1; return 1; } /* tls_create_context CERTFILE PKEYFILE * Create a new SSL_CTX, reading the certificate and private key from CERTFILE * and PKEYFILE. If PKEYFILE is NULL, then we attempt to read the private key * from the certificate file. Returns a valid SSL context on success or NULL * on failure. */ SSL_CTX *tls_create_context(const char *certfile, const char *pkeyfile) { int ret; SSL_CTX *ctx; if (!(ctx = SSL_CTX_new(SSLv23_server_method()))) { log_print(LOG_ERR, "tls_create_context: SSL_CTX_new: %s", tls_errorstr()); return NULL; } /* Set up the password call back. */ SSL_CTX_set_default_passwd_cb(ctx, tls_getpass); /* Load certificate, and, if specified, separate private key. */ SSL_CTX_set_default_passwd_cb_userdata(ctx, (void*)certfile); if ((ret = SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM)) <= 0) { log_print(LOG_ERR, "tls_create_context: %s: %s", certfile, ERR_reason_error_string(ERR_get_error())); SSL_CTX_free(ctx); return NULL; } SSL_CTX_set_default_passwd_cb_userdata(ctx, (void*)pkeyfile); if ((ret = SSL_CTX_use_PrivateKey_file(ctx, pkeyfile ? pkeyfile : certfile, SSL_FILETYPE_PEM)) <= 0) { log_print(LOG_ERR, "tls_create_context: %s: %s", pkeyfile ? pkeyfile : certfile, tls_errorstr()); SSL_CTX_free(ctx); return NULL; } /* Verify that the private key matches the certificate. */ if (!SSL_CTX_check_private_key(ctx)) { log_print(LOG_ERR, _("tls_create_context: private key does not match certificate public key")); SSL_CTX_free(ctx); return NULL; } /* Set various useful options on the context. */ SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); if (!config_get_bool("tls-no-bug-workarounds")) SSL_CTX_set_options(ctx, SSL_OP_ALL); /* bug workarounds */ return ctx; } /* tls_close: * Shut down TLS stuff. */ void tls_close(SSL_CTX *ctx) { SSL_CTX_free(ctx); } #endif /* USE_TLS */