• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2017 - 2018, Yiming Jing, <jingyiming@baidu.com>
9  * Copyright (C) 1998 - 2019, 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:\n"
162               "  CAfile: %s\n  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,
177           "  CAfile: %s\n"
178           "  CApath: %s\n",
179           SSL_CONN_CONFIG(CAfile)?
180           SSL_CONN_CONFIG(CAfile): "none",
181           SSL_CONN_CONFIG(CApath)?
182           SSL_CONN_CONFIG(CApath): "none");
183   }
184 
185   if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
186     int file_type = do_file_type(SSL_SET_OPTION(cert_type));
187 
188     if(SSL_CTX_use_certificate_chain_file(BACKEND->ctx, SSL_SET_OPTION(cert),
189                                      file_type) != 1) {
190       failf(data, "unable to use client certificate (no key or wrong pass"
191             " phrase?)");
192       return CURLE_SSL_CONNECT_ERROR;
193     }
194 
195     file_type = do_file_type(SSL_SET_OPTION(key_type));
196     if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key),
197                                     file_type) != 1) {
198       failf(data, "unable to set private key");
199       return CURLE_SSL_CONNECT_ERROR;
200     }
201     infof(data,
202           "client cert: %s\n",
203           SSL_CONN_CONFIG(clientcert)?
204           SSL_CONN_CONFIG(clientcert): "none");
205   }
206 
207   ciphers = SSL_CONN_CONFIG(cipher_list);
208   if(ciphers) {
209 #ifdef MESALINK_HAVE_CIPHER
210     if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
211       failf(data, "failed setting cipher list: %s", ciphers);
212       return CURLE_SSL_CIPHER;
213     }
214 #endif
215     infof(data, "Cipher selection: %s\n", ciphers);
216   }
217 
218   if(BACKEND->handle)
219     SSL_free(BACKEND->handle);
220   BACKEND->handle = SSL_new(BACKEND->ctx);
221   if(!BACKEND->handle) {
222     failf(data, "SSL: couldn't create a context (handle)!");
223     return CURLE_OUT_OF_MEMORY;
224   }
225 
226   if((hostname_len < USHRT_MAX) &&
227      (0 == Curl_inet_pton(AF_INET, hostname, &addr4))
228 #ifdef ENABLE_IPV6
229      && (0 == Curl_inet_pton(AF_INET6, hostname, &addr6))
230 #endif
231   ) {
232     /* hostname is not a valid IP address */
233     if(SSL_set_tlsext_host_name(BACKEND->handle, hostname) != SSL_SUCCESS) {
234       failf(data,
235             "WARNING: failed to configure server name indication (SNI) "
236             "TLS extension\n");
237       return CURLE_SSL_CONNECT_ERROR;
238     }
239   }
240   else {
241 #ifdef CURLDEBUG
242     /* Check if the hostname is 127.0.0.1 or [::1];
243      * otherwise reject because MesaLink always wants a valid DNS Name
244      * specified in RFC 5280 Section 7.2 */
245     if(strncmp(hostname, "127.0.0.1", 9) == 0
246 #ifdef ENABLE_IPV6
247        || strncmp(hostname, "[::1]", 5) == 0
248 #endif
249     ) {
250       SSL_set_tlsext_host_name(BACKEND->handle, "localhost");
251     }
252     else
253 #endif
254     {
255       failf(data,
256             "ERROR: MesaLink does not accept an IP address as a hostname\n");
257       return CURLE_SSL_CONNECT_ERROR;
258     }
259   }
260 
261 #ifdef MESALINK_HAVE_SESSION
262   if(SSL_SET_OPTION(primary.sessionid)) {
263     void *ssl_sessionid = NULL;
264 
265     Curl_ssl_sessionid_lock(conn);
266     if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
267       /* we got a session id, use it! */
268       if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
269         Curl_ssl_sessionid_unlock(conn);
270         failf(
271           data,
272           "SSL: SSL_set_session failed: %s",
273           ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer));
274         return CURLE_SSL_CONNECT_ERROR;
275       }
276       /* Informational message */
277       infof(data, "SSL re-using session ID\n");
278     }
279     Curl_ssl_sessionid_unlock(conn);
280   }
281 #endif /* MESALINK_HAVE_SESSION */
282 
283   if(SSL_set_fd(BACKEND->handle, (int)sockfd) != SSL_SUCCESS) {
284     failf(data, "SSL: SSL_set_fd failed");
285     return CURLE_SSL_CONNECT_ERROR;
286   }
287 
288   connssl->connecting_state = ssl_connect_2;
289   return CURLE_OK;
290 }
291 
292 static CURLcode
mesalink_connect_step2(struct connectdata * conn,int sockindex)293 mesalink_connect_step2(struct connectdata *conn, int sockindex)
294 {
295   int ret = -1;
296   struct Curl_easy *data = conn->data;
297   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
298 
299   conn->recv[sockindex] = mesalink_recv;
300   conn->send[sockindex] = mesalink_send;
301 
302   ret = SSL_connect(BACKEND->handle);
303   if(ret != SSL_SUCCESS) {
304     int detail = SSL_get_error(BACKEND->handle, ret);
305 
306     if(SSL_ERROR_WANT_CONNECT == detail || SSL_ERROR_WANT_READ == detail) {
307       connssl->connecting_state = ssl_connect_2_reading;
308       return CURLE_OK;
309     }
310     else {
311       char error_buffer[MESALINK_MAX_ERROR_SZ];
312       failf(data,
313             "SSL_connect failed with error %d: %s",
314             detail,
315             ERR_error_string_n(detail, error_buffer, sizeof(error_buffer)));
316       ERR_print_errors_fp(stderr);
317       if(detail && SSL_CONN_CONFIG(verifypeer)) {
318         detail &= ~0xFF;
319         if(detail == TLS_ERROR_WEBPKI_ERRORS) {
320           failf(data, "Cert verify failed");
321           return CURLE_PEER_FAILED_VERIFICATION;
322         }
323       }
324       return CURLE_SSL_CONNECT_ERROR;
325     }
326   }
327 
328   connssl->connecting_state = ssl_connect_3;
329   infof(data,
330         "SSL connection using %s / %s\n",
331         SSL_get_version(BACKEND->handle),
332         SSL_get_cipher_name(BACKEND->handle));
333 
334   return CURLE_OK;
335 }
336 
337 static CURLcode
mesalink_connect_step3(struct connectdata * conn,int sockindex)338 mesalink_connect_step3(struct connectdata *conn, int sockindex)
339 {
340   CURLcode result = CURLE_OK;
341   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
342 
343   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
344 
345 #ifdef MESALINK_HAVE_SESSION
346   if(SSL_SET_OPTION(primary.sessionid)) {
347     bool incache;
348     SSL_SESSION *our_ssl_sessionid;
349     void *old_ssl_sessionid = NULL;
350 
351     our_ssl_sessionid = SSL_get_session(BACKEND->handle);
352 
353     Curl_ssl_sessionid_lock(conn);
354     incache =
355       !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex));
356     if(incache) {
357       if(old_ssl_sessionid != our_ssl_sessionid) {
358         infof(data, "old SSL session ID is stale, removing\n");
359         Curl_ssl_delsessionid(conn, old_ssl_sessionid);
360         incache = FALSE;
361       }
362     }
363 
364     if(!incache) {
365       result = Curl_ssl_addsessionid(
366         conn, our_ssl_sessionid, 0 /* unknown size */, sockindex);
367       if(result) {
368         Curl_ssl_sessionid_unlock(conn);
369         failf(data, "failed to store ssl session");
370         return result;
371       }
372     }
373     Curl_ssl_sessionid_unlock(conn);
374   }
375 #endif /* MESALINK_HAVE_SESSION */
376 
377   connssl->connecting_state = ssl_connect_done;
378 
379   return result;
380 }
381 
382 static ssize_t
mesalink_send(struct connectdata * conn,int sockindex,const void * mem,size_t len,CURLcode * curlcode)383 mesalink_send(struct connectdata *conn, int sockindex, const void *mem,
384               size_t len, CURLcode *curlcode)
385 {
386   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
387   char error_buffer[MESALINK_MAX_ERROR_SZ];
388   int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
389   int rc = SSL_write(BACKEND->handle, mem, memlen);
390 
391   if(rc < 0) {
392     int err = SSL_get_error(BACKEND->handle, rc);
393     switch(err) {
394     case SSL_ERROR_WANT_READ:
395     case SSL_ERROR_WANT_WRITE:
396       /* there's data pending, re-invoke SSL_write() */
397       *curlcode = CURLE_AGAIN;
398       return -1;
399     default:
400       failf(conn->data,
401             "SSL write: %s, errno %d",
402             ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
403             SOCKERRNO);
404       *curlcode = CURLE_SEND_ERROR;
405       return -1;
406     }
407   }
408   return rc;
409 }
410 
411 static void
Curl_mesalink_close(struct connectdata * conn,int sockindex)412 Curl_mesalink_close(struct connectdata *conn, int sockindex)
413 {
414   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
415 
416   if(BACKEND->handle) {
417     (void)SSL_shutdown(BACKEND->handle);
418     SSL_free(BACKEND->handle);
419     BACKEND->handle = NULL;
420   }
421   if(BACKEND->ctx) {
422     SSL_CTX_free(BACKEND->ctx);
423     BACKEND->ctx = NULL;
424   }
425 }
426 
427 static ssize_t
mesalink_recv(struct connectdata * conn,int num,char * buf,size_t buffersize,CURLcode * curlcode)428 mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize,
429               CURLcode *curlcode)
430 {
431   struct ssl_connect_data *connssl = &conn->ssl[num];
432   char error_buffer[MESALINK_MAX_ERROR_SZ];
433   int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
434   int nread = SSL_read(BACKEND->handle, buf, buffsize);
435 
436   if(nread <= 0) {
437     int err = SSL_get_error(BACKEND->handle, nread);
438 
439     switch(err) {
440     case SSL_ERROR_ZERO_RETURN: /* no more data */
441     case IO_ERROR_CONNECTION_ABORTED:
442       break;
443     case SSL_ERROR_WANT_READ:
444     case SSL_ERROR_WANT_WRITE:
445       /* there's data pending, re-invoke SSL_read() */
446       *curlcode = CURLE_AGAIN;
447       return -1;
448     default:
449       failf(conn->data,
450             "SSL read: %s, errno %d",
451             ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
452             SOCKERRNO);
453       *curlcode = CURLE_RECV_ERROR;
454       return -1;
455     }
456   }
457   return nread;
458 }
459 
460 static size_t
Curl_mesalink_version(char * buffer,size_t size)461 Curl_mesalink_version(char *buffer, size_t size)
462 {
463   return msnprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING);
464 }
465 
466 static int
Curl_mesalink_init(void)467 Curl_mesalink_init(void)
468 {
469   return (SSL_library_init() == SSL_SUCCESS);
470 }
471 
472 /*
473  * This function is called to shut down the SSL layer but keep the
474  * socket open (CCC - Clear Command Channel)
475  */
476 static int
Curl_mesalink_shutdown(struct connectdata * conn,int sockindex)477 Curl_mesalink_shutdown(struct connectdata *conn, int sockindex)
478 {
479   int retval = 0;
480   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
481 
482   if(BACKEND->handle) {
483     SSL_free(BACKEND->handle);
484     BACKEND->handle = NULL;
485   }
486   return retval;
487 }
488 
489 static CURLcode
mesalink_connect_common(struct connectdata * conn,int sockindex,bool nonblocking,bool * done)490 mesalink_connect_common(struct connectdata *conn, int sockindex,
491                         bool nonblocking, bool *done)
492 {
493   CURLcode result;
494   struct Curl_easy *data = conn->data;
495   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
496   curl_socket_t sockfd = conn->sock[sockindex];
497   timediff_t timeout_ms;
498   int what;
499 
500   /* check if the connection has already been established */
501   if(ssl_connection_complete == connssl->state) {
502     *done = TRUE;
503     return CURLE_OK;
504   }
505 
506   if(ssl_connect_1 == connssl->connecting_state) {
507     /* Find out how much more time we're allowed */
508     timeout_ms = Curl_timeleft(data, NULL, TRUE);
509 
510     if(timeout_ms < 0) {
511       /* no need to continue if time already is up */
512       failf(data, "SSL connection timeout");
513       return CURLE_OPERATION_TIMEDOUT;
514     }
515 
516     result = mesalink_connect_step1(conn, sockindex);
517     if(result)
518       return result;
519   }
520 
521   while(ssl_connect_2 == connssl->connecting_state ||
522         ssl_connect_2_reading == connssl->connecting_state ||
523         ssl_connect_2_writing == connssl->connecting_state) {
524 
525     /* check allowed time left */
526     timeout_ms = Curl_timeleft(data, NULL, TRUE);
527 
528     if(timeout_ms < 0) {
529       /* no need to continue if time already is up */
530       failf(data, "SSL connection timeout");
531       return CURLE_OPERATION_TIMEDOUT;
532     }
533 
534     /* if ssl is expecting something, check if it's available. */
535     if(connssl->connecting_state == ssl_connect_2_reading ||
536        connssl->connecting_state == ssl_connect_2_writing) {
537 
538       curl_socket_t writefd =
539         ssl_connect_2_writing == connssl->connecting_state ? sockfd
540                                                            : CURL_SOCKET_BAD;
541       curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state
542                                ? sockfd
543                                : CURL_SOCKET_BAD;
544 
545       what = Curl_socket_check(
546         readfd, CURL_SOCKET_BAD, writefd,
547         nonblocking ? 0 : (time_t)timeout_ms);
548       if(what < 0) {
549         /* fatal error */
550         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
551         return CURLE_SSL_CONNECT_ERROR;
552       }
553       else if(0 == what) {
554         if(nonblocking) {
555           *done = FALSE;
556           return CURLE_OK;
557         }
558         else {
559           /* timeout */
560           failf(data, "SSL connection timeout");
561           return CURLE_OPERATION_TIMEDOUT;
562         }
563       }
564       /* socket is readable or writable */
565     }
566 
567     /* Run transaction, and return to the caller if it failed or if
568      * this connection is part of a multi handle and this loop would
569      * execute again. This permits the owner of a multi handle to
570      * abort a connection attempt before step2 has completed while
571      * ensuring that a client using select() or epoll() will always
572      * have a valid fdset to wait on.
573      */
574     result = mesalink_connect_step2(conn, sockindex);
575 
576     if(result ||
577        (nonblocking && (ssl_connect_2 == connssl->connecting_state ||
578                         ssl_connect_2_reading == connssl->connecting_state ||
579                         ssl_connect_2_writing == connssl->connecting_state))) {
580       return result;
581     }
582   } /* repeat step2 until all transactions are done. */
583 
584   if(ssl_connect_3 == connssl->connecting_state) {
585     result = mesalink_connect_step3(conn, sockindex);
586     if(result)
587       return result;
588   }
589 
590   if(ssl_connect_done == connssl->connecting_state) {
591     connssl->state = ssl_connection_complete;
592     conn->recv[sockindex] = mesalink_recv;
593     conn->send[sockindex] = mesalink_send;
594     *done = TRUE;
595   }
596   else
597     *done = FALSE;
598 
599   /* Reset our connect state machine */
600   connssl->connecting_state = ssl_connect_1;
601 
602   return CURLE_OK;
603 }
604 
605 static CURLcode
Curl_mesalink_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)606 Curl_mesalink_connect_nonblocking(struct connectdata *conn, int sockindex,
607                                   bool *done)
608 {
609   return mesalink_connect_common(conn, sockindex, TRUE, done);
610 }
611 
612 static CURLcode
Curl_mesalink_connect(struct connectdata * conn,int sockindex)613 Curl_mesalink_connect(struct connectdata *conn, int sockindex)
614 {
615   CURLcode result;
616   bool done = FALSE;
617 
618   result = mesalink_connect_common(conn, sockindex, FALSE, &done);
619   if(result)
620     return result;
621 
622   DEBUGASSERT(done);
623 
624   return CURLE_OK;
625 }
626 
627 static void *
Curl_mesalink_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)628 Curl_mesalink_get_internals(struct ssl_connect_data *connssl,
629                             CURLINFO info UNUSED_PARAM)
630 {
631   (void)info;
632   return BACKEND->handle;
633 }
634 
635 const struct Curl_ssl Curl_ssl_mesalink = {
636   { CURLSSLBACKEND_MESALINK, "MesaLink" }, /* info */
637 
638   SSLSUPP_SSL_CTX,
639 
640   sizeof(struct ssl_backend_data),
641 
642   Curl_mesalink_init, /* init */
643   Curl_none_cleanup, /* cleanup */
644   Curl_mesalink_version, /* version */
645   Curl_none_check_cxn, /* check_cxn */
646   Curl_mesalink_shutdown, /* shutdown */
647   Curl_none_data_pending, /* data_pending */
648   Curl_none_random, /* random */
649   Curl_none_cert_status_request, /* cert_status_request */
650   Curl_mesalink_connect, /* connect */
651   Curl_mesalink_connect_nonblocking, /* connect_nonblocking */
652   Curl_mesalink_get_internals, /* get_internals */
653   Curl_mesalink_close, /* close_one */
654   Curl_none_close_all, /* close_all */
655   Curl_none_session_free, /* session_free */
656   Curl_none_set_engine, /* set_engine */
657   Curl_none_set_engine_default, /* set_engine_default */
658   Curl_none_engines_list, /* engines_list */
659   Curl_none_false_start, /* false_start */
660   Curl_none_md5sum, /* md5sum */
661   NULL /* sha256sum */
662 };
663 
664 #endif
665