iostream-openssl.c revision 4584a00276941db3f64c4db1a1bed91fe107af81
/* Copyright (c) 2009-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream-private.h"
#include "ostream-private.h"
#include "iostream-openssl.h"
static void
{
/* This error should normally be logged by lib-ssl-iostream's
caller. But if verbose=TRUE, log it here as well to make
sure that the error is always logged. */
}
}
{
struct ssl_iostream *ssl_io;
if ((where & SSL_CB_ALERT) != 0) {
switch (ret & 0xff) {
case SSL_AD_CLOSE_NOTIFY:
i_debug("%sSSL alert: %s",
break;
default:
i_debug("%sSSL alert: where=0x%x, ret=%d: %s %s",
break;
}
} else if (ret == 0) {
i_debug("%sSSL failed: where=0x%x: %s",
} else {
i_debug("%sSSL: where=0x%x, ret=%d: %s",
}
}
static int
const char **error_r)
{
X509 *x;
int ret = 0;
return -1;
}
if (x != NULL) {
if (ERR_peek_error() != 0)
ret = 0;
X509_free(x);
}
if (ret == 0) {
return -1;
}
return 0;
}
static int
const struct ssl_iostream_cert *set,
const char **error_r)
{
int ret = 0;
return -1;
ret = -1;
}
return ret;
}
static int
{
struct ssl_iostream *ssl_io;
char certname[1024];
certname[0] = '\0';
else
if (preverify_ok == 0) {
"Received invalid SSL certificate: %s: %s",
if (ssl_io->verbose_invalid_cert)
}
if (preverify_ok == 0) {
if (!ssl_io->allow_invalid_cert) {
return 0;
}
}
return 1;
}
static int
const struct ssl_iostream_settings *set,
const char **error_r)
{
int verify_flags;
"Can't set cipher list to '%s': %s",
return -1;
}
}
"Failed to set curve list to '%s'",
set->curve_list);
return -1;
}
}
#endif
if (set->prefer_server_ciphers)
#if defined(HAVE_SSL_CLEAR_OPTIONS)
#endif
}
return -1;
}
return -1;
}
return -1;
}
return -1;
}
if (set->verify_remote_cert) {
else
}
"Invalid cert_username_field: %s",
return -1;
}
} else {
}
return 0;
}
static int
const struct ssl_iostream_settings *set,
struct ssl_iostream **iostream_r,
const char **error_r)
{
struct ssl_iostream *ssl_io;
return -1;
}
/* BIO pairs use default buffer sizes (17 kB in OpenSSL 0.9.8e).
Each of the BIOs have one "write buffer". BIO_write() copies data
to them, while BIO_read() reads from the other BIO's write buffer
into the given buffer. The bio_int is used by OpenSSL and bio_ext
is used by this library. */
return -1;
}
/* bio_int will be freed by SSL_free() */
#ifdef HAVE_SSL_GET_SERVERNAME
#endif
return -1;
}
*iostream_r = ssl_io;
return 0;
}
{
}
{
return;
}
{
/* if bidirectional shutdown fails we need to clear
the error queue */
}
(void)openssl_iostream_more(ssl_io);
/* close the plain i/o streams, because their fd may be closed soon,
but we may still keep this ssl-iostream referenced until later. */
}
{
unsigned char buffer[IO_BLOCK_SIZE];
bool bytes_sent = FALSE;
int ret;
/* bytes contains how many SSL encrypted bytes we should be
sending out */
if (max_bytes == 0) {
/* wait until output buffer clears */
TRUE);
break;
}
}
/* BIO_read() is guaranteed to return all the bytes that
BIO_ctrl_pending() returned */
/* we limited number of read bytes to plain_output's
available size. this send() is guaranteed to either
fully succeed or completely fail due to some error. */
if (sent < 0) {
break;
}
bytes_sent = TRUE;
}
return bytes_sent;
}
static ssize_t
{
if (*size_r > 0)
return 0;
return -1;
return 0;
}
{
const unsigned char *data;
int ret;
bool bytes_read = FALSE;
/* bytes contains how many bytes we can write to bio_ext */
}
return FALSE;
}
if (size == 0) {
/* wait for more input */
break;
}
bytes_read = TRUE;
}
/* shouldn't happen */
i_error("SSL BIO buffer size too small");
i_strdup("SSL BIO buffer size too small");
return FALSE;
}
i_error("SSL: Too much data in buffered plain input buffer");
i_strdup("SSL: Too much data in buffered plain input buffer");
return FALSE;
}
if (bytes_read) {
if (ssl_io->ostream_flush_waiting_input) {
}
}
return bytes_read;
}
{
bool ret;
return ret;
}
{
int ret;
if (!ssl_io->handshaked) {
return ret;
}
(void)openssl_iostream_bio_sync(ssl_io);
return 1;
}
static int
const char *func_name, bool write_error)
{
int err;
switch (err) {
case SSL_ERROR_WANT_WRITE:
if (!openssl_iostream_bio_sync(ssl_io)) {
if (!write_error)
i_panic("SSL ostream buffer size not unlimited");
return 0;
}
return -1;
}
return 1;
case SSL_ERROR_WANT_READ:
(void)openssl_iostream_bio_sync(ssl_io);
return -1;
}
case SSL_ERROR_SYSCALL:
/* eat up the error queue */
if (ERR_peek_error() != 0) {
} else if (ret != 0) {
} else {
/* EOF. */
errstr = "Disconnected";
break;
}
break;
case SSL_ERROR_ZERO_RETURN:
/* clean connection closing */
return -1;
case SSL_ERROR_SSL:
break;
default:
break;
}
return -1;
}
const char *func_name)
{
}
const char *func_name)
{
}
static int
const char *verify_name)
{
return -1;
}
{
int ret;
"SSL_connect()");
if (ret <= 0)
return ret;
}
} else {
"SSL_accept()");
if (ret <= 0)
return ret;
}
}
/* handshake finished */
(void)openssl_iostream_bio_sync(ssl_io);
}
"SSL certificate doesn't match expected host name %s",
ssl_io->connected_host));
}
}
if (ssl_io->handshake_failed) {
return -1;
}
return 1;
}
static void
void *context)
{
}
const char *prefix)
{
}
{
return ssl_io->handshaked;
}
static bool
{
return ssl_io->handshake_failed;
}
static bool
{
}
static bool
{
}
static const char *
{
char *name;
int len;
return NULL;
if (len < 0)
name = "";
else {
name = "";
/* NUL characters in name. Someone's trying to fake
being another user? Don't allow it. */
name = "";
}
}
}
{
}
static const char *
{
#if defined(HAVE_SSL_COMPRESSION) && !defined(OPENSSL_NO_COMP)
const COMP_METHOD *comp;
#else
return NULL;
#endif
}
static const char *
{
const SSL_CIPHER *cipher;
#if defined(HAVE_SSL_COMPRESSION) && !defined(OPENSSL_NO_COMP)
const COMP_METHOD *comp;
#endif
const char *comp_str;
if (!ssl_io->handshaked)
return "";
#if defined(HAVE_SSL_COMPRESSION) && !defined(OPENSSL_NO_COMP)
#else
comp_str = "";
#endif
return t_strdup_printf("%s with cipher %s (%d/%d bits)%s",
}
static const char *
{
return ssl_io->last_error;
}
static const struct iostream_ssl_vfuncs ssl_vfuncs = {
};
void ssl_iostream_openssl_init(void)
{
unsigned char buf;
i_fatal("OpenSSL RNG failed to initialize");
}
void ssl_iostream_openssl_deinit(void)
{
}