/*
* 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 <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#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 */
syntax highlighted by Code2HTML, v. 0.9.1