VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/vtls/mesalink.c@ 86643

Last change on this file since 86643 was 85671, checked in by vboxsync, 4 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

  • Property svn:eol-style set to native
File size: 17.8 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2017 - 2018, Yiming Jing, <[email protected]>
9 * Copyright (C) 1998 - 2018, Daniel Stenberg, <[email protected]>, 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 https://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 MesaLink-specific code for the TLS/SSL layer. No code
26 * but vtls.c should ever call or use these functions.
27 *
28 */
29
30/*
31 * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
32 * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
33 *
34 * Thanks for code and inspiration!
35 */
36
37#include "curl_setup.h"
38
39#ifdef USE_MESALINK
40
41#include <mesalink/options.h>
42#include <mesalink/version.h>
43
44#include "urldata.h"
45#include "sendf.h"
46#include "inet_pton.h"
47#include "vtls.h"
48#include "parsedate.h"
49#include "connect.h" /* for the connect timeout */
50#include "select.h"
51#include "strcase.h"
52#include "x509asn1.h"
53#include "curl_printf.h"
54
55#include "mesalink.h"
56#include <mesalink/openssl/ssl.h>
57#include <mesalink/openssl/err.h>
58
59/* The last #include files should be: */
60#include "curl_memory.h"
61#include "memdebug.h"
62
63#define MESALINK_MAX_ERROR_SZ 80
64
65struct ssl_backend_data
66{
67 SSL_CTX *ctx;
68 SSL *handle;
69};
70
71#define BACKEND connssl->backend
72
73static Curl_recv mesalink_recv;
74static Curl_send mesalink_send;
75
76/*
77 * This function loads all the client/CA certificates and CRLs. Setup the TLS
78 * layer and do all necessary magic.
79 */
80static CURLcode
81mesalink_connect_step1(struct connectdata *conn, int sockindex)
82{
83 char *ciphers;
84 struct Curl_easy *data = conn->data;
85 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
86 const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
87 const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
88 const char *const ssl_capath = SSL_CONN_CONFIG(CApath);
89 struct in_addr addr4;
90#ifdef ENABLE_IPV6
91 struct in6_addr addr6;
92#endif
93 const char *const hostname =
94 SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name;
95 size_t hostname_len = strlen(hostname);
96
97 SSL_METHOD *req_method = NULL;
98 curl_socket_t sockfd = conn->sock[sockindex];
99
100 if(connssl->state == ssl_connection_complete)
101 return CURLE_OK;
102
103 if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
104 failf(data, "MesaLink does not support to set maximum SSL/TLS version");
105 return CURLE_SSL_CONNECT_ERROR;
106 }
107
108 switch(SSL_CONN_CONFIG(version)) {
109 case CURL_SSLVERSION_SSLv3:
110 case CURL_SSLVERSION_TLSv1:
111 case CURL_SSLVERSION_TLSv1_0:
112 case CURL_SSLVERSION_TLSv1_1:
113 failf(data, "MesaLink does not support SSL 3.0, TLS 1.0, or TLS 1.1");
114 return CURLE_NOT_BUILT_IN;
115 case CURL_SSLVERSION_DEFAULT:
116 case CURL_SSLVERSION_TLSv1_2:
117 req_method = TLSv1_2_client_method();
118 break;
119 case CURL_SSLVERSION_TLSv1_3:
120 req_method = TLSv1_3_client_method();
121 break;
122 case CURL_SSLVERSION_SSLv2:
123 failf(data, "MesaLink does not support SSLv2");
124 return CURLE_SSL_CONNECT_ERROR;
125 default:
126 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
127 return CURLE_SSL_CONNECT_ERROR;
128 }
129
130 if(!req_method) {
131 failf(data, "SSL: couldn't create a method!");
132 return CURLE_OUT_OF_MEMORY;
133 }
134
135 if(BACKEND->ctx)
136 SSL_CTX_free(BACKEND->ctx);
137 BACKEND->ctx = SSL_CTX_new(req_method);
138
139 if(!BACKEND->ctx) {
140 failf(data, "SSL: couldn't create a context!");
141 return CURLE_OUT_OF_MEMORY;
142 }
143
144 SSL_CTX_set_verify(
145 BACKEND->ctx, verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
146
147 if(ssl_cafile || ssl_capath) {
148 if(!SSL_CTX_load_verify_locations(BACKEND->ctx, ssl_cafile, ssl_capath)) {
149 if(verifypeer) {
150 failf(data,
151 "error setting certificate verify locations:\n"
152 " CAfile: %s\n CApath: %s",
153 ssl_cafile ? ssl_cafile : "none",
154 ssl_capath ? ssl_capath : "none");
155 return CURLE_SSL_CACERT_BADFILE;
156 }
157 infof(data,
158 "error setting certificate verify locations,"
159 " continuing anyway:\n");
160 }
161 else {
162 infof(data, "successfully set certificate verify locations:\n");
163 }
164 infof(data,
165 " CAfile: %s\n"
166 " CApath: %s\n",
167 ssl_cafile ? ssl_cafile : "none",
168 ssl_capath ? ssl_capath : "none");
169 }
170
171 ciphers = SSL_CONN_CONFIG(cipher_list);
172 if(ciphers) {
173#ifdef MESALINK_HAVE_CIPHER
174 if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
175 failf(data, "failed setting cipher list: %s", ciphers);
176 return CURLE_SSL_CIPHER;
177 }
178#endif
179 infof(data, "Cipher selection: %s\n", ciphers);
180 }
181
182 if(BACKEND->handle)
183 SSL_free(BACKEND->handle);
184 BACKEND->handle = SSL_new(BACKEND->ctx);
185 if(!BACKEND->handle) {
186 failf(data, "SSL: couldn't create a context (handle)!");
187 return CURLE_OUT_OF_MEMORY;
188 }
189
190 if((hostname_len < USHRT_MAX) &&
191 (0 == Curl_inet_pton(AF_INET, hostname, &addr4))
192#ifdef ENABLE_IPV6
193 && (0 == Curl_inet_pton(AF_INET6, hostname, &addr6))
194#endif
195 ) {
196 /* hostname is not a valid IP address */
197 if(SSL_set_tlsext_host_name(BACKEND->handle, hostname) != SSL_SUCCESS) {
198 failf(data,
199 "WARNING: failed to configure server name indication (SNI) "
200 "TLS extension\n");
201 return CURLE_SSL_CONNECT_ERROR;
202 }
203 }
204 else {
205#ifdef CURLDEBUG
206 /* Check if the hostname is 127.0.0.1 or [::1];
207 * otherwise reject because MesaLink always wants a valid DNS Name
208 * specified in RFC 5280 Section 7.2 */
209 if(strncmp(hostname, "127.0.0.1", 9) == 0
210#ifdef ENABLE_IPV6
211 || strncmp(hostname, "[::1]", 5) == 0
212#endif
213 ) {
214 SSL_set_tlsext_host_name(BACKEND->handle, "localhost");
215 }
216 else
217#endif
218 {
219 failf(data,
220 "ERROR: MesaLink does not accept an IP address as a hostname\n");
221 return CURLE_SSL_CONNECT_ERROR;
222 }
223 }
224
225#ifdef MESALINK_HAVE_SESSION
226 if(SSL_SET_OPTION(primary.sessionid)) {
227 void *ssl_sessionid = NULL;
228
229 Curl_ssl_sessionid_lock(conn);
230 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
231 /* we got a session id, use it! */
232 if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
233 Curl_ssl_sessionid_unlock(conn);
234 failf(
235 data,
236 "SSL: SSL_set_session failed: %s",
237 ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer));
238 return CURLE_SSL_CONNECT_ERROR;
239 }
240 /* Informational message */
241 infof(data, "SSL re-using session ID\n");
242 }
243 Curl_ssl_sessionid_unlock(conn);
244 }
245#endif /* MESALINK_HAVE_SESSION */
246
247 if(SSL_set_fd(BACKEND->handle, (int)sockfd) != SSL_SUCCESS) {
248 failf(data, "SSL: SSL_set_fd failed");
249 return CURLE_SSL_CONNECT_ERROR;
250 }
251
252 connssl->connecting_state = ssl_connect_2;
253 return CURLE_OK;
254}
255
256static CURLcode
257mesalink_connect_step2(struct connectdata *conn, int sockindex)
258{
259 int ret = -1;
260 struct Curl_easy *data = conn->data;
261 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
262
263 conn->recv[sockindex] = mesalink_recv;
264 conn->send[sockindex] = mesalink_send;
265
266 ret = SSL_connect(BACKEND->handle);
267 if(ret != SSL_SUCCESS) {
268 char error_buffer[MESALINK_MAX_ERROR_SZ];
269 int detail = SSL_get_error(BACKEND->handle, ret);
270
271 if(SSL_ERROR_WANT_CONNECT == detail) {
272 connssl->connecting_state = ssl_connect_2_reading;
273 return CURLE_OK;
274 }
275 else {
276 failf(data,
277 "SSL_connect failed with error %d: %s",
278 detail,
279 ERR_error_string_n(detail, error_buffer, sizeof(error_buffer)));
280 ERR_print_errors_fp(stderr);
281 if(detail && SSL_CONN_CONFIG(verifypeer)) {
282 detail &= ~0xFF;
283 if(detail == TLS_ERROR_WEBPKI_ERRORS) {
284 failf(data, "Cert verify failed");
285 return CURLE_PEER_FAILED_VERIFICATION;
286 }
287 }
288 return CURLE_SSL_CONNECT_ERROR;
289 }
290 }
291
292 connssl->connecting_state = ssl_connect_3;
293 infof(data,
294 "SSL connection using %s / %s\n",
295 SSL_get_version(BACKEND->handle),
296 SSL_get_cipher_name(BACKEND->handle));
297
298 return CURLE_OK;
299}
300
301static CURLcode
302mesalink_connect_step3(struct connectdata *conn, int sockindex)
303{
304 CURLcode result = CURLE_OK;
305 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
306
307 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
308
309#ifdef MESALINK_HAVE_SESSION
310 if(SSL_SET_OPTION(primary.sessionid)) {
311 bool incache;
312 SSL_SESSION *our_ssl_sessionid;
313 void *old_ssl_sessionid = NULL;
314
315 our_ssl_sessionid = SSL_get_session(BACKEND->handle);
316
317 Curl_ssl_sessionid_lock(conn);
318 incache =
319 !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex));
320 if(incache) {
321 if(old_ssl_sessionid != our_ssl_sessionid) {
322 infof(data, "old SSL session ID is stale, removing\n");
323 Curl_ssl_delsessionid(conn, old_ssl_sessionid);
324 incache = FALSE;
325 }
326 }
327
328 if(!incache) {
329 result = Curl_ssl_addsessionid(
330 conn, our_ssl_sessionid, 0 /* unknown size */, sockindex);
331 if(result) {
332 Curl_ssl_sessionid_unlock(conn);
333 failf(data, "failed to store ssl session");
334 return result;
335 }
336 }
337 Curl_ssl_sessionid_unlock(conn);
338 }
339#endif /* MESALINK_HAVE_SESSION */
340
341 connssl->connecting_state = ssl_connect_done;
342
343 return result;
344}
345
346static ssize_t
347mesalink_send(struct connectdata *conn, int sockindex, const void *mem,
348 size_t len, CURLcode *curlcode)
349{
350 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
351 char error_buffer[MESALINK_MAX_ERROR_SZ];
352 int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
353 int rc = SSL_write(BACKEND->handle, mem, memlen);
354
355 if(rc < 0) {
356 int err = SSL_get_error(BACKEND->handle, rc);
357 switch(err) {
358 case SSL_ERROR_WANT_READ:
359 case SSL_ERROR_WANT_WRITE:
360 /* there's data pending, re-invoke SSL_write() */
361 *curlcode = CURLE_AGAIN;
362 return -1;
363 default:
364 failf(conn->data,
365 "SSL write: %s, errno %d",
366 ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
367 SOCKERRNO);
368 *curlcode = CURLE_SEND_ERROR;
369 return -1;
370 }
371 }
372 return rc;
373}
374
375static void
376Curl_mesalink_close(struct connectdata *conn, int sockindex)
377{
378 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
379
380 if(BACKEND->handle) {
381 (void)SSL_shutdown(BACKEND->handle);
382 SSL_free(BACKEND->handle);
383 BACKEND->handle = NULL;
384 }
385 if(BACKEND->ctx) {
386 SSL_CTX_free(BACKEND->ctx);
387 BACKEND->ctx = NULL;
388 }
389}
390
391static ssize_t
392mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize,
393 CURLcode *curlcode)
394{
395 struct ssl_connect_data *connssl = &conn->ssl[num];
396 char error_buffer[MESALINK_MAX_ERROR_SZ];
397 int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
398 int nread = SSL_read(BACKEND->handle, buf, buffsize);
399
400 if(nread <= 0) {
401 int err = SSL_get_error(BACKEND->handle, nread);
402
403 switch(err) {
404 case SSL_ERROR_ZERO_RETURN: /* no more data */
405 case IO_ERROR_CONNECTION_ABORTED:
406 break;
407 case SSL_ERROR_WANT_READ:
408 case SSL_ERROR_WANT_WRITE:
409 /* there's data pending, re-invoke SSL_read() */
410 *curlcode = CURLE_AGAIN;
411 return -1;
412 default:
413 failf(conn->data,
414 "SSL read: %s, errno %d",
415 ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
416 SOCKERRNO);
417 *curlcode = CURLE_RECV_ERROR;
418 return -1;
419 }
420 }
421 return nread;
422}
423
424static size_t
425Curl_mesalink_version(char *buffer, size_t size)
426{
427 return msnprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING);
428}
429
430static int
431Curl_mesalink_init(void)
432{
433 return (SSL_library_init() == SSL_SUCCESS);
434}
435
436/*
437 * This function is called to shut down the SSL layer but keep the
438 * socket open (CCC - Clear Command Channel)
439 */
440static int
441Curl_mesalink_shutdown(struct connectdata *conn, int sockindex)
442{
443 int retval = 0;
444 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
445
446 if(BACKEND->handle) {
447 SSL_free(BACKEND->handle);
448 BACKEND->handle = NULL;
449 }
450 return retval;
451}
452
453static CURLcode
454mesalink_connect_common(struct connectdata *conn, int sockindex,
455 bool nonblocking, bool *done)
456{
457 CURLcode result;
458 struct Curl_easy *data = conn->data;
459 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
460 curl_socket_t sockfd = conn->sock[sockindex];
461 time_t timeout_ms;
462 int what;
463
464 /* check if the connection has already been established */
465 if(ssl_connection_complete == connssl->state) {
466 *done = TRUE;
467 return CURLE_OK;
468 }
469
470 if(ssl_connect_1 == connssl->connecting_state) {
471 /* Find out how much more time we're allowed */
472 timeout_ms = Curl_timeleft(data, NULL, TRUE);
473
474 if(timeout_ms < 0) {
475 /* no need to continue if time already is up */
476 failf(data, "SSL connection timeout");
477 return CURLE_OPERATION_TIMEDOUT;
478 }
479
480 result = mesalink_connect_step1(conn, sockindex);
481 if(result)
482 return result;
483 }
484
485 while(ssl_connect_2 == connssl->connecting_state ||
486 ssl_connect_2_reading == connssl->connecting_state ||
487 ssl_connect_2_writing == connssl->connecting_state) {
488
489 /* check allowed time left */
490 timeout_ms = Curl_timeleft(data, NULL, TRUE);
491
492 if(timeout_ms < 0) {
493 /* no need to continue if time already is up */
494 failf(data, "SSL connection timeout");
495 return CURLE_OPERATION_TIMEDOUT;
496 }
497
498 /* if ssl is expecting something, check if it's available. */
499 if(connssl->connecting_state == ssl_connect_2_reading ||
500 connssl->connecting_state == ssl_connect_2_writing) {
501
502 curl_socket_t writefd =
503 ssl_connect_2_writing == connssl->connecting_state ? sockfd
504 : CURL_SOCKET_BAD;
505 curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state
506 ? sockfd
507 : CURL_SOCKET_BAD;
508
509 what = Curl_socket_check(
510 readfd, CURL_SOCKET_BAD, writefd, nonblocking ? 0 : timeout_ms);
511 if(what < 0) {
512 /* fatal error */
513 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
514 return CURLE_SSL_CONNECT_ERROR;
515 }
516 else if(0 == what) {
517 if(nonblocking) {
518 *done = FALSE;
519 return CURLE_OK;
520 }
521 else {
522 /* timeout */
523 failf(data, "SSL connection timeout");
524 return CURLE_OPERATION_TIMEDOUT;
525 }
526 }
527 /* socket is readable or writable */
528 }
529
530 /* Run transaction, and return to the caller if it failed or if
531 * this connection is part of a multi handle and this loop would
532 * execute again. This permits the owner of a multi handle to
533 * abort a connection attempt before step2 has completed while
534 * ensuring that a client using select() or epoll() will always
535 * have a valid fdset to wait on.
536 */
537 result = mesalink_connect_step2(conn, sockindex);
538
539 if(result ||
540 (nonblocking && (ssl_connect_2 == connssl->connecting_state ||
541 ssl_connect_2_reading == connssl->connecting_state ||
542 ssl_connect_2_writing == connssl->connecting_state))) {
543 return result;
544 }
545 } /* repeat step2 until all transactions are done. */
546
547 if(ssl_connect_3 == connssl->connecting_state) {
548 result = mesalink_connect_step3(conn, sockindex);
549 if(result)
550 return result;
551 }
552
553 if(ssl_connect_done == connssl->connecting_state) {
554 connssl->state = ssl_connection_complete;
555 conn->recv[sockindex] = mesalink_recv;
556 conn->send[sockindex] = mesalink_send;
557 *done = TRUE;
558 }
559 else
560 *done = FALSE;
561
562 /* Reset our connect state machine */
563 connssl->connecting_state = ssl_connect_1;
564
565 return CURLE_OK;
566}
567
568static CURLcode
569Curl_mesalink_connect_nonblocking(struct connectdata *conn, int sockindex,
570 bool *done)
571{
572 return mesalink_connect_common(conn, sockindex, TRUE, done);
573}
574
575static CURLcode
576Curl_mesalink_connect(struct connectdata *conn, int sockindex)
577{
578 CURLcode result;
579 bool done = FALSE;
580
581 result = mesalink_connect_common(conn, sockindex, FALSE, &done);
582 if(result)
583 return result;
584
585 DEBUGASSERT(done);
586
587 return CURLE_OK;
588}
589
590static void *
591Curl_mesalink_get_internals(struct ssl_connect_data *connssl,
592 CURLINFO info UNUSED_PARAM)
593{
594 (void)info;
595 return BACKEND->handle;
596}
597
598const struct Curl_ssl Curl_ssl_mesalink = {
599 { CURLSSLBACKEND_MESALINK, "MesaLink" }, /* info */
600
601 SSLSUPP_SSL_CTX,
602
603 sizeof(struct ssl_backend_data),
604
605 Curl_mesalink_init, /* init */
606 Curl_none_cleanup, /* cleanup */
607 Curl_mesalink_version, /* version */
608 Curl_none_check_cxn, /* check_cxn */
609 Curl_mesalink_shutdown, /* shutdown */
610 Curl_none_data_pending, /* data_pending */
611 Curl_none_random, /* random */
612 Curl_none_cert_status_request, /* cert_status_request */
613 Curl_mesalink_connect, /* connect */
614 Curl_mesalink_connect_nonblocking, /* connect_nonblocking */
615 Curl_mesalink_get_internals, /* get_internals */
616 Curl_mesalink_close, /* close_one */
617 Curl_none_close_all, /* close_all */
618 Curl_none_session_free, /* session_free */
619 Curl_none_set_engine, /* set_engine */
620 Curl_none_set_engine_default, /* set_engine_default */
621 Curl_none_engines_list, /* engines_list */
622 Curl_none_false_start, /* false_start */
623 Curl_none_md5sum, /* md5sum */
624 NULL /* sha256sum */
625};
626
627#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette