Annotation of embedaddon/curl/lib/vtls/wolfssl.c, revision 1.1.1.1

1.1       misho       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>