You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kg...@apache.org on 2012/08/10 20:15:10 UTC
svn commit: r1371798 - in /qpid/proton/branches/driver_abstraction/proton-c:
./ src/ src/drivers/
Author: kgiusti
Date: Fri Aug 10 18:15:10 2012
New Revision: 1371798
URL: http://svn.apache.org/viewvc?rev=1371798&view=rev
Log:
checkpoint - it compiles
Added:
qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c (with props)
qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c (contents, props changed)
- copied, changed from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_poll.c
qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c (contents, props changed)
- copied, changed from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_select.c
qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h (with props)
qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c (contents, props changed)
- copied, changed from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c
Removed:
qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c
qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_openssl.c
qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_poll.c
qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_select.c
Modified:
qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt
qpid/proton/branches/driver_abstraction/proton-c/src/driver.c
qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h
Modified: qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt?rev=1371798&r1=1371797&r2=1371798&view=diff
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt (original)
+++ qpid/proton/branches/driver_abstraction/proton-c/CMakeLists.txt Fri Aug 10 18:15:10 2012
@@ -50,20 +50,20 @@ add_custom_command (
if (POLLER STREQUAL poll)
set (pn_driver_impl
- src/drivers/driver_poll.c
+ src/drivers/poll.c
)
elseif (POLLER STREQUAL select)
set (pn_driver_impl
- src/drivers/driver_select.c
+ src/drivers/select.c
)
endif (POLLER STREQUAL poll)
# Link in openssl if present
if (SSL_IMPL STREQUAL openssl)
- set (pn_driver_ssl_impl src/drivers/driver_openssl.c)
+ set (pn_driver_ssl_impl src/drivers/openssl.c)
set (LINK_DEPS ${LINK_DEPS} ssl crypto)
else (SSL_IMPL STREQUAL openssl)
- set (pn_driver_ssl_impl src/drivers/driver_no_ssl.c)
+ set (pn_driver_ssl_impl src/drivers/ssl_stub.c)
endif (SSL_IMPL STREQUAL openssl)
Modified: qpid/proton/branches/driver_abstraction/proton-c/src/driver.c
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/driver.c?rev=1371798&r1=1371797&r2=1371798&view=diff
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/driver.c (original)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/driver.c Fri Aug 10 18:15:10 2012
@@ -25,6 +25,7 @@
#include <proton/sasl.h>
#include "util.h"
#include "driver_impl.h"
+#include "drivers/ssl.h"
#include <stdio.h>
#include <time.h>
@@ -168,6 +169,7 @@ pn_connector_t *pn_listener_accept(pn_li
pn_connector_t *c = pn_connector_fd(l->driver, sock, NULL);
snprintf(c->name, PN_CONNECTOR_NAME_MAX, "%s:%s", host, serv);
c->listener = l;
+ pn_listener_init_ssl_client( l, c ); // @todo KAG: deal with error case!!!
return c;
}
}
@@ -186,6 +188,7 @@ void pn_listener_free(pn_listener_t *l)
if (!l) return;
if (l->driver) pn_driver_remove_listener(l->driver, l);
+ pn_listener_free_ssl(l);
pn_listener_impl_destroy(l);
free(l);
}
@@ -282,6 +285,7 @@ pn_connector_t *pn_connector_fd(pn_drive
c->read = pn_connector_read;
c->write = pn_connector_write;
c->tick = pn_connector_tick;
+ c->io_handler = pn_io_handler;
c->input_size = 0;
c->input_eos = false;
c->output_size = 0;
@@ -368,10 +372,11 @@ void pn_connector_free(pn_connector_t *c
if (!ctor) return;
if (ctor->driver) pn_driver_remove_connector(ctor->driver, ctor);
+
+ pn_connector_impl_destroy(ctor);
ctor->connection = NULL;
ctor->transport = NULL;
pn_sasl_free(ctor->sasl);
- pn_connector_impl_destroy(ctor);
free(ctor);
}
@@ -592,21 +597,13 @@ void pn_connector_process(pn_connector_t
c->pending_tick = false;
}
- if (c->pending_read) {
- c->read(c);
- c->pending_read = false;
- }
- pn_connector_process_input(c);
- pn_connector_process_output(c);
- if (c->pending_write) {
- c->write(c);
- c->pending_write = false;
- }
+ c->io_handler(c);
+
if (c->output_size == 0 && c->input_done && c->output_done) {
if (c->trace & (PN_TRACE_FRM | PN_TRACE_RAW | PN_TRACE_DRV)) {
fprintf(stderr, "Closed %s\n", c->name);
}
- pn_connector_close(c);
+ pn_connector_shutdown_ssl(c); // AMQP finished, perform clean shutdown
}
}
}
@@ -672,7 +669,10 @@ void pn_driver_wakeup(pn_driver_t *d)
void pn_driver_wait(pn_driver_t *d, int timeout)
{
- pn_driver_impl_wait(d, timeout);
+ // if SSL/TlS has data available, no need to wait for I/O
+ if (!pn_driver_ssl_data_ready(d)) {
+ pn_driver_impl_wait(d, timeout);
+ }
d->listener_next = d->listener_head;
d->connector_next = d->connector_head;
}
@@ -707,3 +707,28 @@ pn_connector_t *pn_driver_connector(pn_d
return NULL;
}
+
+
+/** default I/O handling routine */
+int pn_io_handler(pn_connector_t *c)
+{
+ if (c->pending_read) {
+ c->read(c);
+ c->pending_read = false;
+ }
+ pn_connector_process_input(c);
+ pn_connector_process_output(c);
+ if (c->pending_write) {
+ c->write(c);
+ c->pending_write = false;
+ }
+ return 0;
+}
+
+/** stub handling routine */
+int pn_null_io_handler(pn_connector_t *c)
+{
+ return 0;
+}
+
+
Modified: qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h?rev=1371798&r1=1371797&r2=1371798&view=diff
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h (original)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/driver_impl.h Fri Aug 10 18:15:10 2012
@@ -84,6 +84,9 @@ struct pn_connector_t {
void (*read)(pn_connector_t *);
void (*write) (pn_connector_t *);
time_t (*tick)(pn_connector_t *sel, time_t now);
+
+ int (*io_handler)(pn_connector_t *);
+
size_t input_size;
char input[PN_CONNECTOR_IO_BUF_SIZE];
bool input_eos;
@@ -105,8 +108,9 @@ struct pn_connector_t {
int pn_connector_impl_init( struct pn_connector_t *);
void pn_connector_impl_destroy( struct pn_connector_t *);
-
void pn_driver_impl_wait(struct pn_driver_t *, int timeout_ms);
+int pn_io_handler(pn_connector_t *);
+int pn_null_io_handler(pn_connector_t *);
#endif /* driver.h */
Added: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c?rev=1371798&view=auto
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c (added)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c Fri Aug 10 18:15:10 2012
@@ -0,0 +1,744 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#define _POSIX_C_SOURCE 1
+
+#include <proton/driver.h>
+#include "../driver_impl.h"
+#include "../util.h"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <sys/socket.h>
+
+
+/** @file
+ * SSL/TLS support API.
+ *
+ * This file contains stub implementations of the SSL/TLS API. This implementation is
+ * used if there is no SSL/TLS support in the system's environment.
+ */
+
+static int ssl_initialized;
+
+struct pn_listener_ssl_impl_t {
+ SSL_CTX *ctx;
+ bool allow_unsecured;
+ bool ca_db;
+ char *keyfile_pw;
+};
+typedef struct pn_listener_ssl_impl_t pn_listener_ssl_impl_t;
+
+
+struct pn_connector_ssl_impl_t {
+
+ enum { SSL_CLIENT, SSL_SERVER } mode;
+ SSL_CTX *ctx; // NULL if mode=SSL_SERVER - uses listener's ctx
+ SSL *ssl;
+ BIO *sbio;
+ char *keyfile_pw;
+ bool read_stalled; // SSL has data to read, but client buffer is full.
+};
+typedef struct pn_connector_ssl_impl_t pn_connector_ssl_impl_t;
+
+/* */
+static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata);
+static int configure_ca_database(SSL_CTX *ctx, const char *certificate_db);
+static int start_check_for_ssl( pn_connector_t *client );
+static int handle_check_for_ssl( pn_connector_t *client );
+static int start_ssl_connect(pn_connector_t *client);
+static int handle_ssl_connect( pn_connector_t *client );
+static int start_ssl_accept(pn_connector_t *client);
+static int handle_ssl_accept(pn_connector_t *client);
+static int start_ssl_connection_up( pn_connector_t *c );
+static int handle_ssl_connection_up( pn_connector_t *c );
+static int start_clear_connected( pn_connector_t *c );
+static int start_ssl_shutdown( pn_connector_t *c );
+static int handle_ssl_shutdown( pn_connector_t *c );
+
+/** Public API - visible to application code */
+
+int pn_listener_ssl_server_init(pn_listener_t *listener,
+ const char *certificate_file,
+ const char *private_key_file,
+ const char *password,
+ const char *certificate_db)
+{
+ listener->ssl = calloc(1, sizeof(pn_listener_ssl_impl_t));
+ // note: see pn_listener_free_ssl for cleanup/deallocation
+ if (!listener->ssl) {
+ perror("calloc()");
+ return -1;
+ }
+ pn_listener_ssl_impl_t *impl = listener->ssl;
+
+ if (!ssl_initialized) {
+ ssl_initialized = 1;
+ SSL_library_init();
+ }
+
+ impl->ctx = SSL_CTX_new(SSLv23_server_method());
+ if (!impl->ctx) {
+ perror("unable to initialize SSL context");
+ return -2;
+ }
+
+ if (SSL_CTX_use_certificate_chain_file(impl->ctx, certificate_file) != 1) {
+ fprintf(stderr, "SSL_CTX_use_certificate_chain_file( %s ) failed\n", certificate_file);
+ return -3;
+ }
+
+ if (password) {
+ impl->keyfile_pw = pn_strdup(password); // @todo: obfuscate me!!!
+ SSL_CTX_set_default_passwd_cb(impl->ctx, keyfile_pw_cb);
+ SSL_CTX_set_default_passwd_cb_userdata(impl->ctx, impl->keyfile_pw);
+ }
+
+ if (SSL_CTX_use_PrivateKey_file(impl->ctx, private_key_file, SSL_FILETYPE_PEM) != 1) {
+ fprintf(stderr, "SSL_CTX_use_PrivateKey_file( %s ) failed\n", private_key_file);
+ return -4;
+ }
+
+ if (certificate_db) {
+ impl->ca_db = true;
+ if (configure_ca_database(impl->ctx, certificate_db)) {
+ return -5;
+ }
+ }
+ return 0;
+}
+
+
+int pn_listener_ssl_allow_unsecured_clients(pn_listener_t *listener)
+{
+ if (!listener->ssl) {
+ fprintf(stderr, "SSL not initialized");
+ return -1;
+ }
+
+ listener->ssl->allow_unsecured = true;
+ return 0;
+}
+
+
+
+int pn_connector_ssl_client_init(pn_connector_t *connector,
+ const char *certificate_db)
+{
+ connector->ssl = calloc(1, sizeof(pn_connector_ssl_impl_t));
+ if (!connector->ssl) {
+ perror("calloc()");
+ return -1;
+ }
+ pn_connector_ssl_impl_t *impl = connector->ssl;
+
+ impl->mode = SSL_CLIENT;
+
+ if (!ssl_initialized) {
+ ssl_initialized = 1;
+ SSL_library_init();
+ }
+
+ impl->ctx = SSL_CTX_new(SSLv23_client_method());
+ if (!impl->ctx) {
+ perror("unable to initialize SSL context");
+ return -2;
+ }
+
+ if (configure_ca_database(impl->ctx, certificate_db)) {
+ return -3;
+ }
+
+ /* Force servers to authenticate */
+ SSL_CTX_set_verify( connector->ssl->ctx,
+ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ 0 /*?verify callback?*/ );
+
+#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
+ SSL_CTX_set_verify_depth(connector->ssl->ctx, 1);
+#endif
+
+ /* make the socket nonblocking*/
+ int flags = fcntl(connector->fd, F_GETFL, 0);
+
+ flags |= O_NONBLOCK;
+ if (fcntl(connector->fd, F_SETFL, flags)) {
+ // @todo: better error handling - fail this connection
+ perror("fcntl");
+ return -1;
+ }
+
+ return start_ssl_connect( connector ); // start connecting!
+}
+
+
+int pn_connector_ssl_set_client_auth(pn_connector_t *connector,
+ const char *certificate_file,
+ const char *private_key_file,
+ const char *password)
+{
+ // @todo check state to verify not yet connected!
+
+ pn_connector_ssl_impl_t *impl = connector->ssl;
+
+ if (!impl || impl->mode != SSL_CLIENT) {
+ fprintf(stderr, "Error: connector not configured as SSL client.\n");
+ return -1;
+ }
+
+ if (SSL_CTX_use_certificate_chain_file(impl->ctx, certificate_file) != 1) {
+ fprintf(stderr, "SSL_CTX_use_certificate_chain_file( %s ) failed\n", certificate_file);
+ return -3;
+ }
+
+ if (password) {
+ impl->keyfile_pw = pn_strdup(password); // @todo: obfuscate me!!!
+ SSL_CTX_set_default_passwd_cb(impl->ctx, keyfile_pw_cb);
+ SSL_CTX_set_default_passwd_cb_userdata(impl->ctx, impl->keyfile_pw);
+ }
+
+ if (SSL_CTX_use_PrivateKey_file(impl->ctx, private_key_file, SSL_FILETYPE_PEM) != 1) {
+ fprintf(stderr, "SSL_CTX_use_PrivateKey_file( %s ) failed\n", private_key_file);
+ return -4;
+ }
+
+ return 0;
+}
+
+
+int pn_connector_ssl_authenticate_client(pn_connector_t *connector,
+ const char *trusted_CAs_file)
+{
+ pn_connector_ssl_impl_t *impl = connector->ssl;
+
+ if (!impl || impl->mode != SSL_SERVER) {
+ fprintf(stderr, "Error: connector not configured as SSL server.\n");
+ }
+
+ // @todo: make sure certificate_db is set...
+
+
+ // load the CA's that we trust - this will be sent to the client when client
+ // authentication is requested
+ STACK_OF(X509_NAME) *cert_names;
+ cert_names = SSL_load_client_CA_file( trusted_CAs_file );
+ if (cert_names != NULL)
+ SSL_set_client_CA_list(impl->ssl, cert_names);
+ else {
+ fprintf(stderr, "Unable to process file of trusted_CAs: %s\n", trusted_CAs_file);
+ return -1;
+ }
+
+ SSL_set_verify( impl->ssl,
+ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ 0 /*?verify callback?*/);
+ return 0;
+}
+
+
+/** Abstraction API - visible to Driver only - see ssl.h */
+
+
+int pn_driver_ssl_data_ready( pn_driver_t *d )
+{
+ int ready = 0;
+
+ // check if any stalled readers exist, and if they have buffer space available.
+ pn_connector_t *c = d->connector_head;
+ while (c) {
+ if (!c->closed && c->ssl) {
+ pn_connector_ssl_impl_t *impl = c->ssl;
+ if (impl->read_stalled && (c->input_size < PN_CONNECTOR_IO_BUF_SIZE)) {
+ impl->read_stalled = 0;
+ c->pending_read = true;
+ ready += 1;
+ }
+ }
+ c = c->connector_next;
+ }
+ return ready;
+}
+
+
+int pn_listener_init_ssl_client( pn_listener_t *l, pn_connector_t *c)
+{
+ if (!l->ssl) return 0;
+ assert(!c->ssl);
+
+ c->ssl = calloc(1, sizeof(pn_connector_ssl_impl_t));
+ if (!c->ssl) {
+ perror("calloc()");
+ return -1;
+ }
+ pn_connector_ssl_impl_t *impl = c->ssl;
+
+ impl->mode = SSL_SERVER;
+ impl->ctx = NULL; // share the acceptor's context
+
+ /* make the socket nonblocking*/
+ int flags = fcntl(c->fd, F_GETFL, 0);
+
+ flags |= O_NONBLOCK;
+ if (fcntl(c->fd, F_SETFL, flags)) {
+ // @todo: better error handling - fail this connection
+ perror("fcntl");
+ return -1;
+ }
+
+ if (l->ssl->allow_unsecured) {
+ return start_check_for_ssl(c);
+ } else {
+ return start_ssl_accept(c);
+ }
+}
+
+void pn_connector_shutdown_ssl( pn_connector_t *c)
+{
+ if (c->ssl) {
+ if (start_ssl_shutdown(c) == 0)
+ return; // shutting down
+ }
+ // if no ssl or shutdown fails, just close the underlying socket
+ pn_connector_close(c);
+}
+
+void pn_listener_free_ssl( pn_listener_t *l )
+{
+ if (l->ssl) {
+ pn_listener_ssl_impl_t *impl = l->ssl;
+ // note: ctx is referenced counted - will not actually free until all child SSL
+ // connections are freed.
+ if (impl->ctx) SSL_CTX_free(impl->ctx);
+ if (impl->keyfile_pw) {
+ memset( impl->keyfile_pw, 0, strlen( impl->keyfile_pw ) );
+ free( impl->keyfile_pw );
+ }
+ free(l->ssl);
+ l->ssl = NULL;
+ }
+}
+
+
+void pn_connector_free_ssl( pn_connector_t *c )
+{
+ if (c->ssl) {
+ pn_connector_ssl_impl_t *impl = c->ssl;
+ if (impl->ssl) SSL_free(impl->ssl);
+ if (impl->sbio) BIO_free(impl->sbio);
+ if (impl->ctx) SSL_CTX_free(impl->ctx);
+ if (impl->keyfile_pw) {
+ memset( impl->keyfile_pw, 0, strlen( impl->keyfile_pw ) );
+ free( impl->keyfile_pw );
+ }
+ free(c->ssl);
+ c->ssl = NULL;
+ }
+}
+
+
+/** Private: */
+
+static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata)
+{
+ strncpy(buf, (char *)userdata, size); // @todo: un-obfuscate me!!!
+ buf[size - 1] = '\0';
+ return(strlen(buf));
+}
+
+
+// Configure the database containing trusted CA certificates
+static int configure_ca_database(SSL_CTX *ctx, const char *certificate_db)
+{
+ // certificates can be either a file or a directory, which determines how it is passed
+ // to SSL_CTX_load_verify_locations()
+ struct stat sbuf;
+ if (stat( certificate_db, &sbuf ) != 0) {
+ fprintf(stderr, "stat(%s) failed: %s\n", certificate_db, strerror(errno));
+ return -1;
+ }
+ const char *file;
+ const char *dir;
+ if (S_ISDIR(sbuf.st_mode)) {
+ dir = certificate_db;
+ file = NULL;
+ } else {
+ dir = NULL;
+ file = certificate_db;
+ }
+
+ if (SSL_CTX_load_verify_locations( ctx, file, dir ) != 1) {
+ fprintf(stderr, "SSL_CTX_load_verify_locations( %s ) failed\n", certificate_db);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+
+/* STATE: check_for_ssl
+ *
+ * The server will allow both encrypted and non-encrypted clients. Determine if
+ * encryption is being used by peeking at the first few bytes of incoming data.
+ */
+
+static int start_check_for_ssl( pn_connector_t *client )
+{
+ client->status |= PN_SEL_RD;
+ client->io_handler = handle_check_for_ssl;
+ return 0;
+}
+
+
+static int handle_check_for_ssl( pn_connector_t *client )
+{
+ unsigned char buf[5];
+ int rc;
+ int retries = 3;
+
+ do {
+ rc = recv(client->fd, buf, sizeof(buf), MSG_PEEK);
+ if (rc == sizeof(buf))
+ break;
+ if (rc < 0 && errno != EINTR && errno != EAGAIN) {
+ perror("handle_check_for_ssl() recv failed:");
+ break;
+ }
+ } while (retries-- > 0);
+
+ if (rc == sizeof(buf)) {
+ /*
+ * SSLv2 Client Hello format
+ * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
+ *
+ * Bytes 0-1: RECORD-LENGTH
+ * Byte 2: MSG-CLIENT-HELLO (1)
+ * Byte 3: CLIENT-VERSION-MSB
+ * Byte 4: CLIENT-VERSION-LSB
+ *
+ * Allowed versions:
+ * 2.0 - SSLv2
+ * 3.0 - SSLv3
+ * 3.1 - TLS 1.0
+ * 3.2 - TLS 1.1
+ * 3.3 - TLS 1.2
+ *
+ * The version sent in the Client-Hello is the latest version supported by
+ * the client. NSS may send version 3.x in an SSLv2 header for
+ * maximum compatibility.
+ */
+ int isSSL2Handshake = buf[2] == 1 && // MSG-CLIENT-HELLO
+ ((buf[3] == 3 && buf[4] <= 3) || // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+ (buf[3] == 2 && buf[4] == 0)); // SSL 2
+
+ /*
+ * SSLv3/TLS Client Hello format
+ * RFC 2246
+ *
+ * Byte 0: ContentType (handshake - 22)
+ * Bytes 1-2: ProtocolVersion {major, minor}
+ *
+ * Allowed versions:
+ * 3.0 - SSLv3
+ * 3.1 - TLS 1.0
+ * 3.2 - TLS 1.1
+ * 3.3 - TLS 1.2
+ */
+ int isSSL3Handshake = buf[0] == 22 && // handshake
+ (buf[1] == 3 && buf[2] <= 3); // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
+
+ if (isSSL2Handshake || isSSL3Handshake) {
+ if (client->driver->trace & PN_TRACE_DRV) fprintf(stderr, "Connector %s using encryption.\n", client->name);
+ return start_ssl_accept( client );
+ }
+ }
+ if (client->driver->trace & PN_TRACE_DRV) fprintf(stderr, "Connector %s not using encryption.\n", client->name);
+ return start_clear_connected( client );
+}
+
+
+/* STATE: ssl_connect
+ *
+ * Start the SSL connection to the server. This will require I/O to complete the
+ * handshake.
+ */
+static int start_ssl_connect(pn_connector_t *client)
+{
+ pn_connector_ssl_impl_t *impl = client->ssl;
+ if (!impl) return -1;
+
+ impl->ssl = SSL_new(impl->ctx);
+ impl->sbio = BIO_new_socket( client->fd, BIO_NOCLOSE );
+ SSL_set_bio(impl->ssl, impl->sbio, impl->sbio);
+#if 0
+ // @todo reconnect support
+ if (conn->reconnecting && conn->session) {
+ printf("Resuming old session...\n");
+ SSL_set_session(conn->ssl, conn->session);
+ SSL_SESSION_free(conn->session);
+ conn->session = NULL;
+ }
+#endif
+ return handle_ssl_connect(client);
+}
+
+
+int handle_ssl_connect( pn_connector_t *client )
+{
+ pn_connector_ssl_impl_t *impl = client->ssl;
+ if (!impl) return -1;
+
+ int rc = SSL_connect( impl->ssl );
+ switch (SSL_get_error( impl->ssl, rc )) {
+ case SSL_ERROR_NONE:
+ // connection completed
+ return start_ssl_connection_up( client );
+
+ case SSL_ERROR_WANT_READ:
+ printf(" need read...\n");
+ client->status |= PN_SEL_RD;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ printf(" need write...\n");
+ client->status |= PN_SEL_WR;
+ break;
+ default:
+ fprintf(stderr, "SSL_connect() failure");
+ return -1;
+ }
+
+ client->io_handler = handle_ssl_connect;
+ return 0;
+}
+
+
+
+/* STATE: ssl_accept
+ *
+ * Accept the client connection. This may require I/O to complete the handshake.
+ */
+
+static int start_ssl_accept(pn_connector_t *client)
+{
+ pn_connector_ssl_impl_t *impl = client->ssl;
+ if (!impl) return -1;
+
+ impl->sbio = BIO_new_socket(client->fd, BIO_NOCLOSE);
+ impl->ssl = SSL_new(impl->ctx);
+ SSL_set_bio(impl->ssl, impl->sbio, impl->sbio);
+
+ return handle_ssl_accept(client);
+}
+
+static int handle_ssl_accept(pn_connector_t *client)
+{
+ pn_connector_ssl_impl_t *impl = client->ssl;
+ if (!impl) return -1;
+
+ int rc = SSL_accept(impl->ssl);
+ switch (SSL_get_error(impl->ssl, rc)) {
+ case SSL_ERROR_NONE:
+ // connection completed
+ return start_ssl_connection_up( client );
+
+ case SSL_ERROR_WANT_READ:
+ printf(" need read...\n");
+ client->status |= PN_SEL_RD;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ printf(" need write...\n");
+ client->status |= PN_SEL_WR;
+ break;
+ default:
+ fprintf(stderr, "SSL_accept() failure\n");
+ return -1;
+ }
+ client->io_handler = handle_ssl_accept;
+ return 0;
+}
+
+
+/* STATE: ssl_connection_up
+ *
+ * The SSL connection is up and data is passing!
+ */
+int start_ssl_connection_up( pn_connector_t *c )
+{
+ printf("ssl_connection_up\n");
+ c->io_handler = handle_ssl_connection_up;
+ c->status |= PN_SEL_RD;
+ return 0;
+}
+
+
+int handle_ssl_connection_up( pn_connector_t *c )
+{
+ int rc;
+ int ssl_err;
+ int read_blocked = 0;
+ int write_blocked = 0;
+ int need_read = 0;
+ int need_write = 0;
+ int input_space;
+ pn_connector_ssl_impl_t *impl = c->ssl;
+ assert(impl);
+
+ printf("handle_ssl_connection_up\n");
+
+ c->status &= ~(PN_SEL_RD | PN_SEL_WR);
+
+ do {
+ input_space = PN_CONNECTOR_IO_BUF_SIZE - c->input_size;
+ if (!read_blocked && input_space > 0) {
+ rc = SSL_read(impl->ssl, &c->input[c->input_size], input_space);
+ printf("read %d possible bytes: actual = %d\n", input_space, rc);
+ ssl_err = SSL_get_error( impl->ssl, rc );
+ if (ssl_err == SSL_ERROR_NONE) {
+ c->input_size += rc;
+ printf("... read bytes now =%d\n", (int)c->input_size);
+ } else if (ssl_err == SSL_ERROR_WANT_READ) {
+ // socket read blocked
+ printf("need read\n");
+ read_blocked = 1;
+ need_read = 1;
+ } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
+ printf("need write\n");
+ read_blocked = 1;
+ write_blocked = 1;
+ need_write = 1;
+ } else {
+ if (ssl_err == SSL_ERROR_ZERO_RETURN) {
+ /* remote shutdown */
+ printf("zero return (read)\n");
+ } else {
+ perror("Unexpected SSL read failure, errno:");
+ printf("- SSL read status: %d\n", ssl_err);
+ }
+ return start_ssl_shutdown(c);
+ }
+ }
+
+ // we need to re-call SSL_read when the receive buffer is drained (do not need to wait for I/O!)
+ if (!read_blocked && SSL_pending(impl->ssl) && PN_CONNECTOR_IO_BUF_SIZE == c->input_size) {
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!! >>>>> READ STALLED <<<<<< !!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ impl->read_stalled = true;
+ }
+
+ if (!write_blocked && c->output_size > 0) {
+
+ rc = SSL_write( impl->ssl, c->output, c->output_size );
+ ssl_err = SSL_get_error( impl->ssl, rc );
+ if (ssl_err == SSL_ERROR_NONE) {
+ c->output_size -= rc;
+ if (c->output_size > 0)
+ memmove(c->output, c->output + rc, c->output_size);
+ } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
+ /* We would have blocked */
+ printf("need write\n");
+ write_blocked = 1;
+ need_write = 1;
+ } else if (ssl_err == SSL_ERROR_WANT_READ) {
+ printf("need read\n");
+ read_blocked = 1;
+ write_blocked = 1;
+ need_read = 1;
+ } else {
+ if (ssl_err == SSL_ERROR_ZERO_RETURN)
+ printf("zero return (write)\n");
+ else {
+ perror("Unexpected SSL_write failure, errno:");
+ printf("- SSL write status: %d\n", ssl_err);
+ }
+ return start_ssl_shutdown(c);
+ }
+ }
+
+ } while ((!read_blocked && c->input_size < PN_CONNECTOR_IO_BUF_SIZE) ||
+ (!write_blocked && c->output_size));
+
+ if (need_read) c->status |= PN_SEL_RD;
+ if (need_write) c->status |= PN_SEL_WR;
+
+ return 0;
+}
+
+
+/* STATE: clear_connected
+ *
+ * The peer has connected without SSL (in the clear). Use the default I/O handler
+ */
+static int start_clear_connected( pn_connector_t *c )
+{
+ pn_connector_free_ssl( c );
+ c->io_handler = pn_io_handler;
+ return 0;
+}
+
+
+/* STATE: ssl_shutdown
+ *
+ * Shutting down the SSL connection.
+ */
+static int start_ssl_shutdown( pn_connector_t *c )
+{
+ return handle_ssl_shutdown( c );
+}
+
+static int handle_ssl_shutdown( pn_connector_t *c )
+{
+ int rc;
+ pn_connector_ssl_impl_t *impl = c->ssl;
+ if (!impl) return -1;
+
+ printf("handle_ssl_shutdown...\n");
+
+ do {
+ rc = SSL_shutdown( impl->ssl );
+ } while (rc == 0);
+
+ switch (SSL_get_error( impl->ssl, rc )) {
+ case SSL_ERROR_WANT_READ:
+ printf(" need read...\n");
+ c->status |= PN_SEL_RD;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ printf(" need write...\n");
+ c->status |= PN_SEL_WR;
+ break;
+ default: // whatever- consider us closed
+ case SSL_ERROR_NONE:
+ // shutdown completed
+ pn_connector_close( c );
+ return 0;
+ }
+ c->io_handler = handle_ssl_shutdown;
+ return 0;
+}
+
+
+
+
Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/openssl.c
------------------------------------------------------------------------------
svn:eol-style = native
Copied: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c (from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_poll.c)
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c?p2=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c&p1=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_poll.c&r1=1371797&r2=1371798&rev=1371798&view=diff
==============================================================================
(empty)
Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/poll.c
------------------------------------------------------------------------------
svn:eol-style = native
Copied: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c (from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_select.c)
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c?p2=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c&p1=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_select.c&r1=1371797&r2=1371798&rev=1371798&view=diff
==============================================================================
(empty)
Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/select.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h?rev=1371798&view=auto
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h (added)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h Fri Aug 10 18:15:10 2012
@@ -0,0 +1,75 @@
+#ifndef PROTON_SRC_DRIVERS_SSL_H
+#define PROTON_SRC_DRIVERS_SSL_H 1
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#define _POSIX_C_SOURCE 1
+
+/** @file
+ * Internal API for SSL/TLS support in the Driver Layer.
+ *
+ * Generic API to abstract the implementation of SSL/TLS from the Driver codebase.
+ *
+ */
+
+
+/** Configure SSL/TLS on a connector that has just been accepted on the given listener.
+ *
+ * @param[in,out] l the listener that has accepted the connnector c.
+ * @param[in,out] c the connector that will be configured for SSL/TLS (client mode).
+ * @return 0 on success, else an error code if SSL/TLS cannot be configured.
+ */
+int pn_listener_init_ssl_client( pn_listener_t *l, pn_connector_t *c);
+
+
+/** Start the SSL/TLS shutdown handshake.
+ *
+ * The SSL/TLS shutdown involves a protocol handshake. This call will initiate the
+ * shutdown process, which may not complete on return from this function. Once the
+ * handshake is completed, the connector will be closed and pn_connector_closed() will
+ * return TRUE.
+ *
+ * @param[in,out] c the connector to shutdown.
+ */
+void pn_connector_shutdown_ssl( pn_connector_t *c);
+
+
+/** Release any SSL/TLS related resources used by the listener.
+ *
+ * @param[in,out] l the listener to clean up.
+ */
+void pn_listener_free_ssl( pn_listener_t *l);
+
+
+/** Release any SSL/TLS related resources used by the connector.
+ *
+ * @param[in,out] c the connector to clean up.
+ */
+void pn_connector_free_ssl( pn_connector_t *c);
+
+/** Check if the SSL/TLS layer has data ready for reading or writing
+ *
+ * @param[in] d the driver
+ * @return 0 if no data ready, else !0
+ */
+int pn_driver_ssl_data_ready( pn_driver_t *d );
+
+#endif /* ssl.h */
Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl.h
------------------------------------------------------------------------------
svn:eol-style = native
Copied: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c (from r1371797, qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c)
URL: http://svn.apache.org/viewvc/qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c?p2=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c&p1=qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c&r1=1371797&r2=1371798&rev=1371798&view=diff
==============================================================================
--- qpid/proton/branches/driver_abstraction/proton-c/src/drivers/driver_no_ssl.c (original)
+++ qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c Fri Aug 10 18:15:10 2012
@@ -22,6 +22,7 @@
#define _POSIX_C_SOURCE 1
#include <proton/driver.h>
+#include "ssl.h"
/** @file
@@ -65,3 +66,29 @@ int pn_connector_ssl_authenticate_peer(p
{
return -1;
}
+
+int pn_listener_init_ssl_client( pn_listener_t *l, pn_connector_t *c)
+{
+ return 0; // support routine - always succeed.
+}
+
+void pn_connector_shutdown_ssl( pn_connector_t *c)
+{
+ // since there's no SSL/TLS, we just close the connector
+ pn_connector_close( c );
+}
+
+
+void pn_listener_free_ssl( pn_listener_t * )
+{
+}
+
+
+void pn_connector_free_ssl( pn_connector_t * )
+{
+}
+
+int pn_driver_ssl_data_ready( pn_driver_t * )
+{
+ return 0;
+}
Propchange: qpid/proton/branches/driver_abstraction/proton-c/src/drivers/ssl_stub.c
------------------------------------------------------------------------------
svn:eol-style = native
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org