From 2524aa23a092893259545d19b9e46d4d0d673061 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Wed, 28 Jan 2015 16:07:50 +0100 Subject: [PATCH] SSL utils: Added helper functions for managing OpenSSL servers and clients. The module provides session management for OpenSSL servers and clients and helper functions for I/O operations. --- configure.ac | 7 + src/Makefile.am | 11 +- src/include/utils/ssl.h | 153 ++++++++++++ src/utils/ssl.c | 516 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 683 insertions(+), 4 deletions(-) create mode 100644 src/include/utils/ssl.h create mode 100644 src/utils/ssl.c diff --git a/configure.ac b/configure.ac index 325a733..a03b5ce 100644 --- a/configure.ac +++ b/configure.ac @@ -483,6 +483,12 @@ if test "x$have_fopencookie" = "xyes"; then AC_DEFINE([HAVE_FOPENCOOKIE], 1) fi +dnl OpenSSL support +PKG_CHECK_MODULES([OPENSSL], [openssl], [have_openssl="yes"], [have_openssl="no"]) +if test "x$have_openssl" != "xyes"; then + AC_MSG_ERROR([OpenSSL not found]) +fi + dnl readline support AC_ARG_WITH([readline], [AS_HELP_STRING([--with-readline], @@ -720,6 +726,7 @@ AC_MSG_RESULT() AC_MSG_RESULT([ Libraries:]) AC_MSG_RESULT([ libdbi: . . . . . . . . . . $with_libdbi]) AC_MSG_RESULT([ libedit: . . . . . . . . . $have_libedit]) +AC_MSG_RESULT([ libopenssl: . . . . . . . . $have_openssl]) AC_MSG_RESULT([ libreadline: . . . . . . . $have_libreadline]) AC_MSG_RESULT([ librrd: . . . . . . . . . . $have_librrd]) AC_MSG_RESULT() diff --git a/src/Makefile.am b/src/Makefile.am index 7cff3e8..6521e84 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,6 +39,7 @@ pkgutilsinclude_HEADERS = \ include/utils/llist.h \ include/utils/os.h \ include/utils/proto.h \ + include/utils/ssl.h \ include/utils/strbuf.h \ include/utils/unixsock.h @@ -95,14 +96,15 @@ libsysdb_la_SOURCES = \ utils/llist.c include/utils/llist.h \ utils/os.c include/utils/os.h \ utils/proto.c include/utils/proto.h \ + utils/ssl.c include/utils/ssl.h \ utils/strbuf.c include/utils/strbuf.h \ utils/unixsock.c include/utils/unixsock.h -libsysdb_la_CFLAGS = $(AM_CFLAGS) +libsysdb_la_CFLAGS = $(AM_CFLAGS) @OPENSSL_CFLAGS@ libsysdb_la_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) libsysdb_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:0:0 \ -pthread -lm -lrt libsysdb_la_LIBADD = libsysdb_fe_parser.la \ - $(LIBLTDL) liboconfig/liboconfig.la + $(LIBLTDL) liboconfig/liboconfig.la @OPENSSL_LIBS@ libsysdb_la_DEPENDENCIES = libsysdb_fe_parser.la liboconfig/liboconfig.la if BUILD_WITH_LIBDBI @@ -134,11 +136,12 @@ endif sysdbd_SOURCES = tools/sysdbd/main.c include/sysdb.h \ tools/sysdbd/configfile.c tools/sysdbd/configfile.h \ $(libsysdb_la_SOURCES) -sysdbd_CFLAGS = $(AM_CFLAGS) -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" +sysdbd_CFLAGS = $(AM_CFLAGS) @OPENSSL_CFLAGS@ \ + -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" sysdbd_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) sysdbd_LDFLAGS = $(AM_LDFLAGS) -export-dynamic -pthread -lm sysdbd_LDADD = libsysdb_fe_parser.la liboconfig/liboconfig.la \ - $(LIBLTDL) -lrt + $(LIBLTDL) -lrt @OPENSSL_LIBS@ sysdbd_DEPENDENCIES = libsysdb_fe_parser.la liboconfig/liboconfig.la if BUILD_WITH_LIBDBI diff --git a/src/include/utils/ssl.h b/src/include/utils/ssl.h new file mode 100644 index 0000000..6489f8b --- /dev/null +++ b/src/include/utils/ssl.h @@ -0,0 +1,153 @@ +/* + * SysDB - src/include/utils/ssl.h + * Copyright (C) 2015 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SDB_UTILS_SSL_H +#define SDB_UTILS_SSL_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SDB_SSL_KEYFILE +# define SDB_SSL_KEYFILE SYSCONFDIR "/sysdb/ssl/key.pem" +#endif +#ifndef SDB_SSL_CERTFILE +# define SDB_SSL_CERTFILE SYSCONFDIR "/sysdb/ssl/cert.pem" +#endif +#ifndef SDB_SSL_CRLFILE +# define SDB_SSL_CRLFILE SYSCONFDIR "/sysdb/ssl/crl.pem" +#endif +#ifndef SDB_SSL_CAFILE +# define SDB_SSL_CAFILE SYSCONFDIR "/ssl/certs/ca-certificates.crt" +#endif + +typedef struct { + char *ca_file; + char *key_file; + char *cert_file; + char *crl_file; +} sdb_ssl_options_t; +#define SDB_SSL_DEFAULT_OPTIONS { \ + SDB_SSL_CAFILE, SDB_SSL_KEYFILE, SDB_SSL_CERTFILE, SDB_SSL_CRLFILE, \ +} + +struct sdb_ssl_client; +typedef struct sdb_ssl_client sdb_ssl_client_t; + +struct sdb_ssl_server; +typedef struct sdb_ssl_server sdb_ssl_server_t; + +struct sdb_ssl_session; +typedef struct sdb_ssl_session sdb_ssl_session_t; + +/* + * sdb_ssl_client_create: + * Allocate and initialize a TLS/SSL client using the specified options. If no + * options are specified, default values will be used instead. + */ +sdb_ssl_client_t * +sdb_ssl_client_create(sdb_ssl_options_t *opts); + +/* + * sdb_ssl_client_destroy: + * Destroy a TLS/SSL client and free all of its memory. + */ +void +sdb_ssl_client_destroy(sdb_ssl_client_t *client); + +/* + * sdb_ssl_client_connect: + * Initialize a TLS/SSL session on the specified socket. + */ +sdb_ssl_session_t * +sdb_ssl_client_connect(sdb_ssl_client_t *client, int fd); + +/* + * sdb_ssl_server_create: + * Allocate and initialize a TLS/SSL server using the specified options. If no + * options are specified, default values will be used instead. + */ +sdb_ssl_server_t * +sdb_ssl_server_create(sdb_ssl_options_t *opts); + +/* + * sdb_ssl_server_destroy: + * Destroy a TLS/SSL server and free all of its memory. + */ +void +sdb_ssl_server_destroy(sdb_ssl_server_t *server); + +/* + * sdb_ssl_server_accept: + * Initialize a TLS/SSL session on the specified socket. + */ +sdb_ssl_session_t * +sdb_ssl_server_accept(sdb_ssl_server_t *server, int fd); + +/* + * sdb_ssl_session_destroy: + * Shutdown and destroy a TLS/SSL session. + */ +void +sdb_ssl_session_destroy(sdb_ssl_session_t *session); + +/* + * sdb_ssl_session_peer: + * Return the name of the peer of a TLS/SSL session. + * + * Returns: + * - a dynamically allocated string on success + * - NULL else + */ +char * +sdb_ssl_session_peer(sdb_ssl_session_t *session); + +/* + * sdb_ssl_session_write: + * Write a message to an open TLS/SSL session. + */ +ssize_t +sdb_ssl_session_write(sdb_ssl_session_t *session, const void *buf, size_t n); + +/* + * sdb_ssl_session_read: + * Read from an open TLS/SSL session. + */ +ssize_t +sdb_ssl_session_read(sdb_ssl_session_t *session, void *buf, size_t n); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SDB_UTILS_SSL_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/utils/ssl.c b/src/utils/ssl.c new file mode 100644 index 0000000..477d16c --- /dev/null +++ b/src/utils/ssl.c @@ -0,0 +1,516 @@ +/* + * SysDB - src/utils/ssl.c + * Copyright (C) 2015 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "utils/ssl.h" +#include "utils/error.h" + +#include + +#include +#include + +#include +#include +#include +#include + +/* + * data types + */ + +struct sdb_ssl_client { + SSL_CTX *ctx; + sdb_ssl_options_t opts; +}; + +struct sdb_ssl_server { + SSL_CTX *ctx; + sdb_ssl_options_t opts; +}; + +struct sdb_ssl_session { + SSL *ssl; +}; + +/* + * private helper functions + */ + +/* log all pending SSL errors */ +static void +ssl_log(int prio, const char *prefix, ...) +{ + char msg[1024]; + va_list ap; + + va_start(ap, prefix); + vsnprintf(msg, sizeof(msg), prefix, ap); + msg[sizeof(msg) - 1] = '\0'; + va_end(ap); + + while (42) { + unsigned long e = ERR_get_error(); + if (! e) + break; + sdb_log(prio, "%s: %s", msg, ERR_reason_error_string(e)); + } +} /* ssl_log */ + +static void +ssl_log_err(int prio, SSL *ssl, int status, const char *prefix, ...) +{ + int err = SSL_get_error(ssl, status); + char msg[1024]; + va_list ap; + + va_start(ap, prefix); + vsnprintf(msg, sizeof(msg), prefix, ap); + msg[sizeof(msg) - 1] = '\0'; + va_end(ap); + + errno = 0; + switch (err) { + case SSL_ERROR_NONE: + sdb_log(prio, "%s: success", msg); + break; + case SSL_ERROR_ZERO_RETURN: + errno = ECONNRESET; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + errno = EWOULDBLOCK; + break; + case SSL_ERROR_WANT_CONNECT: + case SSL_ERROR_WANT_ACCEPT: + sdb_log(prio, "%s: connection not set up", msg); + break; + case SSL_ERROR_WANT_X509_LOOKUP: + sdb_log(prio, "%s: application error", msg); + break; + case SSL_ERROR_SYSCALL: + if (ERR_peek_error()) + return ssl_log(prio, msg); + if (! status) + sdb_log(prio, "%s: unexpected end-of-file", msg); + else if (! errno) + errno = EIO; + case SSL_ERROR_SSL: + return ssl_log(prio, msg); + default: + sdb_log(prio, "%s: unkown SSL error %d", msg, err); + break; + } + + if (errno) { + char errbuf[1024]; + sdb_log(prio, "%s: %s", msg, + sdb_strerror(errno, errbuf, sizeof(errbuf))); + } +} /* ssl_log_err */ + +static int +copy_options(sdb_ssl_options_t *dst, sdb_ssl_options_t *src) +{ + sdb_ssl_options_t def = SDB_SSL_DEFAULT_OPTIONS; + + if (! src) + src = &def; + + if (! src->ca_file) + src->ca_file = def.ca_file; + if (! src->key_file) + src->key_file = def.key_file; + if (! src->cert_file) + src->cert_file = def.cert_file; + + dst->ca_file = strdup(src->ca_file); + dst->key_file = strdup(src->key_file); + dst->cert_file = strdup(src->cert_file); + if ((! dst->ca_file) || (! dst->key_file) || (! dst->cert_file)) + return -1; + if (src->crl_file) { + dst->crl_file = strdup(src->crl_file); + if (! dst->crl_file) + return -1; + } + return 0; +} /* copy_options */ + +static void +free_options(sdb_ssl_options_t *opts) +{ + if (opts->ca_file) + free(opts->ca_file); + if (opts->key_file) + free(opts->key_file); + if (opts->cert_file) + free(opts->cert_file); + if (opts->crl_file) + free(opts->crl_file); +} /* free_options */ + +/* + * public API + */ + +sdb_ssl_client_t * +sdb_ssl_client_create(sdb_ssl_options_t *opts) +{ + sdb_ssl_client_t *client; + + client = calloc(1, sizeof(*client)); + if (! client) + return NULL; + + if (copy_options(&client->opts, opts)) { + sdb_ssl_client_destroy(client); + return NULL; + } + + client->ctx = SSL_CTX_new(SSLv23_client_method()); + if (! client->ctx) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to create SSL context"); + sdb_ssl_client_destroy(client); + return NULL; + } + + if (! SSL_CTX_load_verify_locations(client->ctx, + client->opts.ca_file, NULL)) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to load CA file"); + sdb_ssl_client_destroy(client); + return NULL; + } + if (! SSL_CTX_use_certificate_file(client->ctx, + client->opts.cert_file, SSL_FILETYPE_PEM)) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to load cert file '%s'", + client->opts.cert_file); + sdb_ssl_client_destroy(client); + return NULL; + } + if (! SSL_CTX_use_PrivateKey_file(client->ctx, + client->opts.key_file, SSL_FILETYPE_PEM)) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to load key file '%s'", + client->opts.key_file); + sdb_ssl_client_destroy(client); + return NULL; + } + if (! SSL_CTX_check_private_key(client->ctx)) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to verify key (%s)", + client->opts.key_file); + sdb_ssl_client_destroy(client); + return NULL; + } + + SSL_CTX_set_mode(client->ctx, SSL_MODE_AUTO_RETRY); + SSL_CTX_set_verify(client->ctx, SSL_VERIFY_PEER, NULL); + SSL_CTX_set_verify_depth(client->ctx, 1); + return client; +} /* sdb_ssl_client_create */ + +void +sdb_ssl_client_destroy(sdb_ssl_client_t *client) +{ + if (! client) + return; + + if (client->ctx) + SSL_CTX_free(client->ctx); + free_options(&client->opts); + free(client); +} /* sdb_ssl_client_destroy */ + +sdb_ssl_session_t * +sdb_ssl_client_connect(sdb_ssl_client_t *client, int fd) +{ + sdb_ssl_session_t *session; + int status; + BIO *bio; + + if ((! client) || (fd < 0)) + return NULL; + + session = calloc(1, sizeof(*session)); + if (! session) + return NULL; + + bio = BIO_new_socket(fd, BIO_NOCLOSE); + if (! bio) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to create SSL socket"); + sdb_ssl_session_destroy(session); + return NULL; + } + session->ssl = SSL_new(client->ctx); + if (! session->ssl) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to create SSL object"); + sdb_ssl_session_destroy(session); + return NULL; + } + SSL_set_bio(session->ssl, bio, bio); + + if ((status = SSL_connect(session->ssl)) <= 0) { + ssl_log_err(SDB_LOG_ERR, session->ssl, status, + "ssl: Failed to initialize SSL session"); + sdb_ssl_session_destroy(session); + return NULL; + } + if (SSL_get_verify_result(session->ssl) != X509_V_OK) { + sdb_log(SDB_LOG_ERR, "Failed to verify SSL connection"); + sdb_ssl_session_destroy(session); + return NULL; + } + return session; +} /* sdb_ssl_client_connect */ + +sdb_ssl_server_t * +sdb_ssl_server_create(sdb_ssl_options_t *opts) +{ + sdb_ssl_server_t *server; + + server = calloc(1, sizeof(*server)); + if (! server) + return NULL; + + if (copy_options(&server->opts, opts)) { + sdb_ssl_server_destroy(server); + return NULL; + } + + server->ctx = SSL_CTX_new(SSLv23_server_method()); + if (! server->ctx) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to create SSL context"); + sdb_ssl_server_destroy(server); + return NULL; + } + + /* Recommendation documented at + * https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ */ + if (! SSL_CTX_set_cipher_list(server->ctx, + "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:" + "DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:" + "!aNULL:!MD5:!DSS")) { + sdb_log(SDB_LOG_ERR, "ssl: Invalid cipher list"); + sdb_ssl_server_destroy(server); + return NULL; + } + + if (! SSL_CTX_load_verify_locations(server->ctx, + server->opts.ca_file, NULL)) { + ssl_log(SDB_LOG_ERR, "Failed to load CA file %s", + server->opts.ca_file); + return NULL; + } + SSL_CTX_set_client_CA_list(server->ctx, + SSL_load_client_CA_file(server->opts.ca_file)); + + if (! SSL_CTX_use_certificate_file(server->ctx, + server->opts.cert_file, SSL_FILETYPE_PEM)) { + ssl_log(SDB_LOG_ERR, "Failed to load SSL cert file %s", + server->opts.cert_file); + return NULL; + } + if (! SSL_CTX_use_PrivateKey_file(server->ctx, + server->opts.key_file, SSL_FILETYPE_PEM)) { + ssl_log(SDB_LOG_ERR, "Failed to load SSL key file %s", + server->opts.key_file); + return NULL; + } + if (! SSL_CTX_check_private_key(server->ctx)) { + ssl_log(SDB_LOG_ERR, "Failed to verify SSL private key"); + return NULL; + } + + SSL_CTX_set_mode(server->ctx, SSL_MODE_AUTO_RETRY); + SSL_CTX_set_verify(server->ctx, + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + SSL_CTX_set_verify_depth(server->ctx, 1); + + /* TODO: handle server->opts.crl_file */ + return server; +} /* sdb_ssl_server_create */ + +void +sdb_ssl_server_destroy(sdb_ssl_server_t *server) +{ + if (! server) + return; + + if (server->ctx) + SSL_CTX_free(server->ctx); + free_options(&server->opts); + free(server); +} /* sdb_ssl_server_destroy */ + +sdb_ssl_session_t * +sdb_ssl_server_accept(sdb_ssl_server_t *server, int fd) +{ + sdb_ssl_session_t *session; + int status; + BIO *bio; + + if ((! server) || (fd < 0)) + return NULL; + + session = calloc(1, sizeof(*session)); + if (! session) + return NULL; + + bio = BIO_new_socket(fd, BIO_NOCLOSE); + if (! bio) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to create SSL socket"); + sdb_ssl_session_destroy(session); + return NULL; + } + session->ssl = SSL_new(server->ctx); + if (! session->ssl) { + ssl_log(SDB_LOG_ERR, "ssl: Failed to create SSL object"); + sdb_ssl_session_destroy(session); + return NULL; + } + SSL_set_bio(session->ssl, bio, bio); + + while (42) { + if ((status = SSL_accept(session->ssl)) <= 0) { + if (SSL_get_error(session->ssl, status) == SSL_ERROR_WANT_READ) + continue; + + ssl_log_err(SDB_LOG_ERR, session->ssl, status, + "ssl: Failed to initialize SSL session"); + sdb_ssl_session_destroy(session); + return NULL; + } + break; + } + if (SSL_get_verify_result(session->ssl) != X509_V_OK) { + sdb_log(SDB_LOG_ERR, "Failed to verify SSL connection"); + sdb_ssl_session_destroy(session); + return NULL; + } + return session; +} /* sdb_ssl_server_accept */ + +void +sdb_ssl_session_destroy(sdb_ssl_session_t *session) +{ + if (! session) + return; + + if (session->ssl) { + SSL_shutdown(session->ssl); + SSL_clear(session->ssl); + SSL_free(session->ssl); + } + free(session); +} /* sdb_ssl_session_destroy */ + +char * +sdb_ssl_session_peer(sdb_ssl_session_t *session) +{ + X509 *x509; + X509_NAME *name; + + char *peer = NULL; + char p[1024]; + + if (! session) + return NULL; + + x509 = SSL_get_peer_certificate(session->ssl); + if (! x509) + return NULL; + name = X509_get_subject_name(x509); + if (! name) { + X509_free(x509); + return NULL; + } + + if (X509_NAME_get_text_by_NID(name, NID_commonName, p, sizeof(p)) > 0) + peer = strdup(p); + + X509_free(x509); + return peer; +} /* sdb_ssl_session_peer */ + +ssize_t +sdb_ssl_session_write(sdb_ssl_session_t *session, const void *buf, size_t n) +{ + int status; + + if (! session) + return -1; + + status = SSL_write(session->ssl, buf, (int)n); + if (status) { + if ((status < 0) && (errno != EAGAIN)) + ssl_log_err(SDB_LOG_ERR, session->ssl, status, "ssl: Write error"); + return (ssize_t)status; + } + + status = SSL_get_error(session->ssl, status); + if (status == SSL_ERROR_ZERO_RETURN) + return 0; + + if ((status == SSL_ERROR_WANT_READ) || (status == SSL_ERROR_WANT_WRITE)) { + errno = EWOULDBLOCK; + return -1; + } + errno = ECONNRESET; + return -1; +} /* sdb_ssl_session_write */ + +ssize_t +sdb_ssl_session_read(sdb_ssl_session_t *session, void *buf, size_t n) +{ + int status; + + if (! session) + return -1; + + status = SSL_read(session->ssl, buf, (int)n); + if (status) { + if ((status < 0) && (errno != EAGAIN)) + ssl_log_err(SDB_LOG_ERR, session->ssl, status, "ssl: Read error"); + return (ssize_t)status; + } + + status = SSL_get_error(session->ssl, status); + if (status == SSL_ERROR_ZERO_RETURN) + return 0; + + if ((status == SSL_ERROR_WANT_READ) || (status == SSL_ERROR_WANT_WRITE)) { + errno = EWOULDBLOCK; + return -1; + } + errno = ECONNRESET; + return -1; +} /* sdb_ssl_session_read */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + -- 2.30.2