File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vtls / wolfssl.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>