From 173e563d3fcd87a03a65a9444d284d71a121e5b4 Mon Sep 17 00:00:00 2001 From: Michael Steinert Date: Mon, 3 Dec 2012 12:53:53 -0700 Subject: Start addressing review comments Signed-off-by: Michael Steinert --- Makefile.am | 14 +- examples/amqp_bind.c | 2 +- examples/amqp_consumer.c | 2 +- examples/amqp_exchange_declare.c | 2 +- examples/amqp_listen.c | 2 +- examples/amqp_listenq.c | 2 +- examples/amqp_producer.c | 2 +- examples/amqp_rpc_sendstring_client.c | 2 +- examples/amqp_sendstring.c | 2 +- examples/amqp_unbind.c | 2 +- examples/amqps_bind.c | 2 +- examples/amqps_consumer.c | 2 +- examples/amqps_exchange_declare.c | 2 +- examples/amqps_listen.c | 2 +- examples/amqps_listenq.c | 2 +- examples/amqps_producer.c | 2 +- examples/amqps_sendstring.c | 2 +- examples/amqps_unbind.c | 2 +- librabbitmq/CMakeLists.txt | 10 +- librabbitmq/amqp-cyassl.c | 225 -------------- librabbitmq/amqp-gnutls.c | 312 ------------------- librabbitmq/amqp-openssl.c | 556 ---------------------------------- librabbitmq/amqp-polarssl.c | 305 ------------------- librabbitmq/amqp-socket.h | 65 ---- librabbitmq/amqp-ssl-socket.h | 134 -------- librabbitmq/amqp-tcp-socket.c | 125 -------- librabbitmq/amqp-tcp-socket.h | 55 ---- librabbitmq/amqp_connection.c | 2 +- librabbitmq/amqp_cyassl.c | 225 ++++++++++++++ librabbitmq/amqp_gnutls.c | 312 +++++++++++++++++++ librabbitmq/amqp_openssl.c | 556 ++++++++++++++++++++++++++++++++++ librabbitmq/amqp_polarssl.c | 305 +++++++++++++++++++ librabbitmq/amqp_private.h | 2 +- librabbitmq/amqp_socket.h | 65 ++++ librabbitmq/amqp_ssl_socket.h | 138 +++++++++ librabbitmq/amqp_tcp_socket.c | 125 ++++++++ librabbitmq/amqp_tcp_socket.h | 55 ++++ tools/common.c | 4 +- 38 files changed, 1814 insertions(+), 1810 deletions(-) delete mode 100644 librabbitmq/amqp-cyassl.c delete mode 100644 librabbitmq/amqp-gnutls.c delete mode 100644 librabbitmq/amqp-openssl.c delete mode 100644 librabbitmq/amqp-polarssl.c delete mode 100644 librabbitmq/amqp-socket.h delete mode 100644 librabbitmq/amqp-ssl-socket.h delete mode 100644 librabbitmq/amqp-tcp-socket.c delete mode 100644 librabbitmq/amqp-tcp-socket.h create mode 100644 librabbitmq/amqp_cyassl.c create mode 100644 librabbitmq/amqp_gnutls.c create mode 100644 librabbitmq/amqp_openssl.c create mode 100644 librabbitmq/amqp_polarssl.c create mode 100644 librabbitmq/amqp_socket.h create mode 100644 librabbitmq/amqp_ssl_socket.h create mode 100644 librabbitmq/amqp_tcp_socket.c create mode 100644 librabbitmq/amqp_tcp_socket.h diff --git a/Makefile.am b/Makefile.am index 92c35b9..3201f7d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,7 +13,7 @@ lib_LTLIBRARIES = librabbitmq/librabbitmq.la librabbitmq_librabbitmq_la_SOURCES = \ librabbitmq/amqp-socket.h \ - librabbitmq/amqp-tcp-socket.c \ + librabbitmq/amqp_tcp_socket.c \ librabbitmq/amqp_api.c \ librabbitmq/amqp_connection.c \ librabbitmq/amqp_mem.c \ @@ -29,19 +29,19 @@ librabbitmq_librabbitmq_la_SOURCES += librabbitmq/amqp_framing.c endif if SSL_CYASSL -librabbitmq_librabbitmq_la_SOURCES += librabbitmq/amqp-cyassl.c +librabbitmq_librabbitmq_la_SOURCES += librabbitmq/amqp_cyassl.c endif if SSL_GNUTLS -librabbitmq_librabbitmq_la_SOURCES += librabbitmq/amqp-gnutls.c +librabbitmq_librabbitmq_la_SOURCES += librabbitmq/amqp_gnutls.c endif if SSL_OPENSSL -librabbitmq_librabbitmq_la_SOURCES += librabbitmq/amqp-openssl.c +librabbitmq_librabbitmq_la_SOURCES += librabbitmq/amqp_openssl.c endif if SSL_POLARSSL -librabbitmq_librabbitmq_la_SOURCES += librabbitmq/amqp-polarssl.c +librabbitmq_librabbitmq_la_SOURCES += librabbitmq/amqp_polarssl.c endif librabbitmq_librabbitmq_la_CFLAGS = \ @@ -71,10 +71,10 @@ endif include_HEADERS = \ $(top_srcdir)/librabbitmq/amqp.h - $(top_builddir)/librabbitmq/amqp-tcp-socket.h \ + $(top_builddir)/librabbitmq/amqp_tcp_socket.h if SSL -include_HEADERS += librabbitmq/amqp-ssl-socket.h +include_HEADERS += librabbitmq/amqp_ssl_socket.h endif if REGENERATE_AMQP_FRAMING diff --git a/examples/amqp_bind.c b/examples/amqp_bind.c index 1bc82f9..765e746 100644 --- a/examples/amqp_bind.c +++ b/examples/amqp_bind.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqp_consumer.c b/examples/amqp_consumer.c index ea97428..72bf654 100644 --- a/examples/amqp_consumer.c +++ b/examples/amqp_consumer.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqp_exchange_declare.c b/examples/amqp_exchange_declare.c index 091ce30..55860e5 100644 --- a/examples/amqp_exchange_declare.c +++ b/examples/amqp_exchange_declare.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqp_listen.c b/examples/amqp_listen.c index 3ad9fdd..9385c17 100644 --- a/examples/amqp_listen.c +++ b/examples/amqp_listen.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqp_listenq.c b/examples/amqp_listenq.c index 08f3d2a..54c1189 100644 --- a/examples/amqp_listenq.c +++ b/examples/amqp_listenq.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqp_producer.c b/examples/amqp_producer.c index aa86e63..efa1a20 100644 --- a/examples/amqp_producer.c +++ b/examples/amqp_producer.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqp_rpc_sendstring_client.c b/examples/amqp_rpc_sendstring_client.c index 0b187f6..6688195 100644 --- a/examples/amqp_rpc_sendstring_client.c +++ b/examples/amqp_rpc_sendstring_client.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqp_sendstring.c b/examples/amqp_sendstring.c index 0e624f9..0b64024 100644 --- a/examples/amqp_sendstring.c +++ b/examples/amqp_sendstring.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqp_unbind.c b/examples/amqp_unbind.c index cc42d1a..7948d0b 100644 --- a/examples/amqp_unbind.c +++ b/examples/amqp_unbind.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqps_bind.c b/examples/amqps_bind.c index 050be73..1a9328d 100644 --- a/examples/amqps_bind.c +++ b/examples/amqps_bind.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include "utils.h" diff --git a/examples/amqps_consumer.c b/examples/amqps_consumer.c index cccbe33..5832421 100644 --- a/examples/amqps_consumer.c +++ b/examples/amqps_consumer.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqps_exchange_declare.c b/examples/amqps_exchange_declare.c index bcf30b1..ed46348 100644 --- a/examples/amqps_exchange_declare.c +++ b/examples/amqps_exchange_declare.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include "utils.h" diff --git a/examples/amqps_listen.c b/examples/amqps_listen.c index 25f8371..8d99066 100644 --- a/examples/amqps_listen.c +++ b/examples/amqps_listen.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqps_listenq.c b/examples/amqps_listenq.c index 2bb1760..74aa813 100644 --- a/examples/amqps_listenq.c +++ b/examples/amqps_listenq.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include diff --git a/examples/amqps_producer.c b/examples/amqps_producer.c index 866f8f8..9cf32ab 100644 --- a/examples/amqps_producer.c +++ b/examples/amqps_producer.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include "utils.h" diff --git a/examples/amqps_sendstring.c b/examples/amqps_sendstring.c index c1f10df..d3a647e 100644 --- a/examples/amqps_sendstring.c +++ b/examples/amqps_sendstring.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include "utils.h" diff --git a/examples/amqps_unbind.c b/examples/amqps_unbind.c index 58a6730..53c6088 100644 --- a/examples/amqps_unbind.c +++ b/examples/amqps_unbind.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include "utils.h" diff --git a/librabbitmq/CMakeLists.txt b/librabbitmq/CMakeLists.txt index 3a42a19..52e2682 100644 --- a/librabbitmq/CMakeLists.txt +++ b/librabbitmq/CMakeLists.txt @@ -80,23 +80,23 @@ if (ENABLE_SSL_SUPPORT) add_definitions(-DWITH_SSL=1) if (SSL_ENGINE STREQUAL "OpenSSL") - set(AMQP_SSL_SRCS amqp-ssl-socket.h amqp-openssl.c) + set(AMQP_SSL_SRCS amqp_ssl_socket.h amqp_openssl.c) include_directories(${OPENSSL_INCLUDE_DIR}) set(AMQP_SSL_LIBS ${OPENSSL_LIBRARIES}) elseif (SSL_ENGINE STREQUAL "cyaSSL") - set(AMQP_SSL_SRCS amqp-ssl-socket.h amqp-cyassl.c) + set(AMQP_SSL_SRCS amqp_ssl_socket.h amqp_cyassl.c) include_directories(${CYASSL_INCLUDE_DIR}) set(AMQP_SSL_LIBS ${CYASSL_LIBRARIES}) elseif (SSL_ENGINE STREQUAL "GnuTLS") - set(AMQP_SSL_SRCS amqp-ssl-socket.h amqp-gnutls.c) + set(AMQP_SSL_SRCS amqp_ssl_socket.h amqp_gnutls.c) include_directories(${GNUTLS_INCLUDE_DIR}) add_definitions(${GNUTLS_DEFINITIONS}) set(AMQP_SSL_LIBS ${GNUTLS_LIBRARIES}) elseif (SSL_ENGINE STREQUAL "PolarSSL") - set(AMQP_SSL_SRCS amqp-ssl-socket.h amqp-polarssl.c) + set(AMQP_SSL_SRCS amqp_ssl_socket.h amqp_polarssl.c) include_directories(${POLARSSL_INCLUDE_DIR}) set(AMQP_SSL_LIBS ${POLARSSL_LIBRARIES}) @@ -118,7 +118,7 @@ set(RABBITMQ_SOURCES ${AMQP_FRAMING_H_PATH} ${AMQP_FRAMING_C_PATH} amqp_api.c amqp.h amqp_connection.c amqp_mem.c amqp_private.h amqp_socket.c - amqp_table.c amqp_url.c amqp-socket.h amqp-tcp-socket.c amqp-tcp-socket.h + amqp_table.c amqp_url.c amqp_socket.h amqp_tcp_socket.c amqp_tcp_socket.h ${SOCKET_IMPL}/socket.h ${SOCKET_IMPL}/socket.c ${AMQP_SSL_SRCS} ) diff --git a/librabbitmq/amqp-cyassl.c b/librabbitmq/amqp-cyassl.c deleted file mode 100644 index f3ee909..0000000 --- a/librabbitmq/amqp-cyassl.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2012 Michael Steinert - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "amqp-ssl-socket.h" -#include "amqp_private.h" -#include -#include - -struct amqp_ssl_socket_t { - CYASSL_CTX *ctx; - CYASSL *ssl; - int sockfd; - char *buffer; - size_t length; -}; - -static ssize_t -amqp_ssl_socket_send(void *base, - const void *buf, - size_t len, - AMQP_UNUSED int flags) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return CyaSSL_write(self->ssl, buf, len); -} - -static ssize_t -amqp_ssl_socket_writev(void *base, - const struct iovec *iov, - int iovcnt) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - ssize_t written = -1; - char *bufferp; - size_t bytes; - int i; - bytes = 0; - for (i = 0; i < iovcnt; ++i) { - bytes += iov[i].iov_len; - } - if (self->length < bytes) { - free(self->buffer); - self->buffer = malloc(bytes); - if (!self->buffer) { - self->length = 0; - goto exit; - } - self->length = bytes; - } - bufferp = self->buffer; - for (i = 0; i < iovcnt; ++i) { - memcpy(bufferp, iov[i].iov_base, iov[i].iov_len); - bufferp += iov[i].iov_len; - } - written = CyaSSL_write(self->ssl, self->buffer, bytes); -exit: - return written; -} - -static ssize_t -amqp_ssl_socket_recv(void *base, - void *buf, - size_t len, - AMQP_UNUSED int flags) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return CyaSSL_read(self->ssl, buf, len); -} - -static int -amqp_ssl_socket_get_sockfd(void *base) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return self->sockfd; -} - -static int -amqp_ssl_socket_close(void *base) -{ - int status = -1; - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - if (self->sockfd >= 0) { - status = amqp_os_socket_close(self->sockfd); - } - if (self) { - CyaSSL_free(self->ssl); - CyaSSL_CTX_free(self->ctx); - free(self->buffer); - free(self); - } - return status; -} - -static int -amqp_ssl_socket_error(AMQP_UNUSED void *user_data) -{ - return -1; -} - -static int -amqp_ssl_socket_open(void *base, const char *host, int port) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - int status; - self->sockfd = amqp_open_socket(host, port); - if (0 > self->sockfd) { - return -1; - } - CyaSSL_set_fd(self->ssl, self->sockfd); - status = CyaSSL_connect(self->ssl); - if (SSL_SUCCESS != status) { - return -1; - } - return 0; -} - -static const struct amqp_socket_class_t amqp_ssl_socket_class = { - amqp_ssl_socket_writev, /* writev */ - amqp_ssl_socket_send, /* send */ - amqp_ssl_socket_recv, /* recv */ - amqp_ssl_socket_open, /* open */ - amqp_ssl_socket_close, /* close */ - amqp_ssl_socket_error, /* error */ - amqp_ssl_socket_get_sockfd /* get_sockfd */ -}; - -amqp_socket_t * -amqp_ssl_socket_new(void) -{ - struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self)); - if (!self) { - goto error; - } - CyaSSL_Init(); - self->ctx = CyaSSL_CTX_new(CyaSSLv23_client_method()); - if (!self->ctx) { - goto error; - } - return (amqp_socket_t *)self; -error: - amqp_socket_close((amqp_socket_t *)self); - return NULL; -} - -int -amqp_ssl_socket_set_cacert(amqp_socket_t *base, - const char *cacert) -{ - int status; - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - status = CyaSSL_CTX_load_verify_locations(self->ctx, cacert, NULL); - if (SSL_SUCCESS != status) { - return -1; - } - return 0; -} - -int -amqp_ssl_socket_set_key(amqp_socket_t *base, - const char *cert, - const char *key) -{ - int status; - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - status = CyaSSL_CTX_use_PrivateKey_file(self->ctx, key, - SSL_FILETYPE_PEM); - if (SSL_SUCCESS != status) { - return -1; - } - status = CyaSSL_CTX_use_certificate_chain_file(self->ctx, cert); - return 0; -} - -int -amqp_ssl_socket_set_key_buffer(AMQP_UNUSED amqp_socket_t *base, - AMQP_UNUSED const char *cert, - AMQP_UNUSED const void *key, - AMQP_UNUSED size_t n) -{ - amqp_abort("%s is not implemented for CyaSSL", __func__); - return -1; -} - -void -amqp_ssl_socket_set_verify(AMQP_UNUSED amqp_socket_t *base, - AMQP_UNUSED amqp_boolean_t verify) -{ - /* noop for CyaSSL */ -} - -void -amqp_set_initialize_ssl_library(AMQP_UNUSED amqp_boolean_t do_initialize) -{ -} diff --git a/librabbitmq/amqp-gnutls.c b/librabbitmq/amqp-gnutls.c deleted file mode 100644 index 66b3def..0000000 --- a/librabbitmq/amqp-gnutls.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright 2012 Michael Steinert - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "amqp-ssl-socket.h" -#include "amqp_private.h" -#include -#include -#include - -struct amqp_ssl_socket_t { - gnutls_session_t session; - gnutls_certificate_credentials_t credentials; - int sockfd; - char *host; - char *buffer; - size_t length; -}; - -static ssize_t -amqp_ssl_socket_send(void *base, - const void *buf, - size_t len, - AMQP_UNUSED int flags) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return gnutls_record_send(self->session, buf, len); -} - -static ssize_t -amqp_ssl_socket_writev(void *base, - const struct iovec *iov, - int iovcnt) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - ssize_t written = -1; - char *bufferp; - size_t bytes; - int i; - bytes = 0; - for (i = 0; i < iovcnt; ++i) { - bytes += iov[i].iov_len; - } - if (self->length < bytes) { - free(self->buffer); - self->buffer = malloc(bytes); - if (!self->buffer) { - self->length = 0; - goto exit; - } - self->length = 0; - } - bufferp = self->buffer; - for (i = 0; i < iovcnt; ++i) { - memcpy(bufferp, iov[i].iov_base, iov[i].iov_len); - bufferp += iov[i].iov_len; - } - written = gnutls_record_send(self->session, self->buffer, bytes); -exit: - return written; -} - -static ssize_t -amqp_ssl_socket_recv(void *base, - void *buf, - size_t len, - AMQP_UNUSED int flags) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return gnutls_record_recv(self->session, buf, len); -} - -static int -amqp_ssl_socket_open(void *base, const char *host, int port) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - int status; - self->sockfd = amqp_open_socket(host, port); - if (0 > self->sockfd) { - return -1; - } - gnutls_transport_set_ptr(self->session, - (gnutls_transport_ptr_t)self->sockfd); - do { - status = gnutls_handshake(self->session); - } while (status < 0 && !gnutls_error_is_fatal(status)); - return status; -} - -static int -amqp_ssl_socket_close(void *base) -{ - int status = -1; - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - if (self->sockfd >= 0) { - status = amqp_os_socket_close(self->sockfd); - } - if (self) { - gnutls_deinit(self->session); - gnutls_certificate_free_credentials(self->credentials); - free(self->host); - free(self->buffer); - free(self); - } - return status; -} - -static int -amqp_ssl_socket_error(AMQP_UNUSED void *user_data) -{ - return -1; -} - -static int -amqp_ssl_socket_get_sockfd(void *base) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return self->sockfd; -} - -static int -amqp_ssl_verify(gnutls_session_t session) -{ - int ret; - unsigned int status, size; - const gnutls_datum_t *list; - gnutls_x509_crt_t cert = NULL; - struct amqp_ssl_socket_t *self = gnutls_session_get_ptr(session); - ret = gnutls_certificate_verify_peers2(session, &status); - if (0 > ret) { - goto error; - } - if (status & GNUTLS_CERT_INVALID) { - goto error; - } - if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { - goto error; - } - if (status & GNUTLS_CERT_REVOKED) { - goto error; - } - if (status & GNUTLS_CERT_EXPIRED) { - goto error; - } - if (status & GNUTLS_CERT_NOT_ACTIVATED) { - goto error; - } - if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { - goto error; - } - if (gnutls_x509_crt_init(&cert) < 0) { - goto error; - } - list = gnutls_certificate_get_peers(session, &size); - if (!list) { - goto error; - } - ret = gnutls_x509_crt_import(cert, &list[0], GNUTLS_X509_FMT_DER); - if (0 > ret) { - goto error; - } - if (!gnutls_x509_crt_check_hostname(cert, self->host)) { - goto error; - } - gnutls_x509_crt_deinit(cert); - return 0; -error: - if (cert) { - gnutls_x509_crt_deinit (cert); - } - return GNUTLS_E_CERTIFICATE_ERROR; -} - -static const struct amqp_socket_class_t amqp_ssl_socket_class = { - amqp_ssl_socket_writev, /* writev */ - amqp_ssl_socket_send, /* send */ - amqp_ssl_socket_recv, /* recv */ - amqp_ssl_socket_open, /* open */ - amqp_ssl_socket_close, /* close */ - amqp_ssl_socket_error, /* error */ - amqp_ssl_socket_get_sockfd /* get_sockfd */ -}; - -amqp_socket_t * -amqp_ssl_socket_new(void) -{ - struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self)); - const char *error; - int status; - if (!self) { - goto error; - } - gnutls_global_init(); - status = gnutls_init(&self->session, GNUTLS_CLIENT); - if (GNUTLS_E_SUCCESS != status) { - goto error; - } - status = gnutls_certificate_allocate_credentials(&self->credentials); - if (GNUTLS_E_SUCCESS != status) { - goto error; - } - status = gnutls_credentials_set(self->session, GNUTLS_CRD_CERTIFICATE, - self->credentials); - if (GNUTLS_E_SUCCESS != status) { - goto error; - } - gnutls_session_set_ptr(self->session, self); - status = gnutls_priority_set_direct(self->session, "NORMAL", &error); - if (GNUTLS_E_SUCCESS != status) { - goto error; - } - return (amqp_socket_t *)self; -error: - amqp_socket_close((amqp_socket_t *)self); - return NULL; -} - -int -amqp_ssl_socket_set_cacert(amqp_socket_t *base, - const char *cacert) -{ - int status; - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - status = gnutls_certificate_set_x509_trust_file(self->credentials, - cacert, - GNUTLS_X509_FMT_PEM); - if (0 > status) { - return -1; - } - return 0; -} - -int -amqp_ssl_socket_set_key(amqp_socket_t *base, - const char *cert, - const char *key) -{ - int status; - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - status = gnutls_certificate_set_x509_key_file(self->credentials, - cert, - key, - GNUTLS_X509_FMT_PEM); - if (0 > status) { - return -1; - } - - return 0; -} - -int -amqp_ssl_socket_set_key_buffer(AMQP_UNUSED amqp_socket_t *base, - AMQP_UNUSED const char *cert, - AMQP_UNUSED const void *key, - AMQP_UNUSED size_t n) -{ - amqp_abort("%s is not implemented for GnuTLS", __func__); - return -1; -} - -void -amqp_ssl_socket_set_verify(amqp_socket_t *base, - amqp_boolean_t verify) -{ - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - if (verify) { - gnutls_certificate_set_verify_function(self->credentials, - amqp_ssl_verify); - } else { - gnutls_certificate_set_verify_function(self->credentials, - NULL); - } -} - -void -amqp_set_initialize_ssl_library(AMQP_UNUSED amqp_boolean_t do_initialize) -{ -} diff --git a/librabbitmq/amqp-openssl.c b/librabbitmq/amqp-openssl.c deleted file mode 100644 index 04be202..0000000 --- a/librabbitmq/amqp-openssl.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright 2012 Michael Steinert - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "amqp-ssl-socket.h" -#include "amqp_private.h" -#include "threads.h" -#include -#include -#include -#include -#include - -#include "socket.h" - -static int initialize_openssl(void); -static int destroy_openssl(void); - -static int open_ssl_connections = 0; -static amqp_boolean_t do_initialize_openssl = 1; -static amqp_boolean_t openssl_initialized = 0; - -#ifdef ENABLE_THREAD_SAFETY -static unsigned long amqp_ssl_threadid_callback(void); -static void amqp_ssl_locking_callback(int mode, int n, const char *file, int line); - -#ifdef _WIN32 -static long win32_create_mutex = 0; -static pthread_mutex_t openssl_init_mutex = NULL; -#else -static pthread_mutex_t openssl_init_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif -static pthread_mutex_t *amqp_openssl_lockarray = NULL; -#endif /* ENABLE_THREAD_SAFETY */ - -struct amqp_ssl_socket_t { - const struct amqp_socket_class_t *klass; - SSL_CTX *ctx; - int sockfd; - SSL *ssl; - char *buffer; - size_t length; - amqp_boolean_t verify; -}; - -static ssize_t -amqp_ssl_socket_send(void *base, - const void *buf, - size_t len, - AMQP_UNUSED int flags) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - ssize_t sent; - ERR_clear_error(); - sent = SSL_write(self->ssl, buf, len); - if (0 > sent) { - switch (SSL_get_error(self->ssl, sent)) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - sent = 0; - break; - } - } - return sent; -} - -static ssize_t -amqp_ssl_socket_writev(void *base, - const struct iovec *iov, - int iovcnt) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - ssize_t written = -1; - char *bufferp; - size_t bytes; - int i; - bytes = 0; - for (i = 0; i < iovcnt; ++i) { - bytes += iov[i].iov_len; - } - if (self->length < bytes) { - free(self->buffer); - self->buffer = malloc(bytes); - if (!self->buffer) { - self->length = 0; - goto exit; - } - self->length = bytes; - } - bufferp = self->buffer; - for (i = 0; i < iovcnt; ++i) { - memcpy(bufferp, iov[i].iov_base, iov[i].iov_len); - bufferp += iov[i].iov_len; - } - written = amqp_ssl_socket_send(self, self->buffer, bytes, 0); -exit: - return written; -} - -static ssize_t -amqp_ssl_socket_recv(void *base, - void *buf, - size_t len, - AMQP_UNUSED int flags) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - ssize_t received; - ERR_clear_error(); - received = SSL_read(self->ssl, buf, len); - if (0 > received) { - switch(SSL_get_error(self->ssl, received)) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - received = 0; - break; - } - } - return received; -} - -static int -amqp_ssl_socket_verify(void *base, const char *host) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - unsigned char *utf8_value = NULL, *cp, ch; - int pos, utf8_length, status = 0; - ASN1_STRING *entry_string; - X509_NAME_ENTRY *entry; - X509_NAME *name; - X509 *peer; - peer = SSL_get_peer_certificate(self->ssl); - if (!peer) { - goto error; - } - name = X509_get_subject_name(peer); - if (!name) { - goto error; - } - pos = X509_NAME_get_index_by_NID(name, NID_commonName, -1); - if (0 > pos) { - goto error; - } - entry = X509_NAME_get_entry(name, pos); - if (!entry) { - goto error; - } - entry_string = X509_NAME_ENTRY_get_data(entry); - if (!entry_string) { - goto error; - } - utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_string); - if (0 > utf8_length) { - goto error; - } - while (utf8_length > 0 && utf8_value[utf8_length - 1] == 0) { - --utf8_length; - } - if (utf8_length >= 256) { - goto error; - } - if ((size_t)utf8_length != strlen((char *)utf8_value)) { - goto error; - } - for (cp = utf8_value; (ch = *cp) != '\0'; ++cp) { - if (isascii(ch) && !isprint(ch)) { - goto error; - } - } -#ifdef _MSC_VER -#define strcasecmp _stricmp -#endif - if (strcasecmp(host, (char *)utf8_value)) { - goto error; - } -#ifdef _MSC_VER -#undef strcasecmp -#endif -exit: - OPENSSL_free(utf8_value); - return status; -error: - status = -1; - goto exit; -} - -static int -amqp_ssl_socket_open(void *base, const char *host, int port) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - long result; - int status; - self->ssl = SSL_new(self->ctx); - if (!self->ssl) { - return -1; - } - SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); - self->sockfd = amqp_open_socket(host, port); - if (0 > self->sockfd) { - return -1; - } - status = SSL_set_fd(self->ssl, self->sockfd); - if (!status) { - return -1; - } - status = SSL_connect(self->ssl); - if (!status) { - return -1; - } - result = SSL_get_verify_result(self->ssl); - if (X509_V_OK != result) { - return -1; - } - if (self->verify) { - int status = amqp_ssl_socket_verify(self, host); - if (status) { - return -1; - } - } - return 0; -} - -static int -amqp_ssl_socket_close(void *base) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - if (self) { - SSL_free(self->ssl); - amqp_os_socket_close(self->sockfd); - SSL_CTX_free(self->ctx); - free(self->buffer); - free(self); - } - destroy_openssl(); - return 0; -} - -static int -amqp_ssl_socket_error(AMQP_UNUSED void *base) -{ - return -1; -} - -static int -amqp_ssl_socket_get_sockfd(void *base) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return self->sockfd; -} - -static const struct amqp_socket_class_t amqp_ssl_socket_class = { - amqp_ssl_socket_writev, /* writev */ - amqp_ssl_socket_send, /* send */ - amqp_ssl_socket_recv, /* recv */ - amqp_ssl_socket_open, /* open */ - amqp_ssl_socket_close, /* close */ - amqp_ssl_socket_error, /* error */ - amqp_ssl_socket_get_sockfd /* get_sockfd */ -}; - -amqp_socket_t * -amqp_ssl_socket_new(void) -{ - struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self)); - int status; - if (!self) { - goto error; - } - status = initialize_openssl(); - if (status) { - goto error; - } - self->ctx = SSL_CTX_new(SSLv23_client_method()); - if (!self->ctx) { - goto error; - } - self->klass = &amqp_ssl_socket_class; - self->verify = 1; - return (amqp_socket_t *)self; -error: - amqp_socket_close((amqp_socket_t *)self); - return NULL; -} - -int -amqp_ssl_socket_set_cacert(amqp_socket_t *base, - const char *cacert) -{ - int status; - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - status = SSL_CTX_load_verify_locations(self->ctx, cacert, NULL); - if (1 != status) { - return -1; - } - return 0; -} - -int -amqp_ssl_socket_set_key(amqp_socket_t *base, - const char *cert, - const char *key) -{ - int status; - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - status = SSL_CTX_use_certificate_chain_file(self->ctx, cert); - if (1 != status) { - return -1; - } - status = SSL_CTX_use_PrivateKey_file(self->ctx, key, - SSL_FILETYPE_PEM); - if (1 != status) { - return -1; - } - return 0; -} - -static int -password_cb(AMQP_UNUSED char *buffer, - AMQP_UNUSED int length, - AMQP_UNUSED int rwflag, - AMQP_UNUSED void *user_data) -{ - amqp_abort("don't use password protected keys!"); - return 0; -} - -int -amqp_ssl_socket_set_key_buffer(amqp_socket_t *base, - const char *cert, - const void *key, - size_t n) -{ - int status = 0; - BIO *buf = NULL; - RSA *rsa = NULL; - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - status = SSL_CTX_use_certificate_chain_file(self->ctx, cert); - if (1 != status) { - return -1; - } - buf = BIO_new_mem_buf((void *)key, n); - if (!buf) { - goto error; - } - rsa = PEM_read_bio_RSAPrivateKey(buf, NULL, password_cb, NULL); - if (!rsa) { - goto error; - } - status = SSL_CTX_use_RSAPrivateKey(self->ctx, rsa); - if (1 != status) { - goto error; - } -exit: - BIO_vfree(buf); - RSA_free(rsa); - return status; -error: - status = -1; - goto exit; -} - -int -amqp_ssl_socket_set_cert(amqp_socket_t *base, - const char *cert) -{ - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - int status = SSL_CTX_use_certificate_chain_file(self->ctx, cert); - if (1 != status) { - return -1; - } - return 0; -} - -void -amqp_ssl_socket_set_verify(amqp_socket_t *base, - amqp_boolean_t verify) -{ - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - self->verify = verify; -} - -void -amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize) -{ - if (!openssl_initialized) { - do_initialize_openssl = do_initialize; - } -} - -#ifdef ENABLE_THREAD_SAFETY -unsigned long -amqp_ssl_threadid_callback(void) -{ - return (unsigned long)pthread_self(); -} - -void -amqp_ssl_locking_callback(int mode, int n, - AMQP_UNUSED const char *file, - AMQP_UNUSED int line) -{ - if (mode & CRYPTO_LOCK) - { - if (pthread_mutex_lock(&amqp_openssl_lockarray[n])) - amqp_abort("Runtime error: Failure in trying to lock OpenSSL mutex"); - } - else - { - if (pthread_mutex_unlock(&amqp_openssl_lockarray[n])) - amqp_abort("Runtime error: Failure in trying to unlock OpenSSL mutex"); - } -} -#endif /* ENABLE_THREAD_SAFETY */ - -static int -initialize_openssl(void) -{ -#ifdef _WIN32 - /* No such thing as PTHREAD_INITIALIZE_MUTEX macro on Win32, so we use this */ - if (NULL == openssl_init_mutex) - { - while (InterlockedExchange(&win32_create_mutex, 1) == 1) - /* Loop, someone else is holding this lock */ ; - - if (NULL == openssl_init_mutex) - { - if (pthread_mutex_init(&openssl_init_mutex, NULL)) - return -1; - } - InterlockedExchange(&win32_create_mutex, 0); - } -#endif /* _WIN32 */ - -#ifdef ENABLE_THREAD_SAFETY - if (pthread_mutex_lock(&openssl_init_mutex)) - return -1; -#endif /* ENABLE_THREAD_SAFETY */ - if (do_initialize_openssl) - { -#ifdef ENABLE_THREAD_SAFETY - if (NULL == amqp_openssl_lockarray) - { - int i = 0; - amqp_openssl_lockarray = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t)); - if (!amqp_openssl_lockarray) - { - pthread_mutex_unlock(&openssl_init_mutex); - return -1; - } - for (i = 0; i < CRYPTO_num_locks(); ++i) - { - if (pthread_mutex_init(&amqp_openssl_lockarray[i], NULL)) - { - free(amqp_openssl_lockarray); - amqp_openssl_lockarray = NULL; - pthread_mutex_unlock(&openssl_init_mutex); - return -1; - } - } - } - - if (0 == open_ssl_connections) - { - CRYPTO_set_id_callback(amqp_ssl_threadid_callback); - CRYPTO_set_locking_callback(amqp_ssl_locking_callback); - } -#endif /* ENABLE_THREAD_SAFETY */ - - if (!openssl_initialized) - { - OPENSSL_config(NULL); - - SSL_library_init(); - SSL_load_error_strings(); - - openssl_initialized = 1; - } - } - - ++open_ssl_connections; - -#ifdef ENABLE_THREAD_SAFETY - pthread_mutex_unlock(&openssl_init_mutex); -#endif /* ENABLE_THREAD_SAFETY */ - return 0; -} - -static int -destroy_openssl(void) -{ -#ifdef ENABLE_THREAD_SAFETY - if (pthread_mutex_lock(&openssl_init_mutex)) - return -1; -#endif /* ENABLE_THREAD_SAFETY */ - - if (open_ssl_connections > 0) - --open_ssl_connections; - -#ifdef ENABLE_THREAD_SAFETY - if (0 == open_ssl_connections && do_initialize_openssl) - { - /* Unsetting these allows the rabbitmq-c library to be unloaded - * safely. We do leak the amqp_openssl_lockarray. Which is only - * an issue if you repeatedly unload and load the library - */ - CRYPTO_set_locking_callback(NULL); - CRYPTO_set_id_callback(NULL); - } - - pthread_mutex_unlock(&openssl_init_mutex); -#endif /* ENABLE_THREAD_SAFETY */ - return 0; -} diff --git a/librabbitmq/amqp-polarssl.c b/librabbitmq/amqp-polarssl.c deleted file mode 100644 index 125918f..0000000 --- a/librabbitmq/amqp-polarssl.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright 2012 Michael Steinert - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "amqp-ssl-socket.h" -#include "amqp_private.h" -#include -#include -#include -#include -#include - -struct amqp_ssl_socket_t { - int sockfd; - entropy_context *entropy; - ctr_drbg_context *ctr_drbg; - x509_cert *cacert; - rsa_context *key; - x509_cert *cert; - ssl_context *ssl; - ssl_session *session; - char *buffer; - size_t length; -}; - -static ssize_t -amqp_ssl_socket_send(void *base, - const void *buf, - size_t len, - AMQP_UNUSED int flags) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return ssl_write(self->ssl, buf, len); -} - -static ssize_t -amqp_ssl_socket_writev(void *base, - const struct iovec *iov, - int iovcnt) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - ssize_t written = -1; - char *bufferp; - size_t bytes; - int i; - bytes = 0; - for (i = 0; i < iovcnt; ++i) { - bytes += iov[i].iov_len; - } - if (self->length < bytes) { - free(self->buffer); - self->buffer = malloc(bytes); - if (!self->buffer) { - self->length = 0; - goto exit; - } - self->length = bytes; - } - bufferp = self->buffer; - for (i = 0; i < iovcnt; ++i) { - memcpy(bufferp, iov[i].iov_base, iov[i].iov_len); - bufferp += iov[i].iov_len; - } - written = ssl_write(self->ssl, (const unsigned char *)self->buffer, - bytes); -exit: - return written; -} - -static ssize_t -amqp_ssl_socket_recv(void *base, - void *buf, - size_t len, - AMQP_UNUSED int flags) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return ssl_read(self->ssl, buf, len); -} - -static int -amqp_ssl_socket_open(void *base, const char *host, int port) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - int status = net_connect(&self->sockfd, host, port); - if (status) { - return -1; - } - if (self->cacert) { - ssl_set_ca_chain(self->ssl, self->cacert, NULL, host); - } - ssl_set_bio(self->ssl, net_recv, &self->sockfd, - net_send, &self->sockfd); - if (self->key && self->cert) { - ssl_set_own_cert(self->ssl, self->cert, self->key); - } - while (0 != (status = ssl_handshake(self->ssl))) { - switch (status) { - case POLARSSL_ERR_NET_WANT_READ: - case POLARSSL_ERR_NET_WANT_WRITE: - continue; - default: - break; - } - } - return status; -} - -static int -amqp_ssl_socket_close(void *base) -{ - int status = -1; - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - if (self) { - free(self->entropy); - free(self->ctr_drbg); - x509_free(self->cacert); - free(self->cacert); - rsa_free(self->key); - free(self->key); - x509_free(self->cert); - free(self->cert); - ssl_free(self->ssl); - free(self->ssl); - free(self->session); - free(self->buffer); - if (self->sockfd >= 0) { - net_close(self->sockfd); - status = 0; - } - free(self); - } - return status; -} - -static int -amqp_ssl_socket_error(AMQP_UNUSED void *user_data) -{ - return -1; -} - -static int -amqp_ssl_socket_get_sockfd(void *base) -{ - struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; - return self->sockfd; -} - -static const struct amqp_socket_class_t amqp_ssl_socket_class = { - amqp_ssl_socket_writev, /* writev */ - amqp_ssl_socket_send, /* send */ - amqp_ssl_socket_recv, /* recv */ - amqp_ssl_socket_open, /* open */ - amqp_ssl_socket_close, /* close */ - amqp_ssl_socket_error, /* error */ - amqp_ssl_socket_get_sockfd /* get_sockfd */ -}; - -amqp_socket_t * -amqp_ssl_socket_new(void) -{ - struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self)); - int status; - if (!self) { - goto error; - } - self->entropy = calloc(1, sizeof(*self->entropy)); - if (!self->entropy) { - goto error; - } - self->sockfd = -1; - entropy_init(self->entropy); - self->ctr_drbg = calloc(1, sizeof(*self->ctr_drbg)); - if (!self->ctr_drbg) { - goto error; - } - status = ctr_drbg_init(self->ctr_drbg, entropy_func, self->entropy, - NULL, 0); - if (status) { - goto error; - } - self->ssl = calloc(1, sizeof(*self->ssl)); - if (!self->ssl) { - goto error; - } - status = ssl_init(self->ssl); - if (status) { - goto error; - } - ssl_set_endpoint(self->ssl, SSL_IS_CLIENT); - ssl_set_rng(self->ssl, ctr_drbg_random, self->ctr_drbg); - ssl_set_ciphersuites(self->ssl, ssl_default_ciphersuites); - self->session = calloc(1, sizeof(*self->session)); - if (!self->session) { - goto error; - } - ssl_set_session(self->ssl, 0, 0, self->session); - return (amqp_socket_t *)self; -error: - amqp_socket_close((amqp_socket_t *)self); - return NULL; -} - -int -amqp_ssl_socket_set_cacert(amqp_socket_t *base, - const char *cacert) -{ - int status; - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - self->cacert = calloc(1, sizeof(*self->cacert)); - if (!self->cacert) { - return -1; - } - status = x509parse_crtfile(self->cacert, cacert); - if (status) { - return -1; - } - return 0; -} - -int -amqp_ssl_socket_set_key(amqp_socket_t *base, - const char *cert, - const char *key) -{ - int status; - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - self->key = calloc(1, sizeof(*self->key)); - if (!self->key) { - return -1; - } - status = x509parse_keyfile(self->key, key, NULL); - if (status) { - return -1; - } - self->cert = calloc(1, sizeof(*self->cert)); - if (!self->cert) { - return -1; - } - status = x509parse_crtfile(self->cert, cert); - if (status) { - return -1; - } - return 0; -} - -int -amqp_ssl_socket_set_key_buffer(AMQP_UNUSED amqp_socket_t *base, - AMQP_UNUSED const char *cert, - AMQP_UNUSED const void *key, - AMQP_UNUSED size_t n) -{ - amqp_abort("%s is not implemented for PolarSSL", __func__); - return -1; -} - -void -amqp_ssl_socket_set_verify(amqp_socket_t *base, - amqp_boolean_t verify) -{ - struct amqp_ssl_socket_t *self; - if (base->klass != &amqp_ssl_socket_class) { - amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); - } - self = (struct amqp_ssl_socket_t *)base; - if (verify) { - ssl_set_authmode(self->ssl, SSL_VERIFY_REQUIRED); - } else { - ssl_set_authmode(self->ssl, SSL_VERIFY_NONE); - } -} - -void -amqp_set_initialize_ssl_library(AMQP_UNUSED amqp_boolean_t do_initialize) -{ -} diff --git a/librabbitmq/amqp-socket.h b/librabbitmq/amqp-socket.h deleted file mode 100644 index a40d13e..0000000 --- a/librabbitmq/amqp-socket.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2012 Michael Steinert - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifndef AMQP_SOCKET_H -#define AMQP_SOCKET_H - -#include "amqp.h" -#include "socket.h" - -AMQP_BEGIN_DECLS - -/* Socket callbacks. */ -typedef ssize_t (*amqp_socket_writev_fn)(void *, const struct iovec *, int); -typedef ssize_t (*amqp_socket_send_fn)(void *, const void *, size_t, int); -typedef ssize_t (*amqp_socket_recv_fn)(void *, void *, size_t, int); -typedef int (*amqp_socket_open_fn)(void *, const char *, int); -typedef int (*amqp_socket_close_fn)(void *); -typedef int (*amqp_socket_error_fn)(void *); -typedef int (*amqp_socket_get_sockfd_fn)(void *); - -struct amqp_socket_class_t { - amqp_socket_writev_fn writev; - amqp_socket_send_fn send; - amqp_socket_recv_fn recv; - amqp_socket_open_fn open; - amqp_socket_close_fn close; - amqp_socket_error_fn error; - amqp_socket_get_sockfd_fn get_sockfd; -}; - -struct amqp_socket_t_ { - const struct amqp_socket_class_t *klass; -}; - -ssize_t -amqp_socket_writev(amqp_socket_t *self, const struct iovec *iov, int iovcnt); - -ssize_t -amqp_socket_send(amqp_socket_t *self, const void *buf, size_t len, int flags); - -ssize_t -amqp_socket_recv(amqp_socket_t *self, void *buf, size_t len, int flags); - -AMQP_END_DECLS - -#endif /* AMQP_SOCKET_H */ diff --git a/librabbitmq/amqp-ssl-socket.h b/librabbitmq/amqp-ssl-socket.h deleted file mode 100644 index 87bce35..0000000 --- a/librabbitmq/amqp-ssl-socket.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2012 Michael Steinert - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** - * \file - * Open an SSL/TLS connection - */ - -#ifndef AMQP_SSL_H -#define AMQP_SSL_H - -#include - -/** - * Create a new SSL/TLS socket object. - * - * \return A new socket object or NULL if an error occurred. - */ -AMQP_PUBLIC_FUNCTION -amqp_socket_t * -AMQP_CALL -amqp_ssl_socket_new(void); - -/** - * Set the CA certificate. - * - * \param [in,out] self An SSL/TLS socket object. - * \param [in] cacert Path to the CA cert file in PEM format. - * - * \return Zero if successful, -1 otherwise. - */ -AMQP_PUBLIC_FUNCTION -int -AMQP_CALL -amqp_ssl_socket_set_cacert(amqp_socket_t *self, - const char *cacert); - -/** - * Set the client key. - * - * \param [in,out] self An SSL/TLS socket object. - * \param [in] cert Path to the client certificate in PEM foramt. - * \param [in] key Path to the client key in PEM format. - * - * \return Zero if successful, -1 otherwise. - */ -AMQP_PUBLIC_FUNCTION -int -AMQP_CALL -amqp_ssl_socket_set_key(amqp_socket_t *self, - const char *cert, - const char *key); - -/** - * Set the client key from a buffer. - * - * \param [in,out] self An SSL/TLS socket object. - * \param [in] cert Path to the client certificate in PEM foramt. - * \param [in] key A buffer containing client key in PEM format. - * \param [in] n The length of the buffer. - * - * \return Zero if successful, -1 otherwise. - */ -AMQP_PUBLIC_FUNCTION -int -AMQP_CALL -amqp_ssl_socket_set_key_buffer(amqp_socket_t *self, - const char *cert, - const void *key, - size_t n); - -/** - * Enable or disable peer verification. - * - * If peer verification is enabled then the common name in the server - * certificate must match the server name. - * - * \param [in,out] self An SSL/TLS socket object. - * \param [in] verify Enable or disable peer verification. - */ -AMQP_PUBLIC_FUNCTION -void -AMQP_CALL -amqp_ssl_socket_set_verify(amqp_socket_t *self, - amqp_boolean_t verify); - -/** - * Sets whether rabbitmq-c initializes the underlying SSL library. - * - * For SSL libraries that require a one-time initialization across - * a whole program (e.g., OpenSSL) this sets whether or not rabbitmq-c - * will initialize the SSL library when the first call to - * amqp_open_ssl_socket() is made. You should call this function with - * do_init = 0 if the underlying SSL library is intialized somewhere else - * the program. - * - * Failing to initialize or double initialization of the SSL library will - * result in undefined behavior - * - * By default rabbitmq-c will initialize the underlying SSL library - * - * NOTE: calling this function after the first socket has been opened with - * amqp_open_ssl_socket() will not have any effect. - * - * \param [in] do_initalize If 0 rabbitmq-c will not initialize the SSL - * library, otherwise rabbitmq-c will initialize the - * SL library - * - */ -AMQP_PUBLIC_FUNCTION -void -AMQP_CALL -amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize); - -#endif /* AMQP_SSL_H */ diff --git a/librabbitmq/amqp-tcp-socket.c b/librabbitmq/amqp-tcp-socket.c deleted file mode 100644 index d6e6fdb..0000000 --- a/librabbitmq/amqp-tcp-socket.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2012 Michael Steinert - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "amqp_private.h" -#include "amqp-tcp-socket.h" -#include -#include - -struct amqp_tcp_socket_t { - const struct amqp_socket_class_t *klass; - int sockfd; -}; - -static ssize_t -amqp_tcp_socket_writev(void *base, const struct iovec *iov, int iovcnt) -{ - struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; - return amqp_os_socket_writev(self->sockfd, iov, iovcnt); -} - -static ssize_t -amqp_tcp_socket_send(void *base, const void *buf, size_t len, int flags) -{ - struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; - return send(self->sockfd, buf, len, flags); -} - -static ssize_t -amqp_tcp_socket_recv(void *base, void *buf, size_t len, int flags) -{ - struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; - return recv(self->sockfd, buf, len, flags); -} - -static int -amqp_tcp_socket_open(void *base, const char *host, int port) -{ - struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; - self->sockfd = amqp_open_socket(host, port); - if (0 > self->sockfd) { - return -1; - } - return 0; -} - -static int -amqp_tcp_socket_close(void *base) -{ - struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; - int status = -1; - if (self) { - status = amqp_os_socket_close(self->sockfd); - free(self); - } - return status; -} - -static int -amqp_tcp_socket_error(AMQP_UNUSED void *base) -{ - return amqp_os_socket_error(); -} - -static int -amqp_tcp_socket_get_sockfd(void *base) -{ - struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; - return self->sockfd; -} - -static const struct amqp_socket_class_t amqp_tcp_socket_class = { - amqp_tcp_socket_writev, /* writev */ - amqp_tcp_socket_send, /* send */ - amqp_tcp_socket_recv, /* recv */ - amqp_tcp_socket_open, /* open */ - amqp_tcp_socket_close, /* close */ - amqp_tcp_socket_error, /* error */ - amqp_tcp_socket_get_sockfd /* get_sockfd */ -}; - -amqp_socket_t * -amqp_tcp_socket_new(void) -{ - struct amqp_tcp_socket_t *self = calloc(1, sizeof(*self)); - if (!self) { - return NULL; - } - self->klass = &amqp_tcp_socket_class; - self->sockfd = -1; - return (amqp_socket_t *)self; -} - -void -amqp_tcp_socket_set_sockfd(amqp_socket_t *base, int sockfd) -{ - struct amqp_tcp_socket_t *self; - if (base->klass != &amqp_tcp_socket_class) { - amqp_abort("<%p> is not of type amqp_tcp_socket_t", base); - } - self = (struct amqp_tcp_socket_t *)base; - self->sockfd = sockfd; -} diff --git a/librabbitmq/amqp-tcp-socket.h b/librabbitmq/amqp-tcp-socket.h deleted file mode 100644 index 6e0afa0..0000000 --- a/librabbitmq/amqp-tcp-socket.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2012 Michael Steinert - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifndef AMQP_TCP_SOCKET_H -#define AMQP_TCP_SOCKET_H - -#include - -AMQP_BEGIN_DECLS - -/** - * Create a new TCP socket. - * - * \return A new socket object or NULL if an error occurred. - */ -AMQP_PUBLIC_FUNCTION -amqp_socket_t * -AMQP_CALL -amqp_tcp_socket_new(void); - -/** - * Assign an open file descriptor to a socket object. - * - * This function must not be used in conjunction with amqp_socket_open(). - * - * \param [in,out] self A TCP socket object. - * \param [in] sockfd An open socket descriptor. - */ -AMQP_PUBLIC_FUNCTION -void -AMQP_CALL -amqp_tcp_socket_set_sockfd(amqp_socket_t *base, int sockfd); - -AMQP_END_DECLS - -#endif /* AMQP_TCP_SOCKET_H */ diff --git a/librabbitmq/amqp_connection.c b/librabbitmq/amqp_connection.c index 4666100..f468f16 100644 --- a/librabbitmq/amqp_connection.c +++ b/librabbitmq/amqp_connection.c @@ -38,7 +38,7 @@ #include "config.h" #endif -#include "amqp-tcp-socket.h" +#include "amqp_tcp_socket.h" #include "amqp_private.h" #include #include diff --git a/librabbitmq/amqp_cyassl.c b/librabbitmq/amqp_cyassl.c new file mode 100644 index 0000000..1daf7a9 --- /dev/null +++ b/librabbitmq/amqp_cyassl.c @@ -0,0 +1,225 @@ +/* + * Copyright 2012 Michael Steinert + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "amqp_ssl_socket.h" +#include "amqp_private.h" +#include +#include + +struct amqp_ssl_socket_t { + CYASSL_CTX *ctx; + CYASSL *ssl; + int sockfd; + char *buffer; + size_t length; +}; + +static ssize_t +amqp_ssl_socket_send(void *base, + const void *buf, + size_t len, + AMQP_UNUSED int flags) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return CyaSSL_write(self->ssl, buf, len); +} + +static ssize_t +amqp_ssl_socket_writev(void *base, + const struct iovec *iov, + int iovcnt) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + ssize_t written = -1; + char *bufferp; + size_t bytes; + int i; + bytes = 0; + for (i = 0; i < iovcnt; ++i) { + bytes += iov[i].iov_len; + } + if (self->length < bytes) { + free(self->buffer); + self->buffer = malloc(bytes); + if (!self->buffer) { + self->length = 0; + goto exit; + } + self->length = bytes; + } + bufferp = self->buffer; + for (i = 0; i < iovcnt; ++i) { + memcpy(bufferp, iov[i].iov_base, iov[i].iov_len); + bufferp += iov[i].iov_len; + } + written = CyaSSL_write(self->ssl, self->buffer, bytes); +exit: + return written; +} + +static ssize_t +amqp_ssl_socket_recv(void *base, + void *buf, + size_t len, + AMQP_UNUSED int flags) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return CyaSSL_read(self->ssl, buf, len); +} + +static int +amqp_ssl_socket_get_sockfd(void *base) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return self->sockfd; +} + +static int +amqp_ssl_socket_close(void *base) +{ + int status = -1; + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + if (self->sockfd >= 0) { + status = amqp_os_socket_close(self->sockfd); + } + if (self) { + CyaSSL_free(self->ssl); + CyaSSL_CTX_free(self->ctx); + free(self->buffer); + free(self); + } + return status; +} + +static int +amqp_ssl_socket_error(AMQP_UNUSED void *user_data) +{ + return -1; +} + +static int +amqp_ssl_socket_open(void *base, const char *host, int port) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + int status; + self->sockfd = amqp_open_socket(host, port); + if (0 > self->sockfd) { + return -1; + } + CyaSSL_set_fd(self->ssl, self->sockfd); + status = CyaSSL_connect(self->ssl); + if (SSL_SUCCESS != status) { + return -1; + } + return 0; +} + +static const struct amqp_socket_class_t amqp_ssl_socket_class = { + amqp_ssl_socket_writev, /* writev */ + amqp_ssl_socket_send, /* send */ + amqp_ssl_socket_recv, /* recv */ + amqp_ssl_socket_open, /* open */ + amqp_ssl_socket_close, /* close */ + amqp_ssl_socket_error, /* error */ + amqp_ssl_socket_get_sockfd /* get_sockfd */ +}; + +amqp_socket_t * +amqp_ssl_socket_new(void) +{ + struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self)); + if (!self) { + goto error; + } + CyaSSL_Init(); + self->ctx = CyaSSL_CTX_new(CyaSSLv23_client_method()); + if (!self->ctx) { + goto error; + } + return (amqp_socket_t *)self; +error: + amqp_socket_close((amqp_socket_t *)self); + return NULL; +} + +int +amqp_ssl_socket_set_cacert(amqp_socket_t *base, + const char *cacert) +{ + int status; + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + status = CyaSSL_CTX_load_verify_locations(self->ctx, cacert, NULL); + if (SSL_SUCCESS != status) { + return -1; + } + return 0; +} + +int +amqp_ssl_socket_set_key(amqp_socket_t *base, + const char *cert, + const char *key) +{ + int status; + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + status = CyaSSL_CTX_use_PrivateKey_file(self->ctx, key, + SSL_FILETYPE_PEM); + if (SSL_SUCCESS != status) { + return -1; + } + status = CyaSSL_CTX_use_certificate_chain_file(self->ctx, cert); + return 0; +} + +int +amqp_ssl_socket_set_key_buffer(AMQP_UNUSED amqp_socket_t *base, + AMQP_UNUSED const char *cert, + AMQP_UNUSED const void *key, + AMQP_UNUSED size_t n) +{ + amqp_abort("%s is not implemented for CyaSSL", __func__); + return -1; +} + +void +amqp_ssl_socket_set_verify(AMQP_UNUSED amqp_socket_t *base, + AMQP_UNUSED amqp_boolean_t verify) +{ + /* noop for CyaSSL */ +} + +void +amqp_set_initialize_ssl_library(AMQP_UNUSED amqp_boolean_t do_initialize) +{ +} diff --git a/librabbitmq/amqp_gnutls.c b/librabbitmq/amqp_gnutls.c new file mode 100644 index 0000000..93273d7 --- /dev/null +++ b/librabbitmq/amqp_gnutls.c @@ -0,0 +1,312 @@ +/* + * Copyright 2012 Michael Steinert + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "amqp_ssl_socket.h" +#include "amqp_private.h" +#include +#include +#include + +struct amqp_ssl_socket_t { + gnutls_session_t session; + gnutls_certificate_credentials_t credentials; + int sockfd; + char *host; + char *buffer; + size_t length; +}; + +static ssize_t +amqp_ssl_socket_send(void *base, + const void *buf, + size_t len, + AMQP_UNUSED int flags) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return gnutls_record_send(self->session, buf, len); +} + +static ssize_t +amqp_ssl_socket_writev(void *base, + const struct iovec *iov, + int iovcnt) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + ssize_t written = -1; + char *bufferp; + size_t bytes; + int i; + bytes = 0; + for (i = 0; i < iovcnt; ++i) { + bytes += iov[i].iov_len; + } + if (self->length < bytes) { + free(self->buffer); + self->buffer = malloc(bytes); + if (!self->buffer) { + self->length = 0; + goto exit; + } + self->length = 0; + } + bufferp = self->buffer; + for (i = 0; i < iovcnt; ++i) { + memcpy(bufferp, iov[i].iov_base, iov[i].iov_len); + bufferp += iov[i].iov_len; + } + written = gnutls_record_send(self->session, self->buffer, bytes); +exit: + return written; +} + +static ssize_t +amqp_ssl_socket_recv(void *base, + void *buf, + size_t len, + AMQP_UNUSED int flags) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return gnutls_record_recv(self->session, buf, len); +} + +static int +amqp_ssl_socket_open(void *base, const char *host, int port) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + int status; + self->sockfd = amqp_open_socket(host, port); + if (0 > self->sockfd) { + return -1; + } + gnutls_transport_set_ptr(self->session, + (gnutls_transport_ptr_t)self->sockfd); + do { + status = gnutls_handshake(self->session); + } while (status < 0 && !gnutls_error_is_fatal(status)); + return status; +} + +static int +amqp_ssl_socket_close(void *base) +{ + int status = -1; + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + if (self->sockfd >= 0) { + status = amqp_os_socket_close(self->sockfd); + } + if (self) { + gnutls_deinit(self->session); + gnutls_certificate_free_credentials(self->credentials); + free(self->host); + free(self->buffer); + free(self); + } + return status; +} + +static int +amqp_ssl_socket_error(AMQP_UNUSED void *user_data) +{ + return -1; +} + +static int +amqp_ssl_socket_get_sockfd(void *base) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return self->sockfd; +} + +static int +amqp_ssl_verify(gnutls_session_t session) +{ + int ret; + unsigned int status, size; + const gnutls_datum_t *list; + gnutls_x509_crt_t cert = NULL; + struct amqp_ssl_socket_t *self = gnutls_session_get_ptr(session); + ret = gnutls_certificate_verify_peers2(session, &status); + if (0 > ret) { + goto error; + } + if (status & GNUTLS_CERT_INVALID) { + goto error; + } + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { + goto error; + } + if (status & GNUTLS_CERT_REVOKED) { + goto error; + } + if (status & GNUTLS_CERT_EXPIRED) { + goto error; + } + if (status & GNUTLS_CERT_NOT_ACTIVATED) { + goto error; + } + if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { + goto error; + } + if (gnutls_x509_crt_init(&cert) < 0) { + goto error; + } + list = gnutls_certificate_get_peers(session, &size); + if (!list) { + goto error; + } + ret = gnutls_x509_crt_import(cert, &list[0], GNUTLS_X509_FMT_DER); + if (0 > ret) { + goto error; + } + if (!gnutls_x509_crt_check_hostname(cert, self->host)) { + goto error; + } + gnutls_x509_crt_deinit(cert); + return 0; +error: + if (cert) { + gnutls_x509_crt_deinit (cert); + } + return GNUTLS_E_CERTIFICATE_ERROR; +} + +static const struct amqp_socket_class_t amqp_ssl_socket_class = { + amqp_ssl_socket_writev, /* writev */ + amqp_ssl_socket_send, /* send */ + amqp_ssl_socket_recv, /* recv */ + amqp_ssl_socket_open, /* open */ + amqp_ssl_socket_close, /* close */ + amqp_ssl_socket_error, /* error */ + amqp_ssl_socket_get_sockfd /* get_sockfd */ +}; + +amqp_socket_t * +amqp_ssl_socket_new(void) +{ + struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self)); + const char *error; + int status; + if (!self) { + goto error; + } + gnutls_global_init(); + status = gnutls_init(&self->session, GNUTLS_CLIENT); + if (GNUTLS_E_SUCCESS != status) { + goto error; + } + status = gnutls_certificate_allocate_credentials(&self->credentials); + if (GNUTLS_E_SUCCESS != status) { + goto error; + } + status = gnutls_credentials_set(self->session, GNUTLS_CRD_CERTIFICATE, + self->credentials); + if (GNUTLS_E_SUCCESS != status) { + goto error; + } + gnutls_session_set_ptr(self->session, self); + status = gnutls_priority_set_direct(self->session, "NORMAL", &error); + if (GNUTLS_E_SUCCESS != status) { + goto error; + } + return (amqp_socket_t *)self; +error: + amqp_socket_close((amqp_socket_t *)self); + return NULL; +} + +int +amqp_ssl_socket_set_cacert(amqp_socket_t *base, + const char *cacert) +{ + int status; + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + status = gnutls_certificate_set_x509_trust_file(self->credentials, + cacert, + GNUTLS_X509_FMT_PEM); + if (0 > status) { + return -1; + } + return 0; +} + +int +amqp_ssl_socket_set_key(amqp_socket_t *base, + const char *cert, + const char *key) +{ + int status; + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + status = gnutls_certificate_set_x509_key_file(self->credentials, + cert, + key, + GNUTLS_X509_FMT_PEM); + if (0 > status) { + return -1; + } + + return 0; +} + +int +amqp_ssl_socket_set_key_buffer(AMQP_UNUSED amqp_socket_t *base, + AMQP_UNUSED const char *cert, + AMQP_UNUSED const void *key, + AMQP_UNUSED size_t n) +{ + amqp_abort("%s is not implemented for GnuTLS", __func__); + return -1; +} + +void +amqp_ssl_socket_set_verify(amqp_socket_t *base, + amqp_boolean_t verify) +{ + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + if (verify) { + gnutls_certificate_set_verify_function(self->credentials, + amqp_ssl_verify); + } else { + gnutls_certificate_set_verify_function(self->credentials, + NULL); + } +} + +void +amqp_set_initialize_ssl_library(AMQP_UNUSED amqp_boolean_t do_initialize) +{ +} diff --git a/librabbitmq/amqp_openssl.c b/librabbitmq/amqp_openssl.c new file mode 100644 index 0000000..c3451ae --- /dev/null +++ b/librabbitmq/amqp_openssl.c @@ -0,0 +1,556 @@ +/* + * Copyright 2012 Michael Steinert + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "amqp_ssl_socket.h" +#include "amqp_private.h" +#include "threads.h" +#include +#include +#include +#include +#include + +#include "socket.h" + +static int initialize_openssl(void); +static int destroy_openssl(void); + +static int open_ssl_connections = 0; +static amqp_boolean_t do_initialize_openssl = 1; +static amqp_boolean_t openssl_initialized = 0; + +#ifdef ENABLE_THREAD_SAFETY +static unsigned long amqp_ssl_threadid_callback(void); +static void amqp_ssl_locking_callback(int mode, int n, const char *file, int line); + +#ifdef _WIN32 +static long win32_create_mutex = 0; +static pthread_mutex_t openssl_init_mutex = NULL; +#else +static pthread_mutex_t openssl_init_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif +static pthread_mutex_t *amqp_openssl_lockarray = NULL; +#endif /* ENABLE_THREAD_SAFETY */ + +struct amqp_ssl_socket_t { + const struct amqp_socket_class_t *klass; + SSL_CTX *ctx; + int sockfd; + SSL *ssl; + char *buffer; + size_t length; + amqp_boolean_t verify; +}; + +static ssize_t +amqp_ssl_socket_send(void *base, + const void *buf, + size_t len, + AMQP_UNUSED int flags) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + ssize_t sent; + ERR_clear_error(); + sent = SSL_write(self->ssl, buf, len); + if (0 > sent) { + switch (SSL_get_error(self->ssl, sent)) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + sent = 0; + break; + } + } + return sent; +} + +static ssize_t +amqp_ssl_socket_writev(void *base, + const struct iovec *iov, + int iovcnt) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + ssize_t written = -1; + char *bufferp; + size_t bytes; + int i; + bytes = 0; + for (i = 0; i < iovcnt; ++i) { + bytes += iov[i].iov_len; + } + if (self->length < bytes) { + free(self->buffer); + self->buffer = malloc(bytes); + if (!self->buffer) { + self->length = 0; + goto exit; + } + self->length = bytes; + } + bufferp = self->buffer; + for (i = 0; i < iovcnt; ++i) { + memcpy(bufferp, iov[i].iov_base, iov[i].iov_len); + bufferp += iov[i].iov_len; + } + written = amqp_ssl_socket_send(self, self->buffer, bytes, 0); +exit: + return written; +} + +static ssize_t +amqp_ssl_socket_recv(void *base, + void *buf, + size_t len, + AMQP_UNUSED int flags) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + ssize_t received; + ERR_clear_error(); + received = SSL_read(self->ssl, buf, len); + if (0 > received) { + switch(SSL_get_error(self->ssl, received)) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + received = 0; + break; + } + } + return received; +} + +static int +amqp_ssl_socket_verify(void *base, const char *host) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + unsigned char *utf8_value = NULL, *cp, ch; + int pos, utf8_length, status = 0; + ASN1_STRING *entry_string; + X509_NAME_ENTRY *entry; + X509_NAME *name; + X509 *peer; + peer = SSL_get_peer_certificate(self->ssl); + if (!peer) { + goto error; + } + name = X509_get_subject_name(peer); + if (!name) { + goto error; + } + pos = X509_NAME_get_index_by_NID(name, NID_commonName, -1); + if (0 > pos) { + goto error; + } + entry = X509_NAME_get_entry(name, pos); + if (!entry) { + goto error; + } + entry_string = X509_NAME_ENTRY_get_data(entry); + if (!entry_string) { + goto error; + } + utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_string); + if (0 > utf8_length) { + goto error; + } + while (utf8_length > 0 && utf8_value[utf8_length - 1] == 0) { + --utf8_length; + } + if (utf8_length >= 256) { + goto error; + } + if ((size_t)utf8_length != strlen((char *)utf8_value)) { + goto error; + } + for (cp = utf8_value; (ch = *cp) != '\0'; ++cp) { + if (isascii(ch) && !isprint(ch)) { + goto error; + } + } +#ifdef _MSC_VER +#define strcasecmp _stricmp +#endif + if (strcasecmp(host, (char *)utf8_value)) { + goto error; + } +#ifdef _MSC_VER +#undef strcasecmp +#endif +exit: + OPENSSL_free(utf8_value); + return status; +error: + status = -1; + goto exit; +} + +static int +amqp_ssl_socket_open(void *base, const char *host, int port) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + long result; + int status; + self->ssl = SSL_new(self->ctx); + if (!self->ssl) { + return -1; + } + SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); + self->sockfd = amqp_open_socket(host, port); + if (0 > self->sockfd) { + return -1; + } + status = SSL_set_fd(self->ssl, self->sockfd); + if (!status) { + return -1; + } + status = SSL_connect(self->ssl); + if (!status) { + return -1; + } + result = SSL_get_verify_result(self->ssl); + if (X509_V_OK != result) { + return -1; + } + if (self->verify) { + int status = amqp_ssl_socket_verify(self, host); + if (status) { + return -1; + } + } + return 0; +} + +static int +amqp_ssl_socket_close(void *base) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + if (self) { + SSL_free(self->ssl); + amqp_os_socket_close(self->sockfd); + SSL_CTX_free(self->ctx); + free(self->buffer); + free(self); + } + destroy_openssl(); + return 0; +} + +static int +amqp_ssl_socket_error(AMQP_UNUSED void *base) +{ + return -1; +} + +static int +amqp_ssl_socket_get_sockfd(void *base) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return self->sockfd; +} + +static const struct amqp_socket_class_t amqp_ssl_socket_class = { + amqp_ssl_socket_writev, /* writev */ + amqp_ssl_socket_send, /* send */ + amqp_ssl_socket_recv, /* recv */ + amqp_ssl_socket_open, /* open */ + amqp_ssl_socket_close, /* close */ + amqp_ssl_socket_error, /* error */ + amqp_ssl_socket_get_sockfd /* get_sockfd */ +}; + +amqp_socket_t * +amqp_ssl_socket_new(void) +{ + struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self)); + int status; + if (!self) { + goto error; + } + status = initialize_openssl(); + if (status) { + goto error; + } + self->ctx = SSL_CTX_new(SSLv23_client_method()); + if (!self->ctx) { + goto error; + } + self->klass = &amqp_ssl_socket_class; + self->verify = 1; + return (amqp_socket_t *)self; +error: + amqp_socket_close((amqp_socket_t *)self); + return NULL; +} + +int +amqp_ssl_socket_set_cacert(amqp_socket_t *base, + const char *cacert) +{ + int status; + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + status = SSL_CTX_load_verify_locations(self->ctx, cacert, NULL); + if (1 != status) { + return -1; + } + return 0; +} + +int +amqp_ssl_socket_set_key(amqp_socket_t *base, + const char *cert, + const char *key) +{ + int status; + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + status = SSL_CTX_use_certificate_chain_file(self->ctx, cert); + if (1 != status) { + return -1; + } + status = SSL_CTX_use_PrivateKey_file(self->ctx, key, + SSL_FILETYPE_PEM); + if (1 != status) { + return -1; + } + return 0; +} + +static int +password_cb(AMQP_UNUSED char *buffer, + AMQP_UNUSED int length, + AMQP_UNUSED int rwflag, + AMQP_UNUSED void *user_data) +{ + amqp_abort("don't use password protected keys!"); + return 0; +} + +int +amqp_ssl_socket_set_key_buffer(amqp_socket_t *base, + const char *cert, + const void *key, + size_t n) +{ + int status = 0; + BIO *buf = NULL; + RSA *rsa = NULL; + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + status = SSL_CTX_use_certificate_chain_file(self->ctx, cert); + if (1 != status) { + return -1; + } + buf = BIO_new_mem_buf((void *)key, n); + if (!buf) { + goto error; + } + rsa = PEM_read_bio_RSAPrivateKey(buf, NULL, password_cb, NULL); + if (!rsa) { + goto error; + } + status = SSL_CTX_use_RSAPrivateKey(self->ctx, rsa); + if (1 != status) { + goto error; + } +exit: + BIO_vfree(buf); + RSA_free(rsa); + return status; +error: + status = -1; + goto exit; +} + +int +amqp_ssl_socket_set_cert(amqp_socket_t *base, + const char *cert) +{ + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + int status = SSL_CTX_use_certificate_chain_file(self->ctx, cert); + if (1 != status) { + return -1; + } + return 0; +} + +void +amqp_ssl_socket_set_verify(amqp_socket_t *base, + amqp_boolean_t verify) +{ + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + self->verify = verify; +} + +void +amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize) +{ + if (!openssl_initialized) { + do_initialize_openssl = do_initialize; + } +} + +#ifdef ENABLE_THREAD_SAFETY +unsigned long +amqp_ssl_threadid_callback(void) +{ + return (unsigned long)pthread_self(); +} + +void +amqp_ssl_locking_callback(int mode, int n, + AMQP_UNUSED const char *file, + AMQP_UNUSED int line) +{ + if (mode & CRYPTO_LOCK) + { + if (pthread_mutex_lock(&amqp_openssl_lockarray[n])) + amqp_abort("Runtime error: Failure in trying to lock OpenSSL mutex"); + } + else + { + if (pthread_mutex_unlock(&amqp_openssl_lockarray[n])) + amqp_abort("Runtime error: Failure in trying to unlock OpenSSL mutex"); + } +} +#endif /* ENABLE_THREAD_SAFETY */ + +static int +initialize_openssl(void) +{ +#ifdef _WIN32 + /* No such thing as PTHREAD_INITIALIZE_MUTEX macro on Win32, so we use this */ + if (NULL == openssl_init_mutex) + { + while (InterlockedExchange(&win32_create_mutex, 1) == 1) + /* Loop, someone else is holding this lock */ ; + + if (NULL == openssl_init_mutex) + { + if (pthread_mutex_init(&openssl_init_mutex, NULL)) + return -1; + } + InterlockedExchange(&win32_create_mutex, 0); + } +#endif /* _WIN32 */ + +#ifdef ENABLE_THREAD_SAFETY + if (pthread_mutex_lock(&openssl_init_mutex)) + return -1; +#endif /* ENABLE_THREAD_SAFETY */ + if (do_initialize_openssl) + { +#ifdef ENABLE_THREAD_SAFETY + if (NULL == amqp_openssl_lockarray) + { + int i = 0; + amqp_openssl_lockarray = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t)); + if (!amqp_openssl_lockarray) + { + pthread_mutex_unlock(&openssl_init_mutex); + return -1; + } + for (i = 0; i < CRYPTO_num_locks(); ++i) + { + if (pthread_mutex_init(&amqp_openssl_lockarray[i], NULL)) + { + free(amqp_openssl_lockarray); + amqp_openssl_lockarray = NULL; + pthread_mutex_unlock(&openssl_init_mutex); + return -1; + } + } + } + + if (0 == open_ssl_connections) + { + CRYPTO_set_id_callback(amqp_ssl_threadid_callback); + CRYPTO_set_locking_callback(amqp_ssl_locking_callback); + } +#endif /* ENABLE_THREAD_SAFETY */ + + if (!openssl_initialized) + { + OPENSSL_config(NULL); + + SSL_library_init(); + SSL_load_error_strings(); + + openssl_initialized = 1; + } + } + + ++open_ssl_connections; + +#ifdef ENABLE_THREAD_SAFETY + pthread_mutex_unlock(&openssl_init_mutex); +#endif /* ENABLE_THREAD_SAFETY */ + return 0; +} + +static int +destroy_openssl(void) +{ +#ifdef ENABLE_THREAD_SAFETY + if (pthread_mutex_lock(&openssl_init_mutex)) + return -1; +#endif /* ENABLE_THREAD_SAFETY */ + + if (open_ssl_connections > 0) + --open_ssl_connections; + +#ifdef ENABLE_THREAD_SAFETY + if (0 == open_ssl_connections && do_initialize_openssl) + { + /* Unsetting these allows the rabbitmq-c library to be unloaded + * safely. We do leak the amqp_openssl_lockarray. Which is only + * an issue if you repeatedly unload and load the library + */ + CRYPTO_set_locking_callback(NULL); + CRYPTO_set_id_callback(NULL); + } + + pthread_mutex_unlock(&openssl_init_mutex); +#endif /* ENABLE_THREAD_SAFETY */ + return 0; +} diff --git a/librabbitmq/amqp_polarssl.c b/librabbitmq/amqp_polarssl.c new file mode 100644 index 0000000..1c7c9f3 --- /dev/null +++ b/librabbitmq/amqp_polarssl.c @@ -0,0 +1,305 @@ +/* + * Copyright 2012 Michael Steinert + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "amqp_ssl_socket.h" +#include "amqp_private.h" +#include +#include +#include +#include +#include + +struct amqp_ssl_socket_t { + int sockfd; + entropy_context *entropy; + ctr_drbg_context *ctr_drbg; + x509_cert *cacert; + rsa_context *key; + x509_cert *cert; + ssl_context *ssl; + ssl_session *session; + char *buffer; + size_t length; +}; + +static ssize_t +amqp_ssl_socket_send(void *base, + const void *buf, + size_t len, + AMQP_UNUSED int flags) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return ssl_write(self->ssl, buf, len); +} + +static ssize_t +amqp_ssl_socket_writev(void *base, + const struct iovec *iov, + int iovcnt) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + ssize_t written = -1; + char *bufferp; + size_t bytes; + int i; + bytes = 0; + for (i = 0; i < iovcnt; ++i) { + bytes += iov[i].iov_len; + } + if (self->length < bytes) { + free(self->buffer); + self->buffer = malloc(bytes); + if (!self->buffer) { + self->length = 0; + goto exit; + } + self->length = bytes; + } + bufferp = self->buffer; + for (i = 0; i < iovcnt; ++i) { + memcpy(bufferp, iov[i].iov_base, iov[i].iov_len); + bufferp += iov[i].iov_len; + } + written = ssl_write(self->ssl, (const unsigned char *)self->buffer, + bytes); +exit: + return written; +} + +static ssize_t +amqp_ssl_socket_recv(void *base, + void *buf, + size_t len, + AMQP_UNUSED int flags) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return ssl_read(self->ssl, buf, len); +} + +static int +amqp_ssl_socket_open(void *base, const char *host, int port) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + int status = net_connect(&self->sockfd, host, port); + if (status) { + return -1; + } + if (self->cacert) { + ssl_set_ca_chain(self->ssl, self->cacert, NULL, host); + } + ssl_set_bio(self->ssl, net_recv, &self->sockfd, + net_send, &self->sockfd); + if (self->key && self->cert) { + ssl_set_own_cert(self->ssl, self->cert, self->key); + } + while (0 != (status = ssl_handshake(self->ssl))) { + switch (status) { + case POLARSSL_ERR_NET_WANT_READ: + case POLARSSL_ERR_NET_WANT_WRITE: + continue; + default: + break; + } + } + return status; +} + +static int +amqp_ssl_socket_close(void *base) +{ + int status = -1; + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + if (self) { + free(self->entropy); + free(self->ctr_drbg); + x509_free(self->cacert); + free(self->cacert); + rsa_free(self->key); + free(self->key); + x509_free(self->cert); + free(self->cert); + ssl_free(self->ssl); + free(self->ssl); + free(self->session); + free(self->buffer); + if (self->sockfd >= 0) { + net_close(self->sockfd); + status = 0; + } + free(self); + } + return status; +} + +static int +amqp_ssl_socket_error(AMQP_UNUSED void *user_data) +{ + return -1; +} + +static int +amqp_ssl_socket_get_sockfd(void *base) +{ + struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; + return self->sockfd; +} + +static const struct amqp_socket_class_t amqp_ssl_socket_class = { + amqp_ssl_socket_writev, /* writev */ + amqp_ssl_socket_send, /* send */ + amqp_ssl_socket_recv, /* recv */ + amqp_ssl_socket_open, /* open */ + amqp_ssl_socket_close, /* close */ + amqp_ssl_socket_error, /* error */ + amqp_ssl_socket_get_sockfd /* get_sockfd */ +}; + +amqp_socket_t * +amqp_ssl_socket_new(void) +{ + struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self)); + int status; + if (!self) { + goto error; + } + self->entropy = calloc(1, sizeof(*self->entropy)); + if (!self->entropy) { + goto error; + } + self->sockfd = -1; + entropy_init(self->entropy); + self->ctr_drbg = calloc(1, sizeof(*self->ctr_drbg)); + if (!self->ctr_drbg) { + goto error; + } + status = ctr_drbg_init(self->ctr_drbg, entropy_func, self->entropy, + NULL, 0); + if (status) { + goto error; + } + self->ssl = calloc(1, sizeof(*self->ssl)); + if (!self->ssl) { + goto error; + } + status = ssl_init(self->ssl); + if (status) { + goto error; + } + ssl_set_endpoint(self->ssl, SSL_IS_CLIENT); + ssl_set_rng(self->ssl, ctr_drbg_random, self->ctr_drbg); + ssl_set_ciphersuites(self->ssl, ssl_default_ciphersuites); + self->session = calloc(1, sizeof(*self->session)); + if (!self->session) { + goto error; + } + ssl_set_session(self->ssl, 0, 0, self->session); + return (amqp_socket_t *)self; +error: + amqp_socket_close((amqp_socket_t *)self); + return NULL; +} + +int +amqp_ssl_socket_set_cacert(amqp_socket_t *base, + const char *cacert) +{ + int status; + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + self->cacert = calloc(1, sizeof(*self->cacert)); + if (!self->cacert) { + return -1; + } + status = x509parse_crtfile(self->cacert, cacert); + if (status) { + return -1; + } + return 0; +} + +int +amqp_ssl_socket_set_key(amqp_socket_t *base, + const char *cert, + const char *key) +{ + int status; + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + self->key = calloc(1, sizeof(*self->key)); + if (!self->key) { + return -1; + } + status = x509parse_keyfile(self->key, key, NULL); + if (status) { + return -1; + } + self->cert = calloc(1, sizeof(*self->cert)); + if (!self->cert) { + return -1; + } + status = x509parse_crtfile(self->cert, cert); + if (status) { + return -1; + } + return 0; +} + +int +amqp_ssl_socket_set_key_buffer(AMQP_UNUSED amqp_socket_t *base, + AMQP_UNUSED const char *cert, + AMQP_UNUSED const void *key, + AMQP_UNUSED size_t n) +{ + amqp_abort("%s is not implemented for PolarSSL", __func__); + return -1; +} + +void +amqp_ssl_socket_set_verify(amqp_socket_t *base, + amqp_boolean_t verify) +{ + struct amqp_ssl_socket_t *self; + if (base->klass != &amqp_ssl_socket_class) { + amqp_abort("<%p> is not of type amqp_ssl_socket_t", base); + } + self = (struct amqp_ssl_socket_t *)base; + if (verify) { + ssl_set_authmode(self->ssl, SSL_VERIFY_REQUIRED); + } else { + ssl_set_authmode(self->ssl, SSL_VERIFY_NONE); + } +} + +void +amqp_set_initialize_ssl_library(AMQP_UNUSED amqp_boolean_t do_initialize) +{ +} diff --git a/librabbitmq/amqp_private.h b/librabbitmq/amqp_private.h index d32f664..7f22ce8 100644 --- a/librabbitmq/amqp_private.h +++ b/librabbitmq/amqp_private.h @@ -92,7 +92,7 @@ char * amqp_os_error_string(int err); -#include "amqp-socket.h" +#include "amqp_socket.h" /* * Connection states: XXX FIX THIS diff --git a/librabbitmq/amqp_socket.h b/librabbitmq/amqp_socket.h new file mode 100644 index 0000000..a40d13e --- /dev/null +++ b/librabbitmq/amqp_socket.h @@ -0,0 +1,65 @@ +/* + * Copyright 2012 Michael Steinert + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef AMQP_SOCKET_H +#define AMQP_SOCKET_H + +#include "amqp.h" +#include "socket.h" + +AMQP_BEGIN_DECLS + +/* Socket callbacks. */ +typedef ssize_t (*amqp_socket_writev_fn)(void *, const struct iovec *, int); +typedef ssize_t (*amqp_socket_send_fn)(void *, const void *, size_t, int); +typedef ssize_t (*amqp_socket_recv_fn)(void *, void *, size_t, int); +typedef int (*amqp_socket_open_fn)(void *, const char *, int); +typedef int (*amqp_socket_close_fn)(void *); +typedef int (*amqp_socket_error_fn)(void *); +typedef int (*amqp_socket_get_sockfd_fn)(void *); + +struct amqp_socket_class_t { + amqp_socket_writev_fn writev; + amqp_socket_send_fn send; + amqp_socket_recv_fn recv; + amqp_socket_open_fn open; + amqp_socket_close_fn close; + amqp_socket_error_fn error; + amqp_socket_get_sockfd_fn get_sockfd; +}; + +struct amqp_socket_t_ { + const struct amqp_socket_class_t *klass; +}; + +ssize_t +amqp_socket_writev(amqp_socket_t *self, const struct iovec *iov, int iovcnt); + +ssize_t +amqp_socket_send(amqp_socket_t *self, const void *buf, size_t len, int flags); + +ssize_t +amqp_socket_recv(amqp_socket_t *self, void *buf, size_t len, int flags); + +AMQP_END_DECLS + +#endif /* AMQP_SOCKET_H */ diff --git a/librabbitmq/amqp_ssl_socket.h b/librabbitmq/amqp_ssl_socket.h new file mode 100644 index 0000000..706d537 --- /dev/null +++ b/librabbitmq/amqp_ssl_socket.h @@ -0,0 +1,138 @@ +/* + * Copyright 2012 Michael Steinert + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file + * Open an SSL/TLS connection + */ + +#ifndef AMQP_SSL_H +#define AMQP_SSL_H + +#include + +AMQP_BEGIN_DECLS + +/** + * Create a new SSL/TLS socket object. + * + * \return A new socket object or NULL if an error occurred. + */ +AMQP_PUBLIC_FUNCTION +amqp_socket_t * +AMQP_CALL +amqp_ssl_socket_new(void); + +/** + * Set the CA certificate. + * + * \param [in,out] self An SSL/TLS socket object. + * \param [in] cacert Path to the CA cert file in PEM format. + * + * \return Zero if successful, -1 otherwise. + */ +AMQP_PUBLIC_FUNCTION +int +AMQP_CALL +amqp_ssl_socket_set_cacert(amqp_socket_t *self, + const char *cacert); + +/** + * Set the client key. + * + * \param [in,out] self An SSL/TLS socket object. + * \param [in] cert Path to the client certificate in PEM foramt. + * \param [in] key Path to the client key in PEM format. + * + * \return Zero if successful, -1 otherwise. + */ +AMQP_PUBLIC_FUNCTION +int +AMQP_CALL +amqp_ssl_socket_set_key(amqp_socket_t *self, + const char *cert, + const char *key); + +/** + * Set the client key from a buffer. + * + * \param [in,out] self An SSL/TLS socket object. + * \param [in] cert Path to the client certificate in PEM foramt. + * \param [in] key A buffer containing client key in PEM format. + * \param [in] n The length of the buffer. + * + * \return Zero if successful, -1 otherwise. + */ +AMQP_PUBLIC_FUNCTION +int +AMQP_CALL +amqp_ssl_socket_set_key_buffer(amqp_socket_t *self, + const char *cert, + const void *key, + size_t n); + +/** + * Enable or disable peer verification. + * + * If peer verification is enabled then the common name in the server + * certificate must match the server name. + * + * \param [in,out] self An SSL/TLS socket object. + * \param [in] verify Enable or disable peer verification. + */ +AMQP_PUBLIC_FUNCTION +void +AMQP_CALL +amqp_ssl_socket_set_verify(amqp_socket_t *self, + amqp_boolean_t verify); + +/** + * Sets whether rabbitmq-c initializes the underlying SSL library. + * + * For SSL libraries that require a one-time initialization across + * a whole program (e.g., OpenSSL) this sets whether or not rabbitmq-c + * will initialize the SSL library when the first call to + * amqp_open_ssl_socket() is made. You should call this function with + * do_init = 0 if the underlying SSL library is intialized somewhere else + * the program. + * + * Failing to initialize or double initialization of the SSL library will + * result in undefined behavior + * + * By default rabbitmq-c will initialize the underlying SSL library + * + * NOTE: calling this function after the first socket has been opened with + * amqp_open_ssl_socket() will not have any effect. + * + * \param [in] do_initalize If 0 rabbitmq-c will not initialize the SSL + * library, otherwise rabbitmq-c will initialize the + * SL library + * + */ +AMQP_PUBLIC_FUNCTION +void +AMQP_CALL +amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize); + +AMQP_END_DECLS + +#endif /* AMQP_SSL_H */ diff --git a/librabbitmq/amqp_tcp_socket.c b/librabbitmq/amqp_tcp_socket.c new file mode 100644 index 0000000..84d8554 --- /dev/null +++ b/librabbitmq/amqp_tcp_socket.c @@ -0,0 +1,125 @@ +/* + * Copyright 2012 Michael Steinert + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "amqp_private.h" +#include "amqp_tcp_socket.h" +#include +#include + +struct amqp_tcp_socket_t { + const struct amqp_socket_class_t *klass; + int sockfd; +}; + +static ssize_t +amqp_tcp_socket_writev(void *base, const struct iovec *iov, int iovcnt) +{ + struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; + return amqp_os_socket_writev(self->sockfd, iov, iovcnt); +} + +static ssize_t +amqp_tcp_socket_send(void *base, const void *buf, size_t len, int flags) +{ + struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; + return send(self->sockfd, buf, len, flags); +} + +static ssize_t +amqp_tcp_socket_recv(void *base, void *buf, size_t len, int flags) +{ + struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; + return recv(self->sockfd, buf, len, flags); +} + +static int +amqp_tcp_socket_open(void *base, const char *host, int port) +{ + struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; + self->sockfd = amqp_open_socket(host, port); + if (0 > self->sockfd) { + return -1; + } + return 0; +} + +static int +amqp_tcp_socket_close(void *base) +{ + struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; + int status = -1; + if (self) { + status = amqp_os_socket_close(self->sockfd); + free(self); + } + return status; +} + +static int +amqp_tcp_socket_error(AMQP_UNUSED void *base) +{ + return amqp_os_socket_error(); +} + +static int +amqp_tcp_socket_get_sockfd(void *base) +{ + struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; + return self->sockfd; +} + +static const struct amqp_socket_class_t amqp_tcp_socket_class = { + amqp_tcp_socket_writev, /* writev */ + amqp_tcp_socket_send, /* send */ + amqp_tcp_socket_recv, /* recv */ + amqp_tcp_socket_open, /* open */ + amqp_tcp_socket_close, /* close */ + amqp_tcp_socket_error, /* error */ + amqp_tcp_socket_get_sockfd /* get_sockfd */ +}; + +amqp_socket_t * +amqp_tcp_socket_new(void) +{ + struct amqp_tcp_socket_t *self = calloc(1, sizeof(*self)); + if (!self) { + return NULL; + } + self->klass = &amqp_tcp_socket_class; + self->sockfd = -1; + return (amqp_socket_t *)self; +} + +void +amqp_tcp_socket_set_sockfd(amqp_socket_t *base, int sockfd) +{ + struct amqp_tcp_socket_t *self; + if (base->klass != &amqp_tcp_socket_class) { + amqp_abort("<%p> is not of type amqp_tcp_socket_t", base); + } + self = (struct amqp_tcp_socket_t *)base; + self->sockfd = sockfd; +} diff --git a/librabbitmq/amqp_tcp_socket.h b/librabbitmq/amqp_tcp_socket.h new file mode 100644 index 0000000..6e0afa0 --- /dev/null +++ b/librabbitmq/amqp_tcp_socket.h @@ -0,0 +1,55 @@ +/* + * Copyright 2012 Michael Steinert + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef AMQP_TCP_SOCKET_H +#define AMQP_TCP_SOCKET_H + +#include + +AMQP_BEGIN_DECLS + +/** + * Create a new TCP socket. + * + * \return A new socket object or NULL if an error occurred. + */ +AMQP_PUBLIC_FUNCTION +amqp_socket_t * +AMQP_CALL +amqp_tcp_socket_new(void); + +/** + * Assign an open file descriptor to a socket object. + * + * This function must not be used in conjunction with amqp_socket_open(). + * + * \param [in,out] self A TCP socket object. + * \param [in] sockfd An open socket descriptor. + */ +AMQP_PUBLIC_FUNCTION +void +AMQP_CALL +amqp_tcp_socket_set_sockfd(amqp_socket_t *base, int sockfd); + +AMQP_END_DECLS + +#endif /* AMQP_TCP_SOCKET_H */ diff --git a/tools/common.c b/tools/common.c index abfba4b..c1844ae 100644 --- a/tools/common.c +++ b/tools/common.c @@ -40,9 +40,9 @@ #include "common.h" #ifdef WITH_SSL -#include +#include #endif -#include +#include #include #include #include -- cgit v1.2.1