1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2017 - 2018, Yiming Jing, <jingyiming@baidu.com>
9 * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
10 *
11 * This software is licensed as described in the file COPYING, which
12 * you should have received as part of this distribution. The terms
13 * are also available at https://curl.haxx.se/docs/copyright.html.
14 *
15 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16 * copies of the Software, and permit persons to whom the Software is
17 * furnished to do so, under the terms of the COPYING file.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ***************************************************************************/
23
24 /*
25 * Source file for all MesaLink-specific code for the TLS/SSL layer. No code
26 * but vtls.c should ever call or use these functions.
27 *
28 */
29
30 /*
31 * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
32 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
33 *
34 * Thanks for code and inspiration!
35 */
36
37 #include "curl_setup.h"
38
39 #ifdef USE_MESALINK
40
41 #include <mesalink/options.h>
42 #include <mesalink/version.h>
43
44 #include "urldata.h"
45 #include "sendf.h"
46 #include "inet_pton.h"
47 #include "vtls.h"
48 #include "parsedate.h"
49 #include "connect.h" /* for the connect timeout */
50 #include "select.h"
51 #include "strcase.h"
52 #include "x509asn1.h"
53 #include "curl_printf.h"
54
55 #include "mesalink.h"
56 #include <mesalink/openssl/ssl.h>
57 #include <mesalink/openssl/err.h>
58
59 /* The last #include files should be: */
60 #include "curl_memory.h"
61 #include "memdebug.h"
62
63 #define MESALINK_MAX_ERROR_SZ 80
64
65 struct ssl_backend_data
66 {
67 SSL_CTX *ctx;
68 SSL *handle;
69 };
70
71 #define BACKEND connssl->backend
72
73 static Curl_recv mesalink_recv;
74 static Curl_send mesalink_send;
75
do_file_type(const char * type)76 static int do_file_type(const char *type)
77 {
78 if(!type || !type[0])
79 return SSL_FILETYPE_PEM;
80 if(strcasecompare(type, "PEM"))
81 return SSL_FILETYPE_PEM;
82 if(strcasecompare(type, "DER"))
83 return SSL_FILETYPE_ASN1;
84 return -1;
85 }
86
87 /*
88 * This function loads all the client/CA certificates and CRLs. Setup the TLS
89 * layer and do all necessary magic.
90 */
91 static CURLcode
mesalink_connect_step1(struct connectdata * conn,int sockindex)92 mesalink_connect_step1(struct connectdata *conn, int sockindex)
93 {
94 char *ciphers;
95 struct Curl_easy *data = conn->data;
96 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
97 struct in_addr addr4;
98 #ifdef ENABLE_IPV6
99 struct in6_addr addr6;
100 #endif
101 const char *const hostname =
102 SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name;
103 size_t hostname_len = strlen(hostname);
104
105 SSL_METHOD *req_method = NULL;
106 curl_socket_t sockfd = conn->sock[sockindex];
107
108 if(connssl->state == ssl_connection_complete)
109 return CURLE_OK;
110
111 if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
112 failf(data, "MesaLink does not support to set maximum SSL/TLS version");
113 return CURLE_SSL_CONNECT_ERROR;
114 }
115
116 switch(SSL_CONN_CONFIG(version)) {
117 case CURL_SSLVERSION_SSLv3:
118 case CURL_SSLVERSION_TLSv1:
119 case CURL_SSLVERSION_TLSv1_0:
120 case CURL_SSLVERSION_TLSv1_1:
121 failf(data, "MesaLink does not support SSL 3.0, TLS 1.0, or TLS 1.1");
122 return CURLE_NOT_BUILT_IN;
123 case CURL_SSLVERSION_DEFAULT:
124 case CURL_SSLVERSION_TLSv1_2:
125 req_method = TLSv1_2_client_method();
126 break;
127 case CURL_SSLVERSION_TLSv1_3:
128 req_method = TLSv1_3_client_method();
129 break;
130 case CURL_SSLVERSION_SSLv2:
131 failf(data, "MesaLink does not support SSLv2");
132 return CURLE_SSL_CONNECT_ERROR;
133 default:
134 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
135 return CURLE_SSL_CONNECT_ERROR;
136 }
137
138 if(!req_method) {
139 failf(data, "SSL: couldn't create a method!");
140 return CURLE_OUT_OF_MEMORY;
141 }
142
143 if(BACKEND->ctx)
144 SSL_CTX_free(BACKEND->ctx);
145 BACKEND->ctx = SSL_CTX_new(req_method);
146
147 if(!BACKEND->ctx) {
148 failf(data, "SSL: couldn't create a context!");
149 return CURLE_OUT_OF_MEMORY;
150 }
151
152 SSL_CTX_set_verify(
153 BACKEND->ctx, SSL_CONN_CONFIG(verifypeer) ?
154 SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
155
156 if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath)) {
157 if(!SSL_CTX_load_verify_locations(BACKEND->ctx, SSL_CONN_CONFIG(CAfile),
158 SSL_CONN_CONFIG(CApath))) {
159 if(SSL_CONN_CONFIG(verifypeer)) {
160 failf(data,
161 "error setting certificate verify locations: "
162 " CAfile: %s CApath: %s",
163 SSL_CONN_CONFIG(CAfile) ?
164 SSL_CONN_CONFIG(CAfile) : "none",
165 SSL_CONN_CONFIG(CApath) ?
166 SSL_CONN_CONFIG(CApath) : "none");
167 return CURLE_SSL_CACERT_BADFILE;
168 }
169 infof(data,
170 "error setting certificate verify locations,"
171 " continuing anyway:\n");
172 }
173 else {
174 infof(data, "successfully set certificate verify locations:\n");
175 }
176 infof(data, " CAfile: %s\n",
177 SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none");
178 infof(data, " CApath: %s\n",
179 SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): "none");
180 }
181
182 if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) {
183 int file_type = do_file_type(SSL_SET_OPTION(cert_type));
184
185 if(SSL_CTX_use_certificate_chain_file(BACKEND->ctx,
186 SSL_SET_OPTION(primary.clientcert),
187 file_type) != 1) {
188 failf(data, "unable to use client certificate (no key or wrong pass"
189 " phrase?)");
190 return CURLE_SSL_CONNECT_ERROR;
191 }
192
193 file_type = do_file_type(SSL_SET_OPTION(key_type));
194 if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key),
195 file_type) != 1) {
196 failf(data, "unable to set private key");
197 return CURLE_SSL_CONNECT_ERROR;
198 }
199 infof(data,
200 "client cert: %s\n",
201 SSL_CONN_CONFIG(clientcert)?
202 SSL_CONN_CONFIG(clientcert): "none");
203 }
204
205 ciphers = SSL_CONN_CONFIG(cipher_list);
206 if(ciphers) {
207 #ifdef MESALINK_HAVE_CIPHER
208 if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
209 failf(data, "failed setting cipher list: %s", ciphers);
210 return CURLE_SSL_CIPHER;
211 }
212 #endif
213 infof(data, "Cipher selection: %s\n", ciphers);
214 }
215
216 if(BACKEND->handle)
217 SSL_free(BACKEND->handle);
218 BACKEND->handle = SSL_new(BACKEND->ctx);
219 if(!BACKEND->handle) {
220 failf(data, "SSL: couldn't create a context (handle)!");
221 return CURLE_OUT_OF_MEMORY;
222 }
223
224 if((hostname_len < USHRT_MAX) &&
225 (0 == Curl_inet_pton(AF_INET, hostname, &addr4))
226 #ifdef ENABLE_IPV6
227 && (0 == Curl_inet_pton(AF_INET6, hostname, &addr6))
228 #endif
229 ) {
230 /* hostname is not a valid IP address */
231 if(SSL_set_tlsext_host_name(BACKEND->handle, hostname) != SSL_SUCCESS) {
232 failf(data,
233 "WARNING: failed to configure server name indication (SNI) "
234 "TLS extension\n");
235 return CURLE_SSL_CONNECT_ERROR;
236 }
237 }
238 else {
239 #ifdef CURLDEBUG
240 /* Check if the hostname is 127.0.0.1 or [::1];
241 * otherwise reject because MesaLink always wants a valid DNS Name
242 * specified in RFC 5280 Section 7.2 */
243 if(strncmp(hostname, "127.0.0.1", 9) == 0
244 #ifdef ENABLE_IPV6
245 || strncmp(hostname, "[::1]", 5) == 0
246 #endif
247 ) {
248 SSL_set_tlsext_host_name(BACKEND->handle, "localhost");
249 }
250 else
251 #endif
252 {
253 failf(data,
254 "ERROR: MesaLink does not accept an IP address as a hostname\n");
255 return CURLE_SSL_CONNECT_ERROR;
256 }
257 }
258
259 #ifdef MESALINK_HAVE_SESSION
260 if(SSL_SET_OPTION(primary.sessionid)) {
261 void *ssl_sessionid = NULL;
262
263 Curl_ssl_sessionid_lock(conn);
264 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
265 /* we got a session id, use it! */
266 if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
267 Curl_ssl_sessionid_unlock(conn);
268 failf(
269 data,
270 "SSL: SSL_set_session failed: %s",
271 ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer));
272 return CURLE_SSL_CONNECT_ERROR;
273 }
274 /* Informational message */
275 infof(data, "SSL re-using session ID\n");
276 }
277 Curl_ssl_sessionid_unlock(conn);
278 }
279 #endif /* MESALINK_HAVE_SESSION */
280
281 if(SSL_set_fd(BACKEND->handle, (int)sockfd) != SSL_SUCCESS) {
282 failf(data, "SSL: SSL_set_fd failed");
283 return CURLE_SSL_CONNECT_ERROR;
284 }
285
286 connssl->connecting_state = ssl_connect_2;
287 return CURLE_OK;
288 }
289
290 static CURLcode
mesalink_connect_step2(struct connectdata * conn,int sockindex)291 mesalink_connect_step2(struct connectdata *conn, int sockindex)
292 {
293 int ret = -1;
294 struct Curl_easy *data = conn->data;
295 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
296
297 conn->recv[sockindex] = mesalink_recv;
298 conn->send[sockindex] = mesalink_send;
299
300 ret = SSL_connect(BACKEND->handle);
301 if(ret != SSL_SUCCESS) {
302 int detail = SSL_get_error(BACKEND->handle, ret);
303
304 if(SSL_ERROR_WANT_CONNECT == detail || SSL_ERROR_WANT_READ == detail) {
305 connssl->connecting_state = ssl_connect_2_reading;
306 return CURLE_OK;
307 }
308 else {
309 char error_buffer[MESALINK_MAX_ERROR_SZ];
310 failf(data,
311 "SSL_connect failed with error %d: %s",
312 detail,
313 ERR_error_string_n(detail, error_buffer, sizeof(error_buffer)));
314 ERR_print_errors_fp(stderr);
315 if(detail && SSL_CONN_CONFIG(verifypeer)) {
316 detail &= ~0xFF;
317 if(detail == TLS_ERROR_WEBPKI_ERRORS) {
318 failf(data, "Cert verify failed");
319 return CURLE_PEER_FAILED_VERIFICATION;
320 }
321 }
322 return CURLE_SSL_CONNECT_ERROR;
323 }
324 }
325
326 connssl->connecting_state = ssl_connect_3;
327 infof(data,
328 "SSL connection using %s / %s\n",
329 SSL_get_version(BACKEND->handle),
330 SSL_get_cipher_name(BACKEND->handle));
331
332 return CURLE_OK;
333 }
334
335 static CURLcode
mesalink_connect_step3(struct connectdata * conn,int sockindex)336 mesalink_connect_step3(struct connectdata *conn, int sockindex)
337 {
338 CURLcode result = CURLE_OK;
339 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
340
341 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
342
343 #ifdef MESALINK_HAVE_SESSION
344 if(SSL_SET_OPTION(primary.sessionid)) {
345 bool incache;
346 SSL_SESSION *our_ssl_sessionid;
347 void *old_ssl_sessionid = NULL;
348
349 our_ssl_sessionid = SSL_get_session(BACKEND->handle);
350
351 Curl_ssl_sessionid_lock(conn);
352 incache =
353 !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex));
354 if(incache) {
355 if(old_ssl_sessionid != our_ssl_sessionid) {
356 infof(data, "old SSL session ID is stale, removing\n");
357 Curl_ssl_delsessionid(conn, old_ssl_sessionid);
358 incache = FALSE;
359 }
360 }
361
362 if(!incache) {
363 result = Curl_ssl_addsessionid(
364 conn, our_ssl_sessionid, 0 /* unknown size */, sockindex);
365 if(result) {
366 Curl_ssl_sessionid_unlock(conn);
367 failf(data, "failed to store ssl session");
368 return result;
369 }
370 }
371 Curl_ssl_sessionid_unlock(conn);
372 }
373 #endif /* MESALINK_HAVE_SESSION */
374
375 connssl->connecting_state = ssl_connect_done;
376
377 return result;
378 }
379
380 static ssize_t
mesalink_send(struct connectdata * conn,int sockindex,const void * mem,size_t len,CURLcode * curlcode)381 mesalink_send(struct connectdata *conn, int sockindex, const void *mem,
382 size_t len, CURLcode *curlcode)
383 {
384 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
385 char error_buffer[MESALINK_MAX_ERROR_SZ];
386 int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
387 int rc = SSL_write(BACKEND->handle, mem, memlen);
388
389 if(rc < 0) {
390 int err = SSL_get_error(BACKEND->handle, rc);
391 switch(err) {
392 case SSL_ERROR_WANT_READ:
393 case SSL_ERROR_WANT_WRITE:
394 /* there's data pending, re-invoke SSL_write() */
395 *curlcode = CURLE_AGAIN;
396 return -1;
397 default:
398 failf(conn->data,
399 "SSL write: %s, errno %d",
400 ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
401 SOCKERRNO);
402 *curlcode = CURLE_SEND_ERROR;
403 return -1;
404 }
405 }
406 return rc;
407 }
408
409 static void
Curl_mesalink_close(struct connectdata * conn,int sockindex)410 Curl_mesalink_close(struct connectdata *conn, int sockindex)
411 {
412 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
413
414 if(BACKEND->handle) {
415 (void)SSL_shutdown(BACKEND->handle);
416 SSL_free(BACKEND->handle);
417 BACKEND->handle = NULL;
418 }
419 if(BACKEND->ctx) {
420 SSL_CTX_free(BACKEND->ctx);
421 BACKEND->ctx = NULL;
422 }
423 }
424
425 static ssize_t
mesalink_recv(struct connectdata * conn,int num,char * buf,size_t buffersize,CURLcode * curlcode)426 mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize,
427 CURLcode *curlcode)
428 {
429 struct ssl_connect_data *connssl = &conn->ssl[num];
430 char error_buffer[MESALINK_MAX_ERROR_SZ];
431 int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
432 int nread = SSL_read(BACKEND->handle, buf, buffsize);
433
434 if(nread <= 0) {
435 int err = SSL_get_error(BACKEND->handle, nread);
436
437 switch(err) {
438 case SSL_ERROR_ZERO_RETURN: /* no more data */
439 case IO_ERROR_CONNECTION_ABORTED:
440 break;
441 case SSL_ERROR_WANT_READ:
442 case SSL_ERROR_WANT_WRITE:
443 /* there's data pending, re-invoke SSL_read() */
444 *curlcode = CURLE_AGAIN;
445 return -1;
446 default:
447 failf(conn->data,
448 "SSL read: %s, errno %d",
449 ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
450 SOCKERRNO);
451 *curlcode = CURLE_RECV_ERROR;
452 return -1;
453 }
454 }
455 return nread;
456 }
457
458 static size_t
Curl_mesalink_version(char * buffer,size_t size)459 Curl_mesalink_version(char *buffer, size_t size)
460 {
461 return msnprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING);
462 }
463
464 static int
Curl_mesalink_init(void)465 Curl_mesalink_init(void)
466 {
467 return (SSL_library_init() == SSL_SUCCESS);
468 }
469
470 /*
471 * This function is called to shut down the SSL layer but keep the
472 * socket open (CCC - Clear Command Channel)
473 */
474 static int
Curl_mesalink_shutdown(struct connectdata * conn,int sockindex)475 Curl_mesalink_shutdown(struct connectdata *conn, int sockindex)
476 {
477 int retval = 0;
478 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
479
480 if(BACKEND->handle) {
481 SSL_free(BACKEND->handle);
482 BACKEND->handle = NULL;
483 }
484 return retval;
485 }
486
487 static CURLcode
mesalink_connect_common(struct connectdata * conn,int sockindex,bool nonblocking,bool * done)488 mesalink_connect_common(struct connectdata *conn, int sockindex,
489 bool nonblocking, bool *done)
490 {
491 CURLcode result;
492 struct Curl_easy *data = conn->data;
493 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
494 curl_socket_t sockfd = conn->sock[sockindex];
495 timediff_t timeout_ms;
496 int what;
497
498 /* check if the connection has already been established */
499 if(ssl_connection_complete == connssl->state) {
500 *done = TRUE;
501 return CURLE_OK;
502 }
503
504 if(ssl_connect_1 == connssl->connecting_state) {
505 /* Find out how much more time we're allowed */
506 timeout_ms = Curl_timeleft(data, NULL, TRUE);
507
508 if(timeout_ms < 0) {
509 /* no need to continue if time already is up */
510 failf(data, "SSL connection timeout");
511 return CURLE_OPERATION_TIMEDOUT;
512 }
513
514 result = mesalink_connect_step1(conn, sockindex);
515 if(result)
516 return result;
517 }
518
519 while(ssl_connect_2 == connssl->connecting_state ||
520 ssl_connect_2_reading == connssl->connecting_state ||
521 ssl_connect_2_writing == connssl->connecting_state) {
522
523 /* check allowed time left */
524 timeout_ms = Curl_timeleft(data, NULL, TRUE);
525
526 if(timeout_ms < 0) {
527 /* no need to continue if time already is up */
528 failf(data, "SSL connection timeout");
529 return CURLE_OPERATION_TIMEDOUT;
530 }
531
532 /* if ssl is expecting something, check if it's available. */
533 if(connssl->connecting_state == ssl_connect_2_reading ||
534 connssl->connecting_state == ssl_connect_2_writing) {
535
536 curl_socket_t writefd =
537 ssl_connect_2_writing == connssl->connecting_state ? sockfd
538 : CURL_SOCKET_BAD;
539 curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state
540 ? sockfd
541 : CURL_SOCKET_BAD;
542
543 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
544 nonblocking ? 0 : timeout_ms);
545 if(what < 0) {
546 /* fatal error */
547 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
548 return CURLE_SSL_CONNECT_ERROR;
549 }
550 else if(0 == what) {
551 if(nonblocking) {
552 *done = FALSE;
553 return CURLE_OK;
554 }
555 else {
556 /* timeout */
557 failf(data, "SSL connection timeout");
558 return CURLE_OPERATION_TIMEDOUT;
559 }
560 }
561 /* socket is readable or writable */
562 }
563
564 /* Run transaction, and return to the caller if it failed or if
565 * this connection is part of a multi handle and this loop would
566 * execute again. This permits the owner of a multi handle to
567 * abort a connection attempt before step2 has completed while
568 * ensuring that a client using select() or epoll() will always
569 * have a valid fdset to wait on.
570 */
571 result = mesalink_connect_step2(conn, sockindex);
572
573 if(result ||
574 (nonblocking && (ssl_connect_2 == connssl->connecting_state ||
575 ssl_connect_2_reading == connssl->connecting_state ||
576 ssl_connect_2_writing == connssl->connecting_state))) {
577 return result;
578 }
579 } /* repeat step2 until all transactions are done. */
580
581 if(ssl_connect_3 == connssl->connecting_state) {
582 result = mesalink_connect_step3(conn, sockindex);
583 if(result)
584 return result;
585 }
586
587 if(ssl_connect_done == connssl->connecting_state) {
588 connssl->state = ssl_connection_complete;
589 conn->recv[sockindex] = mesalink_recv;
590 conn->send[sockindex] = mesalink_send;
591 *done = TRUE;
592 }
593 else
594 *done = FALSE;
595
596 /* Reset our connect state machine */
597 connssl->connecting_state = ssl_connect_1;
598
599 return CURLE_OK;
600 }
601
602 static CURLcode
Curl_mesalink_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)603 Curl_mesalink_connect_nonblocking(struct connectdata *conn, int sockindex,
604 bool *done)
605 {
606 return mesalink_connect_common(conn, sockindex, TRUE, done);
607 }
608
609 static CURLcode
Curl_mesalink_connect(struct connectdata * conn,int sockindex)610 Curl_mesalink_connect(struct connectdata *conn, int sockindex)
611 {
612 CURLcode result;
613 bool done = FALSE;
614
615 result = mesalink_connect_common(conn, sockindex, FALSE, &done);
616 if(result)
617 return result;
618
619 DEBUGASSERT(done);
620
621 return CURLE_OK;
622 }
623
624 static void *
Curl_mesalink_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)625 Curl_mesalink_get_internals(struct ssl_connect_data *connssl,
626 CURLINFO info UNUSED_PARAM)
627 {
628 (void)info;
629 return BACKEND->handle;
630 }
631
632 const struct Curl_ssl Curl_ssl_mesalink = {
633 { CURLSSLBACKEND_MESALINK, "MesaLink" }, /* info */
634
635 SSLSUPP_SSL_CTX,
636
637 sizeof(struct ssl_backend_data),
638
639 Curl_mesalink_init, /* init */
640 Curl_none_cleanup, /* cleanup */
641 Curl_mesalink_version, /* version */
642 Curl_none_check_cxn, /* check_cxn */
643 Curl_mesalink_shutdown, /* shutdown */
644 Curl_none_data_pending, /* data_pending */
645 Curl_none_random, /* random */
646 Curl_none_cert_status_request, /* cert_status_request */
647 Curl_mesalink_connect, /* connect */
648 Curl_mesalink_connect_nonblocking, /* connect_nonblocking */
649 Curl_mesalink_get_internals, /* get_internals */
650 Curl_mesalink_close, /* close_one */
651 Curl_none_close_all, /* close_all */
652 Curl_none_session_free, /* session_free */
653 Curl_none_set_engine, /* set_engine */
654 Curl_none_set_engine_default, /* set_engine_default */
655 Curl_none_engines_list, /* engines_list */
656 Curl_none_false_start, /* false_start */
657 Curl_none_md5sum, /* md5sum */
658 NULL /* sha256sum */
659 };
660
661 #endif
662