diff options
author | Han Mai <cafe2310@gmail.com> | 2019-04-29 11:43:46 +0700 |
---|---|---|
committer | Alan Antonuk <alan.antonuk@gmail.com> | 2020-06-25 22:52:56 -0700 |
commit | f182c13765e2a653da3bd9c3b49cac92e8dbd9fa (patch) | |
tree | c76bb0b945d16f959e6e6388c1653535fc6ffc52 | |
parent | 91759021f5d938dbef0c358e2194377c406ce418 (diff) | |
download | rabbitmq-c-f182c13765e2a653da3bd9c3b49cac92e8dbd9fa.tar.gz |
Support openssl engine setting
-rw-r--r-- | examples/amqp_ssl_connect.c | 9 | ||||
-rw-r--r-- | librabbitmq/amqp.h | 3 | ||||
-rw-r--r-- | librabbitmq/amqp_api.c | 6 | ||||
-rw-r--r-- | librabbitmq/amqp_openssl.c | 71 | ||||
-rw-r--r-- | librabbitmq/amqp_ssl_socket.h | 34 |
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. |