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