1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23/*
24 * Source file for all CyaSSL-specific code for the TLS/SSL layer. No code
25 * but vtls.c should ever call or use these functions.
26 *
27 */
28
29#include "curl_setup.h"
30
31#ifdef USE_CYASSL
32
33#ifdef HAVE_LIMITS_H
34#include <limits.h>
35#endif
36
37#include "urldata.h"
38#include "sendf.h"
39#include "inet_pton.h"
40#include "cyassl.h"
41#include "vtls.h"
42#include "parsedate.h"
43#include "connect.h" /* for the connect timeout */
44#include "select.h"
45#include "rawstr.h"
46
47#define _MPRINTF_REPLACE /* use our functions only */
48#include <curl/mprintf.h>
49#include "curl_memory.h"
50/* The last #include file should be: */
51#include "memdebug.h"
52#include <cyassl/ssl.h>
53#include <cyassl/error.h>
54
55
56static Curl_recv cyassl_recv;
57static Curl_send cyassl_send;
58
59
60static int do_file_type(const char *type)
61{
62  if(!type || !type[0])
63    return SSL_FILETYPE_PEM;
64  if(Curl_raw_equal(type, "PEM"))
65    return SSL_FILETYPE_PEM;
66  if(Curl_raw_equal(type, "DER"))
67    return SSL_FILETYPE_ASN1;
68  return -1;
69}
70
71/*
72 * This function loads all the client/CA certificates and CRLs. Setup the TLS
73 * layer and do all necessary magic.
74 */
75static CURLcode
76cyassl_connect_step1(struct connectdata *conn,
77                     int sockindex)
78{
79  struct SessionHandle *data = conn->data;
80  struct ssl_connect_data* conssl = &conn->ssl[sockindex];
81  SSL_METHOD* req_method = NULL;
82  void* ssl_sessionid = NULL;
83  curl_socket_t sockfd = conn->sock[sockindex];
84
85  if(conssl->state == ssl_connection_complete)
86    return CURLE_OK;
87
88  /* CyaSSL doesn't support SSLv2 */
89  if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
90    failf(data, "CyaSSL does not support SSLv2");
91    return CURLE_SSL_CONNECT_ERROR;
92  }
93
94  /* check to see if we've been told to use an explicit SSL/TLS version */
95  switch(data->set.ssl.version) {
96  case CURL_SSLVERSION_DEFAULT:
97    /* we try to figure out version */
98    req_method = SSLv23_client_method();
99    break;
100  case CURL_SSLVERSION_TLSv1:
101    infof(data, "CyaSSL cannot be configured to use TLS 1.0-1.2, "
102          "TLS 1.0 is used exclusively\n");
103    req_method = TLSv1_client_method();
104    break;
105  case CURL_SSLVERSION_TLSv1_0:
106    req_method = TLSv1_client_method();
107    break;
108  case CURL_SSLVERSION_TLSv1_1:
109    req_method = TLSv1_1_client_method();
110    break;
111  case CURL_SSLVERSION_TLSv1_2:
112    req_method = TLSv1_2_client_method();
113    break;
114  case CURL_SSLVERSION_SSLv3:
115    req_method = SSLv3_client_method();
116    break;
117  default:
118    req_method = TLSv1_client_method();
119  }
120
121  if(!req_method) {
122    failf(data, "SSL: couldn't create a method!");
123    return CURLE_OUT_OF_MEMORY;
124  }
125
126  if(conssl->ctx)
127    SSL_CTX_free(conssl->ctx);
128  conssl->ctx = SSL_CTX_new(req_method);
129
130  if(!conssl->ctx) {
131    failf(data, "SSL: couldn't create a context!");
132    return CURLE_OUT_OF_MEMORY;
133  }
134
135#ifndef NO_FILESYSTEM
136  /* load trusted cacert */
137  if(data->set.str[STRING_SSL_CAFILE]) {
138    if(!SSL_CTX_load_verify_locations(conssl->ctx,
139                                      data->set.str[STRING_SSL_CAFILE],
140                                      data->set.str[STRING_SSL_CAPATH])) {
141      if(data->set.ssl.verifypeer) {
142        /* Fail if we insiste on successfully verifying the server. */
143        failf(data,"error setting certificate verify locations:\n"
144              "  CAfile: %s\n  CApath: %s",
145              data->set.str[STRING_SSL_CAFILE]?
146              data->set.str[STRING_SSL_CAFILE]: "none",
147              data->set.str[STRING_SSL_CAPATH]?
148              data->set.str[STRING_SSL_CAPATH] : "none");
149        return CURLE_SSL_CACERT_BADFILE;
150      }
151      else {
152        /* Just continue with a warning if no strict  certificate
153           verification is required. */
154        infof(data, "error setting certificate verify locations,"
155              " continuing anyway:\n");
156      }
157    }
158    else {
159      /* Everything is fine. */
160      infof(data, "successfully set certificate verify locations:\n");
161    }
162    infof(data,
163          "  CAfile: %s\n"
164          "  CApath: %s\n",
165          data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
166          "none",
167          data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
168          "none");
169  }
170
171  /* Load the client certificate, and private key */
172  if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) {
173    int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]);
174
175    if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT],
176                                     file_type) != 1) {
177      failf(data, "unable to use client certificate (no key or wrong pass"
178            " phrase?)");
179      return CURLE_SSL_CONNECT_ERROR;
180    }
181
182    file_type = do_file_type(data->set.str[STRING_KEY_TYPE]);
183    if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY],
184                                    file_type) != 1) {
185      failf(data, "unable to set private key");
186      return CURLE_SSL_CONNECT_ERROR;
187    }
188  }
189#else
190  if(CyaSSL_no_filesystem_verify(conssl->ctx)!= SSL_SUCCESS) {
191    return CURLE_SSL_CONNECT_ERROR;
192  }
193#endif /* NO_FILESYSTEM */
194
195  /* SSL always tries to verify the peer, this only says whether it should
196   * fail to connect if the verification fails, or if it should continue
197   * anyway. In the latter case the result of the verification is checked with
198   * SSL_get_verify_result() below. */
199  SSL_CTX_set_verify(conssl->ctx,
200                     data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
201                     NULL);
202
203  /* Let's make an SSL structure */
204  if(conssl->handle)
205    SSL_free(conssl->handle);
206  conssl->handle = SSL_new(conssl->ctx);
207  if(!conssl->handle) {
208    failf(data, "SSL: couldn't create a context (handle)!");
209    return CURLE_OUT_OF_MEMORY;
210  }
211
212  /* Check if there's a cached ID we can/should use here! */
213  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
214    /* we got a session id, use it! */
215    if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
216      failf(data, "SSL: SSL_set_session failed: %s",
217            ERR_error_string(SSL_get_error(conssl->handle, 0),NULL));
218      return CURLE_SSL_CONNECT_ERROR;
219    }
220    /* Informational message */
221    infof (data, "SSL re-using session ID\n");
222  }
223
224  /* pass the raw socket into the SSL layer */
225  if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
226    failf(data, "SSL: SSL_set_fd failed");
227    return CURLE_SSL_CONNECT_ERROR;
228  }
229
230  conssl->connecting_state = ssl_connect_2;
231  return CURLE_OK;
232}
233
234
235static CURLcode
236cyassl_connect_step2(struct connectdata *conn,
237                     int sockindex)
238{
239  int ret = -1;
240  struct SessionHandle *data = conn->data;
241  struct ssl_connect_data* conssl = &conn->ssl[sockindex];
242
243  infof(data, "CyaSSL: Connecting to %s:%d\n",
244        conn->host.name, conn->remote_port);
245
246  conn->recv[sockindex] = cyassl_recv;
247  conn->send[sockindex] = cyassl_send;
248
249  /* Enable RFC2818 checks */
250  if(data->set.ssl.verifyhost) {
251    ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name);
252    if(ret == SSL_FAILURE)
253      return CURLE_OUT_OF_MEMORY;
254  }
255
256  ret = SSL_connect(conssl->handle);
257  if(ret != 1) {
258    char error_buffer[80];
259    int  detail = SSL_get_error(conssl->handle, ret);
260
261    if(SSL_ERROR_WANT_READ == detail) {
262      conssl->connecting_state = ssl_connect_2_reading;
263      return CURLE_OK;
264    }
265    else if(SSL_ERROR_WANT_WRITE == detail) {
266      conssl->connecting_state = ssl_connect_2_writing;
267      return CURLE_OK;
268    }
269    /* There is no easy way to override only the CN matching.
270     * This will enable the override of both mismatching SubjectAltNames
271     * as also mismatching CN fields */
272    else if(DOMAIN_NAME_MISMATCH == detail) {
273#if 1
274      failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
275            conn->host.dispname);
276      return CURLE_PEER_FAILED_VERIFICATION;
277#else
278      /* When the CyaSSL_check_domain_name() is used and you desire to continue
279       * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0',
280       * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only
281       * way to do this is currently to switch the CyaSSL_check_domain_name()
282       * in and out based on the 'data->set.ssl.verifyhost' value. */
283      if(data->set.ssl.verifyhost) {
284        failf(data,
285              "\tsubject alt name(s) or common name do not match \"%s\"\n",
286              conn->host.dispname);
287        return CURLE_PEER_FAILED_VERIFICATION;
288      }
289      else {
290        infof(data,
291              "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
292              conn->host.dispname);
293        return CURLE_OK;
294      }
295#endif
296    }
297    else {
298      failf(data, "SSL_connect failed with error %d: %s", detail,
299          ERR_error_string(detail, error_buffer));
300      return CURLE_SSL_CONNECT_ERROR;
301    }
302  }
303
304  conssl->connecting_state = ssl_connect_3;
305  infof(data, "SSL connected\n");
306
307  return CURLE_OK;
308}
309
310
311static CURLcode
312cyassl_connect_step3(struct connectdata *conn,
313                     int sockindex)
314{
315  CURLcode retcode = CURLE_OK;
316  void *old_ssl_sessionid=NULL;
317  struct SessionHandle *data = conn->data;
318  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
319  int incache;
320  SSL_SESSION *our_ssl_sessionid;
321
322  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
323
324  our_ssl_sessionid = SSL_get_session(connssl->handle);
325
326  incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
327  if(incache) {
328    if(old_ssl_sessionid != our_ssl_sessionid) {
329      infof(data, "old SSL session ID is stale, removing\n");
330      Curl_ssl_delsessionid(conn, old_ssl_sessionid);
331      incache = FALSE;
332    }
333  }
334  if(!incache) {
335    retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
336                                    0 /* unknown size */);
337    if(retcode) {
338      failf(data, "failed to store ssl session");
339      return retcode;
340    }
341  }
342
343  connssl->connecting_state = ssl_connect_done;
344
345  return retcode;
346}
347
348
349static ssize_t cyassl_send(struct connectdata *conn,
350                           int sockindex,
351                           const void *mem,
352                           size_t len,
353                           CURLcode *curlcode)
354{
355  char error_buffer[80];
356  int  memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
357  int  rc     = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
358
359  if(rc < 0) {
360    int err = SSL_get_error(conn->ssl[sockindex].handle, rc);
361
362    switch(err) {
363    case SSL_ERROR_WANT_READ:
364    case SSL_ERROR_WANT_WRITE:
365      /* there's data pending, re-invoke SSL_write() */
366      *curlcode = CURLE_AGAIN;
367      return -1;
368    default:
369      failf(conn->data, "SSL write: %s, errno %d",
370            ERR_error_string(err, error_buffer),
371            SOCKERRNO);
372      *curlcode = CURLE_SEND_ERROR;
373      return -1;
374    }
375  }
376  return rc;
377}
378
379void Curl_cyassl_close_all(struct SessionHandle *data)
380{
381  (void)data;
382}
383
384void Curl_cyassl_close(struct connectdata *conn, int sockindex)
385{
386  struct ssl_connect_data *conssl = &conn->ssl[sockindex];
387
388  if(conssl->handle) {
389    (void)SSL_shutdown(conssl->handle);
390    SSL_free (conssl->handle);
391    conssl->handle = NULL;
392  }
393  if(conssl->ctx) {
394    SSL_CTX_free (conssl->ctx);
395    conssl->ctx = NULL;
396  }
397}
398
399static ssize_t cyassl_recv(struct connectdata *conn,
400                           int num,
401                           char *buf,
402                           size_t buffersize,
403                           CURLcode *curlcode)
404{
405  char error_buffer[80];
406  int  buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
407  int  nread    = SSL_read(conn->ssl[num].handle, buf, buffsize);
408
409  if(nread < 0) {
410    int err = SSL_get_error(conn->ssl[num].handle, nread);
411
412    switch(err) {
413    case SSL_ERROR_ZERO_RETURN: /* no more data */
414      break;
415    case SSL_ERROR_WANT_READ:
416    case SSL_ERROR_WANT_WRITE:
417      /* there's data pending, re-invoke SSL_read() */
418      *curlcode = CURLE_AGAIN;
419      return -1;
420    default:
421      failf(conn->data, "SSL read: %s, errno %d",
422            ERR_error_string(err, error_buffer),
423            SOCKERRNO);
424      *curlcode = CURLE_RECV_ERROR;
425      return -1;
426    }
427  }
428  return nread;
429}
430
431
432void Curl_cyassl_session_free(void *ptr)
433{
434  (void)ptr;
435  /* CyaSSL reuses sessions on own, no free */
436}
437
438
439size_t Curl_cyassl_version(char *buffer, size_t size)
440{
441#ifdef CYASSL_VERSION
442  return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION);
443#else
444  return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8");
445#endif
446}
447
448
449int Curl_cyassl_init(void)
450{
451  if(CyaSSL_Init() == 0)
452    return 1;
453
454  return -1;
455}
456
457
458bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex)
459{
460  if(conn->ssl[connindex].handle)   /* SSL is in use */
461    return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
462  else
463    return FALSE;
464}
465
466
467/*
468 * This function is called to shut down the SSL layer but keep the
469 * socket open (CCC - Clear Command Channel)
470 */
471int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
472{
473  int retval = 0;
474  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
475
476  if(connssl->handle) {
477    SSL_free (connssl->handle);
478    connssl->handle = NULL;
479  }
480  return retval;
481}
482
483
484static CURLcode
485cyassl_connect_common(struct connectdata *conn,
486                      int sockindex,
487                      bool nonblocking,
488                      bool *done)
489{
490  CURLcode retcode;
491  struct SessionHandle *data = conn->data;
492  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
493  curl_socket_t sockfd = conn->sock[sockindex];
494  long timeout_ms;
495  int what;
496
497  /* check if the connection has already been established */
498  if(ssl_connection_complete == connssl->state) {
499    *done = TRUE;
500    return CURLE_OK;
501  }
502
503  if(ssl_connect_1==connssl->connecting_state) {
504    /* Find out how much more time we're allowed */
505    timeout_ms = Curl_timeleft(data, NULL, TRUE);
506
507    if(timeout_ms < 0) {
508      /* no need to continue if time already is up */
509      failf(data, "SSL connection timeout");
510      return CURLE_OPERATION_TIMEDOUT;
511    }
512    retcode = cyassl_connect_step1(conn, sockindex);
513    if(retcode)
514      return retcode;
515  }
516
517  while(ssl_connect_2 == connssl->connecting_state ||
518        ssl_connect_2_reading == connssl->connecting_state ||
519        ssl_connect_2_writing == connssl->connecting_state) {
520
521    /* check allowed time left */
522    timeout_ms = Curl_timeleft(data, NULL, TRUE);
523
524    if(timeout_ms < 0) {
525      /* no need to continue if time already is up */
526      failf(data, "SSL connection timeout");
527      return CURLE_OPERATION_TIMEDOUT;
528    }
529
530    /* if ssl is expecting something, check if it's available. */
531    if(connssl->connecting_state == ssl_connect_2_reading
532       || connssl->connecting_state == ssl_connect_2_writing) {
533
534      curl_socket_t writefd = ssl_connect_2_writing==
535        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
536      curl_socket_t readfd = ssl_connect_2_reading==
537        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
538
539      what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
540      if(what < 0) {
541        /* fatal error */
542        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
543        return CURLE_SSL_CONNECT_ERROR;
544      }
545      else if(0 == what) {
546        if(nonblocking) {
547          *done = FALSE;
548          return CURLE_OK;
549        }
550        else {
551          /* timeout */
552          failf(data, "SSL connection timeout");
553          return CURLE_OPERATION_TIMEDOUT;
554        }
555      }
556      /* socket is readable or writable */
557    }
558
559    /* Run transaction, and return to the caller if it failed or if
560     * this connection is part of a multi handle and this loop would
561     * execute again. This permits the owner of a multi handle to
562     * abort a connection attempt before step2 has completed while
563     * ensuring that a client using select() or epoll() will always
564     * have a valid fdset to wait on.
565     */
566    retcode = cyassl_connect_step2(conn, sockindex);
567    if(retcode || (nonblocking &&
568                   (ssl_connect_2 == connssl->connecting_state ||
569                    ssl_connect_2_reading == connssl->connecting_state ||
570                    ssl_connect_2_writing == connssl->connecting_state)))
571      return retcode;
572
573  } /* repeat step2 until all transactions are done. */
574
575  if(ssl_connect_3==connssl->connecting_state) {
576    retcode = cyassl_connect_step3(conn, sockindex);
577    if(retcode)
578      return retcode;
579  }
580
581  if(ssl_connect_done==connssl->connecting_state) {
582    connssl->state = ssl_connection_complete;
583    conn->recv[sockindex] = cyassl_recv;
584    conn->send[sockindex] = cyassl_send;
585    *done = TRUE;
586  }
587  else
588    *done = FALSE;
589
590  /* Reset our connect state machine */
591  connssl->connecting_state = ssl_connect_1;
592
593  return CURLE_OK;
594}
595
596
597CURLcode
598Curl_cyassl_connect_nonblocking(struct connectdata *conn,
599                                int sockindex,
600                                bool *done)
601{
602  return cyassl_connect_common(conn, sockindex, TRUE, done);
603}
604
605
606CURLcode
607Curl_cyassl_connect(struct connectdata *conn,
608                    int sockindex)
609{
610  CURLcode retcode;
611  bool done = FALSE;
612
613  retcode = cyassl_connect_common(conn, sockindex, FALSE, &done);
614  if(retcode)
615    return retcode;
616
617  DEBUGASSERT(done);
618
619  return CURLE_OK;
620}
621
622#endif
623