File Coverage

amqp_openssl.c
Criterion Covered Total %
statement 0 329 0.0
branch 0 122 0.0
condition n/a
subroutine n/a
pod n/a
total 0 451 0.0


line stmt bran cond sub pod time code
1             // Copyright 2007 - 2021, Alan Antonuk and the rabbitmq-c contributors.
2             // SPDX-License-Identifier: mit
3              
4             #ifdef HAVE_CONFIG_H
5             #include "config.h"
6             #endif
7              
8             #ifdef _MSC_VER
9             #define _CRT_SECURE_NO_WARNINGS
10             #endif
11              
12             // Use OpenSSL v1.1.1 API.
13             #define OPENSSL_API_COMPAT 10101
14              
15             #include "amqp_openssl_bio.h"
16             #include "amqp_private.h"
17             #include "amqp_socket.h"
18             #include "amqp_time.h"
19             #include "rabbitmq-c/ssl_socket.h"
20             #include "threads.h"
21              
22             #include
23             #include
24             #include
25             #include
26             #ifdef ENABLE_SSL_ENGINE_API
27             #include
28             #endif
29             #include
30             #include
31             #include
32             #include
33             #include
34             #include
35              
36             static int initialize_ssl_and_increment_connections(void);
37             static int decrement_ssl_connections(void);
38              
39             static pthread_mutex_t openssl_init_mutex = PTHREAD_MUTEX_INITIALIZER;
40             static amqp_boolean_t openssl_bio_initialized = 0;
41             static int openssl_connections = 0;
42             #ifdef ENABLE_SSL_ENGINE_API
43             static ENGINE *openssl_engine = NULL;
44             #endif
45              
46             #define CHECK_SUCCESS(condition) \
47             do { \
48             int check_success_ret = (condition); \
49             if (check_success_ret) { \
50             amqp_abort("Check %s failed <%d>: %s", #condition, check_success_ret, \
51             strerror(check_success_ret)); \
52             } \
53             } while (0)
54              
55             struct amqp_ssl_socket_t {
56             const struct amqp_socket_class_t *klass;
57             SSL_CTX *ctx;
58             int sockfd;
59             SSL *ssl;
60             amqp_boolean_t verify_peer;
61             amqp_boolean_t verify_hostname;
62             int internal_error;
63             };
64              
65 0           static ssize_t amqp_ssl_socket_send(void *base, const void *buf, size_t len,
66             AMQP_UNUSED int flags) {
67 0           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
68             int res;
69 0 0         if (-1 == self->sockfd) {
70 0           return AMQP_STATUS_SOCKET_CLOSED;
71             }
72              
73             /* SSL_write takes an int for length of buffer, protect against len being
74             * larger than larger than what SSL_write can take */
75 0 0         if (len > INT_MAX) {
76 0           return AMQP_STATUS_INVALID_PARAMETER;
77             }
78              
79 0           ERR_clear_error();
80 0           self->internal_error = 0;
81              
82             /* This will only return on error, or once the whole buffer has been
83             * written to the SSL stream. See SSL_MODE_ENABLE_PARTIAL_WRITE */
84 0           res = SSL_write(self->ssl, buf, (int)len);
85 0 0         if (0 >= res) {
86 0           self->internal_error = SSL_get_error(self->ssl, res);
87             /* TODO: Close connection if it isn't already? */
88             /* TODO: Possibly be more intelligent in reporting WHAT went wrong */
89 0           switch (self->internal_error) {
90 0           case SSL_ERROR_WANT_READ:
91 0           res = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
92 0           break;
93 0           case SSL_ERROR_WANT_WRITE:
94 0           res = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
95 0           break;
96 0           case SSL_ERROR_ZERO_RETURN:
97 0           res = AMQP_STATUS_CONNECTION_CLOSED;
98 0           break;
99 0           default:
100 0           res = AMQP_STATUS_SSL_ERROR;
101 0           break;
102             }
103             } else {
104 0           self->internal_error = 0;
105             }
106              
107 0           return (ssize_t)res;
108             }
109              
110 0           static ssize_t amqp_ssl_socket_recv(void *base, void *buf, size_t len,
111             AMQP_UNUSED int flags) {
112 0           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
113             int received;
114 0 0         if (-1 == self->sockfd) {
115 0           return AMQP_STATUS_SOCKET_CLOSED;
116             }
117              
118             /* SSL_read takes an int for length of buffer, protect against len being
119             * larger than larger than what SSL_read can take */
120 0 0         if (len > INT_MAX) {
121 0           return AMQP_STATUS_INVALID_PARAMETER;
122             }
123              
124 0           ERR_clear_error();
125 0           self->internal_error = 0;
126              
127 0           received = SSL_read(self->ssl, buf, (int)len);
128 0 0         if (0 >= received) {
129 0           self->internal_error = SSL_get_error(self->ssl, received);
130 0           switch (self->internal_error) {
131 0           case SSL_ERROR_WANT_READ:
132 0           received = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
133 0           break;
134 0           case SSL_ERROR_WANT_WRITE:
135 0           received = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
136 0           break;
137 0           case SSL_ERROR_ZERO_RETURN:
138 0           received = AMQP_STATUS_CONNECTION_CLOSED;
139 0           break;
140 0           default:
141 0           received = AMQP_STATUS_SSL_ERROR;
142 0           break;
143             }
144             }
145              
146 0           return (ssize_t)received;
147             }
148              
149 0           static int amqp_ssl_socket_open(void *base, const char *host, int port,
150             const struct timeval *timeout) {
151 0           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
152             long result;
153             int status;
154             amqp_time_t deadline;
155             X509 *cert;
156             BIO *bio;
157 0 0         if (-1 != self->sockfd) {
158 0           return AMQP_STATUS_SOCKET_INUSE;
159             }
160 0           ERR_clear_error();
161              
162 0           self->ssl = SSL_new(self->ctx);
163 0 0         if (!self->ssl) {
164 0           self->internal_error = ERR_peek_error();
165 0           status = AMQP_STATUS_SSL_ERROR;
166 0           goto exit;
167             }
168              
169 0           status = amqp_time_from_now(&deadline, timeout);
170 0 0         if (AMQP_STATUS_OK != status) {
171 0           return status;
172             }
173              
174 0           self->sockfd = amqp_open_socket_inner(host, port, deadline);
175 0 0         if (0 > self->sockfd) {
176 0           status = self->sockfd;
177 0           self->internal_error = amqp_os_socket_error();
178 0           self->sockfd = -1;
179 0           goto error_out1;
180             }
181              
182 0           bio = BIO_new(amqp_openssl_bio());
183 0 0         if (!bio) {
184 0           status = AMQP_STATUS_NO_MEMORY;
185 0           goto error_out2;
186             }
187              
188 0           BIO_set_fd(bio, self->sockfd, BIO_NOCLOSE);
189 0           SSL_set_bio(self->ssl, bio, bio);
190              
191 0           status = SSL_set_tlsext_host_name(self->ssl, host);
192 0 0         if (!status) {
193 0           self->internal_error = SSL_get_error(self->ssl, status);
194 0           status = AMQP_STATUS_SSL_ERROR;
195 0           goto error_out2;
196             }
197              
198 0           start_connect:
199 0           status = SSL_connect(self->ssl);
200 0 0         if (status != 1) {
201 0           self->internal_error = SSL_get_error(self->ssl, status);
202 0           switch (self->internal_error) {
203 0           case SSL_ERROR_WANT_READ:
204 0           status = amqp_poll(self->sockfd, AMQP_SF_POLLIN, deadline);
205 0           break;
206 0           case SSL_ERROR_WANT_WRITE:
207 0           status = amqp_poll(self->sockfd, AMQP_SF_POLLOUT, deadline);
208 0           break;
209 0           default:
210 0           status = AMQP_STATUS_SSL_CONNECTION_FAILED;
211             }
212 0 0         if (AMQP_STATUS_OK == status) {
213 0           goto start_connect;
214             }
215 0           goto error_out2;
216             }
217              
218             #if OPENSSL_VERSION_NUMBER < 0x30000000L
219             cert = SSL_get_peer_certificate(self->ssl);
220             #else
221 0           cert = SSL_get1_peer_certificate(self->ssl);
222             #endif
223              
224 0 0         if (self->verify_peer) {
225 0 0         if (!cert) {
226 0           self->internal_error = 0;
227 0           status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED;
228 0           goto error_out3;
229             }
230              
231 0           result = SSL_get_verify_result(self->ssl);
232 0 0         if (X509_V_OK != result) {
233 0           self->internal_error = result;
234 0           status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED;
235 0           goto error_out4;
236             }
237             }
238 0 0         if (self->verify_hostname) {
239 0 0         if (!cert) {
240 0           self->internal_error = 0;
241 0           status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED;
242 0           goto error_out3;
243             }
244              
245 0 0         if (1 != X509_check_host(cert, host, strlen(host),
246             X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS, NULL)) {
247 0           self->internal_error = 0;
248 0           status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED;
249 0           goto error_out4;
250             }
251             }
252              
253 0           X509_free(cert);
254 0           self->internal_error = 0;
255 0           status = AMQP_STATUS_OK;
256              
257 0           exit:
258 0           return status;
259              
260 0           error_out4:
261 0           X509_free(cert);
262 0           error_out3:
263 0           SSL_shutdown(self->ssl);
264 0           error_out2:
265 0           amqp_os_socket_close(self->sockfd);
266 0           self->sockfd = -1;
267 0           error_out1:
268 0           SSL_free(self->ssl);
269 0           self->ssl = NULL;
270 0           goto exit;
271             }
272              
273 0           static int amqp_ssl_socket_close(void *base, amqp_socket_close_enum force) {
274 0           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
275              
276 0 0         if (-1 == self->sockfd) {
277 0           return AMQP_STATUS_SOCKET_CLOSED;
278             }
279              
280 0 0         if (AMQP_SC_NONE == force) {
281             /* don't try too hard to shutdown the connection */
282 0           SSL_shutdown(self->ssl);
283             }
284              
285 0           SSL_free(self->ssl);
286 0           self->ssl = NULL;
287              
288 0 0         if (amqp_os_socket_close(self->sockfd)) {
289 0           return AMQP_STATUS_SOCKET_ERROR;
290             }
291 0           self->sockfd = -1;
292              
293 0           return AMQP_STATUS_OK;
294             }
295              
296 0           static int amqp_ssl_socket_get_sockfd(void *base) {
297 0           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
298 0           return self->sockfd;
299             }
300              
301 0           static void amqp_ssl_socket_delete(void *base) {
302 0           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
303              
304 0 0         if (self) {
305 0           amqp_ssl_socket_close(self, AMQP_SC_NONE);
306              
307 0           SSL_CTX_free(self->ctx);
308 0           free(self);
309             }
310 0           decrement_ssl_connections();
311 0           }
312              
313             static const struct amqp_socket_class_t amqp_ssl_socket_class = {
314             amqp_ssl_socket_send, /* send */
315             amqp_ssl_socket_recv, /* recv */
316             amqp_ssl_socket_open, /* open */
317             amqp_ssl_socket_close, /* close */
318             amqp_ssl_socket_get_sockfd, /* get_sockfd */
319             amqp_ssl_socket_delete /* delete */
320             };
321              
322 0           amqp_socket_t *amqp_ssl_socket_new(amqp_connection_state_t state) {
323 0           struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self));
324             int status;
325 0 0         if (!self) {
326 0           return NULL;
327             }
328              
329 0           self->sockfd = -1;
330 0           self->klass = &amqp_ssl_socket_class;
331 0           self->verify_peer = 1;
332 0           self->verify_hostname = 1;
333              
334 0           status = initialize_ssl_and_increment_connections();
335 0 0         if (status) {
336 0           goto error;
337             }
338              
339 0           self->ctx = SSL_CTX_new(TLS_client_method());
340 0 0         if (!self->ctx) {
341 0           goto error;
342             }
343 0           status = amqp_ssl_socket_set_ssl_versions((amqp_socket_t *)self, AMQP_TLSv1_2,
344             AMQP_TLSvLATEST);
345 0 0         if (status != AMQP_STATUS_OK) {
346 0           goto error;
347             }
348              
349 0           SSL_CTX_set_mode(self->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
350             /* OpenSSL v1.1.1 turns this on by default, which makes the non-blocking
351             * logic not behave as expected, so turn this back off */
352 0           SSL_CTX_clear_mode(self->ctx, SSL_MODE_AUTO_RETRY);
353              
354 0           amqp_set_socket(state, (amqp_socket_t *)self);
355              
356 0           return (amqp_socket_t *)self;
357 0           error:
358 0           amqp_ssl_socket_delete((amqp_socket_t *)self);
359 0           return NULL;
360             }
361              
362 0           void *amqp_ssl_socket_get_context(amqp_socket_t *base) {
363 0 0         if (base->klass != &amqp_ssl_socket_class) {
364 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
365             }
366 0           return ((struct amqp_ssl_socket_t *)base)->ctx;
367             }
368              
369 0           int amqp_ssl_socket_enable_default_verify_paths(amqp_socket_t *base) {
370             int status;
371             struct amqp_ssl_socket_t *self;
372 0 0         if (base->klass != &amqp_ssl_socket_class) {
373 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
374             }
375 0           self = (struct amqp_ssl_socket_t *)base;
376 0           status = SSL_CTX_set_default_verify_paths(self->ctx);
377 0 0         if (1 != status) {
378 0           return AMQP_STATUS_SSL_ERROR;
379             }
380 0           return AMQP_STATUS_OK;
381             }
382              
383 0           int amqp_ssl_socket_set_cacert(amqp_socket_t *base, const char *cacert) {
384             int status;
385             struct amqp_ssl_socket_t *self;
386 0 0         if (base->klass != &amqp_ssl_socket_class) {
387 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
388             }
389 0           self = (struct amqp_ssl_socket_t *)base;
390 0           status = SSL_CTX_load_verify_locations(self->ctx, cacert, NULL);
391 0 0         if (1 != status) {
392 0           return AMQP_STATUS_SSL_ERROR;
393             }
394 0           return AMQP_STATUS_OK;
395             }
396              
397 0           int amqp_ssl_socket_set_key(amqp_socket_t *base, const char *cert,
398             const char *key) {
399             int status;
400             struct amqp_ssl_socket_t *self;
401 0 0         if (base->klass != &amqp_ssl_socket_class) {
402 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
403             }
404 0           self = (struct amqp_ssl_socket_t *)base;
405 0           status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
406 0 0         if (1 != status) {
407 0           return AMQP_STATUS_SSL_ERROR;
408             }
409 0           status = SSL_CTX_use_PrivateKey_file(self->ctx, key, SSL_FILETYPE_PEM);
410 0 0         if (1 != status) {
411 0           return AMQP_STATUS_SSL_ERROR;
412             }
413 0           return AMQP_STATUS_OK;
414             }
415              
416 0           int amqp_ssl_socket_set_key_engine(amqp_socket_t *base, const char *cert,
417             const char *key) {
418             #ifdef ENABLE_SSL_ENGINE_API
419             int status;
420             struct amqp_ssl_socket_t *self;
421             EVP_PKEY *pkey = NULL;
422             if (base->klass != &amqp_ssl_socket_class) {
423             amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
424             }
425             self = (struct amqp_ssl_socket_t *)base;
426             status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
427             if (1 != status) {
428             return AMQP_STATUS_SSL_ERROR;
429             }
430              
431             pkey = ENGINE_load_private_key(openssl_engine, key, NULL, NULL);
432             if (pkey == NULL) {
433             return AMQP_STATUS_SSL_ERROR;
434             }
435              
436             status = SSL_CTX_use_PrivateKey(self->ctx, pkey);
437             EVP_PKEY_free(pkey);
438              
439             if (1 != status) {
440             return AMQP_STATUS_SSL_ERROR;
441             }
442             return AMQP_STATUS_OK;
443             #else
444 0           return AMQP_STATUS_SSL_UNIMPLEMENTED;
445             #endif
446             }
447              
448 0           static int password_cb(AMQP_UNUSED char *buffer, AMQP_UNUSED int length,
449             AMQP_UNUSED int rwflag, AMQP_UNUSED void *user_data) {
450 0           amqp_abort("rabbitmq-c does not support password protected keys");
451             }
452              
453 0           int amqp_ssl_socket_set_key_buffer(amqp_socket_t *base, const char *cert,
454             const void *key, size_t n) {
455 0           int status = AMQP_STATUS_OK;
456 0           BIO *buf = NULL;
457 0           RSA *rsa = NULL;
458             struct amqp_ssl_socket_t *self;
459 0 0         if (base->klass != &amqp_ssl_socket_class) {
460 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
461             }
462 0 0         if (n > INT_MAX) {
463 0           return AMQP_STATUS_INVALID_PARAMETER;
464             }
465 0           self = (struct amqp_ssl_socket_t *)base;
466 0           status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
467 0 0         if (1 != status) {
468 0           return AMQP_STATUS_SSL_ERROR;
469             }
470 0           buf = BIO_new_mem_buf((void *)key, (int)n);
471 0 0         if (!buf) {
472 0           goto error;
473             }
474 0           rsa = PEM_read_bio_RSAPrivateKey(buf, NULL, password_cb, NULL);
475 0 0         if (!rsa) {
476 0           goto error;
477             }
478 0           status = SSL_CTX_use_RSAPrivateKey(self->ctx, rsa);
479 0 0         if (1 != status) {
480 0           goto error;
481             }
482 0           status = AMQP_STATUS_OK;
483 0           exit:
484 0           BIO_vfree(buf);
485 0           RSA_free(rsa);
486 0           return status;
487 0           error:
488 0           status = AMQP_STATUS_SSL_ERROR;
489 0           goto exit;
490             }
491              
492 0           int amqp_ssl_socket_set_cert(amqp_socket_t *base, const char *cert) {
493             int status;
494             struct amqp_ssl_socket_t *self;
495 0 0         if (base->klass != &amqp_ssl_socket_class) {
496 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
497             }
498 0           self = (struct amqp_ssl_socket_t *)base;
499 0           status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
500 0 0         if (1 != status) {
501 0           return AMQP_STATUS_SSL_ERROR;
502             }
503 0           return AMQP_STATUS_OK;
504             }
505              
506 0           void amqp_ssl_socket_set_key_passwd(amqp_socket_t *base, const char *passwd) {
507             struct amqp_ssl_socket_t *self;
508 0 0         if (base->klass != &amqp_ssl_socket_class) {
509 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
510             }
511 0           self = (struct amqp_ssl_socket_t *)base;
512 0           SSL_CTX_set_default_passwd_cb_userdata(self->ctx, (void *)passwd);
513 0           }
514              
515 0           void amqp_ssl_socket_set_verify(amqp_socket_t *base, amqp_boolean_t verify) {
516 0           amqp_ssl_socket_set_verify_peer(base, verify);
517 0           amqp_ssl_socket_set_verify_hostname(base, verify);
518 0           }
519              
520 0           void amqp_ssl_socket_set_verify_peer(amqp_socket_t *base,
521             amqp_boolean_t verify) {
522             struct amqp_ssl_socket_t *self;
523 0 0         if (base->klass != &amqp_ssl_socket_class) {
524 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
525             }
526 0           self = (struct amqp_ssl_socket_t *)base;
527 0           self->verify_peer = verify;
528 0           }
529              
530 0           void amqp_ssl_socket_set_verify_hostname(amqp_socket_t *base,
531             amqp_boolean_t verify) {
532             struct amqp_ssl_socket_t *self;
533 0 0         if (base->klass != &amqp_ssl_socket_class) {
534 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
535             }
536 0           self = (struct amqp_ssl_socket_t *)base;
537 0           self->verify_hostname = verify;
538 0           }
539              
540 0           static int get_tls_version(amqp_tls_version_t ver, int *tls_version) {
541 0           switch (ver) {
542 0           case AMQP_TLSv1_2:
543 0           *tls_version = TLS1_2_VERSION;
544 0           break;
545 0           case AMQP_TLSv1_3:
546             case AMQP_TLSvLATEST:
547 0           *tls_version = TLS1_3_VERSION;
548 0           break;
549 0           default:
550 0           return AMQP_STATUS_UNSUPPORTED;
551             }
552 0           return AMQP_STATUS_OK;
553             }
554              
555 0           int amqp_ssl_socket_set_ssl_versions(amqp_socket_t *base,
556             amqp_tls_version_t min,
557             amqp_tls_version_t max) {
558             struct amqp_ssl_socket_t *self;
559             int min_ver;
560             int max_ver;
561             int status;
562 0 0         if (base->klass != &amqp_ssl_socket_class) {
563 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
564             }
565 0           self = (struct amqp_ssl_socket_t *)base;
566              
567 0 0         if (max < min) {
568 0           return AMQP_STATUS_INVALID_PARAMETER;
569             }
570              
571 0           status = get_tls_version(min, &min_ver);
572 0 0         if (status != AMQP_STATUS_OK) {
573 0           return status;
574             }
575              
576 0           status = get_tls_version(max, &max_ver);
577 0 0         if (status != AMQP_STATUS_OK) {
578 0           return status;
579             }
580              
581 0 0         if (!SSL_CTX_set_min_proto_version(self->ctx, min_ver)) {
582 0           return AMQP_STATUS_INVALID_PARAMETER;
583             }
584 0 0         if (!SSL_CTX_set_max_proto_version(self->ctx, max_ver)) {
585 0           return AMQP_STATUS_INVALID_PARAMETER;
586             }
587              
588 0           return AMQP_STATUS_OK;
589             }
590              
591 0           void amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize) {
592             (void)do_initialize;
593 0           return;
594             }
595              
596 0           int amqp_initialize_ssl_library(void) { return AMQP_STATUS_OK; }
597              
598 0           int amqp_set_ssl_engine(const char *engine) {
599             #ifdef ENABLE_SSL_ENGINE_API
600             int status = AMQP_STATUS_OK;
601             CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
602              
603             if (openssl_engine != NULL) {
604             ENGINE_free(openssl_engine);
605             openssl_engine = NULL;
606             }
607              
608             if (engine == NULL) {
609             goto out;
610             }
611              
612             ENGINE_load_builtin_engines();
613             openssl_engine = ENGINE_by_id(engine);
614             if (openssl_engine == NULL) {
615             status = AMQP_STATUS_SSL_SET_ENGINE_FAILED;
616             goto out;
617             }
618              
619             if (ENGINE_set_default(openssl_engine, ENGINE_METHOD_ALL) == 0) {
620             ENGINE_free(openssl_engine);
621             openssl_engine = NULL;
622             status = AMQP_STATUS_SSL_SET_ENGINE_FAILED;
623             goto out;
624             }
625              
626             out:
627             CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
628             return status;
629             #else
630 0           return AMQP_STATUS_SSL_UNIMPLEMENTED;
631             #endif
632             }
633              
634 0           static int initialize_ssl_and_increment_connections(void) {
635             int status;
636 0 0         CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
637              
638 0 0         if (!openssl_bio_initialized) {
639 0           status = amqp_openssl_bio_init();
640 0 0         if (status) {
641 0           goto exit;
642             }
643 0           openssl_bio_initialized = 1;
644             }
645              
646 0           openssl_connections += 1;
647 0           status = AMQP_STATUS_OK;
648 0           exit:
649 0 0         CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
650 0           return status;
651             }
652              
653 0           static int decrement_ssl_connections(void) {
654 0 0         CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
655              
656 0 0         if (openssl_connections > 0) {
657 0           openssl_connections--;
658             }
659              
660 0 0         if (openssl_connections == 0) {
661 0           amqp_openssl_bio_destroy();
662 0           openssl_bio_initialized = 0;
663             }
664              
665 0 0         CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
666 0           return AMQP_STATUS_OK;
667             }
668              
669 0           int amqp_uninitialize_ssl_library(void) { return AMQP_STATUS_OK; }