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