44e6b9303c523c7e137460de0da05e64730d369a
[platform/upstream/curl.git] / lib / axtls.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2010, DirecTV
9  * contact: Eric Hu <ehu@directv.com>
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 http://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 axTLS-specific code for the TLS/SSL layer. No code
26  * but sslgen.c should ever call or use these functions.
27  */
28
29 #include "curl_setup.h"
30
31 #ifdef USE_AXTLS
32 #include <axTLS/ssl.h>
33 #include "axtls.h"
34
35 #include "sendf.h"
36 #include "inet_pton.h"
37 #include "sslgen.h"
38 #include "parsedate.h"
39 #include "connect.h" /* for the connect timeout */
40 #include "select.h"
41 #define _MPRINTF_REPLACE /* use our functions only */
42 #include <curl/mprintf.h>
43 #include "curl_memory.h"
44 #include <unistd.h>
45 /* The last #include file should be: */
46 #include "memdebug.h"
47 #include "hostcheck.h"
48
49
50 /* Global axTLS init, called from Curl_ssl_init() */
51 int Curl_axtls_init(void)
52 {
53 /* axTLS has no global init.  Everything is done through SSL and SSL_CTX
54  * structs stored in connectdata structure.  Perhaps can move to axtls.h.
55  */
56   return 1;
57 }
58
59 int Curl_axtls_cleanup(void)
60 {
61   /* axTLS has no global cleanup.  Perhaps can move this to axtls.h. */
62   return 1;
63 }
64
65 static CURLcode map_error_to_curl(int axtls_err)
66 {
67   switch (axtls_err) {
68   case SSL_ERROR_NOT_SUPPORTED:
69   case SSL_ERROR_INVALID_VERSION:
70   case -70:                       /* protocol version alert from server */
71     return CURLE_UNSUPPORTED_PROTOCOL;
72     break;
73   case SSL_ERROR_NO_CIPHER:
74     return CURLE_SSL_CIPHER;
75     break;
76   case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */
77   case SSL_ERROR_NO_CERT_DEFINED:
78   case -42:                       /* bad certificate alert from server */
79   case -43:                       /* unsupported cert alert from server */
80   case -44:                       /* cert revoked alert from server */
81   case -45:                       /* cert expired alert from server */
82   case -46:                       /* cert unknown alert from server */
83     return CURLE_SSL_CERTPROBLEM;
84     break;
85   case SSL_X509_ERROR(X509_NOT_OK):
86   case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT):
87   case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE):
88   case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID):
89   case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED):
90   case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED):
91   case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN):
92   case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST):
93   case SSL_X509_ERROR(X509_INVALID_PRIV_KEY):
94     return CURLE_PEER_FAILED_VERIFICATION;
95     break;
96   case -48:                       /* unknown ca alert from server */
97     return CURLE_SSL_CACERT;
98     break;
99   case -49:                       /* access denied alert from server */
100     return CURLE_REMOTE_ACCESS_DENIED;
101     break;
102   case SSL_ERROR_CONN_LOST:
103   case SSL_ERROR_SOCK_SETUP_FAILURE:
104   case SSL_ERROR_INVALID_HANDSHAKE:
105   case SSL_ERROR_INVALID_PROT_MSG:
106   case SSL_ERROR_INVALID_HMAC:
107   case SSL_ERROR_INVALID_SESSION:
108   case SSL_ERROR_INVALID_KEY:     /* it's too bad this doesn't map better */
109   case SSL_ERROR_FINISHED_INVALID:
110   case SSL_ERROR_NO_CLIENT_RENOG:
111   default:
112     return CURLE_SSL_CONNECT_ERROR;
113     break;
114   }
115 }
116
117 static Curl_recv axtls_recv;
118 static Curl_send axtls_send;
119
120 static void free_ssl_structs(struct ssl_connect_data *connssl)
121 {
122   if(connssl->ssl) {
123     ssl_free (connssl->ssl);
124     connssl->ssl = NULL;
125   }
126   if(connssl->ssl_ctx) {
127     ssl_ctx_free(connssl->ssl_ctx);
128     connssl->ssl_ctx = NULL;
129   }
130 }
131
132 /*
133  * For both blocking and non-blocking connects, this function sets up the
134  * ssl context and state.  This function is called after the TCP connect
135  * has completed.
136  */
137 static CURLcode connect_prep(struct connectdata *conn, int sockindex)
138 {
139   struct SessionHandle *data = conn->data;
140   SSL_CTX *ssl_ctx;
141   SSL *ssl = NULL;
142   int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0};
143   int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0};
144   int i, ssl_fcn_return;
145   const uint8_t *ssl_sessionid;
146   size_t ssl_idsize;
147
148   /* Assuming users will not compile in custom key/cert to axTLS.
149   *  Also, even for blocking connects, use axTLS non-blocking feature.
150   */
151   uint32_t client_option = SSL_NO_DEFAULT_KEY |
152     SSL_SERVER_VERIFY_LATER |
153     SSL_CONNECT_IN_PARTS;
154
155   if(conn->ssl[sockindex].state == ssl_connection_complete)
156     /* to make us tolerant against being called more than once for the
157        same connection */
158     return CURLE_OK;
159
160   /* axTLS only supports TLSv1 */
161   /* check to see if we've been told to use an explicit SSL/TLS version */
162   switch(data->set.ssl.version) {
163   case CURL_SSLVERSION_DEFAULT:
164   case CURL_SSLVERSION_TLSv1:
165     break;
166   default:
167     failf(data, "axTLS only supports TLSv1");
168     return CURLE_SSL_CONNECT_ERROR;
169   }
170
171 #ifdef  AXTLSDEBUG
172   client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS;
173 #endif /* AXTLSDEBUG */
174
175   /* Allocate an SSL_CTX struct */
176   ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS);
177   if(ssl_ctx == NULL) {
178     failf(data, "unable to create client SSL context");
179     return CURLE_SSL_CONNECT_ERROR;
180   }
181
182   conn->ssl[sockindex].ssl_ctx = ssl_ctx;
183   conn->ssl[sockindex].ssl = NULL;
184
185   /* Load the trusted CA cert bundle file */
186   if(data->set.ssl.CAfile) {
187     if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL)
188        != SSL_OK) {
189       infof(data, "error reading ca cert file %s \n",
190             data->set.ssl.CAfile);
191       if(data->set.ssl.verifypeer) {
192         return CURLE_SSL_CACERT_BADFILE;
193       }
194     }
195     else
196       infof(data, "found certificates in %s\n", data->set.ssl.CAfile);
197   }
198
199   /* gtls.c tasks we're skipping for now:
200    * 1) certificate revocation list checking
201    * 2) dns name assignment to host
202    * 3) set protocol priority.  axTLS is TLSv1 only, so can probably ignore
203    * 4) set certificate priority.  axTLS ignores type and sends certs in
204    *  order added.  can probably ignore this.
205    */
206
207   /* Load client certificate */
208   if(data->set.str[STRING_CERT]) {
209     i=0;
210     /* Instead of trying to analyze cert type here, let axTLS try them all. */
211     while(cert_types[i] != 0) {
212       ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i],
213                                     data->set.str[STRING_CERT], NULL);
214       if(ssl_fcn_return == SSL_OK) {
215         infof(data, "successfully read cert file %s \n",
216               data->set.str[STRING_CERT]);
217         break;
218       }
219       i++;
220     }
221     /* Tried all cert types, none worked. */
222     if(cert_types[i] == 0) {
223       failf(data, "%s is not x509 or pkcs12 format",
224             data->set.str[STRING_CERT]);
225       return CURLE_SSL_CERTPROBLEM;
226     }
227   }
228
229   /* Load client key.
230      If a pkcs12 file successfully loaded a cert, then there's nothing to do
231      because the key has already been loaded. */
232   if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) {
233     i=0;
234     /* Instead of trying to analyze key type here, let axTLS try them all. */
235     while(key_types[i] != 0) {
236       ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i],
237                                     data->set.str[STRING_KEY], NULL);
238       if(ssl_fcn_return == SSL_OK) {
239         infof(data, "successfully read key file %s \n",
240               data->set.str[STRING_KEY]);
241         break;
242       }
243       i++;
244     }
245     /* Tried all key types, none worked. */
246     if(key_types[i] == 0) {
247       failf(data, "Failure: %s is not a supported key file",
248             data->set.str[STRING_KEY]);
249       return CURLE_SSL_CONNECT_ERROR;
250     }
251   }
252
253   /* gtls.c does more here that is being left out for now
254    * 1) set session credentials.  can probably ignore since axtls puts this
255    *    info in the ssl_ctx struct
256    * 2) setting up callbacks.  these seem gnutls specific
257    */
258
259   /* In axTLS, handshaking happens inside ssl_client_new. */
260   if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) {
261     /* we got a session id, use it! */
262     infof (data, "SSL re-using session ID\n");
263     ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
264                          ssl_sessionid, (uint8_t)ssl_idsize);
265   }
266   else
267     ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0);
268
269   conn->ssl[sockindex].ssl = ssl;
270   return CURLE_OK;
271 }
272
273 /*
274  * For both blocking and non-blocking connects, this function finalizes the
275  * SSL connection.
276  */
277 static CURLcode connect_finish(struct connectdata *conn, int sockindex)
278 {
279   struct SessionHandle *data = conn->data;
280   SSL *ssl = conn->ssl[sockindex].ssl;
281   const uint8_t *ssl_sessionid;
282   size_t ssl_idsize;
283   const char *peer_CN;
284   uint32_t dns_altname_index;
285   const char *dns_altname;
286   int8_t found_subject_alt_names = 0;
287   int8_t found_subject_alt_name_matching_conn = 0;
288
289   /* Here, gtls.c gets the peer certificates and fails out depending on
290    * settings in "data."  axTLS api doesn't have get cert chain fcn, so omit?
291    */
292
293   /* Verify server's certificate */
294   if(data->set.ssl.verifypeer) {
295     if(ssl_verify_cert(ssl) != SSL_OK) {
296       Curl_axtls_close(conn, sockindex);
297       failf(data, "server cert verify failed");
298       return CURLE_PEER_FAILED_VERIFICATION;
299     }
300   }
301   else
302     infof(data, "\t server certificate verification SKIPPED\n");
303
304   /* Here, gtls.c does issuer verification. axTLS has no straightforward
305    * equivalent, so omitting for now.*/
306
307   /* Here, gtls.c does the following
308    * 1) x509 hostname checking per RFC2818.  axTLS doesn't support this, but
309    *    it seems useful. This is now implemented, by Oscar Koeroo
310    * 2) checks cert validity based on time.  axTLS does this in ssl_verify_cert
311    * 3) displays a bunch of cert information.  axTLS doesn't support most of
312    *    this, but a couple fields are available.
313    */
314
315   /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a
316      risk of an inifite loop */
317   for(dns_altname_index = 0; ; dns_altname_index++) {
318     dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index);
319     if(dns_altname == NULL) {
320       break;
321     }
322     found_subject_alt_names = 1;
323
324     infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n",
325           dns_altname, conn->host.name);
326     if(Curl_cert_hostcheck(dns_altname, conn->host.name)) {
327       found_subject_alt_name_matching_conn = 1;
328       break;
329     }
330   }
331
332   /* RFC2818 checks */
333   if(found_subject_alt_names && !found_subject_alt_name_matching_conn) {
334     if(data->set.ssl.verifyhost) {
335       /* Break connection ! */
336       Curl_axtls_close(conn, sockindex);
337       failf(data, "\tsubjectAltName(s) do not match %s\n",
338             conn->host.dispname);
339       return CURLE_PEER_FAILED_VERIFICATION;
340     }
341     else
342       infof(data, "\tsubjectAltName(s) do not match %s\n",
343             conn->host.dispname);
344   }
345   else if(found_subject_alt_names == 0) {
346     /* Per RFC2818, when no Subject Alt Names were available, examine the peer
347        CN as a legacy fallback */
348     peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
349     if(peer_CN == NULL) {
350       if(data->set.ssl.verifyhost) {
351         Curl_axtls_close(conn, sockindex);
352         failf(data, "unable to obtain common name from peer certificate");
353         return CURLE_PEER_FAILED_VERIFICATION;
354       }
355       else
356         infof(data, "unable to obtain common name from peer certificate");
357     }
358     else {
359       if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
360         if(data->set.ssl.verifyhost) {
361           /* Break connection ! */
362           Curl_axtls_close(conn, sockindex);
363           failf(data, "\tcommon name \"%s\" does not match \"%s\"\n",
364                 peer_CN, conn->host.dispname);
365           return CURLE_PEER_FAILED_VERIFICATION;
366         }
367         else
368           infof(data, "\tcommon name \"%s\" does not match \"%s\"\n",
369                 peer_CN, conn->host.dispname);
370       }
371     }
372   }
373
374   /* General housekeeping */
375   conn->ssl[sockindex].state = ssl_connection_complete;
376   conn->recv[sockindex] = axtls_recv;
377   conn->send[sockindex] = axtls_send;
378
379   /* Put our freshly minted SSL session in cache */
380   ssl_idsize = ssl_get_session_id_size(ssl);
381   ssl_sessionid = ssl_get_session_id(ssl);
382   if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize)
383      != CURLE_OK)
384     infof (data, "failed to add session to cache\n");
385
386   return CURLE_OK;
387 }
388
389 /*
390  * Use axTLS's non-blocking connection feature to open an SSL connection.
391  * This is called after a TCP connection is already established.
392 */
393 CURLcode Curl_axtls_connect_nonblocking(
394     struct connectdata *conn,
395     int sockindex,
396     bool *done)
397 {
398   CURLcode conn_step;
399   int ssl_fcn_return;
400
401  *done = FALSE;
402   /* connectdata is calloc'd and connecting_state is only changed in this
403      function, so this is safe, as the state is effectively initialized. */
404   if(conn->ssl[sockindex].connecting_state == ssl_connect_1) {
405     conn_step = connect_prep(conn, sockindex);
406     if(conn_step != CURLE_OK) {
407       Curl_axtls_close(conn, sockindex);
408       return conn_step;
409     }
410     conn->ssl[sockindex].connecting_state = ssl_connect_2;
411   }
412
413   if(conn->ssl[sockindex].connecting_state == ssl_connect_2) {
414     /* Check to make sure handshake was ok. */
415     if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) {
416       ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL);
417       if(ssl_fcn_return < 0) {
418         Curl_axtls_close(conn, sockindex);
419         ssl_display_error(ssl_fcn_return); /* goes to stdout. */
420         return map_error_to_curl(ssl_fcn_return);
421       }
422       else {
423         return CURLE_OK; /* Return control to caller for retries */
424       }
425     }
426     infof (conn->data, "handshake completed successfully\n");
427     conn->ssl[sockindex].connecting_state = ssl_connect_3;
428   }
429
430   if(conn->ssl[sockindex].connecting_state == ssl_connect_3) {
431     conn_step = connect_finish(conn, sockindex);
432     if(conn_step != CURLE_OK) {
433       Curl_axtls_close(conn, sockindex);
434       return conn_step;
435     }
436
437     /* Reset connect state */
438     conn->ssl[sockindex].connecting_state = ssl_connect_1;
439
440     *done = TRUE;
441     return CURLE_OK;
442   }
443
444   /* Unrecognized state.  Things are very bad. */
445   conn->ssl[sockindex].state  = ssl_connection_none;
446   conn->ssl[sockindex].connecting_state = ssl_connect_1;
447   /* Return value perhaps not strictly correct, but distinguishes the issue.*/
448   return CURLE_BAD_FUNCTION_ARGUMENT;
449 }
450
451
452 /*
453  * This function is called after the TCP connect has completed. Setup the TLS
454  * layer and do all necessary magic for a blocking connect.
455  */
456 CURLcode
457 Curl_axtls_connect(struct connectdata *conn,
458                   int sockindex)
459
460 {
461   CURLcode conn_step = connect_prep(conn, sockindex);
462   int ssl_fcn_return;
463   SSL *ssl = conn->ssl[sockindex].ssl;
464
465   if(conn_step != CURLE_OK) {
466     Curl_axtls_close(conn, sockindex);
467     return conn_step;
468   }
469
470   /* Check to make sure handshake was ok. */
471   while(ssl_handshake_status(ssl) != SSL_OK) {
472     ssl_fcn_return = ssl_read(ssl, NULL);
473     if(ssl_fcn_return < 0) {
474       Curl_axtls_close(conn, sockindex);
475       ssl_display_error(ssl_fcn_return); /* goes to stdout. */
476       return map_error_to_curl(ssl_fcn_return);
477     }
478     usleep(10000);
479   }
480   infof (conn->data, "handshake completed successfully\n");
481
482   conn_step = connect_finish(conn, sockindex);
483   if(conn_step != CURLE_OK) {
484     Curl_axtls_close(conn, sockindex);
485     return conn_step;
486   }
487
488   return CURLE_OK;
489 }
490
491 /* return number of sent (non-SSL) bytes */
492 static ssize_t axtls_send(struct connectdata *conn,
493                           int sockindex,
494                           const void *mem,
495                           size_t len,
496                           CURLcode *err)
497 {
498   /* ssl_write() returns 'int' while write() and send() returns 'size_t' */
499   int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len);
500
501   infof(conn->data, "  axtls_send\n");
502
503   if(rc < 0 ) {
504     *err = map_error_to_curl(rc);
505     rc = -1; /* generic error code for send failure */
506   }
507
508   *err = CURLE_OK;
509   return rc;
510 }
511
512 void Curl_axtls_close_all(struct SessionHandle *data)
513 {
514   (void)data;
515   infof(data, "  Curl_axtls_close_all\n");
516 }
517
518 void Curl_axtls_close(struct connectdata *conn, int sockindex)
519 {
520   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
521
522   infof(conn->data, "  Curl_axtls_close\n");
523
524     /* line from ssluse.c: (void)SSL_shutdown(connssl->ssl);
525        axTLS compat layer does nothing for SSL_shutdown */
526
527     /* The following line is from ssluse.c.  There seems to be no axTLS
528        equivalent.  ssl_free and ssl_ctx_free close things.
529        SSL_set_connect_state(connssl->handle); */
530
531   free_ssl_structs(connssl);
532 }
533
534 /*
535  * This function is called to shut down the SSL layer but keep the
536  * socket open (CCC - Clear Command Channel)
537  */
538 int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
539 {
540   /* Outline taken from ssluse.c since functions are in axTLS compat layer.
541      axTLS's error set is much smaller, so a lot of error-handling was removed.
542    */
543   int retval = 0;
544   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
545   struct SessionHandle *data = conn->data;
546   uint8_t *buf;
547   ssize_t nread;
548
549   infof(conn->data, "  Curl_axtls_shutdown\n");
550
551   /* This has only been tested on the proftpd server, and the mod_tls code
552      sends a close notify alert without waiting for a close notify alert in
553      response. Thus we wait for a close notify alert from the server, but
554      we do not send one. Let's hope other servers do the same... */
555
556   /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too
557   if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
558       (void)SSL_shutdown(connssl->ssl);
559   */
560
561   if(connssl->ssl) {
562     int what = Curl_socket_ready(conn->sock[sockindex],
563                                  CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
564     if(what > 0) {
565       /* Something to read, let's do it and hope that it is the close
566          notify alert from the server.  buf is managed internally by
567          axTLS and will be released upon calling ssl_free via
568          free_ssl_structs. */
569       nread = (ssize_t)ssl_read(connssl->ssl, &buf);
570
571       if(nread < SSL_OK) {
572         failf(data, "close notify alert not received during shutdown");
573         retval = -1;
574       }
575     }
576     else if(0 == what) {
577       /* timeout */
578       failf(data, "SSL shutdown timeout");
579     }
580     else {
581       /* anything that gets here is fatally bad */
582       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
583       retval = -1;
584     }
585
586     free_ssl_structs(connssl);
587   }
588   return retval;
589 }
590
591 static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
592                           int num,                  /* socketindex */
593                           char *buf,                /* store read data here */
594                           size_t buffersize,        /* max amount to read */
595                           CURLcode *err)
596 {
597   struct ssl_connect_data *connssl = &conn->ssl[num];
598   ssize_t ret = 0;
599   uint8_t *read_buf;
600
601   infof(conn->data, "  axtls_recv\n");
602
603   *err = CURLE_OK;
604   if(connssl) {
605     ret = ssl_read(connssl->ssl, &read_buf);
606     if(ret > SSL_OK) {
607       /* ssl_read returns SSL_OK if there is more data to read, so if it is
608          larger, then all data has been read already.  */
609       memcpy(buf, read_buf,
610              (size_t)ret > buffersize ? buffersize : (size_t)ret);
611     }
612     else if(ret == SSL_OK) {
613       /* more data to be read, signal caller to call again */
614       *err = CURLE_AGAIN;
615       ret = -1;
616     }
617     else if(ret == -3) {
618       /* With patched axTLS, SSL_CLOSE_NOTIFY=-3.  Hard-coding until axTLS
619          team approves proposed fix. */
620       Curl_axtls_close(conn, num);
621     }
622     else {
623       failf(conn->data, "axTLS recv error (%d)", ret);
624       *err = map_error_to_curl(ret);
625       ret = -1;
626     }
627   }
628
629   return ret;
630 }
631
632 /*
633  * Return codes:
634  *     1 means the connection is still in place
635  *     0 means the connection has been closed
636  *    -1 means the connection status is unknown
637  */
638 int Curl_axtls_check_cxn(struct connectdata *conn)
639 {
640   /* ssluse.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1);
641      axTLS compat layer always returns the last argument, so connection is
642      always alive? */
643
644   infof(conn->data, "  Curl_axtls_check_cxn\n");
645    return 1; /* connection still in place */
646 }
647
648 void Curl_axtls_session_free(void *ptr)
649 {
650   (void)ptr;
651   /* free the ID */
652   /* both ssluse.c and gtls.c do something here, but axTLS's OpenSSL
653      compatibility layer does nothing, so we do nothing too. */
654 }
655
656 size_t Curl_axtls_version(char *buffer, size_t size)
657 {
658   return snprintf(buffer, size, "axTLS/%s", ssl_version());
659 }
660
661 #endif /* USE_AXTLS */