summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHan Mai <cafe2310@gmail.com>2019-04-29 11:43:46 +0700
committerAlan Antonuk <alan.antonuk@gmail.com>2020-06-25 05:05:25 +0000
commiteccdc11ef2be7ab8ca8a26c307003337875a6b43 (patch)
tree33167148d02f634b46ab0700d328c07edb7ca0fa
parentc5cf965ed6d0233468fdea69e8a314f6d46b52c8 (diff)
downloadrabbitmq-c-pr556.tar.gz
Support openssl engine settingpr556
-rw-r--r--examples/amqp_ssl_connect.c9
-rw-r--r--librabbitmq/amqp.h3
-rw-r--r--librabbitmq/amqp_api.c6
-rw-r--r--librabbitmq/amqp_openssl.c71
-rw-r--r--librabbitmq/amqp_ssl_socket.h34
5 files changed, 118 insertions, 5 deletions
diff --git a/examples/amqp_ssl_connect.c b/examples/amqp_ssl_connect.c
index 3674c33..c6dada9 100644
--- a/examples/amqp_ssl_connect.c
+++ b/examples/amqp_ssl_connect.c
@@ -71,8 +71,9 @@ int main(int argc, char const *const *argv) {
if (argc < 3) {
fprintf(stderr,
- "Usage: amqps_connect_timeout host port timeout_sec "
- "[cacert.pem [verifypeer] [verifyhostname] [key.pem cert.pem]]\n");
+ "Usage: amqp_ssl_connect host port timeout_sec "
+ "[cacert.pem [engine engine_ID] [verifypeer] [verifyhostname] "
+ "[key.pem cert.pem]]\n");
return 1;
}
@@ -103,6 +104,10 @@ int main(int argc, char const *const *argv) {
int nextarg = 5;
die_on_error(amqp_ssl_socket_set_cacert(socket, argv[4]),
"setting CA certificate");
+ if (argc > nextarg && !strcmp("engine", argv[nextarg])) {
+ amqp_set_ssl_engine(argv[++nextarg]);
+ nextarg++;
+ }
if (argc > nextarg && !strcmp("verifypeer", argv[nextarg])) {
amqp_ssl_socket_set_verify_peer(socket, 1);
nextarg++;
diff --git a/librabbitmq/amqp.h b/librabbitmq/amqp.h
index d2c458d..d8a8b2e 100644
--- a/librabbitmq/amqp.h
+++ b/librabbitmq/amqp.h
@@ -770,7 +770,8 @@ typedef enum amqp_status_enum_ {
AMQP_STATUS_SSL_PEER_VERIFY_FAILED = -0x0202, /**< SSL validation of peer
certificate failed. */
AMQP_STATUS_SSL_CONNECTION_FAILED = -0x0203, /**< SSL handshake failed. */
- _AMQP_STATUS_SSL_NEXT_VALUE = -0x0204 /**< Internal value */
+ AMQP_STATUS_SSL_SET_ENGINE_FAILED = -0x0204, /**< SSL setting engine failed */
+ _AMQP_STATUS_SSL_NEXT_VALUE = -0x0205 /**< Internal value */
} amqp_status_enum;
/**
diff --git a/librabbitmq/amqp_api.c b/librabbitmq/amqp_api.c
index e29b177..abf60d5 100644
--- a/librabbitmq/amqp_api.c
+++ b/librabbitmq/amqp_api.c
@@ -108,14 +108,16 @@ static const char *tcp_error_strings[] = {
"socket library initialization failed"};
static const char *ssl_error_strings[] = {
- /* AMQP_STATUS_SSL_ERRO R -0x0200 */
+ /* AMQP_STATUS_SSL_ERROR -0x0200 */
"a SSL error occurred",
/* AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED -0x0201 */
"SSL hostname verification failed",
/* AMQP_STATUS_SSL_PEER_VERIFY_FAILED -0x0202 */
"SSL peer cert verification failed",
/* AMQP_STATUS_SSL_CONNECTION_FAILED -0x0203 */
- "SSL handshake failed"};
+ "SSL handshake failed",
+ /* AMQP_STATUS_SSL_SET_ENGINE_FAILED -0x0204 */
+ "SSL setting engine failed"};
static const char *unknown_error_string = "(unknown error)";
diff --git a/librabbitmq/amqp_openssl.c b/librabbitmq/amqp_openssl.c
index 9bb73d2..0a37fe0 100644
--- a/librabbitmq/amqp_openssl.c
+++ b/librabbitmq/amqp_openssl.c
@@ -63,6 +63,7 @@ static amqp_boolean_t do_initialize_openssl = 1;
static amqp_boolean_t openssl_initialized = 0;
static amqp_boolean_t openssl_bio_initialized = 0;
static int openssl_connections = 0;
+static ENGINE *openssl_engine = NULL;
#define CHECK_SUCCESS(condition) \
do { \
@@ -412,6 +413,34 @@ int amqp_ssl_socket_set_key(amqp_socket_t *base, const char *cert,
return AMQP_STATUS_OK;
}
+int amqp_ssl_socket_set_key_engine(amqp_socket_t *base, const char *cert,
+ const char *key) {
+ int status;
+ struct amqp_ssl_socket_t *self;
+ EVP_PKEY *pkey = NULL;
+ if (base->klass != &amqp_ssl_socket_class) {
+ amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
+ }
+ self = (struct amqp_ssl_socket_t *)base;
+ status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
+ if (1 != status) {
+ return AMQP_STATUS_SSL_ERROR;
+ }
+
+ pkey = ENGINE_load_private_key(openssl_engine, key, NULL, NULL);
+ if (pkey == NULL) {
+ return AMQP_STATUS_SSL_ERROR;
+ }
+
+ status = SSL_CTX_use_PrivateKey(self->ctx, pkey);
+ EVP_PKEY_free(pkey);
+
+ if (1 != status) {
+ return AMQP_STATUS_SSL_ERROR;
+ }
+ return AMQP_STATUS_OK;
+}
+
static int password_cb(AMQP_UNUSED char *buffer, AMQP_UNUSED int length,
AMQP_UNUSED int rwflag, AMQP_UNUSED void *user_data) {
amqp_abort("rabbitmq-c does not support password protected keys");
@@ -633,6 +662,43 @@ out:
return status;
}
+int amqp_set_ssl_engine(const char *engine) {
+ int status = AMQP_STATUS_OK;
+ CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
+
+ if (!openssl_initialized) {
+ status = AMQP_STATUS_SSL_ERROR;
+ goto out;
+ }
+
+ if (openssl_engine != NULL) {
+ ENGINE_free(openssl_engine);
+ openssl_engine = NULL;
+ }
+
+ if (engine == NULL) {
+ goto out;
+ }
+
+ ENGINE_load_builtin_engines();
+ openssl_engine = ENGINE_by_id(engine);
+ if (openssl_engine == NULL) {
+ status = AMQP_STATUS_SSL_SET_ENGINE_FAILED;
+ goto out;
+ }
+
+ if (ENGINE_set_default(openssl_engine, ENGINE_METHOD_ALL) == 0) {
+ ENGINE_free(openssl_engine);
+ openssl_engine = NULL;
+ status = AMQP_STATUS_SSL_SET_ENGINE_FAILED;
+ goto out;
+ }
+
+out:
+ CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
+ return status;
+}
+
static int initialize_ssl_and_increment_connections() {
int status;
CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
@@ -701,6 +767,11 @@ int amqp_uninitialize_ssl_library(void) {
free(amqp_openssl_lockarray);
}
+ if (openssl_engine != NULL) {
+ ENGINE_free(openssl_engine);
+ openssl_engine = NULL;
+ }
+
ENGINE_cleanup();
CONF_modules_free();
EVP_cleanup();
diff --git a/librabbitmq/amqp_ssl_socket.h b/librabbitmq/amqp_ssl_socket.h
index 70d1a56..5aab8bf 100644
--- a/librabbitmq/amqp_ssl_socket.h
+++ b/librabbitmq/amqp_ssl_socket.h
@@ -102,6 +102,24 @@ int AMQP_CALL amqp_ssl_socket_set_key(amqp_socket_t *self, const char *cert,
const char *key);
/**
+ * Set the client key use the engine.
+ *
+ * This function requires amqp_set_ssl_engine() has been called.
+ *
+ * \param [in,out] self An SSL/TLS socket object.
+ * \param [in] cert Path to the client certificate in PEM foramt.
+ * \param [in] the key ID.
+ *
+ * \return \ref AMQP_STATUS_OK on success an \ref amqp_status_enum value on
+ * failure.
+ *
+ * \since v0.9.1
+ */
+AMQP_PUBLIC_FUNCTION
+int AMQP_CALL amqp_ssl_socket_set_key_engine(amqp_socket_t *self,
+ const char *cert, const char *key);
+
+/**
* Set the client key from a buffer.
*
* \param [in,out] self An SSL/TLS socket object.
@@ -238,6 +256,22 @@ AMQP_PUBLIC_FUNCTION
int AMQP_CALL amqp_initialize_ssl_library(void);
/**
+ * Set the engine for underlying SSL/TLS library.
+ *
+ * This function is thread-safe, and may be called more than once.
+ *
+ * This function requires amqp_initialize_ssl_library() or amqp_ssl_socket_new()
+ * has been called.
+ *
+ * \param [in] engine the engine ID
+ * \return AMQP_STATUS_OK on success.
+ *
+ * \since v0.9.1
+ */
+AMQP_PUBLIC_FUNCTION
+int amqp_set_ssl_engine(const char *engine);
+
+/**
* Uninitialize the underlying SSL/TLS library.
*
* \return AMQP_STATUS_OK on success.