File Coverage

amqp_openssl.c
Criterion Covered Total %
statement 153 347 44.0
branch 54 164 32.9
condition n/a
subroutine n/a
pod n/a
total 207 511 40.5


line stmt bran cond sub pod time code
1             /*
2             * Portions created by Alan Antonuk are Copyright (c) 2012-2014 Alan Antonuk.
3             * All Rights Reserved.
4             *
5             * Portions created by Michael Steinert are Copyright (c) 2012-2014 Michael
6             * Steinert. All Rights Reserved.
7             *
8             * Permission is hereby granted, free of charge, to any person obtaining a
9             * copy of this software and associated documentation files (the "Software"),
10             * to deal in the Software without restriction, including without limitation
11             * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12             * and/or sell copies of the Software, and to permit persons to whom the
13             * Software is furnished to do so, subject to the following conditions:
14             *
15             * The above copyright notice and this permission notice shall be included in
16             * all copies or substantial portions of the Software.
17             *
18             * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19             * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20             * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21             * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22             * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23             * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24             * DEALINGS IN THE SOFTWARE.
25             */
26              
27             #ifdef HAVE_CONFIG_H
28             #include "config.h"
29             #endif
30              
31             #ifdef _MSC_VER
32             #define _CRT_SECURE_NO_WARNINGS
33             #endif
34              
35             #include "amqp_openssl_bio.h"
36             #include "amqp_openssl_hostname_validation.h"
37             #include "amqp_private.h"
38             #include "amqp_socket.h"
39             #include "amqp_ssl_socket.h"
40             #include "amqp_time.h"
41             #include "threads.h"
42              
43             #include
44             #include
45             #include
46             #include
47             #include
48             #include
49             #include
50             #include
51             #include
52             #include
53              
54             static int initialize_ssl_and_increment_connections(void);
55             static int decrement_ssl_connections(void);
56              
57             static unsigned long ssl_threadid_callback(void);
58             static void ssl_locking_callback(int mode, int n, const char *file, int line);
59             static pthread_mutex_t *amqp_openssl_lockarray = NULL;
60              
61             static pthread_mutex_t openssl_init_mutex = PTHREAD_MUTEX_INITIALIZER;
62             static amqp_boolean_t do_initialize_openssl = 1;
63             static amqp_boolean_t openssl_initialized = 0;
64             static amqp_boolean_t openssl_bio_initialized = 0;
65             static int openssl_connections = 0;
66              
67             #define CHECK_SUCCESS(condition) \
68             do { \
69             int check_success_ret = (condition); \
70             if (check_success_ret) { \
71             amqp_abort("Check %s failed <%d>: %s", #condition, check_success_ret, \
72             strerror(check_success_ret)); \
73             } \
74             } while (0)
75              
76             struct amqp_ssl_socket_t {
77             const struct amqp_socket_class_t *klass;
78             SSL_CTX *ctx;
79             int sockfd;
80             SSL *ssl;
81             amqp_boolean_t verify_peer;
82             amqp_boolean_t verify_hostname;
83             int internal_error;
84             };
85              
86 18           static ssize_t amqp_ssl_socket_send(void *base, const void *buf, size_t len,
87             AMQP_UNUSED int flags) {
88 18           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
89             int res;
90 18 50         if (-1 == self->sockfd) {
91 0           return AMQP_STATUS_SOCKET_CLOSED;
92             }
93              
94             /* SSL_write takes an int for length of buffer, protect against len being
95             * larger than larger than what SSL_write can take */
96 18 50         if (len > INT_MAX) {
97 0           return AMQP_STATUS_INVALID_PARAMETER;
98             }
99              
100 18           ERR_clear_error();
101 18           self->internal_error = 0;
102              
103             /* This will only return on error, or once the whole buffer has been
104             * written to the SSL stream. See SSL_MODE_ENABLE_PARTIAL_WRITE */
105 18           res = SSL_write(self->ssl, buf, (int)len);
106 18 50         if (0 >= res) {
107 0           self->internal_error = SSL_get_error(self->ssl, res);
108             /* TODO: Close connection if it isn't already? */
109             /* TODO: Possibly be more intelligent in reporting WHAT went wrong */
110 0           switch (self->internal_error) {
111             case SSL_ERROR_WANT_READ:
112 0           res = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
113 0           break;
114             case SSL_ERROR_WANT_WRITE:
115 0           res = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
116 0           break;
117             case SSL_ERROR_ZERO_RETURN:
118 0           res = AMQP_STATUS_CONNECTION_CLOSED;
119 0           break;
120             default:
121 0           res = AMQP_STATUS_SSL_ERROR;
122 0           break;
123             }
124             } else {
125 18           self->internal_error = 0;
126             }
127              
128 18           return (ssize_t)res;
129             }
130              
131 30           static ssize_t amqp_ssl_socket_recv(void *base, void *buf, size_t len,
132             AMQP_UNUSED int flags) {
133 30           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
134             int received;
135 30 50         if (-1 == self->sockfd) {
136 0           return AMQP_STATUS_SOCKET_CLOSED;
137             }
138              
139             /* SSL_read takes an int for length of buffer, protect against len being
140             * larger than larger than what SSL_read can take */
141 30 50         if (len > INT_MAX) {
142 0           return AMQP_STATUS_INVALID_PARAMETER;
143             }
144              
145 30           ERR_clear_error();
146 30           self->internal_error = 0;
147              
148 30           received = SSL_read(self->ssl, buf, (int)len);
149 30 100         if (0 >= received) {
150 15           self->internal_error = SSL_get_error(self->ssl, received);
151 15           switch (self->internal_error) {
152             case SSL_ERROR_WANT_READ:
153 15           received = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD;
154 15           break;
155             case SSL_ERROR_WANT_WRITE:
156 0           received = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE;
157 0           break;
158             case SSL_ERROR_ZERO_RETURN:
159 0           received = AMQP_STATUS_CONNECTION_CLOSED;
160 0           break;
161             default:
162 0           received = AMQP_STATUS_SSL_ERROR;
163 0           break;
164             }
165             }
166              
167 30           return (ssize_t)received;
168             }
169              
170 1           static int amqp_ssl_socket_open(void *base, const char *host, int port,
171             const struct timeval *timeout) {
172 1           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
173             long result;
174             int status;
175             amqp_time_t deadline;
176             X509 *cert;
177             BIO *bio;
178 1 50         if (-1 != self->sockfd) {
179 0           return AMQP_STATUS_SOCKET_INUSE;
180             }
181 1           ERR_clear_error();
182              
183 1           self->ssl = SSL_new(self->ctx);
184 1 50         if (!self->ssl) {
185 0           self->internal_error = ERR_peek_error();
186 0           status = AMQP_STATUS_SSL_ERROR;
187 0           goto exit;
188             }
189              
190 1           status = amqp_time_from_now(&deadline, timeout);
191 1 50         if (AMQP_STATUS_OK != status) {
192 0           return status;
193             }
194              
195 1           self->sockfd = amqp_open_socket_inner(host, port, deadline);
196 1 50         if (0 > self->sockfd) {
197 0           status = self->sockfd;
198 0           self->internal_error = amqp_os_socket_error();
199 0           self->sockfd = -1;
200 0           goto error_out1;
201             }
202              
203 1           bio = BIO_new(amqp_openssl_bio());
204 1 50         if (!bio) {
205 0           status = AMQP_STATUS_NO_MEMORY;
206 0           goto error_out2;
207             }
208              
209 1           BIO_set_fd(bio, self->sockfd, BIO_NOCLOSE);
210 1           SSL_set_bio(self->ssl, bio, bio);
211              
212 1           status = SSL_set_tlsext_host_name(self->ssl, host);
213 1 50         if (!status) {
214 0           self->internal_error = SSL_get_error(self->ssl, status);
215 0           status = AMQP_STATUS_SSL_ERROR;
216 0           goto error_out2;
217             }
218              
219             start_connect:
220 3           status = SSL_connect(self->ssl);
221 3 100         if (status != 1) {
222 2           self->internal_error = SSL_get_error(self->ssl, status);
223 2           switch (self->internal_error) {
224             case SSL_ERROR_WANT_READ:
225 2           status = amqp_poll(self->sockfd, AMQP_SF_POLLIN, deadline);
226 2           break;
227             case SSL_ERROR_WANT_WRITE:
228 0           status = amqp_poll(self->sockfd, AMQP_SF_POLLOUT, deadline);
229 0           break;
230             default:
231 0           status = AMQP_STATUS_SSL_CONNECTION_FAILED;
232             }
233 2 50         if (AMQP_STATUS_OK == status) {
234 2           goto start_connect;
235             }
236 0           goto error_out2;
237             }
238              
239 1           cert = SSL_get_peer_certificate(self->ssl);
240              
241 1 50         if (self->verify_peer) {
242 1 50         if (!cert) {
243 0           self->internal_error = 0;
244 0           status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED;
245 0           goto error_out3;
246             }
247              
248 1           result = SSL_get_verify_result(self->ssl);
249 1 50         if (X509_V_OK != result) {
250 0           self->internal_error = result;
251 0           status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED;
252 0           goto error_out4;
253             }
254             }
255 1 50         if (self->verify_hostname) {
256 1 50         if (!cert) {
257 0           self->internal_error = 0;
258 0           status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED;
259 0           goto error_out3;
260             }
261              
262 1 50         if (AMQP_HVR_MATCH_FOUND != amqp_ssl_validate_hostname(host, cert)) {
263 0           self->internal_error = 0;
264 0           status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED;
265 0           goto error_out4;
266             }
267             }
268              
269 1           X509_free(cert);
270 1           self->internal_error = 0;
271 1           status = AMQP_STATUS_OK;
272              
273             exit:
274 1           return status;
275              
276             error_out4:
277 0           X509_free(cert);
278             error_out3:
279 0           SSL_shutdown(self->ssl);
280             error_out2:
281 0           amqp_os_socket_close(self->sockfd);
282 0           self->sockfd = -1;
283             error_out1:
284 0           SSL_free(self->ssl);
285 0           self->ssl = NULL;
286 1           goto exit;
287             }
288              
289 1           static int amqp_ssl_socket_close(void *base, amqp_socket_close_enum force) {
290 1           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
291              
292 1 50         if (-1 == self->sockfd) {
293 0           return AMQP_STATUS_SOCKET_CLOSED;
294             }
295              
296 1 50         if (AMQP_SC_NONE == force) {
297             /* don't try too hard to shutdown the connection */
298 1           SSL_shutdown(self->ssl);
299             }
300              
301 1           SSL_free(self->ssl);
302 1           self->ssl = NULL;
303              
304 1 50         if (amqp_os_socket_close(self->sockfd)) {
305 0           return AMQP_STATUS_SOCKET_ERROR;
306             }
307 1           self->sockfd = -1;
308              
309 1           return AMQP_STATUS_OK;
310             }
311              
312 31           static int amqp_ssl_socket_get_sockfd(void *base) {
313 31           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
314 31           return self->sockfd;
315             }
316              
317 1           static void amqp_ssl_socket_delete(void *base) {
318 1           struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base;
319              
320 1 50         if (self) {
321 1           amqp_ssl_socket_close(self, AMQP_SC_NONE);
322              
323 1           SSL_CTX_free(self->ctx);
324 1           free(self);
325             }
326 1           decrement_ssl_connections();
327 1           }
328              
329             static const struct amqp_socket_class_t amqp_ssl_socket_class = {
330             amqp_ssl_socket_send, /* send */
331             amqp_ssl_socket_recv, /* recv */
332             amqp_ssl_socket_open, /* open */
333             amqp_ssl_socket_close, /* close */
334             amqp_ssl_socket_get_sockfd, /* get_sockfd */
335             amqp_ssl_socket_delete /* delete */
336             };
337              
338 1           amqp_socket_t *amqp_ssl_socket_new(amqp_connection_state_t state) {
339 1           struct amqp_ssl_socket_t *self = calloc(1, sizeof(*self));
340             int status;
341 1 50         if (!self) {
342 0           return NULL;
343             }
344              
345 1           self->sockfd = -1;
346 1           self->klass = &amqp_ssl_socket_class;
347 1           self->verify_peer = 1;
348 1           self->verify_hostname = 1;
349              
350 1           status = initialize_ssl_and_increment_connections();
351 1 50         if (status) {
352 0           goto error;
353             }
354              
355 1           self->ctx = SSL_CTX_new(SSLv23_client_method());
356 1 50         if (!self->ctx) {
357 0           goto error;
358             }
359             /* Disable SSLv2 and SSLv3 */
360 1           SSL_CTX_set_options(self->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
361              
362 1           SSL_CTX_set_mode(self->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
363             /* OpenSSL v1.1.1 turns this on by default, which makes the non-blocking
364             * logic not behave as expected, so turn this back off */
365 1           SSL_CTX_clear_mode(self->ctx, SSL_MODE_AUTO_RETRY);
366              
367 1           amqp_set_socket(state, (amqp_socket_t *)self);
368              
369 1           return (amqp_socket_t *)self;
370             error:
371 0           amqp_ssl_socket_delete((amqp_socket_t *)self);
372 0           return NULL;
373             }
374              
375 0           void *amqp_ssl_socket_get_context(amqp_socket_t *base) {
376 0 0         if (base->klass != &amqp_ssl_socket_class) {
377 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
378             }
379 0           return ((struct amqp_ssl_socket_t *)base)->ctx;
380             }
381              
382 1           int amqp_ssl_socket_set_cacert(amqp_socket_t *base, const char *cacert) {
383             int status;
384             struct amqp_ssl_socket_t *self;
385 1 50         if (base->klass != &amqp_ssl_socket_class) {
386 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
387             }
388 1           self = (struct amqp_ssl_socket_t *)base;
389 1           status = SSL_CTX_load_verify_locations(self->ctx, cacert, NULL);
390 1 50         if (1 != status) {
391 0           return AMQP_STATUS_SSL_ERROR;
392             }
393 1           return AMQP_STATUS_OK;
394             }
395              
396 0           int amqp_ssl_socket_set_key(amqp_socket_t *base, const char *cert,
397             const char *key) {
398             int status;
399             struct amqp_ssl_socket_t *self;
400 0 0         if (base->klass != &amqp_ssl_socket_class) {
401 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
402             }
403 0           self = (struct amqp_ssl_socket_t *)base;
404 0           status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
405 0 0         if (1 != status) {
406 0           return AMQP_STATUS_SSL_ERROR;
407             }
408 0           status = SSL_CTX_use_PrivateKey_file(self->ctx, key, SSL_FILETYPE_PEM);
409 0 0         if (1 != status) {
410 0           return AMQP_STATUS_SSL_ERROR;
411             }
412 0           return AMQP_STATUS_OK;
413             }
414              
415 0           static int password_cb(AMQP_UNUSED char *buffer, AMQP_UNUSED int length,
416             AMQP_UNUSED int rwflag, AMQP_UNUSED void *user_data) {
417 0           amqp_abort("rabbitmq-c does not support password protected keys");
418             }
419              
420 0           int amqp_ssl_socket_set_key_buffer(amqp_socket_t *base, const char *cert,
421             const void *key, size_t n) {
422 0           int status = AMQP_STATUS_OK;
423 0           BIO *buf = NULL;
424 0           RSA *rsa = NULL;
425             struct amqp_ssl_socket_t *self;
426 0 0         if (base->klass != &amqp_ssl_socket_class) {
427 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
428             }
429 0 0         if (n > INT_MAX) {
430 0           return AMQP_STATUS_INVALID_PARAMETER;
431             }
432 0           self = (struct amqp_ssl_socket_t *)base;
433 0           status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
434 0 0         if (1 != status) {
435 0           return AMQP_STATUS_SSL_ERROR;
436             }
437 0           buf = BIO_new_mem_buf((void *)key, (int)n);
438 0 0         if (!buf) {
439 0           goto error;
440             }
441 0           rsa = PEM_read_bio_RSAPrivateKey(buf, NULL, password_cb, NULL);
442 0 0         if (!rsa) {
443 0           goto error;
444             }
445 0           status = SSL_CTX_use_RSAPrivateKey(self->ctx, rsa);
446 0 0         if (1 != status) {
447 0           goto error;
448             }
449             exit:
450 0           BIO_vfree(buf);
451 0           RSA_free(rsa);
452 0           return status;
453             error:
454 0           status = AMQP_STATUS_SSL_ERROR;
455 0           goto exit;
456             }
457              
458 0           int amqp_ssl_socket_set_cert(amqp_socket_t *base, const char *cert) {
459             int status;
460             struct amqp_ssl_socket_t *self;
461 0 0         if (base->klass != &amqp_ssl_socket_class) {
462 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
463             }
464 0           self = (struct amqp_ssl_socket_t *)base;
465 0           status = SSL_CTX_use_certificate_chain_file(self->ctx, cert);
466 0 0         if (1 != status) {
467 0           return AMQP_STATUS_SSL_ERROR;
468             }
469 0           return AMQP_STATUS_OK;
470             }
471              
472 0           void amqp_ssl_socket_set_verify(amqp_socket_t *base, amqp_boolean_t verify) {
473 0           amqp_ssl_socket_set_verify_peer(base, verify);
474 0           amqp_ssl_socket_set_verify_hostname(base, verify);
475 0           }
476              
477 0           void amqp_ssl_socket_set_verify_peer(amqp_socket_t *base,
478             amqp_boolean_t verify) {
479             struct amqp_ssl_socket_t *self;
480 0 0         if (base->klass != &amqp_ssl_socket_class) {
481 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
482             }
483 0           self = (struct amqp_ssl_socket_t *)base;
484 0           self->verify_peer = verify;
485 0           }
486              
487 1           void amqp_ssl_socket_set_verify_hostname(amqp_socket_t *base,
488             amqp_boolean_t verify) {
489             struct amqp_ssl_socket_t *self;
490 1 50         if (base->klass != &amqp_ssl_socket_class) {
491 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
492             }
493 1           self = (struct amqp_ssl_socket_t *)base;
494 1           self->verify_hostname = verify;
495 1           }
496              
497 0           int amqp_ssl_socket_set_ssl_versions(amqp_socket_t *base,
498             amqp_tls_version_t min,
499             amqp_tls_version_t max) {
500             struct amqp_ssl_socket_t *self;
501 0 0         if (base->klass != &amqp_ssl_socket_class) {
502 0           amqp_abort("<%p> is not of type amqp_ssl_socket_t", base);
503             }
504 0           self = (struct amqp_ssl_socket_t *)base;
505              
506             {
507             long clear_options;
508 0           long set_options = 0;
509             #if defined(SSL_OP_NO_TLSv1_2)
510 0           amqp_tls_version_t max_supported = AMQP_TLSv1_2;
511 0           clear_options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
512             #elif defined(SSL_OP_NO_TLSv1_1)
513             amqp_tls_version_t max_supported = AMQP_TLSv1_1;
514             clear_options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
515             #elif defined(SSL_OP_NO_TLSv1)
516             amqp_tls_version_t max_supported = AMQP_TLSv1;
517             clear_options = SSL_OP_NO_TLSv1;
518             #else
519             #error "Need a version of OpenSSL that can support TLSv1 or greater."
520             #endif
521              
522 0 0         if (AMQP_TLSvLATEST == max) {
523 0           max = max_supported;
524             }
525 0 0         if (AMQP_TLSvLATEST == min) {
526 0           min = max_supported;
527             }
528              
529 0 0         if (min > max) {
530 0           return AMQP_STATUS_INVALID_PARAMETER;
531             }
532              
533 0 0         if (max > max_supported || min > max_supported) {
    0          
534 0           return AMQP_STATUS_UNSUPPORTED;
535             }
536              
537 0 0         if (min > AMQP_TLSv1) {
538 0           set_options |= SSL_OP_NO_TLSv1;
539             }
540             #ifdef SSL_OP_NO_TLSv1_1
541 0 0         if (min > AMQP_TLSv1_1 || max < AMQP_TLSv1_1) {
    0          
542 0           set_options |= SSL_OP_NO_TLSv1_1;
543             }
544             #endif
545             #ifdef SSL_OP_NO_TLSv1_2
546 0 0         if (max < AMQP_TLSv1_2) {
547 0           set_options |= SSL_OP_NO_TLSv1_2;
548             }
549             #endif
550 0           SSL_CTX_clear_options(self->ctx, clear_options);
551 0           SSL_CTX_set_options(self->ctx, set_options);
552             }
553              
554 0           return AMQP_STATUS_OK;
555             }
556              
557 1           void amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize) {
558 1 50         CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
559              
560 1 50         if (openssl_connections == 0 && !openssl_initialized) {
    50          
561 1           do_initialize_openssl = do_initialize;
562             }
563 1 50         CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
564 1           }
565              
566 141           static unsigned long ssl_threadid_callback(void) {
567 141           return (unsigned long)pthread_self();
568             }
569              
570 57138           static void ssl_locking_callback(int mode, int n, AMQP_UNUSED const char *file,
571             AMQP_UNUSED int line) {
572 57138 100         if (mode & CRYPTO_LOCK) {
573 28569 50         CHECK_SUCCESS(pthread_mutex_lock(&amqp_openssl_lockarray[n]));
574             } else {
575 28569 50         CHECK_SUCCESS(pthread_mutex_unlock(&amqp_openssl_lockarray[n]));
576             }
577 57138           }
578              
579 1           static int setup_openssl(void) {
580             int status;
581              
582             int i;
583 1           amqp_openssl_lockarray = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t));
584 1 50         if (!amqp_openssl_lockarray) {
585 0           status = AMQP_STATUS_NO_MEMORY;
586 0           goto out;
587             }
588 42 100         for (i = 0; i < CRYPTO_num_locks(); i++) {
589 41 50         if (pthread_mutex_init(&amqp_openssl_lockarray[i], NULL)) {
590             int j;
591 0 0         for (j = 0; j < i; j++) {
592 0           pthread_mutex_destroy(&amqp_openssl_lockarray[j]);
593             }
594 0           free(amqp_openssl_lockarray);
595 0           status = AMQP_STATUS_SSL_ERROR;
596 0           goto out;
597             }
598             }
599 1           CRYPTO_set_id_callback(ssl_threadid_callback);
600 1           CRYPTO_set_locking_callback(ssl_locking_callback);
601              
602             #ifdef AMQP_OPENSSL_V110
603             if (OPENSSL_init_ssl(0, NULL) <= 0) {
604             status = AMQP_STATUS_SSL_ERROR;
605             goto out;
606             }
607             #else
608 1           OPENSSL_config(NULL);
609             #endif
610 1           SSL_library_init();
611 1           SSL_load_error_strings();
612              
613 1           status = AMQP_STATUS_OK;
614             out:
615 1           return status;
616             }
617              
618 0           int amqp_initialize_ssl_library(void) {
619             int status;
620 0 0         CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
621              
622 0 0         if (!openssl_initialized) {
623 0           status = setup_openssl();
624 0 0         if (status) {
625 0           goto out;
626             }
627 0           openssl_initialized = 1;
628             }
629              
630 0           status = AMQP_STATUS_OK;
631             out:
632 0 0         CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
633 0           return status;
634             }
635              
636 1           static int initialize_ssl_and_increment_connections() {
637             int status;
638 1 50         CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
639              
640 1 50         if (do_initialize_openssl && !openssl_initialized) {
    50          
641 1           status = setup_openssl();
642 1 50         if (status) {
643 0           goto exit;
644             }
645 1           openssl_initialized = 1;
646             }
647              
648 1 50         if (!openssl_bio_initialized) {
649 1           status = amqp_openssl_bio_init();
650 1 50         if (status) {
651 0           goto exit;
652             }
653 1           openssl_bio_initialized = 1;
654             }
655              
656 1           openssl_connections += 1;
657 1           status = AMQP_STATUS_OK;
658             exit:
659 1 50         CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
660 1           return status;
661             }
662              
663 1           static int decrement_ssl_connections(void) {
664 1 50         CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
665              
666 1 50         if (openssl_connections > 0) {
667 1           openssl_connections--;
668             }
669              
670 1 50         CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
671 1           return AMQP_STATUS_OK;
672             }
673              
674 0           int amqp_uninitialize_ssl_library(void) {
675             int status;
676 0 0         CHECK_SUCCESS(pthread_mutex_lock(&openssl_init_mutex));
677              
678 0 0         if (openssl_connections > 0) {
679 0           status = AMQP_STATUS_SOCKET_INUSE;
680 0           goto out;
681             }
682              
683 0           amqp_openssl_bio_destroy();
684 0           openssl_bio_initialized = 0;
685              
686             #ifndef AMQP_OPENSSL_V110
687 0           ERR_remove_state(0);
688             #endif
689              
690             #ifndef LIBRESSL_VERSION_NUMBER
691 0           FIPS_mode_set(0);
692             #endif
693              
694 0           CRYPTO_set_locking_callback(NULL);
695 0           CRYPTO_set_id_callback(NULL);
696             {
697             int i;
698 0 0         for (i = 0; i < CRYPTO_num_locks(); i++) {
699 0           pthread_mutex_destroy(&amqp_openssl_lockarray[i]);
700             }
701 0           free(amqp_openssl_lockarray);
702             }
703              
704 0           ENGINE_cleanup();
705 0           CONF_modules_free();
706 0           EVP_cleanup();
707 0           CRYPTO_cleanup_all_ex_data();
708 0           ERR_free_strings();
709             #if (OPENSSL_VERSION_NUMBER >= 0x10002003L) && !defined(LIBRESSL_VERSION_NUMBER)
710 0           SSL_COMP_free_compression_methods();
711             #endif
712              
713 0           openssl_initialized = 0;
714              
715 0           status = AMQP_STATUS_OK;
716             out:
717 0 0         CHECK_SUCCESS(pthread_mutex_unlock(&openssl_init_mutex));
718 0           return status;
719             }