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