1 #include "memcached.h"
2
3 #ifdef TLS
4
5 #include "tls.h"
6 #include <string.h>
7 #include <sysexits.h>
8 #include <sys/param.h>
9 #include <openssl/ssl.h>
10 #include <openssl/err.h>
11
12 /* constant session ID context for application-level SSL session scoping.
13 * used in server-side SSL session caching, when enabled. */
14 #define SESSION_ID_CONTEXT "memcached"
15
16 #ifndef MAXPATHLEN
17 #define MAXPATHLEN 4096
18 #endif
19
20 static ssize_t ssl_read(conn *c, void *buf, size_t count);
21 static ssize_t ssl_sendmsg(conn *c, struct msghdr *msg, int flags);
22 static ssize_t ssl_write(conn *c, void *buf, size_t count);
23 static void print_ssl_error(char *buff, size_t len);
24 static void ssl_callback(const SSL *s, int where, int ret);
25 static int ssl_new_session_callback(SSL *s, SSL_SESSION *sess);
26
27 static pthread_mutex_t ssl_ctx_lock = PTHREAD_MUTEX_INITIALIZER;
28
29 const unsigned ERROR_MSG_SIZE = 64;
30 const size_t SSL_ERROR_MSG_SIZE = 256;
31
SSL_LOCK(void)32 static void SSL_LOCK(void) {
33 pthread_mutex_lock(&(ssl_ctx_lock));
34 }
35
SSL_UNLOCK(void)36 static void SSL_UNLOCK(void) {
37 pthread_mutex_unlock(&(ssl_ctx_lock));
38 }
39
ssl_accept(conn * c,int sfd,bool * fail)40 void *ssl_accept(conn *c, int sfd, bool *fail) {
41 SSL *ssl = NULL;
42 if (c->ssl_enabled) {
43 assert(IS_TCP(c->transport) && settings.ssl_enabled);
44
45 if (settings.ssl_ctx == NULL) {
46 if (settings.verbose) {
47 fprintf(stderr, "SSL context is not initialized\n");
48 }
49 *fail = true;
50 return NULL;
51 }
52 SSL_LOCK();
53 ssl = SSL_new(settings.ssl_ctx);
54 SSL_UNLOCK();
55 if (ssl == NULL) {
56 if (settings.verbose) {
57 fprintf(stderr, "Failed to created the SSL object\n");
58 }
59 *fail = true;
60 ERR_clear_error();
61 return NULL;
62 }
63 SSL_set_fd(ssl, sfd);
64
65 if (c->ssl_enabled == MC_SSL_ENABLED_NOPEER) {
66 // Don't enforce peer certs for this socket.
67 SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
68 } else if (c->ssl_enabled == MC_SSL_ENABLED_PEER) {
69 // Force peer validation for this socket.
70 SSL_set_verify(ssl, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
71 }
72
73 ERR_clear_error();
74 int ret = SSL_accept(ssl);
75 if (ret <= 0) {
76 int err = SSL_get_error(ssl, ret);
77 if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
78 // we're actually fine, let the worker thread continue.
79 ERR_clear_error();
80 } else {
81 // TODO: ship full error to log stream? conn events?
82 // SYSCALL specifically means we need to check errno/strerror.
83 // Else we need to look at the main error stack.
84 if (err == SSL_ERROR_SYSCALL) {
85 LOGGER_LOG(NULL, LOG_CONNEVENTS, LOGGER_CONNECTION_TLSERROR,
86 NULL, c->sfd, strerror(errno));
87 } else {
88 char ssl_err[SSL_ERROR_MSG_SIZE];
89 // OpenSSL internal error. One or more, but lets only care about
90 // the top error for now.
91 print_ssl_error(ssl_err, SSL_ERROR_MSG_SIZE);
92 LOGGER_LOG(NULL, LOG_CONNEVENTS, LOGGER_CONNECTION_TLSERROR,
93 NULL, c->sfd, ssl_err);
94 }
95 ERR_clear_error();
96 SSL_free(ssl);
97 STATS_LOCK();
98 stats.ssl_handshake_errors++;
99 STATS_UNLOCK();
100 *fail = true;
101 return NULL;
102 }
103 }
104 }
105
106 return ssl;
107 }
108
109 /*
110 * Note on setting errno in the follow functions:
111 * We either have to refactor callers of read/write/sendmsg to take an error
112 * flag to find out if we're in an EAGAIN state, or we ensure the errno is set
113 * properly before returning from our TLS call. We do this because it's
114 * _possible_ for OpenSSL to do something weird and land with an errno that
115 * doesn't match the WANT_READ|WRITE state.
116 *
117 * Also: we _might_ have to communicate from these calls if we need to wait on
118 * reads or write. Since I haven't yet proved that's even possible I'll save
119 * that for a future refactor.
120 */
121
122 // TODO: add int offset, and find the nth NID here.
123 // or different function that accepts a string, then does etc?
124 // Caller _must immediately_ use the string and not store the pointer.
ssl_get_peer_cn(conn * c,int * len)125 const unsigned char *ssl_get_peer_cn(conn *c, int *len) {
126 if (!c->ssl) {
127 return NULL;
128 }
129
130 // can't use get0 to avoid getting a reference since that requires 3.0.0+
131 X509 *cert = SSL_get_peer_certificate(c->ssl);
132 if (cert == NULL) {
133 return NULL;
134 }
135 X509_NAME *name = X509_get_subject_name(cert);
136 if (name == NULL) {
137 X509_free(cert);
138 return NULL;
139 }
140
141 int r = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
142 if (r == -1) {
143 X509_free(cert);
144 return NULL;
145 }
146 ASN1_STRING *asn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, r));
147
148 if (asn1 == NULL) {
149 X509_free(cert);
150 return NULL;
151 }
152 *len = ASN1_STRING_length(asn1);
153 X509_free(cert);
154 return ASN1_STRING_get0_data(asn1);
155 }
156
157 /*
158 * Reads decrypted data from the underlying BIO read buffers,
159 * which reads from the socket.
160 */
ssl_read(conn * c,void * buf,size_t count)161 static ssize_t ssl_read(conn *c, void *buf, size_t count) {
162 assert (c != NULL);
163 /* TODO : document the state machine interactions for SSL_read with
164 non-blocking sockets/ SSL re-negotiations
165 */
166
167 ssize_t ret = SSL_read(c->ssl, buf, count);
168 if (ret <= 0) {
169 int err = SSL_get_error(c->ssl, ret);
170 if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
171 errno = EAGAIN;
172 } else if (err == SSL_ERROR_ZERO_RETURN) {
173 // TLS session is closed... let the caller move this along.
174 return 0;
175 } else if (err == SSL_ERROR_SYSCALL) {
176 // need to rely on errno to find out what happened
177 LOGGER_LOG(c->thread->l, LOG_CONNEVENTS, LOGGER_CONNECTION_TLSERROR,
178 NULL, c->sfd, strerror(errno));
179 } else if (ret != 0) {
180 char ssl_err[SSL_ERROR_MSG_SIZE];
181 // OpenSSL internal error. One or more, but lets only care about
182 // the top error for now.
183 print_ssl_error(ssl_err, SSL_ERROR_MSG_SIZE);
184 LOGGER_LOG(c->thread->l, LOG_CONNEVENTS, LOGGER_CONNECTION_TLSERROR,
185 NULL, c->sfd, ssl_err);
186 STATS_LOCK();
187 stats.ssl_proto_errors++;
188 STATS_UNLOCK();
189 }
190 ERR_clear_error();
191 }
192
193 return ret;
194 }
195
196 /*
197 * Writes data to the underlying BIO write buffers,
198 * which encrypt and write them to the socket.
199 */
ssl_write(conn * c,void * buf,size_t count)200 static ssize_t ssl_write(conn *c, void *buf, size_t count) {
201 assert (c != NULL);
202
203 ssize_t ret = SSL_write(c->ssl, buf, count);
204 if (ret <= 0) {
205 int err = SSL_get_error(c->ssl, ret);
206 if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
207 errno = EAGAIN;
208 } else if (err == SSL_ERROR_ZERO_RETURN) {
209 // TLS session is closed... let the caller move this along.
210 return 0;
211 } else if (err == SSL_ERROR_SYSCALL) {
212 // need to rely on errno to find out what happened
213 LOGGER_LOG(c->thread->l, LOG_CONNEVENTS, LOGGER_CONNECTION_TLSERROR,
214 NULL, c->sfd, strerror(errno));
215 } else if (ret != 0) {
216 char ssl_err[SSL_ERROR_MSG_SIZE];
217 // OpenSSL internal error. One or more, but lets only care about
218 // the top error for now.
219 print_ssl_error(ssl_err, SSL_ERROR_MSG_SIZE);
220 LOGGER_LOG(c->thread->l, LOG_CONNEVENTS, LOGGER_CONNECTION_TLSERROR,
221 NULL, c->sfd, ssl_err);
222 STATS_LOCK();
223 stats.ssl_proto_errors++;
224 STATS_UNLOCK();
225 }
226 ERR_clear_error();
227 }
228 return ret;
229 }
230
231 /*
232 * SSL sendmsg implementation. Perform a SSL_write.
233 */
ssl_sendmsg(conn * c,struct msghdr * msg,int flags)234 static ssize_t ssl_sendmsg(conn *c, struct msghdr *msg, int flags) {
235 assert (c != NULL);
236 size_t buf_remain = settings.ssl_wbuf_size;
237 size_t bytes = 0;
238 size_t to_copy;
239 int i;
240
241 // ssl_wbuf is pointing to the buffer allocated in the worker thread.
242 assert(c->ssl_wbuf);
243 // TODO: allocate a fix buffer in crawler/logger if they start using
244 // the sendmsg method. Also, set c->ssl_wbuf when the side thread
245 // start owning the connection and reset the pointer in
246 // conn_worker_readd.
247 // Currently this connection would not be served by a different thread
248 // than the one it's assigned.
249 assert(pthread_equal(c->thread->thread_id, pthread_self()) != 0);
250
251 char *bp = c->ssl_wbuf;
252 for (i = 0; i < msg->msg_iovlen; i++) {
253 size_t len = msg->msg_iov[i].iov_len;
254 to_copy = len < buf_remain ? len : buf_remain;
255
256 memcpy(bp + bytes, (void*)msg->msg_iov[i].iov_base, to_copy);
257 buf_remain -= to_copy;
258 bytes += to_copy;
259 if (buf_remain == 0)
260 break;
261 }
262 /* TODO : document the state machine interactions for SSL_write with
263 non-blocking sockets/ SSL re-negotiations
264 */
265 return ssl_write(c, c->ssl_wbuf, bytes);
266 }
267
268 /*
269 * Prints an SSL error into the buff, if there's any.
270 */
print_ssl_error(char * buff,size_t len)271 static void print_ssl_error(char *buff, size_t len) {
272 unsigned long err;
273 if ((err = ERR_get_error()) != 0) {
274 ERR_error_string_n(err, buff, len);
275 }
276 }
277
278 /*
279 * Loads server certificates to the SSL context and validate them.
280 * @return whether certificates are successfully loaded and verified or not.
281 * @param error_msg contains the error when unsuccessful.
282 */
load_server_certificates(char ** errmsg)283 static bool load_server_certificates(char **errmsg) {
284 bool success = false;
285
286 const size_t CRLF_NULLCHAR_LEN = 3;
287 char *error_msg = malloc(MAXPATHLEN + ERROR_MSG_SIZE +
288 SSL_ERROR_MSG_SIZE);
289 size_t errmax = MAXPATHLEN + ERROR_MSG_SIZE + SSL_ERROR_MSG_SIZE -
290 CRLF_NULLCHAR_LEN;
291
292 if (error_msg == NULL) {
293 *errmsg = NULL;
294 return false;
295 }
296
297 if (settings.ssl_ctx == NULL) {
298 snprintf(error_msg, errmax, "Error TLS not enabled\r\n");
299 *errmsg = error_msg;
300 return false;
301 }
302
303 char *ssl_err_msg = malloc(SSL_ERROR_MSG_SIZE);
304 if (ssl_err_msg == NULL) {
305 free(error_msg);
306 *errmsg = NULL;
307 return false;
308 }
309 bzero(ssl_err_msg, SSL_ERROR_MSG_SIZE);
310 size_t err_msg_size = 0;
311
312 SSL_LOCK();
313 if (!SSL_CTX_use_certificate_chain_file(settings.ssl_ctx,
314 settings.ssl_chain_cert)) {
315 print_ssl_error(ssl_err_msg, SSL_ERROR_MSG_SIZE);
316 err_msg_size = snprintf(error_msg, errmax, "Error loading the certificate chain: "
317 "%s : %s", settings.ssl_chain_cert, ssl_err_msg);
318 } else if (!SSL_CTX_use_PrivateKey_file(settings.ssl_ctx, settings.ssl_key,
319 settings.ssl_keyformat)) {
320 print_ssl_error(ssl_err_msg, SSL_ERROR_MSG_SIZE);
321 err_msg_size = snprintf(error_msg, errmax, "Error loading the key: %s : %s",
322 settings.ssl_key, ssl_err_msg);
323 } else if (!SSL_CTX_check_private_key(settings.ssl_ctx)) {
324 print_ssl_error(ssl_err_msg, SSL_ERROR_MSG_SIZE);
325 err_msg_size = snprintf(error_msg, errmax, "Error validating the certificate: %s",
326 ssl_err_msg);
327 } else if (settings.ssl_ca_cert) {
328 if (!SSL_CTX_load_verify_locations(settings.ssl_ctx,
329 settings.ssl_ca_cert, NULL)) {
330 print_ssl_error(ssl_err_msg, SSL_ERROR_MSG_SIZE);
331 err_msg_size = snprintf(error_msg, errmax,
332 "Error loading the CA certificate: %s : %s",
333 settings.ssl_ca_cert, ssl_err_msg);
334 } else {
335 SSL_CTX_set_client_CA_list(settings.ssl_ctx,
336 SSL_load_client_CA_file(settings.ssl_ca_cert));
337 success = true;
338 }
339 } else {
340 success = true;
341 }
342 SSL_UNLOCK();
343 free(ssl_err_msg);
344 if (success) {
345 settings.ssl_last_cert_refresh_time = current_time;
346 free(error_msg);
347 } else {
348 *errmsg = error_msg;
349 error_msg += (err_msg_size >= errmax ? errmax - 1: err_msg_size);
350 snprintf(error_msg, CRLF_NULLCHAR_LEN, "\r\n");
351 // Print if there are more errors and drain the queue.
352 ERR_print_errors_fp(stderr);
353 }
354 return success;
355 }
356
ssl_conn_close(void * ssl_in)357 void ssl_conn_close(void *ssl_in) {
358 SSL *ssl = ssl_in;
359 SSL_shutdown(ssl);
360 SSL_free(ssl);
361 }
362
ssl_init_conn(conn * c,void * ssl_in)363 void ssl_init_conn(conn *c, void *ssl_in) {
364 if (ssl_in) {
365 SSL *ssl = ssl_in;
366 c->ssl = (SSL*)ssl;
367 c->read = ssl_read;
368 c->sendmsg = ssl_sendmsg;
369 c->write = ssl_write;
370 SSL_set_info_callback(c->ssl, ssl_callback);
371 }
372 }
373
ssl_init_settings(void)374 void ssl_init_settings(void) {
375 settings.ssl_enabled = false;
376 settings.ssl_ctx = NULL;
377 settings.ssl_chain_cert = NULL;
378 settings.ssl_key = NULL;
379 settings.ssl_verify_mode = SSL_VERIFY_NONE;
380 settings.ssl_keyformat = SSL_FILETYPE_PEM;
381 settings.ssl_ciphers = NULL;
382 settings.ssl_ca_cert = NULL;
383 settings.ssl_last_cert_refresh_time = current_time;
384 settings.ssl_wbuf_size = 16 * 1024; // default is 16KB (SSL max frame size is 17KB)
385 settings.ssl_session_cache = false;
386 settings.ssl_kernel_tls = false;
387 settings.ssl_min_version = TLS1_2_VERSION;
388 }
389
390 /*
391 * Verify SSL settings and initiates the SSL context.
392 */
ssl_init(void)393 int ssl_init(void) {
394 assert(settings.ssl_enabled);
395
396 OPENSSL_init_ssl(0, NULL);
397
398 // SSL context for the process. All connections will share one
399 // process level context.
400 settings.ssl_ctx = SSL_CTX_new(TLS_server_method());
401
402 SSL_CTX_set_min_proto_version(settings.ssl_ctx, settings.ssl_min_version);
403
404 // The server certificate, private key and validations.
405 char *error_msg;
406 if (!load_server_certificates(&error_msg)) {
407 fprintf(stderr, "%s", error_msg);
408 free(error_msg);
409 exit(EX_USAGE);
410 }
411
412 // The verification mode of client certificate, default is SSL_VERIFY_PEER.
413 SSL_CTX_set_verify(settings.ssl_ctx, settings.ssl_verify_mode, NULL);
414 if (settings.ssl_ciphers && !SSL_CTX_set_cipher_list(settings.ssl_ctx,
415 settings.ssl_ciphers)) {
416 fprintf(stderr, "Error setting the provided cipher(s): %s\n",
417 settings.ssl_ciphers);
418 exit(EX_USAGE);
419 }
420
421 // Optional session caching; default disabled.
422 if (settings.ssl_session_cache) {
423 SSL_CTX_sess_set_new_cb(settings.ssl_ctx, ssl_new_session_callback);
424 SSL_CTX_set_session_cache_mode(settings.ssl_ctx, SSL_SESS_CACHE_SERVER);
425 SSL_CTX_set_session_id_context(settings.ssl_ctx,
426 (const unsigned char *) SESSION_ID_CONTEXT,
427 strlen(SESSION_ID_CONTEXT));
428 } else {
429 SSL_CTX_set_session_cache_mode(settings.ssl_ctx, SSL_SESS_CACHE_OFF);
430 }
431
432 // Optional kernel TLS offload; default disabled.
433 if (settings.ssl_kernel_tls) {
434 #if defined(SSL_OP_ENABLE_KTLS)
435 SSL_CTX_set_options(settings.ssl_ctx, SSL_OP_ENABLE_KTLS);
436 #else
437 fprintf(stderr, "Kernel TLS offload is not available\n");
438 exit(EX_USAGE);
439 #endif
440 }
441
442 #ifdef SSL_OP_NO_RENEGOTIATION
443 // Disable TLS re-negotiation if SSL_OP_NO_RENEGOTIATION is defined for
444 // openssl 1.1.0h or above
445 SSL_CTX_set_options(settings.ssl_ctx, SSL_OP_NO_RENEGOTIATION);
446 #endif
447
448 // Release TLS read/write buffers of idle connections
449 SSL_CTX_set_mode(settings.ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
450
451 return 0;
452 }
453
454 /*
455 * This method is registered with each SSL connection and abort the SSL session
456 * if a client initiates a renegotiation for openssl versions before 1.1.0h.
457 * For openssl 1.1.0h and above, TLS re-negotiation is disabled by setting the
458 * SSL_OP_NO_RENEGOTIATION option in SSL_CTX_set_options.
459 */
ssl_callback(const SSL * s,int where,int ret)460 void ssl_callback(const SSL *s, int where, int ret) {
461 // useful for debugging.
462 // fprintf(stderr, "WHERE: %d RET: %d CODE: %s LONG: %s\n", where, ret, SSL_state_string(s), SSL_state_string_long(s));
463 #ifndef SSL_OP_NO_RENEGOTIATION
464 SSL* ssl = (SSL*)s;
465 if (SSL_in_before(ssl)) {
466 fprintf(stderr, "%d: SSL renegotiation is not supported, "
467 "closing the connection\n", SSL_get_fd(ssl));
468 SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
469 return;
470 }
471 #endif
472 }
473
474 /*
475 * This method is invoked with every new successfully negotiated SSL session,
476 * when server-side session caching is enabled. Note that this method is not
477 * invoked when a session is reused.
478 */
ssl_new_session_callback(SSL * s,SSL_SESSION * sess)479 int ssl_new_session_callback(SSL *s, SSL_SESSION *sess) {
480 STATS_LOCK();
481 stats.ssl_new_sessions++;
482 STATS_UNLOCK();
483
484 return 0;
485 }
486
refresh_certs(char ** errmsg)487 bool refresh_certs(char **errmsg) {
488 return load_server_certificates(errmsg);
489 }
490
ssl_help(void)491 void ssl_help(void) {
492 printf(" - ssl_chain_cert: certificate chain file in PEM format\n"
493 " - ssl_key: private key, if not part of the -ssl_chain_cert\n"
494 " - ssl_keyformat: private key format (PEM, DER or ENGINE) (default: PEM)\n");
495 printf(" - ssl_verify_mode: peer certificate verification mode, default is 0(None).\n"
496 " valid values are 0(None), 1(Request), 2(Require)\n"
497 " or 3(Once)\n");
498 printf(" - ssl_ciphers: specify cipher list to be used\n"
499 " - ssl_ca_cert: PEM format file of acceptable client CA's\n"
500 " - ssl_wbuf_size: size in kilobytes of per-connection SSL output buffer\n"
501 " (default: %u)\n", settings.ssl_wbuf_size / (1 << 10));
502 printf(" - ssl_session_cache: enable server-side SSL session cache, to support session\n"
503 " resumption\n"
504 " - ssl_kernel_tls: enable kernel TLS offload\n"
505 " - ssl_min_version: minimum protocol version to accept (default: %s)\n",
506 ssl_proto_text(settings.ssl_min_version));
507 #if defined(TLS1_3_VERSION)
508 printf(" valid values are 0(%s), 1(%s), 2(%s), or 3(%s).\n",
509 ssl_proto_text(TLS1_VERSION), ssl_proto_text(TLS1_1_VERSION),
510 ssl_proto_text(TLS1_2_VERSION), ssl_proto_text(TLS1_3_VERSION));
511 #else
512 printf(" valid values are 0(%s), 1(%s), or 2(%s).\n",
513 ssl_proto_text(TLS1_VERSION), ssl_proto_text(TLS1_1_VERSION),
514 ssl_proto_text(TLS1_2_VERSION));
515 #endif
516 verify_default("ssl_keyformat", settings.ssl_keyformat == SSL_FILETYPE_PEM);
517 verify_default("ssl_verify_mode", settings.ssl_verify_mode == SSL_VERIFY_NONE);
518 verify_default("ssl_min_version", settings.ssl_min_version == TLS1_2_VERSION);
519 }
520
ssl_proto_text(int version)521 const char *ssl_proto_text(int version) {
522 switch (version) {
523 case TLS1_VERSION:
524 return "tlsv1.0";
525 case TLS1_1_VERSION:
526 return "tlsv1.1";
527 case TLS1_2_VERSION:
528 return "tlsv1.2";
529 #if defined(TLS1_3_VERSION)
530 case TLS1_3_VERSION:
531 return "tlsv1.3";
532 #endif
533 default:
534 return "unknown";
535 }
536 }
537
538 // TODO: would be nice to pull the entire set of startup option parsing into
539 // here like we do with extstore. To save time I'm only pulling subsection
540 // that require openssl headers to start.
ssl_set_verify_mode(int verify)541 bool ssl_set_verify_mode(int verify) {
542 switch(verify) {
543 case 0:
544 settings.ssl_verify_mode = SSL_VERIFY_NONE;
545 break;
546 case 1:
547 settings.ssl_verify_mode = SSL_VERIFY_PEER;
548 break;
549 case 2:
550 settings.ssl_verify_mode = SSL_VERIFY_PEER |
551 SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
552 break;
553 case 3:
554 settings.ssl_verify_mode = SSL_VERIFY_PEER |
555 SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
556 SSL_VERIFY_CLIENT_ONCE;
557 break;
558 default:
559 return false;
560 }
561 return true;
562 }
563
ssl_set_min_version(int version)564 bool ssl_set_min_version(int version) {
565 switch (version) {
566 case 0:
567 settings.ssl_min_version = TLS1_VERSION;
568 break;
569 case 1:
570 settings.ssl_min_version = TLS1_1_VERSION;
571 break;
572 case 2:
573 settings.ssl_min_version = TLS1_2_VERSION;
574 break;
575 #if defined(TLS1_3_VERSION)
576 case 3:
577 settings.ssl_min_version = TLS1_3_VERSION;
578 break;
579 #endif
580 default:
581 return false;
582 }
583 return true;
584 }
585
586 #endif // ifdef TLS
587