1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2014-2020 Couchbase, Inc.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 
18 /**
19  * This file contains the common bucket of routines necessary for interfacing
20  * with OpenSSL.
21  */
22 #include "ssl_iot_common.h"
23 #include "settings.h"
24 #include "logging.h"
25 #include <openssl/err.h>
26 #include <openssl/opensslv.h>
27 
28 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
29 #define HAVE_CIPHERSUITES 1
30 #endif
31 
32 #define LOGARGS(ssl, lvl) ((lcbio_SOCKET *)SSL_get_app_data(ssl))->settings, "SSL", lvl, __FILE__, __LINE__
33 static char *global_event = "dummy event for ssl";
34 
35 /******************************************************************************
36  ******************************************************************************
37  ** Boilerplate lcbio_TABLE Wrappers                                         **
38  ******************************************************************************
39  ******************************************************************************/
loop_run(lcb_io_opt_t io)40 static void loop_run(lcb_io_opt_t io)
41 {
42     lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
43     IOT_START(xs->orig);
44 }
loop_stop(lcb_io_opt_t io)45 static void loop_stop(lcb_io_opt_t io)
46 {
47     lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
48     IOT_STOP(xs->orig);
49 }
create_event(lcb_io_opt_t io)50 static void *create_event(lcb_io_opt_t io)
51 {
52     (void)io;
53     return global_event;
54 }
destroy_event(lcb_io_opt_t io, void *event)55 static void destroy_event(lcb_io_opt_t io, void *event)
56 {
57     (void)io;
58     (void)event;
59 }
create_timer(lcb_io_opt_t io)60 static void *create_timer(lcb_io_opt_t io)
61 {
62     lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
63     return xs->orig->timer.create(IOT_ARG(xs->orig));
64 }
schedule_timer(lcb_io_opt_t io, void *timer, lcb_uint32_t us, void *arg, lcb_ioE_callback callback)65 static int schedule_timer(lcb_io_opt_t io, void *timer, lcb_uint32_t us, void *arg, lcb_ioE_callback callback)
66 {
67     lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
68     return xs->orig->timer.schedule(IOT_ARG(xs->orig), timer, us, arg, callback);
69 }
destroy_timer(lcb_io_opt_t io, void *timer)70 static void destroy_timer(lcb_io_opt_t io, void *timer)
71 {
72     lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
73     xs->orig->timer.destroy(IOT_ARG(xs->orig), timer);
74 }
cancel_timer(lcb_io_opt_t io, void *timer)75 static void cancel_timer(lcb_io_opt_t io, void *timer)
76 {
77     lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
78     xs->orig->timer.cancel(IOT_ARG(xs->orig), timer);
79 }
Eis_closed(lcb_io_opt_t io, lcb_socket_t sock, int flags)80 static int Eis_closed(lcb_io_opt_t io, lcb_socket_t sock, int flags)
81 {
82     lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
83     return xs->orig->u_io.v0.io.is_closed(IOT_ARG(xs->orig), sock, flags);
84 }
Cis_closed(lcb_io_opt_t io, lcb_sockdata_t *sd, int flags)85 static int Cis_closed(lcb_io_opt_t io, lcb_sockdata_t *sd, int flags)
86 {
87     lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
88     return xs->orig->u_io.completion.is_closed(IOT_ARG(xs->orig), sd, flags);
89 }
90 
91 /******************************************************************************
92  ******************************************************************************
93  ** Common Routines for lcbio_TABLE Emulation                                **
94  ******************************************************************************
95  ******************************************************************************/
iotssl_init_common(lcbio_XSSL *xs, lcbio_TABLE *orig, SSL_CTX *sctx)96 void iotssl_init_common(lcbio_XSSL *xs, lcbio_TABLE *orig, SSL_CTX *sctx)
97 {
98     lcbio_TABLE *base = &xs->base_;
99     xs->iops_dummy_ = calloc(1, sizeof(*xs->iops_dummy_));
100     xs->iops_dummy_->v.v0.cookie = xs;
101     xs->orig = orig;
102     base->model = xs->orig->model;
103     base->p = xs->iops_dummy_;
104     base->refcount = 1;
105     base->loop.start = loop_run;
106     base->loop.stop = loop_stop;
107     base->timer.create = create_timer;
108     base->timer.destroy = destroy_timer;
109     base->timer.schedule = schedule_timer;
110     base->timer.cancel = cancel_timer;
111 
112     if (orig->model == LCB_IOMODEL_EVENT) {
113         base->u_io.v0.ev.create = create_event;
114         base->u_io.v0.ev.destroy = destroy_event;
115         base->u_io.v0.io.is_closed = Eis_closed;
116     } else {
117         base->u_io.completion.is_closed = Cis_closed;
118     }
119 
120     lcbio_table_ref(xs->orig);
121 
122     xs->error = 0;
123     xs->ssl = SSL_new(sctx);
124 
125     xs->rbio = BIO_new(BIO_s_mem());
126     xs->wbio = BIO_new(BIO_s_mem());
127 
128     SSL_set_bio(xs->ssl, xs->rbio, xs->wbio);
129     SSL_set_read_ahead(xs->ssl, 0);
130 
131     /* Indicate that we are a client */
132     SSL_set_connect_state(xs->ssl);
133 }
134 
iotssl_destroy_common(lcbio_XSSL *xs)135 void iotssl_destroy_common(lcbio_XSSL *xs)
136 {
137     free(xs->iops_dummy_);
138     SSL_free(xs->ssl);
139     lcbio_table_unref(xs->orig);
140 }
141 
142 #if LCB_CAN_OPTIMIZE_SSL_BIO
iotssl_bm_reserve(BUF_MEM *bm)143 void iotssl_bm_reserve(BUF_MEM *bm)
144 {
145     int oldlen;
146     oldlen = bm->length;
147     while (bm->max - bm->length < 4096) {
148         /* there's also a BUF_MEM_grow_clean() but that actually clears the
149          * used portion of the buffer */
150         BUF_MEM_grow(bm, bm->max + 4096);
151     }
152     bm->length = oldlen;
153 }
154 #endif
155 
iotssl_log_errors(lcbio_XSSL *xs)156 void iotssl_log_errors(lcbio_XSSL *xs)
157 {
158     unsigned long curerr;
159     while ((curerr = ERR_get_error())) {
160         char errbuf[4096];
161         ERR_error_string_n(curerr, errbuf, sizeof errbuf);
162         lcb_log(LOGARGS(xs->ssl, LCB_LOG_ERROR), "%s", errbuf);
163 
164         if (xs->errcode != LCB_SUCCESS) {
165             continue; /* Already set */
166         }
167 
168         if (ERR_GET_LIB(curerr) == ERR_LIB_SSL) {
169             switch (ERR_GET_REASON(curerr)) {
170                 case SSL_R_CERTIFICATE_VERIFY_FAILED:
171 #ifdef SSL_R_MISSING_VERIFY_MESSAGE
172                 case SSL_R_MISSING_VERIFY_MESSAGE:
173 #endif
174                     xs->errcode = LCB_ERR_SSL_CANTVERIFY;
175                     break;
176 
177                 case SSL_R_BAD_PROTOCOL_VERSION_NUMBER:
178                 case SSL_R_UNKNOWN_PROTOCOL:
179                 case SSL_R_WRONG_VERSION_NUMBER:
180                 case SSL_R_UNKNOWN_SSL_VERSION:
181                 case SSL_R_UNSUPPORTED_SSL_VERSION:
182                     xs->errcode = LCB_ERR_PROTOCOL_ERROR;
183                     break;
184                 default:
185                     xs->errcode = LCB_ERR_SSL_ERROR;
186             }
187         }
188     }
189 }
190 
log_global_errors(lcb_settings *settings)191 static void log_global_errors(lcb_settings *settings)
192 {
193     unsigned long curerr;
194     while ((curerr = ERR_get_error())) {
195         char errbuf[4096];
196         ERR_error_string_n(curerr, errbuf, sizeof errbuf);
197         lcb_log(settings, "SSL", LCB_LOG_ERROR, __FILE__, __LINE__, "SSL Error: %ld, %s", curerr, errbuf);
198     }
199 }
200 
iotssl_maybe_error(lcbio_XSSL *xs, int rv)201 int iotssl_maybe_error(lcbio_XSSL *xs, int rv)
202 {
203     lcb_assert(rv < 1);
204     if (rv == -1) {
205         int err = SSL_get_error(xs->ssl, rv);
206         if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
207             /* this is ok. */
208             return 0;
209         }
210     }
211     iotssl_log_errors(xs);
212     return -1;
213 }
214 
215 /******************************************************************************
216  ******************************************************************************
217  ** Higher Level SSL_CTX Wrappers                                            **
218  ******************************************************************************
219  ******************************************************************************/
log_callback(const SSL *ssl, int where, int ret)220 static void log_callback(const SSL *ssl, int where, int ret)
221 {
222     int should_log = 0;
223     lcbio_SOCKET *sock = SSL_get_app_data(ssl);
224     /* Ignore low-level SSL stuff */
225 
226     if (where & SSL_CB_ALERT) {
227         should_log = 1;
228     }
229     if (where == SSL_CB_HANDSHAKE_START || where == SSL_CB_HANDSHAKE_DONE) {
230         should_log = 1;
231     }
232     if ((where & SSL_CB_EXIT) && ret == 0) {
233         should_log = 1;
234     }
235 
236     if (!should_log) {
237         return;
238     }
239 
240     lcb_log(LOGARGS(ssl, LCB_LOG_TRACE), "<%s:%s> sock=%p: ST(0x%x). %s. R(0x%x) %s (%s)",
241             sock->info ? sock->info->ep_remote.host : "", sock->info ? sock->info->ep_remote.port : "", (void *)sock,
242             where, SSL_state_string_long(ssl), ret, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
243 
244     if (where == SSL_CB_HANDSHAKE_DONE) {
245         lcb_log(LOGARGS(ssl, LCB_LOG_DEBUG), "sock=%p. Using SSL version %s. Cipher=%s", (void *)sock,
246                 SSL_get_version(ssl), SSL_get_cipher_name(ssl));
247     }
248 }
249 
250 #ifdef LCB_TLS_LOG_KEYS
log_keys_callback(const SSL *ssl, const char *line)251 static void log_keys_callback(const SSL *ssl, const char *line)
252 {
253     const char *log_file_path = getenv("LCB_TLS_KEY_LOG_FILE");
254     if (log_file_path) {
255         FILE *log_file = fopen(log_file_path, "a+");
256         if (log_file) {
257             fprintf(log_file, "%s\n", line);
258             fclose(log_file);
259         }
260     }
261     (void)ssl;
262 }
263 #endif
264 
265 #if 0
266 static void
267 msg_callback(int write_p, int version, int ctype, const void *buf, size_t n,
268     SSL *ssl, void *arg)
269 {
270     printf("Got message (%s). V=0x%x. T=%d. N=%lu\n",
271         write_p ? ">" : "<", version, ctype, n);
272     (void)ssl; (void)arg; (void)buf;
273 }
274 #endif
275 
276 struct lcbio_SSLCTX {
277     SSL_CTX *ctx;
278 };
279 
280 #define LOGARGS_S(settings, lvl) settings, "SSL", lvl, __FILE__, __LINE__
281 
decode_ssl_protocol(const char *protocol)282 static long decode_ssl_protocol(const char *protocol)
283 {
284     long disallow = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
285     if (!protocol) {
286         // The caller didn't care.. allow all from TLS 1
287         return disallow;
288     }
289     if (strcasecmp(protocol, "tlsv1.1") == 0) {
290         disallow |= SSL_OP_NO_TLSv1;
291     } else if (strcasecmp(protocol, "tlsv1.2") == 0) {
292         disallow |= SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1;
293 #ifdef HAVE_CIPHERSUITES
294     } else if (strcasecmp(protocol, "tlsv1.3") == 0) {
295         disallow |= SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1;
296 #endif
297     }
298     return disallow;
299 }
300 
lcbio_ssl_new(const char *tsfile, const char *cafile, const char *keyfile, int noverify, lcb_STATUS *errp, lcb_settings *settings)301 lcbio_pSSLCTX lcbio_ssl_new(const char *tsfile, const char *cafile, const char *keyfile, int noverify, lcb_STATUS *errp,
302                             lcb_settings *settings)
303 {
304     lcb_STATUS err_s;
305     lcbio_pSSLCTX ret;
306 
307     static const char *default_ssl_cipher_list =
308         "DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DES-CBC3-SHA:DES-"
309         "CBC3-MD5:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:SEED-SHA:RC2-CBC-"
310         "MD5:RC4-SHA:RC4-MD5:RC4-MD5:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA:DES-CBC-MD5:EXP-EDH-RSA-DES-"
311         "CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC2-CBC-MD5:EXP-RC4-MD5:EXP-RC4-MD5";
312 
313     const char *cipher_list = getenv("LCB_SSL_CIPHER_LIST");
314 #ifdef HAVE_CIPHERSUITES
315     const char *ciphersuites = getenv("LCB_SSL_CIPHERSUITES");
316 #endif
317     const char *minimum_tls = getenv("LCB_SSL_MINIMUM_TLS");
318 
319     if (!cipher_list) {
320         cipher_list = default_ssl_cipher_list;
321     }
322 
323     if (!errp) {
324         errp = &err_s;
325     }
326 
327     ret = calloc(1, sizeof(*ret));
328     if (!ret) {
329         *errp = LCB_ERR_NO_MEMORY;
330         goto GT_ERR;
331     }
332     ret->ctx = SSL_CTX_new(SSLv23_client_method());
333     if (!ret->ctx) {
334         *errp = LCB_ERR_SSL_ERROR;
335         goto GT_ERR;
336     }
337 
338     if (SSL_CTX_set_cipher_list(ret->ctx, cipher_list) == 0 && strlen(cipher_list) > 0) {
339         /*
340          * The client requested a list of ciphers, but openssl don't support
341          * any of them.
342          */
343         *errp = LCB_ERR_SSL_NO_CIPHERS;
344         goto GT_ERR;
345     }
346 
347 #ifdef HAVE_CIPHERSUITES
348     if (ciphersuites && SSL_CTX_set_ciphersuites(ret->ctx, ciphersuites) == 0 && strlen(ciphersuites) > 0) {
349         *errp = LCB_ERR_SSL_INVALID_CIPHERSUITES;
350         goto GT_ERR;
351     }
352 #endif
353 
354     if (cafile || tsfile) {
355         lcb_log(LOGARGS_S(settings, LCB_LOG_DEBUG), "Load verify locations from \"%s\"", tsfile ? tsfile : cafile);
356         if (!SSL_CTX_load_verify_locations(ret->ctx, tsfile ? tsfile : cafile, NULL)) {
357             *errp = LCB_ERR_SSL_ERROR;
358             goto GT_ERR;
359         }
360         if (cafile && keyfile) {
361             lcb_log(LOGARGS_S(settings, LCB_LOG_DEBUG), "Authenticate with key \"%s\", cert \"%s\"", keyfile, cafile);
362             if (!SSL_CTX_use_certificate_file(ret->ctx, cafile, SSL_FILETYPE_PEM)) {
363                 *errp = LCB_ERR_SSL_ERROR;
364                 goto GT_ERR;
365             }
366             if (!SSL_CTX_use_PrivateKey_file(ret->ctx, keyfile, SSL_FILETYPE_PEM)) {
367                 lcb_log(LOGARGS_S(settings, LCB_LOG_ERROR), "Unable to load private key \"%s\"", keyfile);
368                 *errp = LCB_ERR_SSL_ERROR;
369                 goto GT_ERR;
370             }
371             if (!SSL_CTX_check_private_key(ret->ctx)) {
372                 lcb_log(LOGARGS_S(settings, LCB_LOG_ERROR), "Unable to verify private key \"%s\"", keyfile);
373                 *errp = LCB_ERR_SSL_ERROR;
374                 goto GT_ERR;
375             }
376         }
377     }
378 
379     if (noverify) {
380         SSL_CTX_set_verify(ret->ctx, SSL_VERIFY_NONE, NULL);
381     } else {
382         SSL_CTX_set_verify(ret->ctx, SSL_VERIFY_PEER, NULL);
383     }
384 
385     SSL_CTX_set_info_callback(ret->ctx, log_callback);
386 #ifdef LCB_TLS_LOG_KEYS
387     {
388         const char *log_file_path = getenv("LCB_TLS_KEY_LOG_FILE");
389         if (log_file_path) {
390             SSL_CTX_set_keylog_callback(ret->ctx, log_keys_callback);
391             lcb_log(
392                 LOGARGS_S(settings, LCB_LOG_FATAL),
393                 "LCB_TLS_LOG_KEYS was enabled during build, all TLS keys will be logged for network analysis to \"%s\" "
394                 "(https://wiki.wireshark.org/TLS). DO NOT USE THIS BUILD IN PRODUCTION",
395                 log_file_path);
396         }
397     }
398 #endif
399 #if 0
400     SSL_CTX_set_msg_callback(ret->ctx, msg_callback);
401 #endif
402 
403     /* this will allow us to do SSL_write and use a different buffer if the
404      * first one fails. This is helpful in the scenario where an initial
405      * SSL_write() returns an SSL_ERROR_WANT_READ in the ssl_e.c plugin. In
406      * such a scenario the correct behavior is to return EWOULDBLOCK. However
407      * we have no guarantee that the next time we get a write request we would
408      * be using the same buffer.
409      */
410     SSL_CTX_set_mode(ret->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
411     SSL_CTX_set_options(ret->ctx, decode_ssl_protocol(minimum_tls));
412     return ret;
413 
414 GT_ERR:
415     log_global_errors(settings);
416     if (ret) {
417         if (ret->ctx) {
418             SSL_CTX_free(ret->ctx);
419         }
420         free(ret);
421     }
422     return NULL;
423 }
424 
noop_dtor(lcbio_PROTOCTX *arg)425 static void noop_dtor(lcbio_PROTOCTX *arg)
426 {
427     free(arg);
428 }
429 
lcbio_ssl_apply(lcbio_SOCKET *sock, lcbio_pSSLCTX sctx)430 lcb_STATUS lcbio_ssl_apply(lcbio_SOCKET *sock, lcbio_pSSLCTX sctx)
431 {
432     lcbio_pTABLE old_iot = sock->io, new_iot;
433     lcbio_PROTOCTX *sproto;
434 
435     if (old_iot->model == LCB_IOMODEL_EVENT) {
436         new_iot = lcbio_Essl_new(old_iot, sock->u.fd, sctx->ctx);
437     } else {
438         new_iot = lcbio_Cssl_new(old_iot, sock->u.sd, sctx->ctx);
439     }
440 
441     if (new_iot) {
442         sproto = calloc(1, sizeof(*sproto));
443         sproto->id = LCBIO_PROTOCTX_SSL;
444         sproto->dtor = noop_dtor;
445         lcbio_protoctx_add(sock, sproto);
446         lcbio_table_unref(old_iot);
447         sock->io = new_iot;
448         /* just for logging */
449         SSL_set_app_data(((lcbio_XSSL *)new_iot)->ssl, sock);
450         return LCB_SUCCESS;
451 
452     } else {
453         return LCB_ERR_SSL_ERROR;
454     }
455 }
456 
lcbio_ssl_check(lcbio_SOCKET *sock)457 int lcbio_ssl_check(lcbio_SOCKET *sock)
458 {
459     return lcbio_protoctx_get(sock, LCBIO_PROTOCTX_SSL) != NULL;
460 }
461 
lcbio_ssl_get_error(lcbio_SOCKET *sock)462 lcb_STATUS lcbio_ssl_get_error(lcbio_SOCKET *sock)
463 {
464     lcbio_XSSL *xs = (lcbio_XSSL *)sock->io;
465     return xs->errcode;
466 }
467 
lcbio_ssl_free(lcbio_pSSLCTX ctx)468 void lcbio_ssl_free(lcbio_pSSLCTX ctx)
469 {
470     SSL_CTX_free(ctx->ctx);
471     free(ctx);
472 }
473 
474 /**
475  * According to https://www.openssl.org/docs/crypto/threads.html we need
476  * to install two functions for locking support, a function that returns
477  * a thread ID, and a function which performs locking/unlocking. However later
478  * on in the link it says it will select a default implementation to return
479  * the thread ID, and thus we only need supply the locking function.
480  */
481 #if defined(_POSIX_THREADS)
482 #include <pthread.h>
483 typedef pthread_mutex_t ossl_LOCKTYPE;
ossl_lock_init(ossl_LOCKTYPE *l)484 static void ossl_lock_init(ossl_LOCKTYPE *l)
485 {
486     pthread_mutex_init(l, NULL);
487 }
ossl_lock_acquire(ossl_LOCKTYPE *l)488 static void ossl_lock_acquire(ossl_LOCKTYPE *l)
489 {
490     pthread_mutex_lock(l);
491 }
ossl_lock_release(ossl_LOCKTYPE *l)492 static void ossl_lock_release(ossl_LOCKTYPE *l)
493 {
494     pthread_mutex_unlock(l);
495 }
496 #elif defined(_WIN32)
497 #include <windows.h>
498 typedef CRITICAL_SECTION ossl_LOCKTYPE;
ossl_lock_init(ossl_LOCKTYPE *l)499 static void ossl_lock_init(ossl_LOCKTYPE *l)
500 {
501     InitializeCriticalSection(l);
502 }
ossl_lock_acquire(ossl_LOCKTYPE *l)503 static void ossl_lock_acquire(ossl_LOCKTYPE *l)
504 {
505     EnterCriticalSection(l);
506 }
ossl_lock_release(ossl_LOCKTYPE *l)507 static void ossl_lock_release(ossl_LOCKTYPE *l)
508 {
509     LeaveCriticalSection(l);
510 }
511 #else
512 typedef char ossl_LOCKTYPE;
513 #define ossl_lock_init(l)
514 #define ossl_lock_acquire(l)
515 #define ossl_lock_release(l)
516 #endif
517 
518 static ossl_LOCKTYPE *ossl_locks;
ossl_lockfn(int mode, int lkid, const char *f, int line)519 static void ossl_lockfn(int mode, int lkid, const char *f, int line)
520 {
521     ossl_LOCKTYPE *l = ossl_locks + lkid;
522 
523     if (mode & CRYPTO_LOCK) {
524         ossl_lock_acquire(l);
525     } else {
526         ossl_lock_release(l);
527     }
528 
529     (void)f;
530     (void)line;
531 }
532 
ossl_init_locks(void)533 static void ossl_init_locks(void)
534 {
535     unsigned ii, nlocks;
536     if (CRYPTO_get_locking_callback() != NULL) {
537         /* Someone already set the callback before us. Don't destroy it! */
538         return;
539     }
540     nlocks = CRYPTO_num_locks();
541     ossl_locks = malloc(sizeof(*ossl_locks) * nlocks);
542     for (ii = 0; ii < nlocks; ii++) {
543         ossl_lock_init(ossl_locks + ii);
544     }
545     /* TODO: locking API has been removed in OpenSSL 1.1 */
546     CRYPTO_set_locking_callback(ossl_lockfn);
547     (void)ossl_lockfn;
548 }
549 
550 static volatile int ossl_initialized = 0;
lcbio_ssl_global_init(void)551 void lcbio_ssl_global_init(void)
552 {
553     if (ossl_initialized) {
554         return;
555     }
556     ossl_initialized = 1;
557     SSL_library_init();
558     SSL_load_error_strings();
559     ossl_init_locks();
560 }
561 
lcbio_sslify_if_needed(lcbio_SOCKET *sock, lcb_settings *settings)562 lcb_STATUS lcbio_sslify_if_needed(lcbio_SOCKET *sock, lcb_settings *settings)
563 {
564     if (!(settings->sslopts & LCB_SSL_ENABLED)) {
565         return LCB_SUCCESS; /*not needed*/
566     }
567     if (lcbio_ssl_check(sock)) {
568         return LCB_SUCCESS; /*already ssl*/
569     }
570     return lcbio_ssl_apply(sock, settings->ssl_ctx);
571 }
572