iostream-openssl.c revision ed41ec8aa0efaa50954fd16cb44c86c8350dadcc
/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-openssl.h"
{
struct ssl_iostream *ssl_io;
if ((where & SSL_CB_ALERT) != 0) {
i_warning("%s: SSL alert: where=0x%x, ret=%d: %s %s",
} else if (ret == 0) {
i_warning("%s: SSL failed: where=0x%x: %s",
} else {
i_warning("%s: SSL: where=0x%x, ret=%d: %s",
}
}
static int
{
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_settings *set)
{
int ret = 0;
return -1;
i_error("%s: Can't load SSL private key: %s",
ret = -1;
}
return ret;
}
static int
{
struct ssl_iostream *ssl_io;
char buf[1024];
buf[0] = '\0';
else
if (!preverify_ok) {
i_info("Invalid certificate: %s: %s",
} else {
}
}
if (!preverify_ok) {
if (ssl_io->require_valid_cert)
return 0;
}
return 1;
}
static int
const struct ssl_iostream_settings *set)
{
int verify_flags;
i_error("%s: Can't set cipher list to '%s': %s",
}
return -1;
}
return -1;
}
return -1;
}
if (set->verify_remote_cert) {
else
}
i_error("%s: Invalid cert_username_field: %s",
}
} else {
}
return 0;
}
const struct ssl_iostream_settings *set,
struct ssl_iostream **iostream_r)
{
struct ssl_iostream *ssl_io;
int ret;
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() */
T_BEGIN {
} T_END;
if (ret < 0) {
return -1;
}
*iostream_r = ssl_io;
return 0;
}
{
}
{
return;
}
{
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;
}
{
const unsigned char *data;
bool bytes_read = FALSE;
int ret;
/* bytes contains how many bytes we can write to bio_ext */
size == 0 && !bytes_read) {
return FALSE;
}
if (size == 0) {
/* wait for more input */
break;
}
bytes_read = TRUE;
}
/* shouldn't happen */
i_panic("SSL BIO buffer size too small");
}
if (bytes_read) {
if (ssl_io->ostream_flush_waiting_input) {
}
}
return bytes_read;
}
{
bool ret;
if (ssl_iostream_bio_input(ssl_io))
return ret;
}
{
int ret;
if (!ssl_io->handshaked) {
return ret;
}
(void)ssl_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 (!ssl_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)ssl_iostream_bio_sync(ssl_io);
return -1;
}
case SSL_ERROR_SYSCALL:
/* eat up the error queue */
if (ERR_peek_error() != 0) {
errstr = ssl_iostream_error();
} else if (ret != 0) {
} else {
/* EOF. */
errno = ECONNRESET;
errstr = "Disconnected";
break;
}
break;
case SSL_ERROR_ZERO_RETURN:
/* clean connection closing */
errno = ECONNRESET;
break;
case SSL_ERROR_SSL:
break;
default:
break;
}
return -1;
}
const char *func_name)
{
}
const char *func_name)
{
}
{
const char *cstr;
unsigned int len;
/* NULs in the name - could be some MITM attack.
never allow. */
return "";
}
return cstr;
}
{
return "";
}
{
int cn_idx;
return "";
if (cn_idx == -1)
return "";
return asn1_string_to_c(str);
}
const char *verify_name)
{
const GENERAL_NAME *gn;
const char *dnsname;
unsigned int i, count;
return -1;
/* verify against SubjectAltNames */
for (i = 0; i < count; i++) {
break;
}
}
/* verify against CommonName only when there wasn't any DNS
SubjectAltNames */
if (dns_names)
return i < count ? 0 : -1;
}
{
int ret;
"SSL_connect()");
if (ret <= 0)
return ret;
}
} else {
"SSL_accept()");
if (ret <= 0)
return ret;
}
}
/* handshake finished */
(void)ssl_iostream_bio_sync(ssl_io);
return -1;
}
}
return 1;
}
void *context)
{
}
{
return ssl_io->handshaked;
}
{
}
{
}
{
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 = "";
}
}
}
{
const SSL_CIPHER *cipher;
#ifdef HAVE_SSL_COMPRESSION
const COMP_METHOD *comp;
#endif
const char *comp_str;
if (!ssl_io->handshaked)
return "";
#ifdef HAVE_SSL_COMPRESSION
#else
comp_str = "";
#endif
return t_strdup_printf("%s with cipher %s (%d/%d bits)%s",
}
{
return ssl_io->last_error;
}