You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kw...@apache.org on 2013/01/08 09:29:32 UTC
svn commit: r1430167 [2/3] - in /qpid/proton/branches/jni-binding: ./ bin/
proton-c/ proton-c/bindings/perl/ proton-c/bindings/php/
proton-c/bindings/python/ proton-c/bindings/ruby/
proton-c/bindings/ruby/lib/qpid_proton/ proton-c/include/proton/ proto...
Modified: qpid/proton/branches/jni-binding/proton-c/src/ssl/openssl.c
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-c/src/ssl/openssl.c?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-c/src/ssl/openssl.c (original)
+++ qpid/proton/branches/jni-binding/proton-c/src/ssl/openssl.c Tue Jan 8 08:29:31 2013
@@ -23,11 +23,13 @@
#include "./ssl-internal.h"
#include <proton/engine.h>
#include "../engine/engine-internal.h"
+#include "../platform.h"
#include "../util.h"
#include <openssl/ssl.h>
#include <openssl/dh.h>
#include <openssl/err.h>
+#include <openssl/x509v3.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -41,21 +43,39 @@
*/
static int ssl_initialized;
+static int ssl_ex_data_index;
typedef enum { UNKNOWN_CONNECTION, SSL_CONNECTION, CLEAR_CONNECTION } connection_mode_t;
+typedef struct pn_ssl_session_t pn_ssl_session_t;
-struct pn_ssl_t {
- SSL_CTX *ctx;
- SSL *ssl;
+struct pn_ssl_domain_t {
+ int ref_count;
+
+ SSL_CTX *ctx;
pn_ssl_mode_t mode;
- bool allow_unsecured; // allow non-SSL connections
+
bool has_ca_db; // true when CA database configured
bool has_certificate; // true when certificate configured
char *keyfile_pw;
- pn_ssl_verify_mode_t verify_mode;
+
+ // settings used for all connections
char *trusted_CAs;
+ pn_ssl_verify_mode_t verify_mode;
+ bool allow_unsecured;
+
+ // session cache
+ pn_ssl_session_t *ssn_cache_head;
+ pn_ssl_session_t *ssn_cache_tail;
+};
+
+
+struct pn_ssl_t {
- pn_transport_t *transport;
+ pn_transport_t *transport;
+ pn_ssl_domain_t *domain;
+ const char *session_id;
+ const char *peer_hostname;
+ SSL *ssl;
BIO *bio_ssl; // i/o from/to SSL socket layer
BIO *bio_ssl_io; // SSL "half" of network-facing BIO
@@ -82,6 +102,14 @@ struct pn_ssl_t {
pn_trace_t trace;
};
+struct pn_ssl_session_t {
+ const char *id;
+ SSL_SESSION *session;
+ pn_ssl_session_t *ssn_cache_next;
+ pn_ssl_session_t *ssn_cache_prev;
+};
+
+
// define two sets of allowable ciphers: those that require authentication, and those
// that do not require authentication (anonymous). See ciphers(1).
#define CIPHERS_AUTHENTICATE "ALL:!aNULL:!eNULL:@STRENGTH"
@@ -97,6 +125,9 @@ static ssize_t process_input_unknown(pn_
static ssize_t process_output_unknown(pn_transport_t *transport, char *input_data, size_t len);
static connection_mode_t check_for_ssl_connection( const char *data, size_t len );
static int init_ssl_socket( pn_ssl_t * );
+static void release_ssl_socket( pn_ssl_t * );
+static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
+static void ssl_session_free( pn_ssl_session_t *);
// @todo: used to avoid littering the code with calls to printf...
@@ -120,7 +151,7 @@ static void _log(pn_ssl_t *ssl, const ch
}
// log an error and dump the SSL error stack
-static void _log_ssl_error(pn_ssl_t *ssl, const char *fmt, ...)
+static void _log_ssl_error( const char *fmt, ...)
{
char buf[128]; // see "man ERR_error_string_n()"
va_list ap;
@@ -159,59 +190,148 @@ static int ssl_failed(pn_ssl_t *ssl)
if (ssl_err) {
ERR_error_string_n( ssl_err, buf, sizeof(buf) );
}
- _log_ssl_error(ssl, NULL); // spit out any remaining errors to the log file
+ _log_ssl_error(NULL); // spit out any remaining errors to the log file
return pn_error_format( ssl->transport->error, PN_ERR, "SSL Failure: %s", buf );
}
-// @todo replace with a "reasonable" default (?), allow application to register its own
-// callback.
-#if 0
+/* match the DNS name pattern from the peer certificate against our configured peer
+ hostname */
+static bool match_dns_pattern( const char *hostname,
+ const char *pattern, int plen )
+{
+
+ if (memchr( pattern, '*', plen ) == NULL)
+ return (plen == strlen(hostname) &&
+ strncasecmp( pattern, hostname, plen ) == 0);
+
+ /* dns wildcarded pattern - RFC2818 */
+ char plabel[64]; /* max label length < 63 - RFC1034 */
+ char slabel[64];
+ int slen = strlen(hostname);
+
+ while (plen > 0 && slen > 0) {
+ const char *cptr;
+ int len;
+
+ cptr = memchr( pattern, '.', plen );
+ len = (cptr) ? cptr - pattern : plen;
+ if (len > sizeof(plabel) - 1) return false;
+ memcpy( plabel, pattern, len );
+ plabel[len] = 0;
+ pattern = cptr + 1;
+ plen -= len;
+
+ cptr = memchr( hostname, '.', slen );
+ len = (cptr) ? cptr - hostname : slen;
+ if (len > sizeof(slabel) - 1) return false;
+ memcpy( slabel, hostname, len );
+ slabel[len] = 0;
+ hostname = cptr + 1;
+ slen -= len;
+
+ char *star = strchr( plabel, '*' );
+ if (!star) {
+ if (strcasecmp( plabel, slabel )) return false;
+ } else {
+ *star = '\0';
+ char *prefix = plabel;
+ int prefix_len = strlen(prefix);
+ char *suffix = star + 1;
+ int suffix_len = strlen(suffix);
+ if (prefix_len && strncasecmp( prefix, slabel, prefix_len )) return false;
+ if (suffix_len && strncasecmp( suffix,
+ slabel + (strlen(slabel) - suffix_len),
+ suffix_len )) return false;
+ }
+ }
+
+ return plen == slen;
+}
+
+// Certificate chain verification callback: return 1 if verified,
+// 0 if remote cannot be verified (fail handshake).
+//
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
- fprintf(stderr, "VERIFY_CALLBACK: pre-verify-ok=%d\n", preverify_ok);
+ if (!preverify_ok || X509_STORE_CTX_get_error_depth(ctx) != 0)
+ // already failed, or not at peer cert in chain
+ return preverify_ok;
+
+ X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
+ SSL *ssn = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ if (!ssn) {
+ _log_error("Error: unexpected error - SSL session info not available for peer verify!\n");
+ return 0; // fail connection
+ }
+
+ pn_ssl_t *ssl = (pn_ssl_t *)SSL_get_ex_data(ssn, ssl_ex_data_index);
+ if (!ssl) {
+ _log_error("Error: unexpected error - SSL context info not available for peer verify!\n");
+ return 0; // fail connection
+ }
+
+ if (ssl->domain->verify_mode != PN_SSL_VERIFY_PEER_NAME) return preverify_ok;
+ if (!ssl->peer_hostname) {
+ _log_error("Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!\n");
+ return 0; // fail connection
+ }
+
+ _log( ssl, "Checking identifying name in peer cert against '%s'\n", ssl->peer_hostname);
+
+ bool matched = false;
+
+ /* first check any SubjectAltName entries, as per RFC2818 */
+ GENERAL_NAMES *sans = (GENERAL_NAMES *) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+ if (sans) {
+ int name_ct = sk_GENERAL_NAME_num( sans );
+ int i;
+ for (i = 0; !matched && i < name_ct; ++i) {
+ GENERAL_NAME *name = sk_GENERAL_NAME_value( sans, i );
+ if (name->type == GEN_DNS) {
+ ASN1_STRING *asn1 = name->d.dNSName;
+ if (asn1 && asn1->data && asn1->length) {
+ unsigned char *str;
+ int len = ASN1_STRING_to_UTF8( &str, asn1 );
+ if (len >= 0) {
+ _log( ssl, "SubjectAltName (dns) from peer cert = '%.*s'\n", len, str );
+ matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len );
+ OPENSSL_free( str );
+ }
+ }
+ }
+ }
+ GENERAL_NAMES_free( sans );
+ }
- char buf[256];
- X509 *err_cert;
- int err, depth;
-
- err_cert = X509_STORE_CTX_get_current_cert(ctx);
- err = X509_STORE_CTX_get_error(ctx);
- depth = X509_STORE_CTX_get_error_depth(ctx);
-
- /*
- * Retrieve the pointer to the SSL of the connection currently treated
- * and the application specific data stored into the SSL object.
- */
-
- X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
-
- /*
- * Catch a too long certificate chain. The depth limit set using
- * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
- * that whenever the "depth>verify_depth" condition is met, we
- * have violated the limit and want to log this error condition.
- * We must do it here, because the CHAIN_TOO_LONG error would not
- * be found explicitly; only errors introduced by cutting off the
- * additional certificates would be logged.
- */
- if (!preverify_ok) {
- printf("verify error:num=%d:%s:depth=%d:%s\n", err,
- X509_verify_cert_error_string(err), depth, buf);
- }
-
- /*
- * At this point, err contains the last verification error. We can use
- * it for something special
- */
- if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
- {
- X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
- printf("issuer= %s\n", buf);
- }
+ /* if no general names match, try the CommonName from the subject */
+ X509_NAME *name = X509_get_subject_name(cert);
+ int i = -1;
+ while (!matched && (i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) {
+ X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i);
+ ASN1_STRING *name_asn1 = X509_NAME_ENTRY_get_data(ne);
+ if (name_asn1) {
+ unsigned char *str;
+ int len = ASN1_STRING_to_UTF8( &str, name_asn1);
+ if (len >= 0) {
+ _log( ssl, "commonName from peer cert = '%.*s'\n", len, str );
+ matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len );
+ OPENSSL_free(str);
+ }
+ }
+ }
- return 1;
-}
+ if (!matched) {
+ _log( ssl, "Error: no name matching %s found in peer cert - rejecting handshake.\n",
+ ssl->peer_hostname);
+ preverify_ok = 0;
+#ifdef X509_V_ERR_APPLICATION_VERIFICATION
+ X509_STORE_CTX_set_error( ctx, X509_V_ERR_APPLICATION_VERIFICATION );
#endif
+ } else {
+ _log( ssl, "Name from peer cert matched - peer is valid.\n" );
+ }
+ return preverify_ok;
+}
// this code was generated using the command:
@@ -255,66 +375,174 @@ static DH *get_dh2048()
return(dh);
}
+static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *domain, const char *id )
+{
+ pn_timestamp_t now_msec = pn_i_now();
+ long now_sec = (long)(now_msec / 1000);
+ pn_ssl_session_t *ssn = LL_HEAD( domain, ssn_cache );
+ while (ssn) {
+ long expire = SSL_SESSION_get_time( ssn->session )
+ + SSL_SESSION_get_timeout( ssn->session );
+ if (expire < now_sec) {
+ pn_ssl_session_t *next = ssn->ssn_cache_next;
+ LL_REMOVE( domain, ssn_cache, ssn );
+ ssl_session_free( ssn );
+ ssn = next;
+ continue;
+ }
+
+ if (!strcmp(ssn->id, id)) {
+ break;
+ }
+ ssn = ssn->ssn_cache_next;
+ }
+ return ssn;
+}
+
+static void ssl_session_free( pn_ssl_session_t *ssn)
+{
+ if (ssn) {
+ if (ssn->id) free( (void *)ssn->id );
+ if (ssn->session) SSL_SESSION_free( ssn->session );
+ free( ssn );
+ }
+}
+
/** Public API - visible to application code */
+pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
+{
+ if (!ssl_initialized) {
+ ssl_initialized = 1;
+ SSL_library_init();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+ ssl_ex_data_index = SSL_get_ex_new_index( 0, "org.apache.qpid.proton.ssl",
+ NULL, NULL, NULL);
+ }
-int pn_ssl_set_credentials( pn_ssl_t *ssl,
- const char *certificate_file,
- const char *private_key_file,
- const char *password)
+ pn_ssl_domain_t *domain = calloc(1, sizeof(pn_ssl_domain_t));
+ if (!domain) return NULL;
+
+ domain->ref_count = 1;
+ domain->mode = mode;
+ switch(mode) {
+ case PN_SSL_MODE_CLIENT:
+ domain->ctx = SSL_CTX_new(TLSv1_client_method());
+ if (!domain->ctx) {
+ _log_ssl_error( "Unable to initialize OpenSSL context.\n");
+ free(domain);
+ return NULL;
+ }
+ break;
+
+ case PN_SSL_MODE_SERVER:
+ domain->ctx = SSL_CTX_new(SSLv23_server_method());
+ if (!domain->ctx) {
+ _log_ssl_error("Unable to initialize OpenSSL context.\n");
+ free(domain);
+ return NULL;
+ }
+ SSL_CTX_set_options(domain->ctx, SSL_OP_NO_SSLv2); // v2 is insecure
+ break;
+
+ default:
+ _log_error("Invalid valid for pn_ssl_mode_t: %d\n", mode);
+ free(domain);
+ return NULL;
+ }
+
+ // by default, allow anonymous ciphers so certificates are not required 'out of the box'
+ if (!SSL_CTX_set_cipher_list( domain->ctx, CIPHERS_ANONYMOUS )) {
+ _log_ssl_error("Failed to set cipher list to %s\n", CIPHERS_ANONYMOUS);
+ pn_ssl_domain_free(domain);
+ return NULL;
+ }
+
+ // ditto: by default do not authenticate the peer (can be done by SASL).
+ if (pn_ssl_domain_set_peer_authentication( domain, PN_SSL_ANONYMOUS_PEER, NULL )) {
+ pn_ssl_domain_free(domain);
+ return NULL;
+ }
+
+ DH *dh = get_dh2048();
+ if (dh) {
+ SSL_CTX_set_tmp_dh(domain->ctx, dh);
+ DH_free(dh);
+ SSL_CTX_set_options(domain->ctx, SSL_OP_SINGLE_DH_USE);
+ }
+
+ return domain;
+}
+
+void pn_ssl_domain_free( pn_ssl_domain_t *domain )
{
- if (!ssl) return -1;
- if (ssl->ssl) {
- _log_error("Error: attempting to set credentials while SSL in use.\n");
- return -1;
+ if (--domain->ref_count == 0) {
+
+ pn_ssl_session_t *ssn = LL_HEAD( domain, ssn_cache );
+ while (ssn) {
+ pn_ssl_session_t *next = ssn->ssn_cache_next;
+ LL_REMOVE( domain, ssn_cache, ssn );
+ ssl_session_free( ssn );
+ ssn = next;
+ }
+
+ if (domain->ctx) SSL_CTX_free(domain->ctx);
+ if (domain->keyfile_pw) free(domain->keyfile_pw);
+ if (domain->trusted_CAs) free(domain->trusted_CAs);
+ free(domain);
}
+}
- if (SSL_CTX_use_certificate_chain_file(ssl->ctx, certificate_file) != 1) {
- _log_ssl_error(ssl, "SSL_CTX_use_certificate_chain_file( %s ) failed\n", certificate_file);
+
+int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
+ const char *certificate_file,
+ const char *private_key_file,
+ const char *password)
+{
+ if (!domain || !domain->ctx) return -1;
+
+ if (SSL_CTX_use_certificate_chain_file(domain->ctx, certificate_file) != 1) {
+ _log_ssl_error( "SSL_CTX_use_certificate_chain_file( %s ) failed\n", certificate_file);
return -3;
}
if (password) {
- ssl->keyfile_pw = pn_strdup(password); // @todo: obfuscate me!!!
- SSL_CTX_set_default_passwd_cb(ssl->ctx, keyfile_pw_cb);
- SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ssl->keyfile_pw);
+ domain->keyfile_pw = pn_strdup(password); // @todo: obfuscate me!!!
+ SSL_CTX_set_default_passwd_cb(domain->ctx, keyfile_pw_cb);
+ SSL_CTX_set_default_passwd_cb_userdata(domain->ctx, domain->keyfile_pw);
}
- if (SSL_CTX_use_PrivateKey_file(ssl->ctx, private_key_file, SSL_FILETYPE_PEM) != 1) {
- _log_ssl_error(ssl, "SSL_CTX_use_PrivateKey_file( %s ) failed\n", private_key_file);
+ if (SSL_CTX_use_PrivateKey_file(domain->ctx, private_key_file, SSL_FILETYPE_PEM) != 1) {
+ _log_ssl_error( "SSL_CTX_use_PrivateKey_file( %s ) failed\n", private_key_file);
return -4;
}
- if (SSL_CTX_check_private_key(ssl->ctx) != 1) {
- _log_ssl_error(ssl, "The key file %s is not consistent with the certificate %s\n",
+ if (SSL_CTX_check_private_key(domain->ctx) != 1) {
+ _log_ssl_error( "The key file %s is not consistent with the certificate %s\n",
private_key_file, certificate_file);
return -5;
}
- ssl->has_certificate = true;
+ domain->has_certificate = true;
// bug in older versions of OpenSSL: servers may request client cert even if anonymous
// cipher was negotiated. TLSv1 will reject such a request. Hack: once a cert is
// configured, allow only authenticated ciphers.
- if (!SSL_CTX_set_cipher_list( ssl->ctx, CIPHERS_AUTHENTICATE )) {
- _log_ssl_error(ssl, "Failed to set cipher list to %s\n", CIPHERS_AUTHENTICATE);
+ if (!SSL_CTX_set_cipher_list( domain->ctx, CIPHERS_AUTHENTICATE )) {
+ _log_ssl_error( "Failed to set cipher list to %s\n", CIPHERS_AUTHENTICATE);
return -6;
}
- _log( ssl, "Configured local certificate file %s\n", certificate_file );
return 0;
}
-int pn_ssl_set_trusted_ca_db(pn_ssl_t *ssl,
- const char *certificate_db)
+int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
+ const char *certificate_db)
{
- if (!ssl) return 0;
- if (ssl->ssl) {
- _log_error("Error: attempting to set trusted CA db after SSL connection initialized.\n");
- return -1;
- }
+ if (!domain) return -1;
// certificates can be either a file or a directory, which determines how it is passed
// to SSL_CTX_load_verify_locations()
@@ -334,87 +562,66 @@ int pn_ssl_set_trusted_ca_db(pn_ssl_t *s
file = certificate_db;
}
- if (SSL_CTX_load_verify_locations( ssl->ctx, file, dir ) != 1) {
- _log_ssl_error(ssl, "SSL_CTX_load_verify_locations( %s ) failed\n", certificate_db);
+ if (SSL_CTX_load_verify_locations( domain->ctx, file, dir ) != 1) {
+ _log_ssl_error( "SSL_CTX_load_verify_locations( %s ) failed\n", certificate_db);
return -1;
}
- ssl->has_ca_db = true;
-
- _log( ssl, "loaded trusted CA database: file=%s dir=%s\n", file, dir );
- return 0;
-}
-
+ domain->has_ca_db = true;
-int pn_ssl_allow_unsecured_client(pn_ssl_t *ssl)
-{
- if (ssl) {
- if (ssl->mode != PN_SSL_MODE_SERVER) {
- _log_error("Cannot permit unsecured clients - not a server.\n");
- return -1;
- }
- ssl->allow_unsecured = true;
- ssl->process_input = process_input_unknown;
- ssl->process_output = process_output_unknown;
- _log( ssl, "Allowing connections from unsecured clients.\n" );
- }
return 0;
}
-int pn_ssl_set_peer_authentication(pn_ssl_t *ssl,
- const pn_ssl_verify_mode_t mode,
- const char *trusted_CAs)
+int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
+ const pn_ssl_verify_mode_t mode,
+ const char *trusted_CAs)
{
- if (!ssl) return 0;
- if (ssl->ssl) {
- _log_error("Error: attempting to set peer authentication after SSL connection initialized.\n");
- return -1;
- }
+ if (!domain) return -1;
switch (mode) {
case PN_SSL_VERIFY_PEER:
+ case PN_SSL_VERIFY_PEER_NAME:
- if (!ssl->has_ca_db) {
+ if (!domain->has_ca_db) {
_log_error("Error: cannot verify peer without a trusted CA configured.\n"
- " Use pn_ssl_set_trusted_ca_db()\n");
+ " Use pn_ssl_domain_set_trusted_ca_db()\n");
return -1;
}
- if (ssl->mode == PN_SSL_MODE_SERVER) {
+ if (domain->mode == PN_SSL_MODE_SERVER) {
// openssl requires that server connections supply a list of trusted CAs which is
// sent to the client
if (!trusted_CAs) {
_log_error("Error: a list of trusted CAs must be provided.\n");
return -1;
}
- if (!ssl->has_certificate) {
+ if (!domain->has_certificate) {
_log_error("Error: Server cannot verify peer without configuring a certificate.\n"
- " Use pn_ssl_set_credentials()\n");
+ " Use pn_ssl_domain_set_credentials()\n");
}
- ssl->trusted_CAs = pn_strdup( trusted_CAs );
+ if (domain->trusted_CAs) free(domain->trusted_CAs);
+ domain->trusted_CAs = pn_strdup( trusted_CAs );
STACK_OF(X509_NAME) *cert_names;
- cert_names = SSL_load_client_CA_file( ssl->trusted_CAs );
+ cert_names = SSL_load_client_CA_file( domain->trusted_CAs );
if (cert_names != NULL)
- SSL_CTX_set_client_CA_list(ssl->ctx, cert_names);
+ SSL_CTX_set_client_CA_list(domain->ctx, cert_names);
else {
- _log_error("Unable to process file of trusted CAs: %s\n", trusted_CAs);
+ _log_error("Error: Unable to process file of trusted CAs: %s\n", trusted_CAs);
return -1;
}
}
- SSL_CTX_set_verify( ssl->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
- // verify_callback /*?verify callback?*/ );
+ SSL_CTX_set_verify( domain->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ verify_callback);
#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
- SSL_CTX_set_verify_depth(ssl->ctx, 1);
+ SSL_CTX_set_verify_depth(domain->ctx, 1);
#endif
- _log( ssl, "Peer authentication mode set to VERIFY-PEER\n");
break;
case PN_SSL_ANONYMOUS_PEER: // hippie free love mode... :)
- SSL_CTX_set_verify( ssl->ctx, SSL_VERIFY_NONE, NULL );
- _log( ssl, "Peer authentication mode set to ANONYMOUS-PEER\n");
+ SSL_CTX_set_verify( domain->ctx, SSL_VERIFY_NONE, NULL );
break;
default:
@@ -422,33 +629,44 @@ int pn_ssl_set_peer_authentication(pn_ss
return -1;
}
- ssl->verify_mode = mode;
+ domain->verify_mode = mode;
return 0;
}
-int pn_ssl_get_peer_authentication(pn_ssl_t *ssl,
- pn_ssl_verify_mode_t *mode,
- char *trusted_CAs, size_t *trusted_CAs_size)
+int pn_ssl_init( pn_ssl_t *ssl, pn_ssl_domain_t *domain, const char *session_id)
{
- if (!ssl) return -1;
+ if (!ssl || !domain || ssl->domain) return -1;
- if (mode) *mode = ssl->verify_mode;
- if (trusted_CAs && trusted_CAs_size && *trusted_CAs_size) {
- if (ssl->trusted_CAs) {
- strncpy( trusted_CAs, ssl->trusted_CAs, *trusted_CAs_size );
- trusted_CAs[*trusted_CAs_size - 1] = '\0';
- *trusted_CAs_size = strlen(ssl->trusted_CAs) + 1;
- } else {
- *trusted_CAs = '\0';
- *trusted_CAs_size = 0;
- }
- } else if (trusted_CAs_size) {
- *trusted_CAs_size = (ssl->trusted_CAs) ? strlen(ssl->trusted_CAs) + 1 : 0;
+ ssl->domain = domain;
+ domain->ref_count++;
+ if (domain->allow_unsecured) {
+ ssl->process_input = process_input_unknown;
+ ssl->process_output = process_output_unknown;
+ } else {
+ ssl->process_input = process_input_ssl;
+ ssl->process_output = process_output_ssl;
}
+
+ if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
+ ssl->session_id = pn_strdup(session_id);
+
+ return init_ssl_socket(ssl);
+}
+
+
+int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
+{
+ if (!domain) return -1;
+ if (domain->mode != PN_SSL_MODE_SERVER) {
+ _log_error("Cannot permit unsecured clients - not a server.\n");
+ return -1;
+ }
+ domain->allow_unsecured = true;
return 0;
}
+
bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *buffer, size_t size )
{
const SSL_CIPHER *c;
@@ -480,111 +698,14 @@ bool pn_ssl_get_protocol_name(pn_ssl_t *
}
-
-int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_mode_t mode)
-{
- if (!ssl) return -1;
- if (ssl->mode == mode) return 0; // already set
- if (ssl->ssl) {
- _log_error("Unable to change mode once SSL is active.\n");
- return -1;
- }
-
- // if changing the mode from the default, must release old context
- if (ssl->ctx) SSL_CTX_free( ssl->ctx );
-
- switch (mode) {
- case PN_SSL_MODE_CLIENT:
- _log( ssl, "Setting up Client SSL object.\n" );
- ssl->mode = PN_SSL_MODE_CLIENT;
- ssl->ctx = SSL_CTX_new(SSLv23_client_method());
- if (!ssl->ctx) {
- _log_error("Unable to initialize SSL context: %s\n", strerror(errno));
- return -1;
- }
- break;
-
- case PN_SSL_MODE_SERVER:
- _log( ssl, "Setting up Server SSL object.\n" );
- ssl->mode = PN_SSL_MODE_SERVER;
- ssl->ctx = SSL_CTX_new(SSLv23_server_method());
- if (!ssl->ctx) {
- _log_error("Unable to initialize SSL context: %s\n", strerror(errno));
- return -1;
- }
- break;
-
- default:
- _log_error("Invalid valid for pn_ssl_mode_t: %d\n", mode);
- return -1;
- }
-
- // by default, allow anonymous ciphers so certificates are not required 'out of the box'
- if (!SSL_CTX_set_cipher_list( ssl->ctx, CIPHERS_ANONYMOUS )) {
- _log_ssl_error(ssl, "Failed to set cipher list to %s\n", CIPHERS_ANONYMOUS);
- return -2;
- }
-
- // ditto: by default do not authenticate the peer (can be done by SASL).
- if (pn_ssl_set_peer_authentication( ssl, PN_SSL_ANONYMOUS_PEER, NULL )) {
- return -2;
- }
-
- DH *dh = get_dh2048();
- if (dh) {
- SSL_CTX_set_tmp_dh(ssl->ctx, dh);
- DH_free(dh);
- SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
- }
-
- return 0;
-}
-
-pn_ssl_t *pn_ssl(pn_transport_t *transport)
-{
- if (!transport) return NULL;
- if (transport->ssl) return transport->ssl;
-
- if (!ssl_initialized) {
- ssl_initialized = 1;
- SSL_library_init();
- SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
- }
-
- pn_ssl_t *ssl = calloc(1, sizeof(pn_ssl_t));
- if (!ssl) return NULL;
-
- ssl->transport = transport;
- ssl->process_input = process_input_ssl;
- ssl->process_output = process_output_ssl;
- transport->ssl = ssl;
-
- ssl->trace = PN_TRACE_OFF;
-
- // default mode is client
- if (pn_ssl_init(ssl, PN_SSL_MODE_CLIENT)) {
- free(ssl);
- return NULL;
- }
- return ssl;
-}
-
-
void pn_ssl_free( pn_ssl_t *ssl)
{
if (!ssl) return;
_log( ssl, "SSL socket freed.\n" );
- if (ssl->bio_ssl) BIO_free(ssl->bio_ssl);
- if (ssl->ssl) SSL_free(ssl->ssl);
- else {
- if (ssl->bio_ssl_io) BIO_free(ssl->bio_ssl_io);
- if (ssl->bio_net_io) BIO_free(ssl->bio_net_io);
- }
- if (ssl->ctx) SSL_CTX_free(ssl->ctx);
-
- if (ssl->keyfile_pw) free(ssl->keyfile_pw);
- if (ssl->trusted_CAs) free(ssl->trusted_CAs);
+ release_ssl_socket( ssl );
+ if (ssl->domain) pn_ssl_domain_free(ssl->domain);
+ if (ssl->session_id) free((void *)ssl->session_id);
+ if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
free(ssl);
}
@@ -602,6 +723,22 @@ ssize_t pn_ssl_output(pn_ssl_t *ssl, cha
}
+pn_ssl_t *pn_ssl(pn_transport_t *transport)
+{
+ if (!transport) return NULL;
+ if (transport->ssl) return transport->ssl;
+
+ pn_ssl_t *ssl = calloc(1, sizeof(pn_ssl_t));
+ if (!ssl) return NULL;
+ ssl->transport = transport;
+ transport->ssl = ssl;
+
+ ssl->trace = (transport->disp) ? transport->disp->trace : PN_TRACE_OFF;
+
+ return ssl;
+}
+
+
/** Private: */
static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata)
@@ -616,6 +753,20 @@ static int start_ssl_shutdown( pn_ssl_t
{
if (!ssl->ssl_shutdown) {
_log(ssl, "Shutting down SSL connection...\n");
+ if (ssl->session_id) {
+ // save the negotiated credentials before we close the connection
+ pn_ssl_session_t *ssn = (pn_ssl_session_t *)calloc( 1, sizeof(pn_ssl_session_t));
+ if (ssn) {
+ ssn->id = pn_strdup( ssl->session_id );
+ ssn->session = SSL_get1_session( ssl->ssl );
+ if (ssn->session) {
+ _log( ssl, "Saving SSL session as %s\n", ssl->session_id );
+ LL_ADD( ssl->domain, ssn_cache, ssn );
+ } else {
+ ssl_session_free( ssn );
+ }
+ }
+ }
ssl->ssl_shutdown = true;
BIO_ssl_shutdown( ssl->bio_ssl );
}
@@ -872,13 +1023,37 @@ static ssize_t process_output_ssl( pn_tr
static int init_ssl_socket( pn_ssl_t *ssl )
{
if (ssl->ssl) return 0;
+ if (!ssl->domain) return -1;
- ssl->ssl = SSL_new(ssl->ctx);
+ ssl->ssl = SSL_new(ssl->domain->ctx);
if (!ssl->ssl) {
_log_error( "SSL socket setup failure.\n" );
return -1;
}
+ // store backpointer to pn_ssl_t in SSL object:
+ SSL_set_ex_data(ssl->ssl, ssl_ex_data_index, ssl);
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ if (ssl->peer_hostname && ssl->domain->mode == PN_SSL_MODE_CLIENT) {
+ SSL_set_tlsext_host_name(ssl->ssl, ssl->peer_hostname);
+ }
+#endif
+
+ // restore session, if available
+ if (ssl->session_id) {
+ pn_ssl_session_t *ssn = ssn_cache_find( ssl->domain, ssl->session_id );
+ if (ssn) {
+ _log( ssl, "Restoring previous session id=%s\n", ssn->id );
+ int rc = SSL_set_session( ssl->ssl, ssn->session );
+ if (rc != 1) {
+ _log( ssl, "Session restore failed, id=%s\n", ssn->id );
+ }
+ LL_REMOVE( ssl->domain, ssn_cache, ssn );
+ ssl_session_free( ssn );
+ }
+ }
+
// now layer a BIO over the SSL socket
ssl->bio_ssl = BIO_new(BIO_f_ssl());
if (!ssl->bio_ssl) {
@@ -894,7 +1069,7 @@ static int init_ssl_socket( pn_ssl_t *ss
}
SSL_set_bio(ssl->ssl, ssl->bio_ssl_io, ssl->bio_ssl_io);
- if (ssl->mode == PN_SSL_MODE_SERVER) {
+ if (ssl->domain->mode == PN_SSL_MODE_SERVER) {
SSL_set_accept_state(ssl->ssl);
BIO_set_ssl_mode(ssl->bio_ssl, 0); // server mode
_log( ssl, "Server SSL socket created.\n" );
@@ -906,6 +1081,21 @@ static int init_ssl_socket( pn_ssl_t *ss
return 0;
}
+static void release_ssl_socket( pn_ssl_t *ssl )
+{
+ if (ssl->bio_ssl) BIO_free(ssl->bio_ssl);
+ if (ssl->ssl) SSL_free(ssl->ssl);
+ else {
+ if (ssl->bio_ssl_io) BIO_free(ssl->bio_ssl_io);
+ if (ssl->bio_net_io) BIO_free(ssl->bio_net_io);
+ }
+ ssl->bio_ssl = NULL;
+ ssl->bio_ssl_io = NULL;
+ ssl->bio_net_io = NULL;
+ ssl->ssl = NULL;
+}
+
+
//////// CLEARTEXT CONNECTIONS
static ssize_t process_input_cleartext(pn_transport_t *transport, const char *input_data, size_t len)
@@ -1010,3 +1200,51 @@ void pn_ssl_trace(pn_ssl_t *ssl, pn_trac
{
ssl->trace = trace;
}
+
+
+pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
+{
+ if (!ssl || !ssl->ssl) return PN_SSL_RESUME_UNKNOWN;
+ switch (SSL_session_reused( ssl->ssl )) {
+ case 0: return PN_SSL_RESUME_NEW;
+ case 1: return PN_SSL_RESUME_REUSED;
+ default: break;
+ }
+ return PN_SSL_RESUME_UNKNOWN;
+}
+
+
+int pn_ssl_set_peer_hostname( pn_ssl_t *ssl, const char *hostname )
+{
+ if (!ssl) return -1;
+
+ if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
+ ssl->peer_hostname = NULL;
+ if (hostname) {
+ ssl->peer_hostname = pn_strdup(hostname);
+ if (!ssl->peer_hostname) return -2;
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ if (ssl->ssl && ssl->domain && ssl->domain->mode == PN_SSL_MODE_CLIENT) {
+ SSL_set_tlsext_host_name(ssl->ssl, ssl->peer_hostname);
+ }
+#endif
+ }
+ return 0;
+}
+
+int pn_ssl_get_peer_hostname( pn_ssl_t *ssl, char *hostname, size_t *bufsize )
+{
+ if (!ssl) return -1;
+ if (!ssl->peer_hostname) {
+ *bufsize = 0;
+ if (hostname) *hostname = '\0';
+ return 0;
+ }
+ int len = strlen(ssl->peer_hostname);
+ if (hostname) {
+ if (len >= *bufsize) return -1;
+ strcpy( hostname, ssl->peer_hostname );
+ }
+ *bufsize = len;
+ return 0;
+}
Modified: qpid/proton/branches/jni-binding/proton-c/src/ssl/ssl_stub.c
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-c/src/ssl/ssl_stub.c?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-c/src/ssl/ssl_stub.c (original)
+++ qpid/proton/branches/jni-binding/proton-c/src/ssl/ssl_stub.c Tue Jan 8 08:29:31 2013
@@ -35,72 +35,86 @@ pn_ssl_t *pn_ssl(pn_transport_t *transpo
return NULL;
}
-int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_mode_t mode)
+int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_domain_t *domain,
+ const char *session_id)
{
return -1;
}
+void pn_ssl_free( pn_ssl_t *ssl)
+{
+}
-int pn_ssl_set_credentials(pn_ssl_t *ssl,
- const char *certificate_file,
- const char *private_key_file,
- const char *password)
+void pn_ssl_trace(pn_ssl_t *ssl, pn_trace_t trace)
{
- return -1;
}
-int pn_ssl_set_trusted_ca_db(pn_ssl_t *ssl,
- const char *certificate_db)
+ssize_t pn_ssl_input(pn_ssl_t *ssl, const char *bytes, size_t available)
{
- return -1;
+ return PN_EOS;
}
-int pn_ssl_allow_unsecured_client(pn_ssl_t *ssl)
+ssize_t pn_ssl_output(pn_ssl_t *ssl, char *buffer, size_t max_size)
{
- return -1;
+ return PN_EOS;
}
+bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *buffer, size_t size)
+{
+ return false;
+}
-int pn_ssl_set_peer_authentication(pn_ssl_t *ssl,
- const pn_ssl_verify_mode_t mode,
- const char *trusted_CAs)
+bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *buffer, size_t size)
{
- return -1;
+ return false;
+}
+
+pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode)
+{
+ return NULL;
}
+void pn_ssl_domain_free( pn_ssl_domain_t *d )
+{
+}
-int pn_ssl_get_peer_authentication(pn_ssl_t *ssl,
- pn_ssl_verify_mode_t *mode,
- char *trusted_CAs, size_t *trusted_CAs_size)
+int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
+ const char *certificate_file,
+ const char *private_key_file,
+ const char *password)
{
return -1;
}
-void pn_ssl_free( pn_ssl_t *ssl)
+int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
+ const char *certificate_db)
{
+ return -1;
}
-void pn_ssl_trace(pn_ssl_t *ssl, pn_trace_t trace)
+int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
+ const pn_ssl_verify_mode_t mode,
+ const char *trusted_CAs)
{
+ return -1;
}
-ssize_t pn_ssl_input(pn_ssl_t *ssl, const char *bytes, size_t available)
+int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
{
- return PN_EOS;
+ return -1;
}
-ssize_t pn_ssl_output(pn_ssl_t *ssl, char *buffer, size_t max_size)
+pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *s )
{
- return PN_EOS;
+ return PN_SSL_RESUME_UNKNOWN;
}
-bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *buffer, size_t size)
+int pn_ssl_set_peer_hostname( pn_ssl_t *ssl, const char *hostname)
{
- return false;
+ return -1;
}
-bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *buffer, size_t size)
+int pn_ssl_get_peer_hostname( pn_ssl_t *ssl, char *hostname, size_t *bufsize )
{
- return false;
+ return -1;
}
-
Modified: qpid/proton/branches/jni-binding/proton-c/src/util.c
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-c/src/util.c?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-c/src/util.c (original)
+++ qpid/proton/branches/jni-binding/proton-c/src/util.c Tue Jan 8 08:29:31 2013
@@ -132,11 +132,20 @@ void pn_fatal(char *fmt, ...)
va_end(ap);
}
+static bool pn_i_eq_nocase(const char *a, const char *b)
+{
+ while (*b) {
+ if (tolower(*a++) != tolower(*b++))
+ return false;
+ }
+ return !(*a);
+}
+
bool pn_env_bool(const char *name)
{
char *v = getenv(name);
- return v && (!strcasecmp(v, "true") || !strcasecmp(v, "1") ||
- !strcasecmp(v, "yes"));
+ return v && (pn_i_eq_nocase(v, "true") || pn_i_eq_nocase(v, "1") ||
+ pn_i_eq_nocase(v, "yes") || pn_i_eq_nocase(v, "on"));
}
char *pn_strdup(const char *src)
Modified: qpid/proton/branches/jni-binding/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java Tue Jan 8 08:29:31 2013
@@ -76,7 +76,7 @@ public class AmqpSender extends AmqpLink
final LinkedList<MessageDelivery> outbound = new LinkedList<MessageDelivery>();
long outboundBufferSize;
- public MessageDelivery send(MessageImpl message) {
+ public MessageDelivery send(Message message) {
assertExecuting();
MessageDelivery rc = new MessageDelivery(message) {
@Override
Modified: qpid/proton/branches/jni-binding/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java Tue Jan 8 08:29:31 2013
@@ -17,44 +17,38 @@
package org.apache.qpid.proton.hawtdispatch.api;
-import org.apache.qpid.proton.hawtdispatch.impl.DroppingWritableBuffer;
+import org.apache.qpid.proton.amqp.transport.DeliveryState;
+import org.apache.qpid.proton.engine.impl.DeliveryImpl;
import org.apache.qpid.proton.hawtdispatch.impl.Watch;
import org.apache.qpid.proton.hawtdispatch.impl.WatchBase;
-import org.apache.qpid.proton.codec.CompositeWritableBuffer;
-import org.apache.qpid.proton.codec.WritableBuffer;
-import org.apache.qpid.proton.engine.impl.DeliveryImpl;
import org.apache.qpid.proton.message.Message;
-import org.apache.qpid.proton.amqp.transport.DeliveryState;
import org.apache.qpid.proton.message.impl.MessageImpl;
import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtdispatch.Task;
-import java.nio.ByteBuffer;
-
/**
* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
*/
public abstract class MessageDelivery extends WatchBase {
final int initialSize;
- private MessageImpl message;
+ private Message message;
private Buffer encoded;
public DeliveryImpl delivery;
private int sizeHint = 1024*4;
- static Buffer encode(MessageImpl message, int sizeHint) {
- ByteBuffer buffer = ByteBuffer.wrap(new byte[sizeHint]);
- DroppingWritableBuffer overflow = new DroppingWritableBuffer();
- int c = message.encode(new CompositeWritableBuffer(new WritableBuffer.ByteBufferWrapper(buffer), overflow));
- if( overflow.position() > 0 ) {
- buffer = ByteBuffer.wrap(new byte[sizeHint+overflow.position()]);
- c = message.encode(new WritableBuffer.ByteBufferWrapper(buffer));
+ static Buffer encode(Message message, int sizeHint) {
+ byte[] buffer = new byte[sizeHint];
+ int size = ((MessageImpl)message).encode2(buffer, 0, sizeHint);
+ if( size > sizeHint ) {
+ buffer = new byte[size];
+ size = message.encode(buffer, 0, size);
}
- return new Buffer(buffer.array(), 0, c);
+ return new Buffer(buffer, 0, size);
}
- static MessageImpl decode(Buffer buffer) {
- MessageImpl msg = new MessageImpl();
+ static Message decode(Buffer buffer) {
+ Message msg = new MessageImpl();
int offset = buffer.offset;
int len = buffer.length;
while( len > 0 ) {
@@ -66,7 +60,7 @@ public abstract class MessageDelivery ex
return msg;
}
- public MessageDelivery(MessageImpl message) {
+ public MessageDelivery(Message message) {
this(message, encode(message, 1024*4));
}
@@ -74,7 +68,7 @@ public abstract class MessageDelivery ex
this(null, encoded);
}
- public MessageDelivery(MessageImpl message, Buffer encoded) {
+ public MessageDelivery(Message message, Buffer encoded) {
this.message = message;
this.encoded = encoded;
sizeHint = this.encoded.length;
Modified: qpid/proton/branches/jni-binding/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java Tue Jan 8 08:29:31 2013
@@ -17,6 +17,7 @@
package org.apache.qpid.proton.jms;
import org.apache.qpid.proton.codec.CompositeWritableBuffer;
+import org.apache.qpid.proton.codec.DroppingWritableBuffer;
import org.apache.qpid.proton.codec.WritableBuffer;
import org.apache.qpid.proton.amqp.UnsignedInteger;
Modified: qpid/proton/branches/jni-binding/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java Tue Jan 8 08:29:31 2013
@@ -19,6 +19,7 @@ package org.apache.qpid.proton.jms;
import org.apache.qpid.proton.amqp.messaging.Section;
import org.apache.qpid.proton.codec.CompositeWritableBuffer;
import org.apache.qpid.proton.codec.WritableBuffer;
+import org.apache.qpid.proton.codec.DroppingWritableBuffer;
import org.apache.qpid.proton.amqp.Binary;
import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.UnsignedByte;
Modified: qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Ssl.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Ssl.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Ssl.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Ssl.java Tue Jan 8 08:29:31 2013
@@ -1,6 +1,4 @@
-package org.apache.qpid.proton.engine;
/*
- *
* 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
@@ -19,130 +17,31 @@ package org.apache.qpid.proton.engine;
* under the License.
*
*/
+package org.apache.qpid.proton.engine;
+/**
+ * I represent the details of a particular SSL session.
+ */
public interface Ssl
{
- public enum Mode
- {
- CLIENT, /** Local connection endpoint is an SSL client */
- SERVER /** Local connection endpoint is an SSL server */
- }
-
-
- /** Initialize the pn_ssl_t object.
- *
- * An SSL object be either an SSL server or an SSL client. It cannot be both. Those
- * transports that will be used to accept incoming connection requests must be configured
- * as an SSL server. Those transports that will be used to initiate outbound connections
- * must be configured as an SSL client.
- *
- */
- void init(Mode mode);
-
- Mode getMode();
-
- /** Set the certificate that identifies the local node to the remote.
- *
- * This certificate establishes the identity for the local node. It will be sent to the
- * remote if the remote needs to verify the identity of this node. This may be used for
- * both SSL servers and SSL clients (if client authentication is required by the server).
- *
- * @param certificate_file path to file/database containing the identifying
- * certificate.
- * @param private_key_file path to file/database containing the private key used to
- * sign the certificate
- * @param password the password used to sign the key, else NULL if key is not
- * protected.
- */
- void setCredentials( String certificate_file,
- String private_key_file,
- String password);
-
- String getPrivateKeyFile(); // TODO
- String getPrivateKeyPassword();
-
- String getCertificateFile();
-
- /** Configure the set of trusted CA certificates used by this node to verify peers.
- *
- * If the local SSL client/server needs to verify the identity of the remote, it must
- * validate the signature of the remote's certificate. This function sets the database of
- * trusted CAs that will be used to verify the signature of the remote's certificate.
- *
- * @param certificate_db database of trusted CAs, used to authenticate the peer.
- */
-
- void setTrustedCaDb(String certificate_db);
-
- String getTrustedCaDb();
-
- /** Permit a server to accept connection requests from non-SSL clients.
- *
- * This configures the server to "sniff" the incoming client data stream, and dynamically
- * determine whether SSL/TLS is being used. This option is disabled by default: only
- * clients using SSL/TLS are accepted.
- *
- */
- void allowUnsecuredClient(boolean allowUnsecured);
-
- /** Determines the level of peer validation.
- *
- * VERIFY_PEER will only connect to those peers that provide a valid identifying
- * certificate signed by a trusted CA and are using an authenticated cipher.
- * ANONYMOUS_PEER does not require a valid certificate, and permits use of ciphers that
- * do not provide authentication.
- *
- * ANONYMOUS_PEER is configured by default.
- *
- * These settings can be changed via ::pn_ssl_set_peer_authentication()
- */
- public enum VerifyMode
- {
- VERIFY_PEER, /** require peer to provide a valid identifying certificate */
- ANONYMOUS_PEER, /** do not require a certificate nor cipher authorization */
- }
-
-
- /** Configure the level of verification used on the peer certificate.
- *
- * This method controls how the peer's certificate is validated, if at all. By default,
- * neither servers nor clients attempt to verify their peers (PN_SSL_ANONYMOUS_PEER).
- * Once certificates and trusted CAs are configured, peer verification can be enabled.
- *
- * In order to verify a peer, a trusted CA must be configured. See
- * #setTrustedCaDb().
- *
- * @note Servers must provide their own certificate when verifying a peer. See
- * #setCredentials().
- *
- * @param mode the level of validation to apply to the peer
- */
- void setPeerAuthentication(VerifyMode mode);
-
- VerifyMode getPeerAuthentication();
-
- /** Get the name of the Cipher that is currently in use.
+ /**
+ * Get the name of the Cipher that is currently in use.
*
* Gets a text description of the cipher that is currently active, or returns null if SSL
- * is not active (no cipher). Note that the cipher in use may change over time due to
+ * is not active (no cipher). Note that the cipher in use may change over time due to
* renegotiation or other changes to the SSL state.
*
* @return the name of the cipher in use, or null if none
*/
String getCipherName();
- /** Get the name of the SSL protocol that is currently in use.
+ /**
+ * Get the name of the SSL protocol that is currently in use.
*
* Gets a text description of the SSL protocol that is currently active, or null if SSL
- * is not active. Note that the protocol may change over time due to renegotiation.
+ * is not active. Note that the protocol may change over time due to renegotiation.
*
* @return the name of the protocol in use, or null if none
*/
String getProtocolName();
-
-
-
-
-
-
}
Modified: qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Transport.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Transport.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Transport.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Transport.java Tue Jan 8 08:29:31 2013
@@ -59,6 +59,20 @@ public interface Transport extends Endpo
Sasl sasl();
- Ssl ssl();
+ /**
+ * Wrap this transport's output and input to apply SSL encryption and decryption respectively.
+ *
+ * This method is expected to be called at most once. A subsequent invocation will return the same
+ * {@link Ssl} object, regardless of the parameters supplied.
+ *
+ * @param sslDomain the SSL settings to use
+ * @param sslPeerDetails may be null, in which case SSL session resume will not be attempted
+ * @return an {@link Ssl} object representing the SSL session.
+ */
+ Ssl ssl(SslDomain sslDomain, SslPeerDetails sslPeerDetails);
+ /**
+ * As per {@link #ssl(SslDomain, SslPeerDetails)} but no attempt is made to resume a previous SSL session.
+ */
+ Ssl ssl(SslDomain sslDomain);
}
Modified: qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/Messenger.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/Messenger.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/Messenger.java Tue Jan 8 08:29:31 2013
@@ -145,9 +145,6 @@ public interface Messenger
*/
int incoming();
- AcceptMode getAcceptMode();
- void setAcceptMode(AcceptMode mode);
-
int getIncomingWindow();
void setIncomingWindow(int window);
Modified: qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java Tue Jan 8 08:29:31 2013
@@ -34,8 +34,11 @@ import org.apache.qpid.proton.engine.End
import org.apache.qpid.proton.engine.EndpointState;
import org.apache.qpid.proton.engine.Sasl;
import org.apache.qpid.proton.engine.Ssl;
+import org.apache.qpid.proton.engine.SslDomain;
+import org.apache.qpid.proton.engine.SslPeerDetails;
import org.apache.qpid.proton.engine.Transport;
import org.apache.qpid.proton.engine.TransportException;
+import org.apache.qpid.proton.engine.impl.ssl.ProtonSslEngineProvider;
import org.apache.qpid.proton.engine.impl.ssl.SslImpl;
import org.apache.qpid.proton.framing.TransportFrame;
import org.apache.qpid.proton.amqp.transport.Attach;
@@ -238,12 +241,19 @@ public class TransportImpl extends Endpo
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Note that sslDomain must implement {@link ProtonSslEngineProvider}. This is not possible
+ * enforce at the API level because {@link ProtonSslEngineProvider} is not part of the
+ * public Proton API.</p>
+ */
@Override
- public Ssl ssl()
+ public Ssl ssl(SslDomain sslDomain, SslPeerDetails sslPeerDetails)
{
if (_ssl == null)
{
- _ssl = new SslImpl();
+ _ssl = new SslImpl(sslDomain, sslPeerDetails);
TransportWrapper transportWrapper = _ssl.wrap(_inputProcessor, _outputProcessor);
_inputProcessor = transportWrapper;
_outputProcessor = transportWrapper;
@@ -251,6 +261,12 @@ public class TransportImpl extends Endpo
return _ssl;
}
+ @Override
+ public Ssl ssl(SslDomain sslDomain)
+ {
+ return ssl(sslDomain, null);
+ }
+
private void clearTransportWorkList()
{
DeliveryImpl delivery = _connectionEndpoint.getTransportWorkHead();
Modified: qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/DefaultSslEngineFacade.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/DefaultSslEngineFacade.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/DefaultSslEngineFacade.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/DefaultSslEngineFacade.java Tue Jan 8 08:29:31 2013
@@ -26,7 +26,8 @@ import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLException;
-class DefaultSslEngineFacade implements SslEngineFacade
+
+class DefaultSslEngineFacade implements ProtonSslEngine
{
private final SSLEngine _sslEngine;
@@ -82,4 +83,10 @@ class DefaultSslEngineFacade implements
{
return _sslEngine.getHandshakeStatus();
}
+
+ @Override
+ public boolean getUseClientMode()
+ {
+ return _sslEngine.getUseClientMode();
+ }
}
Modified: qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java Tue Jan 8 08:29:31 2013
@@ -31,7 +31,6 @@ import javax.net.ssl.SSLEngineResult.Sta
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
-import org.apache.qpid.proton.engine.Ssl;
import org.apache.qpid.proton.engine.TransportException;
import org.apache.qpid.proton.engine.impl.TransportInput;
import org.apache.qpid.proton.engine.impl.TransportOutput;
@@ -39,7 +38,6 @@ import org.apache.qpid.proton.engine.imp
/**
* TODO close the SSLEngine when told to, and modify {@link #input(byte[], int, int)} and {@link #output(byte[], int, int)}
* to respond appropriately thereafter.
- * TODO move SSL and possible byte management classes into separate package
*/
public class SimpleSslTransportWrapper implements SslTransportWrapper
{
@@ -55,9 +53,8 @@ public class SimpleSslTransportWrapper i
private final TransportInput _underlyingInput;
private final TransportOutput _underlyingOutput;
- private final Ssl _sslParams;
- private SslEngineFacade _sslEngine;
+ private ProtonSslEngine _sslEngine;
/** Used by {@link #output(byte[], int, int)}. Acts as a buffer for the output from underlyingOutput */
private ByteHolder _clearOutputHolder;
@@ -77,22 +74,11 @@ public class SimpleSslTransportWrapper i
/** could change during the lifetime of the ssl connection owing to renegotiation. */
private String _protocolName;
- private final SslEngineFacadeFactory _sslEngineFacadeFactory;
-
- public SimpleSslTransportWrapper(Ssl sslConfiguration, TransportInput underlyingInput, TransportOutput underlyingOutput)
- {
- this(sslConfiguration, underlyingInput, underlyingOutput, new SslEngineFacadeFactory());
- }
-
- SimpleSslTransportWrapper(Ssl sslConfiguration,
- TransportInput underlyingInput, TransportOutput underlyingOutput,
- SslEngineFacadeFactory sslEngineFacadeFactory)
+ SimpleSslTransportWrapper(ProtonSslEngine sslEngine, TransportInput underlyingInput, TransportOutput underlyingOutput)
{
- _sslParams = sslConfiguration;
_underlyingInput = underlyingInput;
_underlyingOutput = underlyingOutput;
- _sslEngineFacadeFactory = sslEngineFacadeFactory;
- _sslEngine = _sslEngineFacadeFactory.createSslEngineFacade(sslConfiguration);
+ _sslEngine = sslEngine;
createByteHolders();
}
@@ -134,10 +120,7 @@ public class SimpleSslTransportWrapper i
runDelegatedTasks(result);
updateCipherAndProtocolName(result);
- if(_logger.isLoggable(Level.FINEST))
- {
- _logger.log(Level.FINEST, _sslParams.getMode() + " input " + resultToString(result));
- }
+ logEngineClientModeAndResult(result, "input");
Status sslResultStatus = result.getStatus();
HandshakeStatus handshakeStatus = result.getHandshakeStatus();
@@ -180,19 +163,10 @@ public class SimpleSslTransportWrapper i
}
catch(SSLException e)
{
- throw new TransportException(e);
+ throw new TransportException("Problem during input. useClientMode: " + _sslEngine.getUseClientMode(), e);
}
}
- private String resultToString(SSLEngineResult result)
- {
- return new StringBuilder("[SSLEngineResult status = ").append(result.getStatus())
- .append(" handshakeStatus = ").append(result.getHandshakeStatus())
- .append(" bytesConsumed = ").append(result.bytesConsumed())
- .append(" bytesProduced = ").append(result.bytesProduced())
- .append("]").toString();
- }
-
/**
* Write encoded output to the supplied destination.
*
@@ -237,6 +211,8 @@ public class SimpleSslTransportWrapper i
}
SSLEngineResult result = _sslEngine.wrap(_clearOutputHolder.prepareToRead(), sslWrapDst);
+ logEngineClientModeAndResult(result, "output");
+
_clearOutputHolder.prepareToWrite();
Status sslResultStatus = result.getStatus();
@@ -270,7 +246,7 @@ public class SimpleSslTransportWrapper i
}
catch(SSLException e)
{
- throw new TransportException("Mode " + _sslParams.getMode(), e);
+ throw new TransportException("Problem during output. useClientMode: " + _sslEngine.getUseClientMode(), e);
}
}
@@ -315,9 +291,21 @@ public class SimpleSslTransportWrapper i
}
}
- public static void main(String[] args)
+ private void logEngineClientModeAndResult(SSLEngineResult result, String direction)
{
- _logger.info("PHDEBUG in main");
- _logger.info("PHDEBUG in main2");
+ if(_logger.isLoggable(Level.FINEST))
+ {
+ _logger.log(Level.FINEST, "useClientMode = " + _sslEngine.getUseClientMode() + " direction = " + direction
+ + " " + resultToString(result));
+ }
+ }
+
+ private String resultToString(SSLEngineResult result)
+ {
+ return new StringBuilder("[SSLEngineResult status = ").append(result.getStatus())
+ .append(" handshakeStatus = ").append(result.getHandshakeStatus())
+ .append(" bytesConsumed = ").append(result.bytesConsumed())
+ .append(" bytesProduced = ").append(result.bytesProduced())
+ .append("]").toString();
}
}
Modified: qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java Tue Jan 8 08:29:31 2013
@@ -23,11 +23,12 @@ package org.apache.qpid.proton.engine.im
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
-import java.security.Key;
import java.security.KeyManagementException;
+import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
@@ -46,9 +47,8 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
-import org.apache.qpid.proton.engine.Ssl;
-import org.apache.qpid.proton.engine.Ssl.Mode;
-import org.apache.qpid.proton.engine.Ssl.VerifyMode;
+import org.apache.qpid.proton.engine.SslDomain;
+import org.apache.qpid.proton.engine.SslPeerDetails;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMException;
import org.bouncycastle.openssl.PEMReader;
@@ -81,25 +81,51 @@ public class SslEngineFacadeFactory
"SSL_DH_anon_WITH_DES_CBC_SHA",
"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA");
- public SslEngineFacade createSslEngineFacade(Ssl sslConfiguration)
+ /** lazily initialized */
+ private SSLContext _sslContext;
+
+
+ /**
+ * Returns a {@link ProtonSslEngine}. May cache the domain's settings so callers should invoke
+ * {@link #resetCache()} if the domain changes.
+ *
+ * @param peerDetails may be used to return an engine that supports SSL resume.
+ */
+ public ProtonSslEngine createProtonSslEngine(SslDomain domain, SslPeerDetails peerDetails)
{
- SSLEngine engine = createSslEngine(sslConfiguration);
+ SSLEngine engine = createAndInitialiseSslEngine(domain, peerDetails);
+ if(_logger.isLoggable(Level.FINE))
+ {
+ _logger.fine("Created SSL engine: " + engineToString(engine));
+ }
return new DefaultSslEngineFacade(engine);
}
- private SSLEngine createSslEngine(Ssl sslConfiguration)
+
+ /**
+ * Guarantees that no cached settings are used in subsequent calls to
+ * {@link #createProtonSslEngine(SslDomain, SslPeerDetails)}.
+ */
+ public void resetCache()
{
- SSLEngine sslEngine;
+ _sslContext = null;
+ }
+
- SSLContext sslContext = createSslContext(sslConfiguration);
- sslEngine = sslContext.createSSLEngine();
- if (sslConfiguration.getPeerAuthentication() == VerifyMode.ANONYMOUS_PEER)
+ private SSLEngine createAndInitialiseSslEngine(SslDomain domain, SslPeerDetails peerDetails)
+ {
+ SslDomain.Mode mode = domain.getMode();
+
+ SSLContext sslContext = getOrCreateSslContext(domain);
+ SSLEngine sslEngine = createSslEngine(sslContext, peerDetails);
+
+ if (domain.getPeerAuthentication() == SslDomain.VerifyMode.ANONYMOUS_PEER)
{
addAnonymousCipherSuites(sslEngine);
}
else
{
- if (sslConfiguration.getMode() == Mode.SERVER)
+ if (mode == SslDomain.Mode.SERVER)
{
sslEngine.setNeedClientAuth(true);
}
@@ -107,87 +133,129 @@ public class SslEngineFacadeFactory
if(_logger.isLoggable(Level.FINE))
{
- _logger.log(Level.FINE, sslConfiguration.getMode() + " Enabled cipher suites " + Arrays.asList(sslEngine.getEnabledCipherSuites()));
+ _logger.log(Level.FINE, mode + " Enabled cipher suites " + Arrays.asList(sslEngine.getEnabledCipherSuites()));
}
- boolean useClientMode = sslConfiguration.getMode() == Mode.CLIENT ? true : false;
+ boolean useClientMode = mode == SslDomain.Mode.CLIENT ? true : false;
sslEngine.setUseClientMode(useClientMode);
return sslEngine;
}
- private SSLContext createSslContext(Ssl sslConfiguration)
+ /**
+ * @param sslPeerDetails is allowed to be null. A non-null value is used to hint that SSL resumption
+ * should be attempted
+ */
+ private SSLEngine createSslEngine(SSLContext sslContext, SslPeerDetails sslPeerDetails)
{
- final char[] dummyPassword = "unused-passphrase".toCharArray(); // Dummy password required by KeyStore and KeyManagerFactory, but never referred to again
+ final SSLEngine sslEngine;
+ if(sslPeerDetails == null)
+ {
+ sslEngine = sslContext.createSSLEngine();
+ }
+ else
+ {
+ sslEngine = sslContext.createSSLEngine(sslPeerDetails.getHostname(), sslPeerDetails.getPort());
+ }
+ return sslEngine;
+ }
- try
+ private SSLContext getOrCreateSslContext(SslDomain sslDomain)
+ {
+ if(_sslContext == null)
{
- SSLContext sslContext = SSLContext.getInstance(TLS_PROTOCOL);
- KeyStore ksKeys = createKeyStoreFrom(sslConfiguration, dummyPassword);
+ if(_logger.isLoggable(Level.FINE))
+ {
+ _logger.fine("lazily creating new SSLContext using domain " + sslDomain);
+ }
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- kmf.init(ksKeys, dummyPassword);
+ final char[] dummyPassword = "unused-passphrase".toCharArray(); // Dummy password required by KeyStore and KeyManagerFactory, but never referred to again
- final TrustManager[] trustManagers;
- if (sslConfiguration.getTrustedCaDb() == null && sslConfiguration.getPeerAuthentication() == VerifyMode.ANONYMOUS_PEER)
+ try
{
- trustManagers = new TrustManager[] { new AlwaysTrustingTrustManager() };
+ SSLContext sslContext = SSLContext.getInstance(TLS_PROTOCOL);
+ KeyStore ksKeys = createKeyStoreFrom(sslDomain, dummyPassword);
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(ksKeys, dummyPassword);
+
+ final TrustManager[] trustManagers;
+ if (sslDomain.getPeerAuthentication() == SslDomain.VerifyMode.ANONYMOUS_PEER)
+ {
+ trustManagers = new TrustManager[] { new AlwaysTrustingTrustManager() };
+ }
+ else
+ {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(ksKeys);
+ trustManagers = tmf.getTrustManagers();
+ }
+
+ sslContext.init(kmf.getKeyManagers(), trustManagers, null);
+ _sslContext = sslContext;
}
- else
+ catch (NoSuchAlgorithmException e)
{
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- tmf.init(ksKeys);
- trustManagers = tmf.getTrustManagers();
+ throw new IllegalStateException("Unexpected exception creating SSLContext", e);
+ }
+ catch (KeyStoreException e)
+ {
+ throw new IllegalStateException("Unexpected exception creating SSLContext", e);
+ }
+ catch (UnrecoverableKeyException e)
+ {
+ throw new IllegalStateException("Unexpected exception creating SSLContext", e);
+ }
+ catch (KeyManagementException e)
+ {
+ throw new IllegalStateException("Unexpected exception creating SSLContext", e);
}
-
- sslContext.init(kmf.getKeyManagers(), trustManagers, null);
- return sslContext;
- }
- catch (NoSuchAlgorithmException e)
- {
- throw new IllegalStateException("Unexpected exception creating SSLContext", e);
- }
- catch (KeyStoreException e)
- {
- throw new IllegalStateException("Unexpected exception creating SSLContext", e);
- }
- catch (UnrecoverableKeyException e)
- {
- throw new IllegalStateException("Unexpected exception creating SSLContext", e);
- }
- catch (KeyManagementException e)
- {
- throw new IllegalStateException("Unexpected exception creating SSLContext", e);
}
+ return _sslContext;
}
- private KeyStore createKeyStoreFrom(Ssl sslConfiguration, char[] dummyPassword)
+ private KeyStore createKeyStoreFrom(SslDomain sslDomain, char[] dummyPassword)
{
try
{
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(null, null);
- if (sslConfiguration.getTrustedCaDb() != null)
+ if (sslDomain.getTrustedCaDb() != null)
{
String caCertAlias = "cacert";
if(_logger.isLoggable(Level.FINE))
{
- _logger.log(Level.FINE, "_sslParams.getTrustedCaDb() : " + sslConfiguration.getTrustedCaDb());
+ _logger.log(Level.FINE, "_sslParams.getTrustedCaDb() : " + sslDomain.getTrustedCaDb());
}
- Certificate trustedCaCert = (Certificate) readPemObject(sslConfiguration.getTrustedCaDb());
+ Certificate trustedCaCert = (Certificate) readPemObject(sslDomain.getTrustedCaDb(), null, Certificate.class);
keystore.setCertificateEntry(caCertAlias, trustedCaCert);
}
- if (sslConfiguration.getCertificateFile() != null
- && sslConfiguration.getPrivateKeyFile() != null)
+ if (sslDomain.getCertificateFile() != null
+ && sslDomain.getPrivateKeyFile() != null)
{
String clientPrivateKeyAlias = "clientPrivateKey";
- Certificate clientCertificate = (Certificate) readPemObject(sslConfiguration.getCertificateFile());
- Key clientPrivateKey = (Key) readPemObject(
- sslConfiguration.getPrivateKeyFile(),
- sslConfiguration.getPrivateKeyPassword());
+ Certificate clientCertificate = (Certificate) readPemObject(sslDomain.getCertificateFile(), null, Certificate.class);
+ Object keyOrKeyPair = readPemObject(
+ sslDomain.getPrivateKeyFile(),
+ sslDomain.getPrivateKeyPassword(), PrivateKey.class, KeyPair.class);
+
+ final PrivateKey clientPrivateKey;
+ if (keyOrKeyPair instanceof PrivateKey)
+ {
+ clientPrivateKey = (PrivateKey)keyOrKeyPair;
+ }
+ else if (keyOrKeyPair instanceof KeyPair)
+ {
+ clientPrivateKey = ((KeyPair)keyOrKeyPair).getPrivate();
+ }
+ else
+ {
+ // Should not happen - readPemObject will have already verified key type
+ throw new IllegalStateException("Unexpected key type " + keyOrKeyPair);
+ }
keystore.setKeyEntry(clientPrivateKeyAlias, clientPrivateKey,
dummyPassword, new Certificate[] { clientCertificate });
@@ -226,50 +294,79 @@ public class SslEngineFacadeFactory
{
List<String> newEnabled = new ArrayList<String>(currentEnabled);
- boolean addedAnonymousCipherSuite = false;
+ int addedAnonymousCipherSuites = 0;
for (String anonymousCipherSuiteName : anonymousCipherSuites)
{
if (supportedSuites.contains(anonymousCipherSuiteName))
{
newEnabled.add(anonymousCipherSuiteName);
- addedAnonymousCipherSuite = true;
+ addedAnonymousCipherSuites++;
}
}
- if (!addedAnonymousCipherSuite)
+ if (addedAnonymousCipherSuites == 0)
{
throw new IllegalStateException("None of " + anonymousCipherSuites
+ " anonymous cipher suites are within the supported list "
+ supportedSuites);
}
+
+ if(_logger.isLoggable(Level.FINE))
+ {
+ _logger.fine("There are now " + newEnabled.size()
+ + " cipher suites enabled (previously " + currentEnabled.size()
+ + "), including " + addedAnonymousCipherSuites + " out of the "
+ + anonymousCipherSuites.size() + " requested anonymous ones." );
+ }
+
return newEnabled;
}
- private Object readPemObject(String pemFile, final String privateKeyPassword)
+ private String engineToString(SSLEngine engine)
{
- PasswordFinder passwordFinder = new PasswordFinder()
+ return new StringBuilder("[ " )
+ .append(engine)
+ .append(", needClientAuth=").append(engine.getNeedClientAuth())
+ .append(", useClientMode=").append(engine.getUseClientMode())
+ .append(", peerHost=").append(engine.getPeerHost())
+ .append(", peerPort=").append(engine.getPeerPort())
+ .append(" ]").toString();
+ }
+
+ private Object readPemObject(String pemFile, String keyPassword, @SuppressWarnings("rawtypes") Class... expectedInterfaces)
+ {
+ final PasswordFinder passwordFinder;
+ if (keyPassword != null)
{
- @Override
- public char[] getPassword()
- {
- return privateKeyPassword.toCharArray();
- }
- };
+ passwordFinder = getPasswordFinderFor(keyPassword);
+ }
+ else
+ {
+ passwordFinder = null;
+ }
Reader reader = null;
try
{
reader = new FileReader(pemFile);
- return new PEMReader(reader, privateKeyPassword == null ? null : passwordFinder).readObject();
+ PEMReader pemReader = new PEMReader(reader, passwordFinder);
+ Object pemObject = pemReader.readObject();
+ if (!checkPemObjectIsOfAllowedTypes(pemObject, expectedInterfaces))
+ {
+ throw new IllegalStateException("File " + pemFile + " does not provide a object of the required type."
+ + " Read an object of class " + pemObject.getClass().getName()
+ + " whilst expecting an implementation of one of the following : " + Arrays.asList(expectedInterfaces));
+ }
+ return pemObject;
}
catch(PEMException e)
{
_logger.log(Level.SEVERE, "Unable to read PEM object. Perhaps you need the unlimited strength libraries in <java-home>/jre/lib/security/ ?", e);
- throw new RuntimeException(e);
+ throw new IllegalStateException("Unable to read PEM object from file " + pemFile, e);
}
catch (IOException e)
{
- throw new RuntimeException(e);
+ throw new RuntimeException("Unable to read PEM object from file " + pemFile, e);
}
finally
{
@@ -287,9 +384,35 @@ public class SslEngineFacadeFactory
}
}
- private Object readPemObject(String pemFile)
+ @SuppressWarnings("rawtypes")
+ private boolean checkPemObjectIsOfAllowedTypes(Object pemObject, Class... expectedInterfaces)
+ {
+ if (expectedInterfaces.length == 0)
+ {
+ throw new IllegalArgumentException("Must be at least one expectedKeyTypes");
+ }
+
+ for (Class keyInterface : expectedInterfaces)
+ {
+ if (keyInterface.isInstance(pemObject))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private PasswordFinder getPasswordFinderFor(final String keyPassword)
{
- return readPemObject(pemFile, null);
+ PasswordFinder passwordFinder = new PasswordFinder()
+ {
+ @Override
+ public char[] getPassword()
+ {
+ return keyPassword.toCharArray();
+ }
+ };
+ return passwordFinder;
}
private final class AlwaysTrustingTrustManager implements X509TrustManager
Modified: qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java Tue Jan 8 08:29:31 2013
@@ -21,99 +21,32 @@
package org.apache.qpid.proton.engine.impl.ssl;
import org.apache.qpid.proton.engine.Ssl;
+import org.apache.qpid.proton.engine.SslDomain;
+import org.apache.qpid.proton.engine.SslPeerDetails;
import org.apache.qpid.proton.engine.impl.TransportInput;
import org.apache.qpid.proton.engine.impl.TransportOutput;
import org.apache.qpid.proton.engine.impl.TransportWrapper;
import org.apache.qpid.proton.engine.impl.PlainTransportWrapper;
-/*
- * Enables the JSSE system debugging system property:
- *
- * -Djavax.net.debug=all
- */
public class SslImpl implements Ssl
{
- private Mode _mode;
- private VerifyMode _verifyMode = VerifyMode.ANONYMOUS_PEER;
- private String _certificateFile;
- private String _privateKeyFile;
- private String _privateKeyPassword;
- private String _trustedCaDb;
- private boolean _allowUnsecuredClient;
-
private SslTransportWrapper _unsecureClientAwareTransportWrapper;
- @Override
- public void init(Mode mode)
- {
- _mode = mode;
- }
-
- @Override
- public void setCredentials(String certificateFile,
- String privateKeyFile, String privateKeyPassword)
- {
- _certificateFile = certificateFile;
- _privateKeyFile = privateKeyFile;
- _privateKeyPassword = privateKeyPassword;
- }
-
- @Override
- public void setTrustedCaDb(String certificateDb)
- {
- _trustedCaDb = certificateDb;
- }
-
- @Override
- public String getTrustedCaDb()
- {
- return _trustedCaDb;
- }
-
- @Override
- public void allowUnsecuredClient(boolean allowUnsecuredClient)
- {
- if (_mode == Mode.CLIENT)
- {
- throw new IllegalArgumentException("Only servers may allow unsecured clients");
- }
- _allowUnsecuredClient = allowUnsecuredClient;
- }
-
- @Override
- public void setPeerAuthentication(VerifyMode verifyMode)
- {
- _verifyMode = verifyMode;
- }
-
- @Override
- public VerifyMode getPeerAuthentication()
- {
- return _verifyMode;
- }
-
- @Override
- public Mode getMode()
- {
- return _mode;
- }
-
- @Override
- public String getPrivateKeyFile()
- {
- return _privateKeyFile;
- }
+ private final SslDomain _domain;
+ private final ProtonSslEngineProvider _protonSslEngineProvider;
- @Override
- public String getPrivateKeyPassword()
- {
- return _privateKeyPassword;
- }
+ private final SslPeerDetails _peerDetails;
- @Override
- public String getCertificateFile()
- {
- return _certificateFile;
+ /**
+ * @param sslDomain must implement {@link ProtonSslEngineProvider}. This is not possible
+ * enforce at the API level because {@link ProtonSslEngineProvider} is not part of the
+ * public Proton API.</p>
+ */
+ public SslImpl(SslDomain domain, SslPeerDetails peerDetails)
+ {
+ _domain = domain;
+ _protonSslEngineProvider = (ProtonSslEngineProvider)domain;
+ _peerDetails = peerDetails;
}
public TransportWrapper wrap(TransportInput inputProcessor, TransportOutput outputProcessor)
@@ -206,8 +139,12 @@ public class SslImpl implements Ssl
{
if (_transportWrapper == null)
{
- SslTransportWrapper sslTransportWrapper = new SimpleSslTransportWrapper(SslImpl.this, _inputProcessor, _outputProcessor);
- if (_allowUnsecuredClient)
+ SslTransportWrapper sslTransportWrapper = new SimpleSslTransportWrapper(
+ _protonSslEngineProvider.createSslEngine(_peerDetails),
+ _inputProcessor,
+ _outputProcessor);
+
+ if (_domain.allowUnsecuredClient())
{
TransportWrapper plainTransportWrapper = new PlainTransportWrapper(_outputProcessor, _inputProcessor);
_transportWrapper = new SslHandshakeSniffingTransportWrapper(sslTransportWrapper, plainTransportWrapper);
Modified: qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java Tue Jan 8 08:29:31 2013
@@ -28,10 +28,8 @@ import org.apache.qpid.proton.amqp.Symbo
import org.apache.qpid.proton.amqp.UnsignedByte;
import org.apache.qpid.proton.amqp.UnsignedInteger;
import org.apache.qpid.proton.amqp.messaging.*;
-import org.apache.qpid.proton.codec.AMQPDefinedTypes;
-import org.apache.qpid.proton.codec.DecoderImpl;
-import org.apache.qpid.proton.codec.EncoderImpl;
-import org.apache.qpid.proton.codec.WritableBuffer;
+import org.apache.qpid.proton.amqp.messaging.Data;
+import org.apache.qpid.proton.codec.*;
import org.apache.qpid.proton.message.*;
public class MessageImpl implements Message
@@ -675,6 +673,17 @@ public class MessageImpl implements Mess
return encode(new WritableBuffer.ByteBufferWrapper(buffer));
}
+ public int encode2(byte[] data, int offset, int length)
+ {
+ ByteBuffer buffer = ByteBuffer.wrap(data, offset, length);
+ WritableBuffer.ByteBufferWrapper first = new WritableBuffer.ByteBufferWrapper(buffer);
+ DroppingWritableBuffer second = new DroppingWritableBuffer();
+ CompositeWritableBuffer composite = new CompositeWritableBuffer(first, second);
+ int start = composite.position();
+ encode(composite);
+ return composite.position() - start;
+ }
+
public int encode(WritableBuffer buffer)
{
int length = buffer.remaining();
Modified: qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java Tue Jan 8 08:29:31 2013
@@ -43,7 +43,6 @@ import org.apache.qpid.proton.driver.imp
import org.apache.qpid.proton.engine.impl.ConnectionImpl;
import org.apache.qpid.proton.message.Message;
import org.apache.qpid.proton.message.impl.MessageImpl;
-import org.apache.qpid.proton.messenger.AcceptMode;
import org.apache.qpid.proton.messenger.Messenger;
import org.apache.qpid.proton.messenger.MessengerException;
import org.apache.qpid.proton.messenger.Status;
@@ -68,7 +67,6 @@ public class MessengerImpl implements Me
private Driver _driver;
private int _credit;
private int _distributed;
- private AcceptMode _acceptMode = AcceptMode.AUTO;
private TrackerQueue _incoming = new TrackerQueue();
private TrackerQueue _outgoing = new TrackerQueue();
@@ -107,6 +105,7 @@ public class MessengerImpl implements Me
try
{
c.process();
+ c.close();
}
catch (IOException e)
{
@@ -194,9 +193,6 @@ public class MessengerImpl implements Me
Message message = new MessageImpl();
message.decode(_buffer, 0, size);
_incoming.add(delivery);
- if (_acceptMode == AcceptMode.AUTO) {
- _incoming.accept(incomingTracker());
- }
_distributed--;
delivery.getLink().advance();
return message;
@@ -250,15 +246,6 @@ public class MessengerImpl implements Me
}
- public AcceptMode getAcceptMode()
- {
- return _acceptMode;
- }
- public void setAcceptMode(AcceptMode mode)
- {
- _acceptMode = mode;
- }
-
public int getIncomingWindow()
{
return _incoming.getWindow();
Modified: qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/TrackerQueue.java
URL: http://svn.apache.org/viewvc/qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/TrackerQueue.java?rev=1430167&r1=1430166&r2=1430167&view=diff
==============================================================================
--- qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/TrackerQueue.java (original)
+++ qpid/proton/branches/jni-binding/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/TrackerQueue.java Tue Jan 8 08:29:31 2013
@@ -77,6 +77,7 @@ class TrackerQueue
}
int sequence = _hwm++;
_deliveries.add(delivery);
+ slide();
}
Status getStatus(Tracker tracker)
@@ -139,7 +140,7 @@ class TrackerQueue
Delivery d = _deliveries.get(0);
if (d.getLocalState() == null)
{
- return;
+ d.disposition(ACCEPTED);
}
d.settle();
@@ -186,7 +187,6 @@ class TrackerQueue
operation.apply(d);
}
}
- slide();
}
private static interface DeliveryOperation
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org