iostream-openssl.c revision 148a8396be2c1cf7d2aaa55566f7f7dea05388dd
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#include "lib.h"
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#include "istream.h"
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#include "ostream.h"
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#include "iostream-openssl.h"
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#include <openssl/err.h>
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic void ssl_iostream_free(struct ssl_iostream *ssl_io);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic void ssl_info_callback(const SSL *ssl, int where, int ret)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen struct ssl_iostream *ssl_io;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io = SSL_get_ex_data(ssl, dovecot_ssl_extdata_index);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if ((where & SSL_CB_ALERT) != 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_warning("%s: SSL alert: where=0x%x, ret=%d: %s %s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->source, where, ret,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_alert_type_string_long(ret),
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_alert_desc_string_long(ret));
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen } else if (ret == 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_warning("%s: SSL failed: where=0x%x: %s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->source, where, SSL_state_string_long(ssl));
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen } else {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_warning("%s: SSL: where=0x%x, ret=%d: %s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->source, where, ret,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_state_string_long(ssl));
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic int
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenssl_iostream_use_certificate(struct ssl_iostream *ssl_io, const char *cert)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen BIO *in;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen X509 *x;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int ret = 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen in = BIO_new_mem_buf(t_strdup_noconst(cert), strlen(cert));
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (in == NULL) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_error("BIO_new_mem_buf() failed: %s", ssl_iostream_error());
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen x = PEM_read_bio_X509(in, NULL, NULL, NULL);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (x != NULL) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = SSL_use_certificate(ssl_io->ssl, x);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ERR_peek_error() != 0)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen X509_free(x);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen BIO_free(in);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ret == 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_error("%s: Can't load ssl_cert: %s", ssl_io->source,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_iostream_get_use_certificate_error(cert));
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic int
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenssl_iostream_use_key(struct ssl_iostream *ssl_io,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen const struct ssl_iostream_settings *set)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen EVP_PKEY *pkey;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int ret = 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_iostream_load_key(set, ssl_io->source, &pkey) < 0)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (SSL_use_PrivateKey(ssl_io->ssl, pkey) != 1) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_error("%s: Can't load SSL private key: %s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->source, ssl_iostream_key_load_error());
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen EVP_PKEY_free(pkey);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return ret;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic int
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenssl_iostream_verify_client_cert(int preverify_ok, X509_STORE_CTX *ctx)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int ssl_extidx = SSL_get_ex_data_X509_STORE_CTX_idx();
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL *ssl;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen struct ssl_iostream *ssl_io;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl = X509_STORE_CTX_get_ex_data(ctx, ssl_extidx);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io = SSL_get_ex_data(ssl, dovecot_ssl_extdata_index);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->cert_received = TRUE;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_io->verbose ||
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen (ssl_io->verbose_invalid_cert && !preverify_ok)) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen char buf[1024];
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen X509_NAME *subject;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen subject = X509_get_subject_name(ctx->current_cert);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (X509_NAME_oneline(subject, buf, sizeof(buf)) == NULL)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen buf[0] = '\0';
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen else
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen buf[sizeof(buf)-1] = '\0'; /* just in case.. */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (!preverify_ok) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_info("Invalid certificate: %s: %s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen X509_verify_cert_error_string(ctx->error), buf);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen } else {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_info("Valid certificate: %s", buf);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (!preverify_ok) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->cert_broken = TRUE;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_io->require_valid_cert)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic int
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenssl_iostream_set(struct ssl_iostream *ssl_io,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen const struct ssl_iostream_settings *set)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen const struct ssl_iostream_settings *ctx_set = ssl_io->ctx->set;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (set->verbose)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_set_info_callback(ssl_io->ssl, ssl_info_callback);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (set->cipher_list != NULL &&
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen strcmp(ctx_set->cipher_list, set->cipher_list) != 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (!SSL_set_cipher_list(ssl_io->ssl, set->cipher_list)) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_error("%s: Can't set cipher list to '%s': %s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->source, set->cipher_list,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_iostream_error());
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (set->cert != NULL && strcmp(ctx_set->cert, set->cert) != 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_iostream_use_certificate(ssl_io, set->cert) < 0)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (set->key != NULL && strcmp(ctx_set->key, set->key) != 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_iostream_use_key(ssl_io, set) < 0)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (set->verify_remote_cert) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_set_verify(ssl_io->ssl,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_iostream_verify_client_cert);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (set->cert_username_field != NULL) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->username_nid = OBJ_txt2nid(set->cert_username_field);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_io->username_nid == NID_undef) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_error("%s: Invalid cert_username_field: %s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->source, set->cert_username_field);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen } else {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->username_nid = ssl_io->ctx->username_nid;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->verbose = set->verbose;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->verbose_invalid_cert = set->verbose_invalid_cert;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->require_valid_cert = set->require_valid_cert;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenint io_stream_create_ssl(struct ssl_iostream_context *ctx, const char *source,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen const struct ssl_iostream_settings *set,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen struct istream **input, struct ostream **output,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen struct ssl_iostream **iostream_r)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen struct ssl_iostream *ssl_io;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL *ssl;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen BIO *bio_int, *bio_ext;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int ret;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl = SSL_new(ctx->ssl_ctx);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl == NULL) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_error("SSL_new() failed: %s", ssl_iostream_error());
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (BIO_new_bio_pair(&bio_int, 0, &bio_ext, 0) != 1) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_error("BIO_new_bio_pair() failed: %s", ssl_iostream_error());
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_free(ssl);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io = i_new(struct ssl_iostream, 1);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->refcount = 1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->ctx = ctx;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->ssl = ssl;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->bio_ext = bio_ext;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->plain_input = *input;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->plain_output = *output;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->source = i_strdup(source);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_set_bio(ssl_io->ssl, bio_int, bio_int);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_set_ex_data(ssl_io->ssl, dovecot_ssl_extdata_index, ssl_io);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_stream_ref(ssl_io->plain_input);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen o_stream_ref(ssl_io->plain_output);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen T_BEGIN {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = ssl_iostream_set(ssl_io, set);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen } T_END;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ret < 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_iostream_free(ssl_io);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
9ab0786966c0afa8fa09a2faff7c067bc388e694Timo Sirainen o_stream_uncork(ssl_io->plain_output);
9ab0786966c0afa8fa09a2faff7c067bc388e694Timo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen *input = i_stream_create_ssl(ssl_io);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen *output = o_stream_create_ssl(ssl_io);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->ssl_output = *output;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen *iostream_r = ssl_io;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic void ssl_iostream_free(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_stream_unref(&ssl_io->plain_input);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen o_stream_unref(&ssl_io->plain_output);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen BIO_free(ssl_io->bio_ext);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_free(ssl_io->ssl);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_free(ssl_io->last_error);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_free(ssl_io->source);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_free(ssl_io);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenvoid ssl_iostream_unref(struct ssl_iostream **_ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen struct ssl_iostream *ssl_io = *_ssl_io;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen *_ssl_io = NULL;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_assert(ssl_io->refcount > 0);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (--ssl_io->refcount >= 0)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_iostream_free(ssl_io);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic bool ssl_iostream_bio_output(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen size_t bytes, max_bytes;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssize_t sent;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen unsigned char buffer[1024];
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen bool bytes_sent = FALSE;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int ret;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen while ((bytes = BIO_ctrl_pending(ssl_io->bio_ext)) > 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen max_bytes = o_stream_get_buffer_avail_size(ssl_io->plain_output);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (bytes > max_bytes) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (max_bytes == 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen /* wait until output buffer clears */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen break;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen bytes = max_bytes;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (bytes > sizeof(buffer))
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen bytes = sizeof(buffer);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = BIO_read(ssl_io->bio_ext, buffer, bytes);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_assert(ret == (int)bytes);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen sent = o_stream_send(ssl_io->plain_output, buffer, bytes);
148a8396be2c1cf7d2aaa55566f7f7dea05388ddTimo Sirainen if (sent < 0) {
148a8396be2c1cf7d2aaa55566f7f7dea05388ddTimo Sirainen i_assert(ssl_io->plain_output->stream_errno != 0);
148a8396be2c1cf7d2aaa55566f7f7dea05388ddTimo Sirainen ssl_io->ssl_output->stream_errno =
148a8396be2c1cf7d2aaa55566f7f7dea05388ddTimo Sirainen ssl_io->plain_output->stream_errno;
148a8396be2c1cf7d2aaa55566f7f7dea05388ddTimo Sirainen break;
148a8396be2c1cf7d2aaa55566f7f7dea05388ddTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_assert(sent == (ssize_t)bytes);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen bytes_sent = TRUE;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return bytes_sent;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic bool ssl_iostream_bio_input(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen const unsigned char *data;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen size_t size;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen bool bytes_read = FALSE;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int ret;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen while (BIO_ctrl_get_read_request(ssl_io->bio_ext) > 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen (void)i_stream_read_data(ssl_io->plain_input, &data, &size, 0);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (size == 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen /* wait for more input */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen break;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = BIO_write(ssl_io->bio_ext, data, size);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_assert(ret == (ssize_t)size);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_stream_skip(ssl_io->plain_input, size);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen bytes_read = TRUE;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return bytes_read;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenbool ssl_iostream_bio_sync(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen bool ret;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = ssl_iostream_bio_output(ssl_io);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_iostream_bio_input(ssl_io))
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = TRUE;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return ret;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenint ssl_iostream_handle_error(struct ssl_iostream *ssl_io, int ret,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen const char *func_name)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen const char *errstr = NULL;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int err;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen err = SSL_get_error(ssl_io->ssl, ret);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen switch (err) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen case SSL_ERROR_WANT_WRITE:
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (!ssl_iostream_bio_sync(ssl_io))
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen case SSL_ERROR_WANT_READ:
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (!ssl_iostream_bio_sync(ssl_io))
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen case SSL_ERROR_SYSCALL:
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen /* eat up the error queue */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ERR_peek_error() != 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errstr = ssl_iostream_error();
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errno = EINVAL;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen } else if (ret != 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errstr = strerror(errno);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen } else {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen /* EOF. */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errno = ECONNRESET;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errstr = "Disconnected";
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen break;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errstr = t_strdup_printf("%s syscall failed: %s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen func_name, errstr);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen break;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen case SSL_ERROR_ZERO_RETURN:
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen /* clean connection closing */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errno = ECONNRESET;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen break;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen case SSL_ERROR_SSL:
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errstr = t_strdup_printf("%s failed: %s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen func_name, ssl_iostream_error());
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errno = EINVAL;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen break;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen default:
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errstr = t_strdup_printf("%s failed: unknown failure %d (%s)",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen func_name, err, ssl_iostream_error());
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errno = EINVAL;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen break;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (errstr != NULL) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_free(ssl_io->last_error);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->last_error = i_strdup(errstr);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenint ssl_iostream_handshake(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int ret;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_assert(!ssl_io->handshaked);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_io->ctx->client_ctx) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen while ((ret = SSL_connect(ssl_io->ssl)) <= 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = ssl_iostream_handle_error(ssl_io, ret,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen "SSL_connect()");
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ret <= 0)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return ret;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen } else {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen while ((ret = SSL_accept(ssl_io->ssl)) <= 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ret = ssl_iostream_handle_error(ssl_io, ret,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen "SSL_accept()");
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ret <= 0)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return ret;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen (void)ssl_iostream_bio_sync(ssl_io);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen i_free_and_null(ssl_io->last_error);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->handshaked = TRUE;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_io->handshake_callback != NULL) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_io->handshake_callback(ssl_io->handshake_context) < 0) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen errno = EINVAL;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return -1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (ssl_io->ssl_output != NULL)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen (void)o_stream_flush(ssl_io->ssl_output);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return 1;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenvoid ssl_iostream_set_handshake_callback(struct ssl_iostream *ssl_io,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int (*callback)(void *context),
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen void *context)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->handshake_callback = callback;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->handshake_context = context;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenbool ssl_iostream_is_handshaked(const struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return ssl_io->handshaked;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenbool ssl_iostream_has_valid_client_cert(const struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return ssl_io->cert_received && !ssl_io->cert_broken;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenbool ssl_iostream_has_broken_client_cert(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return ssl_io->cert_received && ssl_io->cert_broken;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenconst char *ssl_iostream_get_peer_name(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen X509 *x509;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen char *name;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int len;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (!ssl_iostream_has_valid_client_cert(ssl_io))
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return NULL;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen x509 = SSL_get_peer_certificate(ssl_io->ssl);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (x509 == NULL)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return NULL; /* we should have had it.. */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen len = X509_NAME_get_text_by_NID(X509_get_subject_name(x509),
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->username_nid, NULL, 0);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (len < 0)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen name = "";
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen else {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen name = t_malloc(len + 1);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (X509_NAME_get_text_by_NID(X509_get_subject_name(x509),
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->username_nid,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen name, len + 1) < 0)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen name = "";
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen else if (strlen(name) != (size_t)len) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen /* NUL characters in name. Someone's trying to fake
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen being another user? Don't allow it. */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen name = "";
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen }
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen X509_free(x509);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return *name == '\0' ? NULL : name;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenconst char *ssl_iostream_get_security_string(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
68a8f0794a1c2c2267ae4015ef3ccc00604e9175Timo Sirainen const SSL_CIPHER *cipher;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#ifdef HAVE_SSL_COMPRESSION
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen const COMP_METHOD *comp;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#endif
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen const char *comp_str;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen int bits, alg_bits;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if (!ssl_io->handshaked)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return "";
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen cipher = SSL_get_current_cipher(ssl_io->ssl);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#ifdef HAVE_SSL_COMPRESSION
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen comp = SSL_get_current_compression(ssl_io->ssl);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen comp_str = comp == NULL ? "" :
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen t_strconcat(" ", SSL_COMP_get_name(comp), NULL);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#else
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen comp_str = "";
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen#endif
8f2444f788368b08edb4ac037d5f7e5919cdee0aTimo Sirainen return t_strdup_printf("%s with cipher %s (%d/%d bits)%s",
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_get_version(ssl_io->ssl),
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen SSL_CIPHER_get_name(cipher),
8f2444f788368b08edb4ac037d5f7e5919cdee0aTimo Sirainen bits, alg_bits, comp_str);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenconst char *ssl_iostream_get_last_error(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen{
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen return ssl_io->last_error;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen}