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 "setup.h"
30
31#ifdef USE_AXTLS
32#include <axTLS/ssl.h>
33#include "axtls.h"
34
35#ifdef HAVE_SYS_SOCKET_H
36#include <sys/socket.h>
37#endif
38
39#include "sendf.h"
40#include "inet_pton.h"
41#include "sslgen.h"
42#include "parsedate.h"
43#include "connect.h" /* for the connect timeout */
44#include "select.h"
45#define _MPRINTF_REPLACE /* use our functions only */
46#include <curl/mprintf.h>
47#include "curl_memory.h"
48/* The last #include file should be: */
49#include "memdebug.h"
50
51/* SSL_read is opied from axTLS compat layer */
52static int SSL_read(SSL *ssl, void *buf, int num)
53{
54  uint8_t *read_buf;
55  int ret;
56
57  while((ret = ssl_read(ssl, &read_buf)) == SSL_OK);
58
59  if(ret > SSL_OK) {
60    memcpy(buf, read_buf, ret > num ? num : ret);
61  }
62
63  return ret;
64}
65
66/* Global axTLS init, called from Curl_ssl_init() */
67int Curl_axtls_init(void)
68{
69/* axTLS has no global init.  Everything is done through SSL and SSL_CTX
70 * structs stored in connectdata structure.  Perhaps can move to axtls.h.
71 */
72  return 1;
73}
74
75int Curl_axtls_cleanup(void)
76{
77  /* axTLS has no global cleanup.  Perhaps can move this to axtls.h. */
78  return 1;
79}
80
81static CURLcode map_error_to_curl(int axtls_err)
82{
83  switch (axtls_err) {
84  case SSL_ERROR_NOT_SUPPORTED:
85  case SSL_ERROR_INVALID_VERSION:
86  case -70:                       /* protocol version alert from server */
87    return CURLE_UNSUPPORTED_PROTOCOL;
88    break;
89  case SSL_ERROR_NO_CIPHER:
90    return CURLE_SSL_CIPHER;
91    break;
92  case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */
93  case SSL_ERROR_NO_CERT_DEFINED:
94  case -42:                       /* bad certificate alert from server */
95  case -43:                       /* unsupported cert alert from server */
96  case -44:                       /* cert revoked alert from server */
97  case -45:                       /* cert expired alert from server */
98  case -46:                       /* cert unknown alert from server */
99    return CURLE_SSL_CERTPROBLEM;
100    break;
101  case SSL_X509_ERROR(X509_NOT_OK):
102  case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT):
103  case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE):
104  case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID):
105  case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED):
106  case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED):
107  case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN):
108  case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST):
109  case SSL_X509_ERROR(X509_INVALID_PRIV_KEY):
110    return CURLE_PEER_FAILED_VERIFICATION;
111    break;
112  case -48:                       /* unknown ca alert from server */
113    return CURLE_SSL_CACERT;
114    break;
115  case -49:                       /* access denied alert from server */
116    return CURLE_REMOTE_ACCESS_DENIED;
117    break;
118  case SSL_ERROR_CONN_LOST:
119  case SSL_ERROR_SOCK_SETUP_FAILURE:
120  case SSL_ERROR_INVALID_HANDSHAKE:
121  case SSL_ERROR_INVALID_PROT_MSG:
122  case SSL_ERROR_INVALID_HMAC:
123  case SSL_ERROR_INVALID_SESSION:
124  case SSL_ERROR_INVALID_KEY:     /* it's too bad this doesn't map better */
125  case SSL_ERROR_FINISHED_INVALID:
126  case SSL_ERROR_NO_CLIENT_RENOG:
127  default:
128    return CURLE_SSL_CONNECT_ERROR;
129    break;
130  }
131}
132
133static Curl_recv axtls_recv;
134static Curl_send axtls_send;
135
136/*
137 * This function is called after the TCP connect has completed. Setup the TLS
138 * layer and do all necessary magic.
139 */
140CURLcode
141Curl_axtls_connect(struct connectdata *conn,
142                  int sockindex)
143
144{
145  struct SessionHandle *data = conn->data;
146  SSL_CTX *ssl_ctx;
147  SSL *ssl;
148  int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0};
149  int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0};
150  int i, ssl_fcn_return;
151  const uint8_t *ssl_sessionid;
152  size_t ssl_idsize;
153  const char *x509;
154
155  /* Assuming users will not compile in custom key/cert to axTLS */
156  uint32_t client_option = SSL_NO_DEFAULT_KEY|SSL_SERVER_VERIFY_LATER;
157
158  if(conn->ssl[sockindex].state == ssl_connection_complete)
159    /* to make us tolerant against being called more than once for the
160       same connection */
161    return CURLE_OK;
162
163  /* axTLS only supports TLSv1 */
164  /* check to see if we've been told to use an explicit SSL/TLS version */
165  switch(data->set.ssl.version) {
166  case CURL_SSLVERSION_DEFAULT:
167  case CURL_SSLVERSION_TLSv1:
168    break;
169  default:
170    failf(data, "axTLS only supports TLSv1");
171    return CURLE_SSL_CONNECT_ERROR;
172  }
173
174#ifdef  AXTLSDEBUG
175  client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS;
176#endif /* AXTLSDEBUG */
177
178  /* Allocate an SSL_CTX struct */
179  ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS);
180  if(ssl_ctx == NULL) {
181    failf(data, "unable to create client SSL context");
182    return CURLE_SSL_CONNECT_ERROR;
183  }
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        Curl_axtls_close(conn, sockindex);
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      Curl_axtls_close(conn, sockindex);
227      return CURLE_SSL_CERTPROBLEM;
228    }
229  }
230
231  /* Load client key.
232     If a pkcs12 file successfully loaded a cert, then there's nothing to do
233     because the key has already been loaded. */
234  if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) {
235    i=0;
236    /* Instead of trying to analyze key type here, let axTLS try them all. */
237    while(key_types[i] != 0) {
238      ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i],
239                                    data->set.str[STRING_KEY], NULL);
240      if(ssl_fcn_return == SSL_OK) {
241        infof(data, "successfully read key file %s \n",
242              data->set.str[STRING_KEY]);
243        break;
244      }
245      i++;
246    }
247    /* Tried all key types, none worked. */
248    if(key_types[i] == 0) {
249      failf(data, "Failure: %s is not a supported key file",
250            data->set.str[STRING_KEY]);
251      Curl_axtls_close(conn, sockindex);
252      return CURLE_SSL_CONNECT_ERROR;
253    }
254  }
255
256  /* gtls.c does more here that is being left out for now
257   * 1) set session credentials.  can probably ignore since axtls puts this
258   *    info in the ssl_ctx struct
259   * 2) setting up callbacks.  these seem gnutls specific
260   */
261
262  /* In axTLS, handshaking happens inside ssl_client_new. */
263  if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) {
264    /* we got a session id, use it! */
265    infof (data, "SSL re-using session ID\n");
266    ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
267                         ssl_sessionid, (uint8_t)ssl_idsize);
268  }
269  else
270    ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0);
271
272  /* Check to make sure handshake was ok. */
273  ssl_fcn_return = ssl_handshake_status(ssl);
274  if(ssl_fcn_return != SSL_OK) {
275    Curl_axtls_close(conn, sockindex);
276    ssl_display_error(ssl_fcn_return); /* goes to stdout. */
277    return map_error_to_curl(ssl_fcn_return);
278  }
279  infof (data, "handshake completed successfully\n");
280
281  /* Here, gtls.c gets the peer certificates and fails out depending on
282   * settings in "data."  axTLS api doesn't have get cert chain fcn, so omit?
283   */
284
285  /* Verify server's certificate */
286  if(data->set.ssl.verifypeer) {
287    if(ssl_verify_cert(ssl) != SSL_OK) {
288      Curl_axtls_close(conn, sockindex);
289      failf(data, "server cert verify failed");
290      return CURLE_SSL_CONNECT_ERROR;
291    }
292  }
293  else
294    infof(data, "\t server certificate verification SKIPPED\n");
295
296  /* Here, gtls.c does issuer verification. axTLS has no straightforward
297   * equivalent, so omitting for now.*/
298
299  /* See if common name was set in server certificate */
300  x509 = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
301  if(x509 == NULL)
302    infof(data, "error fetching CN from cert\n");
303
304  /* Here, gtls.c does the following
305   * 1) x509 hostname checking per RFC2818.  axTLS doesn't support this, but
306   *    it seems useful.  Omitting for now.
307   * 2) checks cert validity based on time.  axTLS does this in ssl_verify_cert
308   * 3) displays a bunch of cert information.  axTLS doesn't support most of
309   *    this, but a couple fields are available.
310   */
311
312  /* General housekeeping */
313  conn->ssl[sockindex].state = ssl_connection_complete;
314  conn->ssl[sockindex].ssl = ssl;
315  conn->ssl[sockindex].ssl_ctx = ssl_ctx;
316  conn->recv[sockindex] = axtls_recv;
317  conn->send[sockindex] = axtls_send;
318
319  /* Put our freshly minted SSL session in cache */
320  ssl_idsize = ssl_get_session_id_size(ssl);
321  ssl_sessionid = ssl_get_session_id(ssl);
322  if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize)
323     != CURLE_OK)
324    infof (data, "failed to add session to cache\n");
325
326  return CURLE_OK;
327}
328
329
330/* return number of sent (non-SSL) bytes */
331static ssize_t axtls_send(struct connectdata *conn,
332                          int sockindex,
333                          const void *mem,
334                          size_t len,
335                          CURLcode *err)
336{
337  /* ssl_write() returns 'int' while write() and send() returns 'size_t' */
338  int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len);
339
340  infof(conn->data, "  axtls_send\n");
341
342  if(rc < 0 ) {
343    *err = map_error_to_curl(rc);
344    rc = -1; /* generic error code for send failure */
345  }
346
347  *err = CURLE_OK;
348  return rc;
349}
350
351void Curl_axtls_close_all(struct SessionHandle *data)
352{
353  (void)data;
354  infof(data, "  Curl_axtls_close_all\n");
355}
356
357void Curl_axtls_close(struct connectdata *conn, int sockindex)
358{
359  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
360
361  infof(conn->data, "  Curl_axtls_close\n");
362  if(connssl->ssl) {
363    /* line from ssluse.c: (void)SSL_shutdown(connssl->ssl);
364       axTLS compat layer does nothing for SSL_shutdown */
365
366    /* The following line is from ssluse.c.  There seems to be no axTLS
367       equivalent.  ssl_free and ssl_ctx_free close things.
368       SSL_set_connect_state(connssl->handle); */
369
370    ssl_free (connssl->ssl);
371    connssl->ssl = NULL;
372  }
373  if(connssl->ssl_ctx) {
374    ssl_ctx_free (connssl->ssl_ctx);
375    connssl->ssl_ctx = NULL;
376  }
377}
378
379/*
380 * This function is called to shut down the SSL layer but keep the
381 * socket open (CCC - Clear Command Channel)
382 */
383int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
384{
385  /* Outline taken from ssluse.c since functions are in axTLS compat layer.
386     axTLS's error set is much smaller, so a lot of error-handling was removed.
387   */
388  int retval = 0;
389  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
390  struct SessionHandle *data = conn->data;
391  char buf[120]; /* We will use this for the OpenSSL error buffer, so it has
392                    to be at least 120 bytes long. */
393  ssize_t nread;
394
395  infof(conn->data, "  Curl_axtls_shutdown\n");
396
397  /* This has only been tested on the proftpd server, and the mod_tls code
398     sends a close notify alert without waiting for a close notify alert in
399     response. Thus we wait for a close notify alert from the server, but
400     we do not send one. Let's hope other servers do the same... */
401
402  /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too
403  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
404      (void)SSL_shutdown(connssl->ssl);
405  */
406
407  if(connssl->ssl) {
408    int what = Curl_socket_ready(conn->sock[sockindex],
409                                 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
410    if(what > 0) {
411      /* Something to read, let's do it and hope that it is the close
412         notify alert from the server */
413      nread = (ssize_t)SSL_read(conn->ssl[sockindex].ssl, buf,
414                                sizeof(buf));
415
416      if(nread < SSL_OK) {
417        failf(data, "close notify alert not received during shutdown");
418        retval = -1;
419      }
420    }
421    else if(0 == what) {
422      /* timeout */
423      failf(data, "SSL shutdown timeout");
424    }
425    else {
426      /* anything that gets here is fatally bad */
427      failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
428      retval = -1;
429    }
430
431    ssl_free (connssl->ssl);
432    connssl->ssl = NULL;
433  }
434  return retval;
435}
436
437static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
438                          int num,                  /* socketindex */
439                          char *buf,                /* store read data here */
440                          size_t buffersize,        /* max amount to read */
441                          CURLcode *err)
442{
443  struct ssl_connect_data *connssl = &conn->ssl[num];
444  ssize_t ret = 0;
445
446  infof(conn->data, "  axtls_recv\n");
447
448  if(connssl) {
449    ret = (ssize_t)SSL_read(conn->ssl[num].ssl, buf, (int)buffersize);
450
451    /* axTLS isn't terribly generous about error reporting */
452    /* With patched axTLS, SSL_CLOSE_NOTIFY=-3.  Hard-coding until axTLS
453       team approves proposed fix. */
454    if(ret == -3 ) {
455      Curl_axtls_close(conn, num);
456    }
457    else if(ret < 0) {
458      failf(conn->data, "axTLS recv error (%d)", (int)ret);
459      *err = map_error_to_curl(ret);
460      return -1;
461    }
462  }
463
464  *err = CURLE_OK;
465  return ret;
466}
467
468/*
469 * Return codes:
470 *     1 means the connection is still in place
471 *     0 means the connection has been closed
472 *    -1 means the connection status is unknown
473 */
474int Curl_axtls_check_cxn(struct connectdata *conn)
475{
476  /* ssluse.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1);
477     axTLS compat layer always returns the last argument, so connection is
478     always alive? */
479
480  infof(conn->data, "  Curl_axtls_check_cxn\n");
481   return 1; /* connection still in place */
482}
483
484void Curl_axtls_session_free(void *ptr)
485{
486  (void)ptr;
487  /* free the ID */
488  /* both ssluse.c and gtls.c do something here, but axTLS's OpenSSL
489     compatibility layer does nothing, so we do nothing too. */
490}
491
492size_t Curl_axtls_version(char *buffer, size_t size)
493{
494  return snprintf(buffer, size, "axTLS/%s", ssl_version());
495}
496
497#endif /* USE_AXTLS */
498