source: EcnlProtoTool/trunk/curl-7.57.0/lib/vtls/cyassl.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 31.7 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2017, 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 https://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#define WOLFSSL_OPTIONS_IGNORE_SYS
34/* CyaSSL's version.h, which should contain only the version, should come
35before all other CyaSSL includes and be immediately followed by build config
36aka options.h. https://curl.haxx.se/mail/lib-2015-04/0069.html */
37#include <cyassl/version.h>
38#if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008)
39#if defined(CYASSL_API) || defined(WOLFSSL_API)
40/* Safety measure. If either is defined some API include was already included
41and that's a problem since options.h hasn't been included yet. */
42#error "CyaSSL API was included before the CyaSSL build options."
43#endif
44#include <cyassl/options.h>
45#endif
46
47/* To determine what functions are available we rely on one or both of:
48 - the user's options.h generated by CyaSSL/wolfSSL
49 - the symbols detected by curl's configure
50 Since they are markedly different from one another, and one or the other may
51 not be available, we do some checking below to bring things in sync. */
52
53/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
54#ifndef HAVE_ALPN
55#ifdef HAVE_WOLFSSL_USEALPN
56#define HAVE_ALPN
57#endif
58#endif
59
60/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in
61 options.h, but is only seen in >= 3.6.6 since that's when they started
62 disabling SSLv3 by default. */
63#ifndef WOLFSSL_ALLOW_SSLV3
64#if (LIBCYASSL_VERSION_HEX < 0x03006006) || \
65 defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
66#define WOLFSSL_ALLOW_SSLV3
67#endif
68#endif
69
70/* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC
71 supported curve extension in options.h. Note ECC is enabled separately. */
72#ifndef HAVE_SUPPORTED_CURVES
73#if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \
74 defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE)
75#define HAVE_SUPPORTED_CURVES
76#endif
77#endif
78
79#ifdef HAVE_LIMITS_H
80#include <limits.h>
81#endif
82
83#include "urldata.h"
84#include "sendf.h"
85#include "inet_pton.h"
86#include "vtls.h"
87#include "parsedate.h"
88#include "connect.h" /* for the connect timeout */
89#include "select.h"
90#include "strcase.h"
91#include "x509asn1.h"
92#include "curl_printf.h"
93
94#include <cyassl/openssl/ssl.h>
95#include <cyassl/ssl.h>
96#ifdef HAVE_CYASSL_ERROR_SSL_H
97#include <cyassl/error-ssl.h>
98#else
99#include <cyassl/error.h>
100#endif
101#include <cyassl/ctaocrypt/random.h>
102#include <cyassl/ctaocrypt/sha256.h>
103
104#include "cyassl.h"
105
106/* The last #include files should be: */
107#include "curl_memory.h"
108#include "memdebug.h"
109
110#if LIBCYASSL_VERSION_HEX < 0x02007002 /* < 2.7.2 */
111#define CYASSL_MAX_ERROR_SZ 80
112#endif
113
114/* KEEP_PEER_CERT is a product of the presence of build time symbol
115 OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
116 in wolfSSL's settings.h, and the latter two are build time symbols in
117 options.h. */
118#ifndef KEEP_PEER_CERT
119#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \
120 defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
121 (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
122#define KEEP_PEER_CERT
123#endif
124#endif
125
126struct ssl_backend_data {
127 SSL_CTX* ctx;
128 SSL* handle;
129};
130
131#define BACKEND connssl->backend
132
133static Curl_recv cyassl_recv;
134static Curl_send cyassl_send;
135
136
137static int do_file_type(const char *type)
138{
139 if(!type || !type[0])
140 return SSL_FILETYPE_PEM;
141 if(strcasecompare(type, "PEM"))
142 return SSL_FILETYPE_PEM;
143 if(strcasecompare(type, "DER"))
144 return SSL_FILETYPE_ASN1;
145 return -1;
146}
147
148/*
149 * This function loads all the client/CA certificates and CRLs. Setup the TLS
150 * layer and do all necessary magic.
151 */
152static CURLcode
153cyassl_connect_step1(struct connectdata *conn,
154 int sockindex)
155{
156 char error_buffer[CYASSL_MAX_ERROR_SZ];
157 char *ciphers;
158 struct Curl_easy *data = conn->data;
159 struct ssl_connect_data* connssl = &conn->ssl[sockindex];
160 SSL_METHOD* req_method = NULL;
161 curl_socket_t sockfd = conn->sock[sockindex];
162#ifdef HAVE_SNI
163 bool sni = FALSE;
164#define use_sni(x) sni = (x)
165#else
166#define use_sni(x) Curl_nop_stmt
167#endif
168
169 if(connssl->state == ssl_connection_complete)
170 return CURLE_OK;
171
172 if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
173 failf(data, "CyaSSL does not support to set maximum SSL/TLS version");
174 return CURLE_SSL_CONNECT_ERROR;
175 }
176
177 /* check to see if we've been told to use an explicit SSL/TLS version */
178 switch(SSL_CONN_CONFIG(version)) {
179 case CURL_SSLVERSION_DEFAULT:
180 case CURL_SSLVERSION_TLSv1:
181#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
182 /* minimum protocol version is set later after the CTX object is created */
183 req_method = SSLv23_client_method();
184#else
185 infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
186 "TLS 1.0 is used exclusively\n");
187 req_method = TLSv1_client_method();
188#endif
189 use_sni(TRUE);
190 break;
191 case CURL_SSLVERSION_TLSv1_0:
192 req_method = TLSv1_client_method();
193 use_sni(TRUE);
194 break;
195 case CURL_SSLVERSION_TLSv1_1:
196 req_method = TLSv1_1_client_method();
197 use_sni(TRUE);
198 break;
199 case CURL_SSLVERSION_TLSv1_2:
200 req_method = TLSv1_2_client_method();
201 use_sni(TRUE);
202 break;
203 case CURL_SSLVERSION_TLSv1_3:
204 failf(data, "CyaSSL: TLS 1.3 is not yet supported");
205 return CURLE_SSL_CONNECT_ERROR;
206 case CURL_SSLVERSION_SSLv3:
207#ifdef WOLFSSL_ALLOW_SSLV3
208 req_method = SSLv3_client_method();
209 use_sni(FALSE);
210#else
211 failf(data, "CyaSSL does not support SSLv3");
212 return CURLE_NOT_BUILT_IN;
213#endif
214 break;
215 case CURL_SSLVERSION_SSLv2:
216 failf(data, "CyaSSL does not support SSLv2");
217 return CURLE_SSL_CONNECT_ERROR;
218 default:
219 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
220 return CURLE_SSL_CONNECT_ERROR;
221 }
222
223 if(!req_method) {
224 failf(data, "SSL: couldn't create a method!");
225 return CURLE_OUT_OF_MEMORY;
226 }
227
228 if(BACKEND->ctx)
229 SSL_CTX_free(BACKEND->ctx);
230 BACKEND->ctx = SSL_CTX_new(req_method);
231
232 if(!BACKEND->ctx) {
233 failf(data, "SSL: couldn't create a context!");
234 return CURLE_OUT_OF_MEMORY;
235 }
236
237 switch(SSL_CONN_CONFIG(version)) {
238 case CURL_SSLVERSION_DEFAULT:
239 case CURL_SSLVERSION_TLSv1:
240#if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
241 /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever
242 minimum version of TLS was built in and at least TLS 1.0. For later library
243 versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so
244 we have this short circuit evaluation to find the minimum supported TLS
245 version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion
246 because only the former will work before the user's CTX callback is called.
247 */
248 if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) &&
249 (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) &&
250 (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1)) {
251 failf(data, "SSL: couldn't set the minimum protocol version");
252 return CURLE_SSL_CONNECT_ERROR;
253 }
254#endif
255 break;
256 }
257
258 ciphers = SSL_CONN_CONFIG(cipher_list);
259 if(ciphers) {
260 if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
261 failf(data, "failed setting cipher list: %s", ciphers);
262 return CURLE_SSL_CIPHER;
263 }
264 infof(data, "Cipher selection: %s\n", ciphers);
265 }
266
267#ifndef NO_FILESYSTEM
268 /* load trusted cacert */
269 if(SSL_CONN_CONFIG(CAfile)) {
270 if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx,
271 SSL_CONN_CONFIG(CAfile),
272 SSL_CONN_CONFIG(CApath))) {
273 if(SSL_CONN_CONFIG(verifypeer)) {
274 /* Fail if we insist on successfully verifying the server. */
275 failf(data, "error setting certificate verify locations:\n"
276 " CAfile: %s\n CApath: %s",
277 SSL_CONN_CONFIG(CAfile)?
278 SSL_CONN_CONFIG(CAfile): "none",
279 SSL_CONN_CONFIG(CApath)?
280 SSL_CONN_CONFIG(CApath) : "none");
281 return CURLE_SSL_CACERT_BADFILE;
282 }
283 else {
284 /* Just continue with a warning if no strict certificate
285 verification is required. */
286 infof(data, "error setting certificate verify locations,"
287 " continuing anyway:\n");
288 }
289 }
290 else {
291 /* Everything is fine. */
292 infof(data, "successfully set certificate verify locations:\n");
293 }
294 infof(data,
295 " CAfile: %s\n"
296 " CApath: %s\n",
297 SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
298 "none",
299 SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath):
300 "none");
301 }
302
303 /* Load the client certificate, and private key */
304 if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
305 int file_type = do_file_type(SSL_SET_OPTION(cert_type));
306
307 if(SSL_CTX_use_certificate_file(BACKEND->ctx, SSL_SET_OPTION(cert),
308 file_type) != 1) {
309 failf(data, "unable to use client certificate (no key or wrong pass"
310 " phrase?)");
311 return CURLE_SSL_CONNECT_ERROR;
312 }
313
314 file_type = do_file_type(SSL_SET_OPTION(key_type));
315 if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key),
316 file_type) != 1) {
317 failf(data, "unable to set private key");
318 return CURLE_SSL_CONNECT_ERROR;
319 }
320 }
321#endif /* !NO_FILESYSTEM */
322
323 /* SSL always tries to verify the peer, this only says whether it should
324 * fail to connect if the verification fails, or if it should continue
325 * anyway. In the latter case the result of the verification is checked with
326 * SSL_get_verify_result() below. */
327 SSL_CTX_set_verify(BACKEND->ctx,
328 SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
329 SSL_VERIFY_NONE,
330 NULL);
331
332#ifdef HAVE_SNI
333 if(sni) {
334 struct in_addr addr4;
335#ifdef ENABLE_IPV6
336 struct in6_addr addr6;
337#endif
338 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
339 conn->host.name;
340 size_t hostname_len = strlen(hostname);
341 if((hostname_len < USHRT_MAX) &&
342 (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
343#ifdef ENABLE_IPV6
344 (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
345#endif
346 (CyaSSL_CTX_UseSNI(BACKEND->ctx, CYASSL_SNI_HOST_NAME, hostname,
347 (unsigned short)hostname_len) != 1)) {
348 infof(data, "WARNING: failed to configure server name indication (SNI) "
349 "TLS extension\n");
350 }
351 }
352#endif
353
354#ifdef HAVE_SUPPORTED_CURVES
355 /* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically:
356 https://github.com/wolfSSL/wolfssl/issues/366
357 The supported curves below are those also supported by OpenSSL 1.0.2 and
358 in the same order. */
359 CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x17); /* secp256r1 */
360 CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x19); /* secp521r1 */
361 CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x18); /* secp384r1 */
362#endif
363
364 /* give application a chance to interfere with SSL set up. */
365 if(data->set.ssl.fsslctx) {
366 CURLcode result = CURLE_OK;
367 result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx,
368 data->set.ssl.fsslctxp);
369 if(result) {
370 failf(data, "error signaled by ssl ctx callback");
371 return result;
372 }
373 }
374#ifdef NO_FILESYSTEM
375 else if(SSL_CONN_CONFIG(verifypeer)) {
376 failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built"
377 " with \"no filesystem\". Either disable peer verification"
378 " (insecure) or if you are building an application with libcurl you"
379 " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
380 return CURLE_SSL_CONNECT_ERROR;
381 }
382#endif
383
384 /* Let's make an SSL structure */
385 if(BACKEND->handle)
386 SSL_free(BACKEND->handle);
387 BACKEND->handle = SSL_new(BACKEND->ctx);
388 if(!BACKEND->handle) {
389 failf(data, "SSL: couldn't create a context (handle)!");
390 return CURLE_OUT_OF_MEMORY;
391 }
392
393#ifdef HAVE_ALPN
394 if(conn->bits.tls_enable_alpn) {
395 char protocols[128];
396 *protocols = '\0';
397
398 /* wolfSSL's ALPN protocol name list format is a comma separated string of
399 protocols in descending order of preference, eg: "h2,http/1.1" */
400
401#ifdef USE_NGHTTP2
402 if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
403 strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
404 infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
405 }
406#endif
407
408 strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
409 infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
410
411 if(wolfSSL_UseALPN(BACKEND->handle, protocols,
412 (unsigned)strlen(protocols),
413 WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
414 failf(data, "SSL: failed setting ALPN protocols");
415 return CURLE_SSL_CONNECT_ERROR;
416 }
417 }
418#endif /* HAVE_ALPN */
419
420 /* Check if there's a cached ID we can/should use here! */
421 if(SSL_SET_OPTION(primary.sessionid)) {
422 void *ssl_sessionid = NULL;
423
424 Curl_ssl_sessionid_lock(conn);
425 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
426 /* we got a session id, use it! */
427 if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
428 Curl_ssl_sessionid_unlock(conn);
429 failf(data, "SSL: SSL_set_session failed: %s",
430 ERR_error_string(SSL_get_error(BACKEND->handle, 0),
431 error_buffer));
432 return CURLE_SSL_CONNECT_ERROR;
433 }
434 /* Informational message */
435 infof(data, "SSL re-using session ID\n");
436 }
437 Curl_ssl_sessionid_unlock(conn);
438 }
439
440 /* pass the raw socket into the SSL layer */
441 if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) {
442 failf(data, "SSL: SSL_set_fd failed");
443 return CURLE_SSL_CONNECT_ERROR;
444 }
445
446 connssl->connecting_state = ssl_connect_2;
447 return CURLE_OK;
448}
449
450
451static CURLcode
452cyassl_connect_step2(struct connectdata *conn,
453 int sockindex)
454{
455 int ret = -1;
456 struct Curl_easy *data = conn->data;
457 struct ssl_connect_data* connssl = &conn->ssl[sockindex];
458 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
459 conn->host.name;
460 const char * const dispname = SSL_IS_PROXY() ?
461 conn->http_proxy.host.dispname : conn->host.dispname;
462 const char * const pinnedpubkey = SSL_IS_PROXY() ?
463 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
464 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
465
466 conn->recv[sockindex] = cyassl_recv;
467 conn->send[sockindex] = cyassl_send;
468
469 /* Enable RFC2818 checks */
470 if(SSL_CONN_CONFIG(verifyhost)) {
471 ret = CyaSSL_check_domain_name(BACKEND->handle, hostname);
472 if(ret == SSL_FAILURE)
473 return CURLE_OUT_OF_MEMORY;
474 }
475
476 ret = SSL_connect(BACKEND->handle);
477 if(ret != 1) {
478 char error_buffer[CYASSL_MAX_ERROR_SZ];
479 int detail = SSL_get_error(BACKEND->handle, ret);
480
481 if(SSL_ERROR_WANT_READ == detail) {
482 connssl->connecting_state = ssl_connect_2_reading;
483 return CURLE_OK;
484 }
485 else if(SSL_ERROR_WANT_WRITE == detail) {
486 connssl->connecting_state = ssl_connect_2_writing;
487 return CURLE_OK;
488 }
489 /* There is no easy way to override only the CN matching.
490 * This will enable the override of both mismatching SubjectAltNames
491 * as also mismatching CN fields */
492 else if(DOMAIN_NAME_MISMATCH == detail) {
493#if 1
494 failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
495 dispname);
496 return CURLE_PEER_FAILED_VERIFICATION;
497#else
498 /* When the CyaSSL_check_domain_name() is used and you desire to continue
499 * on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost == 0',
500 * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only
501 * way to do this is currently to switch the CyaSSL_check_domain_name()
502 * in and out based on the 'conn->ssl_config.verifyhost' value. */
503 if(SSL_CONN_CONFIG(verifyhost)) {
504 failf(data,
505 "\tsubject alt name(s) or common name do not match \"%s\"\n",
506 dispname);
507 return CURLE_PEER_FAILED_VERIFICATION;
508 }
509 else {
510 infof(data,
511 "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
512 dispname);
513 return CURLE_OK;
514 }
515#endif
516 }
517#if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
518 else if(ASN_NO_SIGNER_E == detail) {
519 if(SSL_CONN_CONFIG(verifypeer)) {
520 failf(data, "\tCA signer not available for verification\n");
521 return CURLE_SSL_CACERT_BADFILE;
522 }
523 else {
524 /* Just continue with a warning if no strict certificate
525 verification is required. */
526 infof(data, "CA signer not available for verification, "
527 "continuing anyway\n");
528 }
529 }
530#endif
531 else {
532 failf(data, "SSL_connect failed with error %d: %s", detail,
533 ERR_error_string(detail, error_buffer));
534 return CURLE_SSL_CONNECT_ERROR;
535 }
536 }
537
538 if(pinnedpubkey) {
539#ifdef KEEP_PEER_CERT
540 X509 *x509;
541 const char *x509_der;
542 int x509_der_len;
543 curl_X509certificate x509_parsed;
544 curl_asn1Element *pubkey;
545 CURLcode result;
546
547 x509 = SSL_get_peer_certificate(BACKEND->handle);
548 if(!x509) {
549 failf(data, "SSL: failed retrieving server certificate");
550 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
551 }
552
553 x509_der = (const char *)CyaSSL_X509_get_der(x509, &x509_der_len);
554 if(!x509_der) {
555 failf(data, "SSL: failed retrieving ASN.1 server certificate");
556 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
557 }
558
559 memset(&x509_parsed, 0, sizeof x509_parsed);
560 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
561 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
562
563 pubkey = &x509_parsed.subjectPublicKeyInfo;
564 if(!pubkey->header || pubkey->end <= pubkey->header) {
565 failf(data, "SSL: failed retrieving public key from server certificate");
566 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
567 }
568
569 result = Curl_pin_peer_pubkey(data,
570 pinnedpubkey,
571 (const unsigned char *)pubkey->header,
572 (size_t)(pubkey->end - pubkey->header));
573 if(result) {
574 failf(data, "SSL: public key does not match pinned public key!");
575 return result;
576 }
577#else
578 failf(data, "Library lacks pinning support built-in");
579 return CURLE_NOT_BUILT_IN;
580#endif
581 }
582
583#ifdef HAVE_ALPN
584 if(conn->bits.tls_enable_alpn) {
585 int rc;
586 char *protocol = NULL;
587 unsigned short protocol_len = 0;
588
589 rc = wolfSSL_ALPN_GetProtocol(BACKEND->handle, &protocol, &protocol_len);
590
591 if(rc == SSL_SUCCESS) {
592 infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
593 protocol);
594
595 if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
596 !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
597 conn->negnpn = CURL_HTTP_VERSION_1_1;
598#ifdef USE_NGHTTP2
599 else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
600 protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
601 !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
602 NGHTTP2_PROTO_VERSION_ID_LEN))
603 conn->negnpn = CURL_HTTP_VERSION_2;
604#endif
605 else
606 infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
607 protocol);
608 }
609 else if(rc == SSL_ALPN_NOT_FOUND)
610 infof(data, "ALPN, server did not agree to a protocol\n");
611 else {
612 failf(data, "ALPN, failure getting protocol, error %d", rc);
613 return CURLE_SSL_CONNECT_ERROR;
614 }
615 }
616#endif /* HAVE_ALPN */
617
618 connssl->connecting_state = ssl_connect_3;
619#if (LIBCYASSL_VERSION_HEX >= 0x03009010)
620 infof(data, "SSL connection using %s / %s\n",
621 wolfSSL_get_version(BACKEND->handle),
622 wolfSSL_get_cipher_name(BACKEND->handle));
623#else
624 infof(data, "SSL connected\n");
625#endif
626
627 return CURLE_OK;
628}
629
630
631static CURLcode
632cyassl_connect_step3(struct connectdata *conn,
633 int sockindex)
634{
635 CURLcode result = CURLE_OK;
636 struct Curl_easy *data = conn->data;
637 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
638
639 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
640
641 if(SSL_SET_OPTION(primary.sessionid)) {
642 bool incache;
643 SSL_SESSION *our_ssl_sessionid;
644 void *old_ssl_sessionid = NULL;
645
646 our_ssl_sessionid = SSL_get_session(BACKEND->handle);
647
648 Curl_ssl_sessionid_lock(conn);
649 incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
650 sockindex));
651 if(incache) {
652 if(old_ssl_sessionid != our_ssl_sessionid) {
653 infof(data, "old SSL session ID is stale, removing\n");
654 Curl_ssl_delsessionid(conn, old_ssl_sessionid);
655 incache = FALSE;
656 }
657 }
658
659 if(!incache) {
660 result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
661 0 /* unknown size */, sockindex);
662 if(result) {
663 Curl_ssl_sessionid_unlock(conn);
664 failf(data, "failed to store ssl session");
665 return result;
666 }
667 }
668 Curl_ssl_sessionid_unlock(conn);
669 }
670
671 connssl->connecting_state = ssl_connect_done;
672
673 return result;
674}
675
676
677static ssize_t cyassl_send(struct connectdata *conn,
678 int sockindex,
679 const void *mem,
680 size_t len,
681 CURLcode *curlcode)
682{
683 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
684 char error_buffer[CYASSL_MAX_ERROR_SZ];
685 int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
686 int rc = SSL_write(BACKEND->handle, mem, memlen);
687
688 if(rc < 0) {
689 int err = SSL_get_error(BACKEND->handle, rc);
690
691 switch(err) {
692 case SSL_ERROR_WANT_READ:
693 case SSL_ERROR_WANT_WRITE:
694 /* there's data pending, re-invoke SSL_write() */
695 *curlcode = CURLE_AGAIN;
696 return -1;
697 default:
698 failf(conn->data, "SSL write: %s, errno %d",
699 ERR_error_string(err, error_buffer),
700 SOCKERRNO);
701 *curlcode = CURLE_SEND_ERROR;
702 return -1;
703 }
704 }
705 return rc;
706}
707
708static void Curl_cyassl_close(struct connectdata *conn, int sockindex)
709{
710 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
711
712 if(BACKEND->handle) {
713 (void)SSL_shutdown(BACKEND->handle);
714 SSL_free(BACKEND->handle);
715 BACKEND->handle = NULL;
716 }
717 if(BACKEND->ctx) {
718 SSL_CTX_free(BACKEND->ctx);
719 BACKEND->ctx = NULL;
720 }
721}
722
723static ssize_t cyassl_recv(struct connectdata *conn,
724 int num,
725 char *buf,
726 size_t buffersize,
727 CURLcode *curlcode)
728{
729 struct ssl_connect_data *connssl = &conn->ssl[num];
730 char error_buffer[CYASSL_MAX_ERROR_SZ];
731 int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
732 int nread = SSL_read(BACKEND->handle, buf, buffsize);
733
734 if(nread < 0) {
735 int err = SSL_get_error(BACKEND->handle, nread);
736
737 switch(err) {
738 case SSL_ERROR_ZERO_RETURN: /* no more data */
739 break;
740 case SSL_ERROR_WANT_READ:
741 case SSL_ERROR_WANT_WRITE:
742 /* there's data pending, re-invoke SSL_read() */
743 *curlcode = CURLE_AGAIN;
744 return -1;
745 default:
746 failf(conn->data, "SSL read: %s, errno %d",
747 ERR_error_string(err, error_buffer),
748 SOCKERRNO);
749 *curlcode = CURLE_RECV_ERROR;
750 return -1;
751 }
752 }
753 return nread;
754}
755
756
757static void Curl_cyassl_session_free(void *ptr)
758{
759 (void)ptr;
760 /* CyaSSL reuses sessions on own, no free */
761}
762
763
764static size_t Curl_cyassl_version(char *buffer, size_t size)
765{
766#if LIBCYASSL_VERSION_HEX >= 0x03006000
767 return snprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
768#elif defined(WOLFSSL_VERSION)
769 return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
770#elif defined(CYASSL_VERSION)
771 return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION);
772#else
773 return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8");
774#endif
775}
776
777
778static int Curl_cyassl_init(void)
779{
780 return (CyaSSL_Init() == SSL_SUCCESS);
781}
782
783
784static bool Curl_cyassl_data_pending(const struct connectdata* conn,
785 int connindex)
786{
787 const struct ssl_connect_data *connssl = &conn->ssl[connindex];
788 if(BACKEND->handle) /* SSL is in use */
789 return (0 != SSL_pending(BACKEND->handle)) ? TRUE : FALSE;
790 else
791 return FALSE;
792}
793
794
795/*
796 * This function is called to shut down the SSL layer but keep the
797 * socket open (CCC - Clear Command Channel)
798 */
799static int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
800{
801 int retval = 0;
802 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
803
804 if(BACKEND->handle) {
805 SSL_free(BACKEND->handle);
806 BACKEND->handle = NULL;
807 }
808 return retval;
809}
810
811
812static CURLcode
813cyassl_connect_common(struct connectdata *conn,
814 int sockindex,
815 bool nonblocking,
816 bool *done)
817{
818 CURLcode result;
819 struct Curl_easy *data = conn->data;
820 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
821 curl_socket_t sockfd = conn->sock[sockindex];
822 time_t timeout_ms;
823 int what;
824
825 /* check if the connection has already been established */
826 if(ssl_connection_complete == connssl->state) {
827 *done = TRUE;
828 return CURLE_OK;
829 }
830
831 if(ssl_connect_1 == connssl->connecting_state) {
832 /* Find out how much more time we're allowed */
833 timeout_ms = Curl_timeleft(data, NULL, TRUE);
834
835 if(timeout_ms < 0) {
836 /* no need to continue if time already is up */
837 failf(data, "SSL connection timeout");
838 return CURLE_OPERATION_TIMEDOUT;
839 }
840
841 result = cyassl_connect_step1(conn, sockindex);
842 if(result)
843 return result;
844 }
845
846 while(ssl_connect_2 == connssl->connecting_state ||
847 ssl_connect_2_reading == connssl->connecting_state ||
848 ssl_connect_2_writing == connssl->connecting_state) {
849
850 /* check allowed time left */
851 timeout_ms = Curl_timeleft(data, NULL, TRUE);
852
853 if(timeout_ms < 0) {
854 /* no need to continue if time already is up */
855 failf(data, "SSL connection timeout");
856 return CURLE_OPERATION_TIMEDOUT;
857 }
858
859 /* if ssl is expecting something, check if it's available. */
860 if(connssl->connecting_state == ssl_connect_2_reading
861 || connssl->connecting_state == ssl_connect_2_writing) {
862
863 curl_socket_t writefd = ssl_connect_2_writing ==
864 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
865 curl_socket_t readfd = ssl_connect_2_reading ==
866 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
867
868 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
869 nonblocking?0:timeout_ms);
870 if(what < 0) {
871 /* fatal error */
872 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
873 return CURLE_SSL_CONNECT_ERROR;
874 }
875 else if(0 == what) {
876 if(nonblocking) {
877 *done = FALSE;
878 return CURLE_OK;
879 }
880 else {
881 /* timeout */
882 failf(data, "SSL connection timeout");
883 return CURLE_OPERATION_TIMEDOUT;
884 }
885 }
886 /* socket is readable or writable */
887 }
888
889 /* Run transaction, and return to the caller if it failed or if
890 * this connection is part of a multi handle and this loop would
891 * execute again. This permits the owner of a multi handle to
892 * abort a connection attempt before step2 has completed while
893 * ensuring that a client using select() or epoll() will always
894 * have a valid fdset to wait on.
895 */
896 result = cyassl_connect_step2(conn, sockindex);
897 if(result || (nonblocking &&
898 (ssl_connect_2 == connssl->connecting_state ||
899 ssl_connect_2_reading == connssl->connecting_state ||
900 ssl_connect_2_writing == connssl->connecting_state)))
901 return result;
902 } /* repeat step2 until all transactions are done. */
903
904 if(ssl_connect_3 == connssl->connecting_state) {
905 result = cyassl_connect_step3(conn, sockindex);
906 if(result)
907 return result;
908 }
909
910 if(ssl_connect_done == connssl->connecting_state) {
911 connssl->state = ssl_connection_complete;
912 conn->recv[sockindex] = cyassl_recv;
913 conn->send[sockindex] = cyassl_send;
914 *done = TRUE;
915 }
916 else
917 *done = FALSE;
918
919 /* Reset our connect state machine */
920 connssl->connecting_state = ssl_connect_1;
921
922 return CURLE_OK;
923}
924
925
926static CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn,
927 int sockindex, bool *done)
928{
929 return cyassl_connect_common(conn, sockindex, TRUE, done);
930}
931
932
933static CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex)
934{
935 CURLcode result;
936 bool done = FALSE;
937
938 result = cyassl_connect_common(conn, sockindex, FALSE, &done);
939 if(result)
940 return result;
941
942 DEBUGASSERT(done);
943
944 return CURLE_OK;
945}
946
947static CURLcode Curl_cyassl_random(struct Curl_easy *data,
948 unsigned char *entropy, size_t length)
949{
950 RNG rng;
951 (void)data;
952 if(InitRng(&rng))
953 return CURLE_FAILED_INIT;
954 if(length > UINT_MAX)
955 return CURLE_FAILED_INIT;
956 if(RNG_GenerateBlock(&rng, entropy, (unsigned)length))
957 return CURLE_FAILED_INIT;
958 return CURLE_OK;
959}
960
961static void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
962 size_t tmplen,
963 unsigned char *sha256sum /* output */,
964 size_t unused)
965{
966 Sha256 SHA256pw;
967 (void)unused;
968 InitSha256(&SHA256pw);
969 Sha256Update(&SHA256pw, tmp, (word32)tmplen);
970 Sha256Final(&SHA256pw, sha256sum);
971}
972
973static void *Curl_cyassl_get_internals(struct ssl_connect_data *connssl,
974 CURLINFO info UNUSED_PARAM)
975{
976 (void)info;
977 return BACKEND->handle;
978}
979
980const struct Curl_ssl Curl_ssl_cyassl = {
981 { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
982
983 0, /* have_ca_path */
984 0, /* have_certinfo */
985#ifdef KEEP_PEER_CERT
986 1, /* have_pinnedpubkey */
987#else
988 0, /* have_pinnedpubkey */
989#endif
990 1, /* have_ssl_ctx */
991 0, /* support_https_proxy */
992
993 sizeof(struct ssl_backend_data),
994
995 Curl_cyassl_init, /* init */
996 Curl_none_cleanup, /* cleanup */
997 Curl_cyassl_version, /* version */
998 Curl_none_check_cxn, /* check_cxn */
999 Curl_cyassl_shutdown, /* shutdown */
1000 Curl_cyassl_data_pending, /* data_pending */
1001 Curl_cyassl_random, /* random */
1002 Curl_none_cert_status_request, /* cert_status_request */
1003 Curl_cyassl_connect, /* connect */
1004 Curl_cyassl_connect_nonblocking, /* connect_nonblocking */
1005 Curl_cyassl_get_internals, /* get_internals */
1006 Curl_cyassl_close, /* close_one */
1007 Curl_none_close_all, /* close_all */
1008 Curl_cyassl_session_free, /* session_free */
1009 Curl_none_set_engine, /* set_engine */
1010 Curl_none_set_engine_default, /* set_engine_default */
1011 Curl_none_engines_list, /* engines_list */
1012 Curl_none_false_start, /* false_start */
1013 Curl_none_md5sum, /* md5sum */
1014 Curl_cyassl_sha256sum /* sha256sum */
1015};
1016
1017#endif
Note: See TracBrowser for help on using the repository browser.