File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vtls / schannel.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) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
    9:  * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
   10:  * Copyright (C) 2012 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
   11:  *
   12:  * This software is licensed as described in the file COPYING, which
   13:  * you should have received as part of this distribution. The terms
   14:  * are also available at https://curl.haxx.se/docs/copyright.html.
   15:  *
   16:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
   17:  * copies of the Software, and permit persons to whom the Software is
   18:  * furnished to do so, under the terms of the COPYING file.
   19:  *
   20:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
   21:  * KIND, either express or implied.
   22:  *
   23:  ***************************************************************************/
   24: 
   25: /*
   26:  * Source file for all Schannel-specific code for the TLS/SSL layer. No code
   27:  * but vtls.c should ever call or use these functions.
   28:  */
   29: 
   30: #include "curl_setup.h"
   31: 
   32: #ifdef USE_SCHANNEL
   33: 
   34: #define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
   35: 
   36: #ifndef USE_WINDOWS_SSPI
   37: #  error "Can't compile SCHANNEL support without SSPI."
   38: #endif
   39: 
   40: #include "schannel.h"
   41: #include "vtls.h"
   42: #include "sendf.h"
   43: #include "connect.h" /* for the connect timeout */
   44: #include "strerror.h"
   45: #include "select.h" /* for the socket readyness */
   46: #include "inet_pton.h" /* for IP addr SNI check */
   47: #include "curl_multibyte.h"
   48: #include "warnless.h"
   49: #include "x509asn1.h"
   50: #include "curl_printf.h"
   51: #include "multiif.h"
   52: #include "system_win32.h"
   53: 
   54:  /* The last #include file should be: */
   55: #include "curl_memory.h"
   56: #include "memdebug.h"
   57: 
   58: /* ALPN requires version 8.1 of the Windows SDK, which was
   59:    shipped with Visual Studio 2013, aka _MSC_VER 1800:
   60: 
   61:    https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
   62: */
   63: #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
   64: #  define HAS_ALPN 1
   65: #endif
   66: 
   67: #ifndef UNISP_NAME_A
   68: #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
   69: #endif
   70: 
   71: #ifndef UNISP_NAME_W
   72: #define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
   73: #endif
   74: 
   75: #ifndef UNISP_NAME
   76: #ifdef UNICODE
   77: #define UNISP_NAME  UNISP_NAME_W
   78: #else
   79: #define UNISP_NAME  UNISP_NAME_A
   80: #endif
   81: #endif
   82: 
   83: #if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX)
   84: #define HAS_CLIENT_CERT_PATH
   85: #endif
   86: 
   87: #ifdef HAS_CLIENT_CERT_PATH
   88: #ifdef UNICODE
   89: #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
   90: #else
   91: #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
   92: #endif
   93: #endif
   94: 
   95: #ifndef SP_PROT_SSL2_CLIENT
   96: #define SP_PROT_SSL2_CLIENT             0x00000008
   97: #endif
   98: 
   99: #ifndef SP_PROT_SSL3_CLIENT
  100: #define SP_PROT_SSL3_CLIENT             0x00000008
  101: #endif
  102: 
  103: #ifndef SP_PROT_TLS1_CLIENT
  104: #define SP_PROT_TLS1_CLIENT             0x00000080
  105: #endif
  106: 
  107: #ifndef SP_PROT_TLS1_0_CLIENT
  108: #define SP_PROT_TLS1_0_CLIENT           SP_PROT_TLS1_CLIENT
  109: #endif
  110: 
  111: #ifndef SP_PROT_TLS1_1_CLIENT
  112: #define SP_PROT_TLS1_1_CLIENT           0x00000200
  113: #endif
  114: 
  115: #ifndef SP_PROT_TLS1_2_CLIENT
  116: #define SP_PROT_TLS1_2_CLIENT           0x00000800
  117: #endif
  118: 
  119: #ifndef SECBUFFER_ALERT
  120: #define SECBUFFER_ALERT                 17
  121: #endif
  122: 
  123: /* Both schannel buffer sizes must be > 0 */
  124: #define CURL_SCHANNEL_BUFFER_INIT_SIZE   4096
  125: #define CURL_SCHANNEL_BUFFER_FREE_SIZE   1024
  126: 
  127: #define CERT_THUMBPRINT_STR_LEN 40
  128: #define CERT_THUMBPRINT_DATA_LEN 20
  129: 
  130: /* Uncomment to force verbose output
  131:  * #define infof(x, y, ...) printf(y, __VA_ARGS__)
  132:  * #define failf(x, y, ...) printf(y, __VA_ARGS__)
  133:  */
  134: 
  135: #ifndef CALG_SHA_256
  136: #  define CALG_SHA_256 0x0000800c
  137: #endif
  138: 
  139: #define BACKEND connssl->backend
  140: 
  141: static Curl_recv schannel_recv;
  142: static Curl_send schannel_send;
  143: 
  144: static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
  145:                                     const char *pinnedpubkey);
  146: 
  147: static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
  148:                           void *BufDataPtr, unsigned long BufByteSize)
  149: {
  150:   buffer->cbBuffer = BufByteSize;
  151:   buffer->BufferType = BufType;
  152:   buffer->pvBuffer = BufDataPtr;
  153: }
  154: 
  155: static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
  156:                               unsigned long NumArrElem)
  157: {
  158:   desc->ulVersion = SECBUFFER_VERSION;
  159:   desc->pBuffers = BufArr;
  160:   desc->cBuffers = NumArrElem;
  161: }
  162: 
  163: static CURLcode
  164: set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
  165: {
  166:   struct Curl_easy *data = conn->data;
  167:   long ssl_version = SSL_CONN_CONFIG(version);
  168:   long ssl_version_max = SSL_CONN_CONFIG(version_max);
  169:   long i = ssl_version;
  170: 
  171:   switch(ssl_version_max) {
  172:     case CURL_SSLVERSION_MAX_NONE:
  173:     case CURL_SSLVERSION_MAX_DEFAULT:
  174:       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
  175:       break;
  176:   }
  177:   for(; i <= (ssl_version_max >> 16); ++i) {
  178:     switch(i) {
  179:       case CURL_SSLVERSION_TLSv1_0:
  180:         schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
  181:         break;
  182:       case CURL_SSLVERSION_TLSv1_1:
  183:         schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
  184:         break;
  185:       case CURL_SSLVERSION_TLSv1_2:
  186:         schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
  187:         break;
  188:       case CURL_SSLVERSION_TLSv1_3:
  189:         failf(data, "schannel: TLS 1.3 is not yet supported");
  190:         return CURLE_SSL_CONNECT_ERROR;
  191:     }
  192:   }
  193:   return CURLE_OK;
  194: }
  195: 
  196: /*longest is 26, buffer is slightly bigger*/
  197: #define LONGEST_ALG_ID 32
  198: #define CIPHEROPTION(X) \
  199: if(strcmp(#X, tmp) == 0) \
  200:   return X
  201: 
  202: static int
  203: get_alg_id_by_name(char *name)
  204: {
  205:   char tmp[LONGEST_ALG_ID] = { 0 };
  206:   char *nameEnd = strchr(name, ':');
  207:   size_t n = nameEnd ? min((size_t)(nameEnd - name), LONGEST_ALG_ID - 1) : \
  208:     min(strlen(name), LONGEST_ALG_ID - 1);
  209:   strncpy(tmp, name, n);
  210:   tmp[n] = 0;
  211:   CIPHEROPTION(CALG_MD2);
  212:   CIPHEROPTION(CALG_MD4);
  213:   CIPHEROPTION(CALG_MD5);
  214:   CIPHEROPTION(CALG_SHA);
  215:   CIPHEROPTION(CALG_SHA1);
  216:   CIPHEROPTION(CALG_MAC);
  217:   CIPHEROPTION(CALG_RSA_SIGN);
  218:   CIPHEROPTION(CALG_DSS_SIGN);
  219: /*ifdefs for the options that are defined conditionally in wincrypt.h*/
  220: #ifdef CALG_NO_SIGN
  221:   CIPHEROPTION(CALG_NO_SIGN);
  222: #endif
  223:   CIPHEROPTION(CALG_RSA_KEYX);
  224:   CIPHEROPTION(CALG_DES);
  225: #ifdef CALG_3DES_112
  226:   CIPHEROPTION(CALG_3DES_112);
  227: #endif
  228:   CIPHEROPTION(CALG_3DES);
  229:   CIPHEROPTION(CALG_DESX);
  230:   CIPHEROPTION(CALG_RC2);
  231:   CIPHEROPTION(CALG_RC4);
  232:   CIPHEROPTION(CALG_SEAL);
  233: #ifdef CALG_DH_SF
  234:   CIPHEROPTION(CALG_DH_SF);
  235: #endif
  236:   CIPHEROPTION(CALG_DH_EPHEM);
  237: #ifdef CALG_AGREEDKEY_ANY
  238:   CIPHEROPTION(CALG_AGREEDKEY_ANY);
  239: #endif
  240: #ifdef CALG_HUGHES_MD5
  241:   CIPHEROPTION(CALG_HUGHES_MD5);
  242: #endif
  243:   CIPHEROPTION(CALG_SKIPJACK);
  244: #ifdef CALG_TEK
  245:   CIPHEROPTION(CALG_TEK);
  246: #endif
  247:   CIPHEROPTION(CALG_CYLINK_MEK);
  248:   CIPHEROPTION(CALG_SSL3_SHAMD5);
  249: #ifdef CALG_SSL3_MASTER
  250:   CIPHEROPTION(CALG_SSL3_MASTER);
  251: #endif
  252: #ifdef CALG_SCHANNEL_MASTER_HASH
  253:   CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH);
  254: #endif
  255: #ifdef CALG_SCHANNEL_MAC_KEY
  256:   CIPHEROPTION(CALG_SCHANNEL_MAC_KEY);
  257: #endif
  258: #ifdef CALG_SCHANNEL_ENC_KEY
  259:   CIPHEROPTION(CALG_SCHANNEL_ENC_KEY);
  260: #endif
  261: #ifdef CALG_PCT1_MASTER
  262:   CIPHEROPTION(CALG_PCT1_MASTER);
  263: #endif
  264: #ifdef CALG_SSL2_MASTER
  265:   CIPHEROPTION(CALG_SSL2_MASTER);
  266: #endif
  267: #ifdef CALG_TLS1_MASTER
  268:   CIPHEROPTION(CALG_TLS1_MASTER);
  269: #endif
  270: #ifdef CALG_RC5
  271:   CIPHEROPTION(CALG_RC5);
  272: #endif
  273: #ifdef CALG_HMAC
  274:   CIPHEROPTION(CALG_HMAC);
  275: #endif
  276: #if !defined(__W32API_MAJOR_VERSION) || \
  277:     !defined(__W32API_MINOR_VERSION) || \
  278:     defined(__MINGW64_VERSION_MAJOR) || \
  279:     (__W32API_MAJOR_VERSION > 5)     || \
  280:     ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0))
  281:   /* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0,
  282:      see https://osdn.net/projects/mingw/ticket/38391 */
  283:   CIPHEROPTION(CALG_TLS1PRF);
  284: #endif
  285: #ifdef CALG_HASH_REPLACE_OWF
  286:   CIPHEROPTION(CALG_HASH_REPLACE_OWF);
  287: #endif
  288: #ifdef CALG_AES_128
  289:   CIPHEROPTION(CALG_AES_128);
  290: #endif
  291: #ifdef CALG_AES_192
  292:   CIPHEROPTION(CALG_AES_192);
  293: #endif
  294: #ifdef CALG_AES_256
  295:   CIPHEROPTION(CALG_AES_256);
  296: #endif
  297: #ifdef CALG_AES
  298:   CIPHEROPTION(CALG_AES);
  299: #endif
  300: #ifdef CALG_SHA_256
  301:   CIPHEROPTION(CALG_SHA_256);
  302: #endif
  303: #ifdef CALG_SHA_384
  304:   CIPHEROPTION(CALG_SHA_384);
  305: #endif
  306: #ifdef CALG_SHA_512
  307:   CIPHEROPTION(CALG_SHA_512);
  308: #endif
  309: #ifdef CALG_ECDH
  310:   CIPHEROPTION(CALG_ECDH);
  311: #endif
  312: #ifdef CALG_ECMQV
  313:   CIPHEROPTION(CALG_ECMQV);
  314: #endif
  315: #ifdef CALG_ECDSA
  316:   CIPHEROPTION(CALG_ECDSA);
  317: #endif
  318: #ifdef CALG_ECDH_EPHEM
  319:   CIPHEROPTION(CALG_ECDH_EPHEM);
  320: #endif
  321:   return 0;
  322: }
  323: 
  324: static CURLcode
  325: set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers)
  326: {
  327:   char *startCur = ciphers;
  328:   int algCount = 0;
  329:   static ALG_ID algIds[45]; /*There are 45 listed in the MS headers*/
  330:   while(startCur && (0 != *startCur) && (algCount < 45)) {
  331:     long alg = strtol(startCur, 0, 0);
  332:     if(!alg)
  333:       alg = get_alg_id_by_name(startCur);
  334:     if(alg)
  335:       algIds[algCount++] = alg;
  336:     else
  337:       return CURLE_SSL_CIPHER;
  338:     startCur = strchr(startCur, ':');
  339:     if(startCur)
  340:       startCur++;
  341:   }
  342:     schannel_cred->palgSupportedAlgs = algIds;
  343:   schannel_cred->cSupportedAlgs = algCount;
  344:   return CURLE_OK;
  345: }
  346: 
  347: #ifdef HAS_CLIENT_CERT_PATH
  348: static CURLcode
  349: get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
  350:                   TCHAR **thumbprint)
  351: {
  352:   TCHAR *sep;
  353:   TCHAR *store_path_start;
  354:   size_t store_name_len;
  355: 
  356:   sep = _tcschr(path, TEXT('\\'));
  357:   if(sep == NULL)
  358:     return CURLE_SSL_CERTPROBLEM;
  359: 
  360:   store_name_len = sep - path;
  361: 
  362:   if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0)
  363:     *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
  364:   else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0)
  365:     *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  366:   else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0)
  367:     *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
  368:   else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0)
  369:     *store_name = CERT_SYSTEM_STORE_SERVICES;
  370:   else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0)
  371:     *store_name = CERT_SYSTEM_STORE_USERS;
  372:   else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"),
  373:                     store_name_len) == 0)
  374:     *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
  375:   else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"),
  376:                     store_name_len) == 0)
  377:     *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
  378:   else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"),
  379:                     store_name_len) == 0)
  380:     *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
  381:   else
  382:     return CURLE_SSL_CERTPROBLEM;
  383: 
  384:   store_path_start = sep + 1;
  385: 
  386:   sep = _tcschr(store_path_start, TEXT('\\'));
  387:   if(sep == NULL)
  388:     return CURLE_SSL_CERTPROBLEM;
  389: 
  390:   *sep = TEXT('\0');
  391:   *store_path = _tcsdup(store_path_start);
  392:   *sep = TEXT('\\');
  393:   if(*store_path == NULL)
  394:     return CURLE_OUT_OF_MEMORY;
  395: 
  396:   *thumbprint = sep + 1;
  397:   if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
  398:     return CURLE_SSL_CERTPROBLEM;
  399: 
  400:   return CURLE_OK;
  401: }
  402: #endif
  403: 
  404: static CURLcode
  405: schannel_connect_step1(struct connectdata *conn, int sockindex)
  406: {
  407:   ssize_t written = -1;
  408:   struct Curl_easy *data = conn->data;
  409:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  410:   SecBuffer outbuf;
  411:   SecBufferDesc outbuf_desc;
  412:   SecBuffer inbuf;
  413:   SecBufferDesc inbuf_desc;
  414: #ifdef HAS_ALPN
  415:   unsigned char alpn_buffer[128];
  416: #endif
  417:   SCHANNEL_CRED schannel_cred;
  418:   PCCERT_CONTEXT client_certs[1] = { NULL };
  419:   SECURITY_STATUS sspi_status = SEC_E_OK;
  420:   struct curl_schannel_cred *old_cred = NULL;
  421:   struct in_addr addr;
  422: #ifdef ENABLE_IPV6
  423:   struct in6_addr addr6;
  424: #endif
  425:   TCHAR *host_name;
  426:   CURLcode result;
  427:   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
  428:     conn->host.name;
  429: 
  430:   DEBUGF(infof(data,
  431:                "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
  432:                hostname, conn->remote_port));
  433: 
  434:   if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
  435:                                  VERSION_LESS_THAN_EQUAL)) {
  436:      /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
  437:         algorithms that may not be supported by all servers. */
  438:      infof(data, "schannel: Windows version is old and may not be able to "
  439:            "connect to some servers due to lack of SNI, algorithms, etc.\n");
  440:   }
  441: 
  442: #ifdef HAS_ALPN
  443:   /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
  444:      Also it doesn't seem to be supported for Wine, see curl bug #983. */
  445:   BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
  446:                       !GetProcAddress(GetModuleHandleA("ntdll"),
  447:                                       "wine_get_version") &&
  448:                       Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
  449:                                                   VERSION_GREATER_THAN_EQUAL);
  450: #else
  451:   BACKEND->use_alpn = false;
  452: #endif
  453: 
  454: #ifdef _WIN32_WCE
  455: #ifdef HAS_MANUAL_VERIFY_API
  456:   /* certificate validation on CE doesn't seem to work right; we'll
  457:    * do it following a more manual process. */
  458:   BACKEND->use_manual_cred_validation = true;
  459: #else
  460: #error "compiler too old to support requisite manual cert verify for Win CE"
  461: #endif
  462: #else
  463: #ifdef HAS_MANUAL_VERIFY_API
  464:   if(SSL_CONN_CONFIG(CAfile)) {
  465:     if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT,
  466:                                    VERSION_GREATER_THAN_EQUAL)) {
  467:       BACKEND->use_manual_cred_validation = true;
  468:     }
  469:     else {
  470:       failf(data, "schannel: this version of Windows is too old to support "
  471:             "certificate verification via CA bundle file.");
  472:       return CURLE_SSL_CACERT_BADFILE;
  473:     }
  474:   }
  475:   else
  476:     BACKEND->use_manual_cred_validation = false;
  477: #else
  478:   if(SSL_CONN_CONFIG(CAfile)) {
  479:     failf(data, "schannel: CA cert support not built in");
  480:     return CURLE_NOT_BUILT_IN;
  481:   }
  482: #endif
  483: #endif
  484: 
  485:   BACKEND->cred = NULL;
  486: 
  487:   /* check for an existing re-usable credential handle */
  488:   if(SSL_SET_OPTION(primary.sessionid)) {
  489:     Curl_ssl_sessionid_lock(conn);
  490:     if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
  491:       BACKEND->cred = old_cred;
  492:       DEBUGF(infof(data, "schannel: re-using existing credential handle\n"));
  493: 
  494:       /* increment the reference counter of the credential/session handle */
  495:       BACKEND->cred->refcount++;
  496:       DEBUGF(infof(data,
  497:                    "schannel: incremented credential handle refcount = %d\n",
  498:                    BACKEND->cred->refcount));
  499:     }
  500:     Curl_ssl_sessionid_unlock(conn);
  501:   }
  502: 
  503:   if(!BACKEND->cred) {
  504:     /* setup Schannel API options */
  505:     memset(&schannel_cred, 0, sizeof(schannel_cred));
  506:     schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
  507: 
  508:     if(conn->ssl_config.verifypeer) {
  509: #ifdef HAS_MANUAL_VERIFY_API
  510:       if(BACKEND->use_manual_cred_validation)
  511:         schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
  512:       else
  513: #endif
  514:         schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
  515: 
  516:       if(data->set.ssl.no_revoke) {
  517:         schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
  518:           SCH_CRED_IGNORE_REVOCATION_OFFLINE;
  519: 
  520:         DEBUGF(infof(data, "schannel: disabled server certificate revocation "
  521:                      "checks\n"));
  522:       }
  523:       else if(data->set.ssl.revoke_best_effort) {
  524:         schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
  525:           SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
  526: 
  527:         DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
  528:       }
  529:       else {
  530:         schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
  531: 
  532:         DEBUGF(infof(data,
  533:                      "schannel: checking server certificate revocation\n"));
  534:       }
  535:     }
  536:     else {
  537:       schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
  538:         SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
  539:         SCH_CRED_IGNORE_REVOCATION_OFFLINE;
  540:       DEBUGF(infof(data,
  541:                    "schannel: disabled server cert revocation checks\n"));
  542:     }
  543: 
  544:     if(!conn->ssl_config.verifyhost) {
  545:       schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
  546:       DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
  547:                    "comparing the supplied target name with the subject "
  548:                    "names in server certificates.\n"));
  549:     }
  550: 
  551:     switch(conn->ssl_config.version) {
  552:     case CURL_SSLVERSION_DEFAULT:
  553:     case CURL_SSLVERSION_TLSv1:
  554:     case CURL_SSLVERSION_TLSv1_0:
  555:     case CURL_SSLVERSION_TLSv1_1:
  556:     case CURL_SSLVERSION_TLSv1_2:
  557:     case CURL_SSLVERSION_TLSv1_3:
  558:       {
  559:         result = set_ssl_version_min_max(&schannel_cred, conn);
  560:         if(result != CURLE_OK)
  561:           return result;
  562:         break;
  563:       }
  564:     case CURL_SSLVERSION_SSLv3:
  565:       schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
  566:       break;
  567:     case CURL_SSLVERSION_SSLv2:
  568:       schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
  569:       break;
  570:     default:
  571:       failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
  572:       return CURLE_SSL_CONNECT_ERROR;
  573:     }
  574: 
  575:     if(SSL_CONN_CONFIG(cipher_list)) {
  576:       result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list));
  577:       if(CURLE_OK != result) {
  578:         failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
  579:         return result;
  580:       }
  581:     }
  582: 
  583: 
  584: #ifdef HAS_CLIENT_CERT_PATH
  585:     /* client certificate */
  586:     if(data->set.ssl.cert) {
  587:       DWORD cert_store_name;
  588:       TCHAR *cert_store_path = NULL;
  589:       TCHAR *cert_thumbprint_str;
  590:       CRYPT_HASH_BLOB cert_thumbprint;
  591:       BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
  592:       HCERTSTORE cert_store;
  593:       FILE *fInCert = NULL;
  594: 
  595:       TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert);
  596:       if(!cert_path)
  597:         return CURLE_OUT_OF_MEMORY;
  598: 
  599:       result = get_cert_location(cert_path, &cert_store_name,
  600:                                  &cert_store_path, &cert_thumbprint_str);
  601:       if((result != CURLE_OK) && (data->set.ssl.cert[0]!='\0'))
  602:         fInCert = fopen(data->set.ssl.cert, "rb");
  603: 
  604:       if((result != CURLE_OK) && (fInCert == NULL)) {
  605:         failf(data, "schannel: Failed to get certificate location"
  606:               " or file for %s",
  607:               data->set.ssl.cert);
  608:         Curl_unicodefree(cert_path);
  609:         return result;
  610:       }
  611: 
  612:       if(fInCert) {
  613:         /* Reading a .P12 or .pfx file, like the example at bottom of
  614:            https://social.msdn.microsoft.com/Forums/windowsdesktop/
  615:            en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
  616:         */
  617:         void *certdata = NULL;
  618:         long filesize = 0;
  619:         CRYPT_DATA_BLOB datablob;
  620:         WCHAR* pszPassword;
  621:         size_t pwd_len = 0;
  622:         int str_w_len = 0;
  623:         int continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
  624:         if(continue_reading)
  625:           filesize = ftell(fInCert);
  626:         if(filesize < 0)
  627:           continue_reading = 0;
  628:         if(continue_reading)
  629:           continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
  630:         if(continue_reading)
  631:           certdata = malloc(((size_t)filesize) + 1);
  632:         if((certdata == NULL) ||
  633:            ((int) fread(certdata, (size_t)filesize, 1, fInCert) != 1))
  634:           continue_reading = 0;
  635:         fclose(fInCert);
  636:         Curl_unicodefree(cert_path);
  637: 
  638:         if(!continue_reading) {
  639:           failf(data, "schannel: Failed to read cert file %s",
  640:                 data->set.ssl.cert);
  641:           free(certdata);
  642:           return CURLE_SSL_CERTPROBLEM;
  643:         }
  644: 
  645:         /* Convert key-pair data to the in-memory certificate store */
  646:         datablob.pbData = (BYTE*)certdata;
  647:         datablob.cbData = (DWORD)filesize;
  648: 
  649:         if(data->set.ssl.key_passwd != NULL)
  650:           pwd_len = strlen(data->set.ssl.key_passwd);
  651:         pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
  652:         if(pwd_len > 0)
  653:           str_w_len =
  654:             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
  655:                                 data->set.ssl.key_passwd, (int)pwd_len,
  656:                                 pszPassword, (int)(pwd_len + 1));
  657: 
  658:         if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
  659:           pszPassword[str_w_len] = 0;
  660:         else
  661:           pszPassword[0] = 0;
  662: 
  663:         cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
  664:         free(pszPassword);
  665:         free(certdata);
  666:         if(cert_store == NULL) {
  667:           DWORD errorcode = GetLastError();
  668:           if(errorcode == ERROR_INVALID_PASSWORD)
  669:             failf(data, "schannel: Failed to import cert file %s, "
  670:                   "password is bad", data->set.ssl.cert);
  671:           else
  672:             failf(data, "schannel: Failed to import cert file %s, "
  673:                   "last error is 0x%x", data->set.ssl.cert, errorcode);
  674:           return CURLE_SSL_CERTPROBLEM;
  675:         }
  676: 
  677:         client_certs[0] = CertFindCertificateInStore(
  678:             cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
  679:             CERT_FIND_ANY, NULL, NULL);
  680: 
  681:         if(client_certs[0] == NULL) {
  682:           failf(data, "schannel: Failed to get certificate from file %s"
  683:                 ", last error is 0x%x",
  684:                 data->set.ssl.cert, GetLastError());
  685:           CertCloseStore(cert_store, 0);
  686:           return CURLE_SSL_CERTPROBLEM;
  687:         }
  688: 
  689:         schannel_cred.cCreds = 1;
  690:         schannel_cred.paCred = client_certs;
  691:       }
  692:       else {
  693:         cert_store =
  694:           CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
  695:                         (HCRYPTPROV)NULL,
  696:                         CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
  697:                         cert_store_path);
  698:         if(!cert_store) {
  699:           failf(data, "schannel: Failed to open cert store %x %s, "
  700:                 "last error is 0x%x",
  701:                 cert_store_name, cert_store_path, GetLastError());
  702:           free(cert_store_path);
  703:           Curl_unicodefree(cert_path);
  704:           return CURLE_SSL_CERTPROBLEM;
  705:         }
  706:         free(cert_store_path);
  707: 
  708:         cert_thumbprint.pbData = cert_thumbprint_data;
  709:         cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
  710: 
  711:         if(!CryptStringToBinary(cert_thumbprint_str,
  712:                                 CERT_THUMBPRINT_STR_LEN,
  713:                                 CRYPT_STRING_HEX,
  714:                                 cert_thumbprint_data,
  715:                                 &cert_thumbprint.cbData,
  716:                                 NULL, NULL)) {
  717:           Curl_unicodefree(cert_path);
  718:           CertCloseStore(cert_store, 0);
  719:           return CURLE_SSL_CERTPROBLEM;
  720:         }
  721: 
  722:         client_certs[0] = CertFindCertificateInStore(
  723:           cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
  724:           CERT_FIND_HASH, &cert_thumbprint, NULL);
  725: 
  726:         Curl_unicodefree(cert_path);
  727: 
  728:         if(client_certs[0]) {
  729:           schannel_cred.cCreds = 1;
  730:           schannel_cred.paCred = client_certs;
  731:         }
  732:         else {
  733:           /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
  734:           CertCloseStore(cert_store, 0);
  735:           return CURLE_SSL_CERTPROBLEM;
  736:         }
  737:       }
  738:       CertCloseStore(cert_store, 0);
  739:     }
  740: #else
  741:     if(data->set.ssl.cert) {
  742:       failf(data, "schannel: client cert support not built in");
  743:       return CURLE_NOT_BUILT_IN;
  744:     }
  745: #endif
  746: 
  747:     /* allocate memory for the re-usable credential handle */
  748:     BACKEND->cred = (struct curl_schannel_cred *)
  749:       calloc(1, sizeof(struct curl_schannel_cred));
  750:     if(!BACKEND->cred) {
  751:       failf(data, "schannel: unable to allocate memory");
  752: 
  753:       if(client_certs[0])
  754:         CertFreeCertificateContext(client_certs[0]);
  755: 
  756:       return CURLE_OUT_OF_MEMORY;
  757:     }
  758:     BACKEND->cred->refcount = 1;
  759: 
  760:     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
  761:        */
  762:     sspi_status =
  763:       s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
  764:                                          SECPKG_CRED_OUTBOUND, NULL,
  765:                                          &schannel_cred, NULL, NULL,
  766:                                          &BACKEND->cred->cred_handle,
  767:                                          &BACKEND->cred->time_stamp);
  768: 
  769:     if(client_certs[0])
  770:       CertFreeCertificateContext(client_certs[0]);
  771: 
  772:     if(sspi_status != SEC_E_OK) {
  773:       char buffer[STRERROR_LEN];
  774:       failf(data, "schannel: AcquireCredentialsHandle failed: %s",
  775:             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
  776:       Curl_safefree(BACKEND->cred);
  777:       switch(sspi_status) {
  778:         case SEC_E_INSUFFICIENT_MEMORY:
  779:           return CURLE_OUT_OF_MEMORY;
  780:         case SEC_E_NO_CREDENTIALS:
  781:         case SEC_E_SECPKG_NOT_FOUND:
  782:         case SEC_E_NOT_OWNER:
  783:         case SEC_E_UNKNOWN_CREDENTIALS:
  784:         case SEC_E_INTERNAL_ERROR:
  785:         default:
  786:           return CURLE_SSL_CONNECT_ERROR;
  787:       }
  788:     }
  789:   }
  790: 
  791:   /* Warn if SNI is disabled due to use of an IP address */
  792:   if(Curl_inet_pton(AF_INET, hostname, &addr)
  793: #ifdef ENABLE_IPV6
  794:      || Curl_inet_pton(AF_INET6, hostname, &addr6)
  795: #endif
  796:     ) {
  797:     infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
  798:   }
  799: 
  800: #ifdef HAS_ALPN
  801:   if(BACKEND->use_alpn) {
  802:     int cur = 0;
  803:     int list_start_index = 0;
  804:     unsigned int *extension_len = NULL;
  805:     unsigned short* list_len = NULL;
  806: 
  807:     /* The first four bytes will be an unsigned int indicating number
  808:        of bytes of data in the rest of the buffer. */
  809:     extension_len = (unsigned int *)(&alpn_buffer[cur]);
  810:     cur += sizeof(unsigned int);
  811: 
  812:     /* The next four bytes are an indicator that this buffer will contain
  813:        ALPN data, as opposed to NPN, for example. */
  814:     *(unsigned int *)&alpn_buffer[cur] =
  815:       SecApplicationProtocolNegotiationExt_ALPN;
  816:     cur += sizeof(unsigned int);
  817: 
  818:     /* The next two bytes will be an unsigned short indicating the number
  819:        of bytes used to list the preferred protocols. */
  820:     list_len = (unsigned short*)(&alpn_buffer[cur]);
  821:     cur += sizeof(unsigned short);
  822: 
  823:     list_start_index = cur;
  824: 
  825: #ifdef USE_NGHTTP2
  826:     if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
  827:       memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
  828:       cur += NGHTTP2_PROTO_ALPN_LEN;
  829:       infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
  830:     }
  831: #endif
  832: 
  833:     alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
  834:     memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
  835:     cur += ALPN_HTTP_1_1_LENGTH;
  836:     infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
  837: 
  838:     *list_len = curlx_uitous(cur - list_start_index);
  839:     *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
  840: 
  841:     InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
  842:     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
  843:   }
  844:   else {
  845:     InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
  846:     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
  847:   }
  848: #else /* HAS_ALPN */
  849:   InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
  850:   InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
  851: #endif
  852: 
  853:   /* setup output buffer */
  854:   InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
  855:   InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
  856: 
  857:   /* setup request flags */
  858:   BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
  859:     ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
  860:     ISC_REQ_STREAM;
  861: 
  862:   /* allocate memory for the security context handle */
  863:   BACKEND->ctxt = (struct curl_schannel_ctxt *)
  864:     calloc(1, sizeof(struct curl_schannel_ctxt));
  865:   if(!BACKEND->ctxt) {
  866:     failf(data, "schannel: unable to allocate memory");
  867:     return CURLE_OUT_OF_MEMORY;
  868:   }
  869: 
  870:   host_name = Curl_convert_UTF8_to_tchar(hostname);
  871:   if(!host_name)
  872:     return CURLE_OUT_OF_MEMORY;
  873: 
  874:   /* Schannel InitializeSecurityContext:
  875:      https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
  876: 
  877:      At the moment we don't pass inbuf unless we're using ALPN since we only
  878:      use it for that, and Wine (for which we currently disable ALPN) is giving
  879:      us problems with inbuf regardless. https://github.com/curl/curl/issues/983
  880:   */
  881:   sspi_status = s_pSecFn->InitializeSecurityContext(
  882:     &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
  883:     (BACKEND->use_alpn ? &inbuf_desc : NULL),
  884:     0, &BACKEND->ctxt->ctxt_handle,
  885:     &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
  886: 
  887:   Curl_unicodefree(host_name);
  888: 
  889:   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
  890:     char buffer[STRERROR_LEN];
  891:     Curl_safefree(BACKEND->ctxt);
  892:     switch(sspi_status) {
  893:       case SEC_E_INSUFFICIENT_MEMORY:
  894:         failf(data, "schannel: initial InitializeSecurityContext failed: %s",
  895:               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
  896:         return CURLE_OUT_OF_MEMORY;
  897:       case SEC_E_WRONG_PRINCIPAL:
  898:         failf(data, "schannel: SNI or certificate check failed: %s",
  899:               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
  900:         return CURLE_PEER_FAILED_VERIFICATION;
  901:         /*
  902:       case SEC_E_INVALID_HANDLE:
  903:       case SEC_E_INVALID_TOKEN:
  904:       case SEC_E_LOGON_DENIED:
  905:       case SEC_E_TARGET_UNKNOWN:
  906:       case SEC_E_NO_AUTHENTICATING_AUTHORITY:
  907:       case SEC_E_INTERNAL_ERROR:
  908:       case SEC_E_NO_CREDENTIALS:
  909:       case SEC_E_UNSUPPORTED_FUNCTION:
  910:       case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
  911:         */
  912:       default:
  913:         failf(data, "schannel: initial InitializeSecurityContext failed: %s",
  914:               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
  915:         return CURLE_SSL_CONNECT_ERROR;
  916:     }
  917:   }
  918: 
  919:   DEBUGF(infof(data, "schannel: sending initial handshake data: "
  920:                "sending %lu bytes...\n", outbuf.cbBuffer));
  921: 
  922:   /* send initial handshake data which is now stored in output buffer */
  923:   result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
  924:                             outbuf.cbBuffer, &written);
  925:   s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
  926:   if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
  927:     failf(data, "schannel: failed to send initial handshake data: "
  928:           "sent %zd of %lu bytes", written, outbuf.cbBuffer);
  929:     return CURLE_SSL_CONNECT_ERROR;
  930:   }
  931: 
  932:   DEBUGF(infof(data, "schannel: sent initial handshake data: "
  933:                "sent %zd bytes\n", written));
  934: 
  935:   BACKEND->recv_unrecoverable_err = CURLE_OK;
  936:   BACKEND->recv_sspi_close_notify = false;
  937:   BACKEND->recv_connection_closed = false;
  938:   BACKEND->encdata_is_incomplete = false;
  939: 
  940:   /* continue to second handshake step */
  941:   connssl->connecting_state = ssl_connect_2;
  942: 
  943:   return CURLE_OK;
  944: }
  945: 
  946: static CURLcode
  947: schannel_connect_step2(struct connectdata *conn, int sockindex)
  948: {
  949:   int i;
  950:   ssize_t nread = -1, written = -1;
  951:   struct Curl_easy *data = conn->data;
  952:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  953:   unsigned char *reallocated_buffer;
  954:   SecBuffer outbuf[3];
  955:   SecBufferDesc outbuf_desc;
  956:   SecBuffer inbuf[2];
  957:   SecBufferDesc inbuf_desc;
  958:   SECURITY_STATUS sspi_status = SEC_E_OK;
  959:   CURLcode result;
  960:   bool doread;
  961:   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
  962:     conn->host.name;
  963:   const char *pubkey_ptr;
  964: 
  965:   doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
  966: 
  967:   DEBUGF(infof(data,
  968:                "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
  969:                hostname, conn->remote_port));
  970: 
  971:   if(!BACKEND->cred || !BACKEND->ctxt)
  972:     return CURLE_SSL_CONNECT_ERROR;
  973: 
  974:   /* buffer to store previously received and decrypted data */
  975:   if(BACKEND->decdata_buffer == NULL) {
  976:     BACKEND->decdata_offset = 0;
  977:     BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
  978:     BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
  979:     if(BACKEND->decdata_buffer == NULL) {
  980:       failf(data, "schannel: unable to allocate memory");
  981:       return CURLE_OUT_OF_MEMORY;
  982:     }
  983:   }
  984: 
  985:   /* buffer to store previously received and encrypted data */
  986:   if(BACKEND->encdata_buffer == NULL) {
  987:     BACKEND->encdata_is_incomplete = false;
  988:     BACKEND->encdata_offset = 0;
  989:     BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
  990:     BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
  991:     if(BACKEND->encdata_buffer == NULL) {
  992:       failf(data, "schannel: unable to allocate memory");
  993:       return CURLE_OUT_OF_MEMORY;
  994:     }
  995:   }
  996: 
  997:   /* if we need a bigger buffer to read a full message, increase buffer now */
  998:   if(BACKEND->encdata_length - BACKEND->encdata_offset <
  999:      CURL_SCHANNEL_BUFFER_FREE_SIZE) {
 1000:     /* increase internal encrypted data buffer */
 1001:     size_t reallocated_length = BACKEND->encdata_offset +
 1002:       CURL_SCHANNEL_BUFFER_FREE_SIZE;
 1003:     reallocated_buffer = realloc(BACKEND->encdata_buffer,
 1004:                                  reallocated_length);
 1005: 
 1006:     if(reallocated_buffer == NULL) {
 1007:       failf(data, "schannel: unable to re-allocate memory");
 1008:       return CURLE_OUT_OF_MEMORY;
 1009:     }
 1010:     else {
 1011:       BACKEND->encdata_buffer = reallocated_buffer;
 1012:       BACKEND->encdata_length = reallocated_length;
 1013:     }
 1014:   }
 1015: 
 1016:   for(;;) {
 1017:     TCHAR *host_name;
 1018:     if(doread) {
 1019:       /* read encrypted handshake data from socket */
 1020:       result = Curl_read_plain(conn->sock[sockindex],
 1021:                                (char *) (BACKEND->encdata_buffer +
 1022:                                          BACKEND->encdata_offset),
 1023:                                BACKEND->encdata_length -
 1024:                                BACKEND->encdata_offset,
 1025:                                &nread);
 1026:       if(result == CURLE_AGAIN) {
 1027:         if(connssl->connecting_state != ssl_connect_2_writing)
 1028:           connssl->connecting_state = ssl_connect_2_reading;
 1029:         DEBUGF(infof(data, "schannel: failed to receive handshake, "
 1030:                      "need more data\n"));
 1031:         return CURLE_OK;
 1032:       }
 1033:       else if((result != CURLE_OK) || (nread == 0)) {
 1034:         failf(data, "schannel: failed to receive handshake, "
 1035:               "SSL/TLS connection failed");
 1036:         return CURLE_SSL_CONNECT_ERROR;
 1037:       }
 1038: 
 1039:       /* increase encrypted data buffer offset */
 1040:       BACKEND->encdata_offset += nread;
 1041:       BACKEND->encdata_is_incomplete = false;
 1042:       DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
 1043:     }
 1044: 
 1045:     DEBUGF(infof(data,
 1046:                  "schannel: encrypted data buffer: offset %zu length %zu\n",
 1047:                  BACKEND->encdata_offset, BACKEND->encdata_length));
 1048: 
 1049:     /* setup input buffers */
 1050:     InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
 1051:                   curlx_uztoul(BACKEND->encdata_offset));
 1052:     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
 1053:     InitSecBufferDesc(&inbuf_desc, inbuf, 2);
 1054: 
 1055:     /* setup output buffers */
 1056:     InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
 1057:     InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
 1058:     InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
 1059:     InitSecBufferDesc(&outbuf_desc, outbuf, 3);
 1060: 
 1061:     if(inbuf[0].pvBuffer == NULL) {
 1062:       failf(data, "schannel: unable to allocate memory");
 1063:       return CURLE_OUT_OF_MEMORY;
 1064:     }
 1065: 
 1066:     /* copy received handshake data into input buffer */
 1067:     memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
 1068:            BACKEND->encdata_offset);
 1069: 
 1070:     host_name = Curl_convert_UTF8_to_tchar(hostname);
 1071:     if(!host_name)
 1072:       return CURLE_OUT_OF_MEMORY;
 1073: 
 1074:     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
 1075:        */
 1076:     sspi_status = s_pSecFn->InitializeSecurityContext(
 1077:       &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
 1078:       host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
 1079:       &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
 1080: 
 1081:     Curl_unicodefree(host_name);
 1082: 
 1083:     /* free buffer for received handshake data */
 1084:     Curl_safefree(inbuf[0].pvBuffer);
 1085: 
 1086:     /* check if the handshake was incomplete */
 1087:     if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
 1088:       BACKEND->encdata_is_incomplete = true;
 1089:       connssl->connecting_state = ssl_connect_2_reading;
 1090:       DEBUGF(infof(data,
 1091:                    "schannel: received incomplete message, need more data\n"));
 1092:       return CURLE_OK;
 1093:     }
 1094: 
 1095:     /* If the server has requested a client certificate, attempt to continue
 1096:        the handshake without one. This will allow connections to servers which
 1097:        request a client certificate but do not require it. */
 1098:     if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
 1099:        !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
 1100:       BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
 1101:       connssl->connecting_state = ssl_connect_2_writing;
 1102:       DEBUGF(infof(data,
 1103:                    "schannel: a client certificate has been requested\n"));
 1104:       return CURLE_OK;
 1105:     }
 1106: 
 1107:     /* check if the handshake needs to be continued */
 1108:     if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
 1109:       for(i = 0; i < 3; i++) {
 1110:         /* search for handshake tokens that need to be send */
 1111:         if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
 1112:           DEBUGF(infof(data, "schannel: sending next handshake data: "
 1113:                        "sending %lu bytes...\n", outbuf[i].cbBuffer));
 1114: 
 1115:           /* send handshake token to server */
 1116:           result = Curl_write_plain(conn, conn->sock[sockindex],
 1117:                                     outbuf[i].pvBuffer, outbuf[i].cbBuffer,
 1118:                                     &written);
 1119:           if((result != CURLE_OK) ||
 1120:              (outbuf[i].cbBuffer != (size_t) written)) {
 1121:             failf(data, "schannel: failed to send next handshake data: "
 1122:                   "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
 1123:             return CURLE_SSL_CONNECT_ERROR;
 1124:           }
 1125:         }
 1126: 
 1127:         /* free obsolete buffer */
 1128:         if(outbuf[i].pvBuffer != NULL) {
 1129:           s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
 1130:         }
 1131:       }
 1132:     }
 1133:     else {
 1134:       char buffer[STRERROR_LEN];
 1135:       switch(sspi_status) {
 1136:         case SEC_E_INSUFFICIENT_MEMORY:
 1137:           failf(data, "schannel: next InitializeSecurityContext failed: %s",
 1138:                 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
 1139:           return CURLE_OUT_OF_MEMORY;
 1140:         case SEC_E_WRONG_PRINCIPAL:
 1141:           failf(data, "schannel: SNI or certificate check failed: %s",
 1142:                 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
 1143:           return CURLE_PEER_FAILED_VERIFICATION;
 1144:           /*
 1145:         case SEC_E_INVALID_HANDLE:
 1146:         case SEC_E_INVALID_TOKEN:
 1147:         case SEC_E_LOGON_DENIED:
 1148:         case SEC_E_TARGET_UNKNOWN:
 1149:         case SEC_E_NO_AUTHENTICATING_AUTHORITY:
 1150:         case SEC_E_INTERNAL_ERROR:
 1151:         case SEC_E_NO_CREDENTIALS:
 1152:         case SEC_E_UNSUPPORTED_FUNCTION:
 1153:         case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
 1154:           */
 1155:         default:
 1156:           failf(data, "schannel: next InitializeSecurityContext failed: %s",
 1157:                 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
 1158:           return CURLE_SSL_CONNECT_ERROR;
 1159:       }
 1160:     }
 1161: 
 1162:     /* check if there was additional remaining encrypted data */
 1163:     if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
 1164:       DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
 1165:                    inbuf[1].cbBuffer));
 1166:       /*
 1167:         There are two cases where we could be getting extra data here:
 1168:         1) If we're renegotiating a connection and the handshake is already
 1169:         complete (from the server perspective), it can encrypted app data
 1170:         (not handshake data) in an extra buffer at this point.
 1171:         2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
 1172:         connection and this extra data is part of the handshake.
 1173:         We should process the data immediately; waiting for the socket to
 1174:         be ready may fail since the server is done sending handshake data.
 1175:       */
 1176:       /* check if the remaining data is less than the total amount
 1177:          and therefore begins after the already processed data */
 1178:       if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
 1179:         memmove(BACKEND->encdata_buffer,
 1180:                 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
 1181:                 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
 1182:         BACKEND->encdata_offset = inbuf[1].cbBuffer;
 1183:         if(sspi_status == SEC_I_CONTINUE_NEEDED) {
 1184:           doread = FALSE;
 1185:           continue;
 1186:         }
 1187:       }
 1188:     }
 1189:     else {
 1190:       BACKEND->encdata_offset = 0;
 1191:     }
 1192:     break;
 1193:   }
 1194: 
 1195:   /* check if the handshake needs to be continued */
 1196:   if(sspi_status == SEC_I_CONTINUE_NEEDED) {
 1197:     connssl->connecting_state = ssl_connect_2_reading;
 1198:     return CURLE_OK;
 1199:   }
 1200: 
 1201:   /* check if the handshake is complete */
 1202:   if(sspi_status == SEC_E_OK) {
 1203:     connssl->connecting_state = ssl_connect_3;
 1204:     DEBUGF(infof(data, "schannel: SSL/TLS handshake complete\n"));
 1205:   }
 1206: 
 1207:   pubkey_ptr = SSL_IS_PROXY() ?
 1208:     data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
 1209:     data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
 1210:   if(pubkey_ptr) {
 1211:     result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
 1212:     if(result) {
 1213:       failf(data, "SSL: public key does not match pinned public key!");
 1214:       return result;
 1215:     }
 1216:   }
 1217: 
 1218: #ifdef HAS_MANUAL_VERIFY_API
 1219:   if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
 1220:     return Curl_verify_certificate(conn, sockindex);
 1221:   }
 1222: #endif
 1223: 
 1224:   return CURLE_OK;
 1225: }
 1226: 
 1227: static bool
 1228: valid_cert_encoding(const CERT_CONTEXT *cert_context)
 1229: {
 1230:   return (cert_context != NULL) &&
 1231:     ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
 1232:     (cert_context->pbCertEncoded != NULL) &&
 1233:     (cert_context->cbCertEncoded > 0);
 1234: }
 1235: 
 1236: typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
 1237: 
 1238: static void
 1239: traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
 1240:                     void *arg)
 1241: {
 1242:   const CERT_CONTEXT *current_context = NULL;
 1243:   bool should_continue = true;
 1244:   while(should_continue &&
 1245:         (current_context = CertEnumCertificatesInStore(
 1246:           context->hCertStore,
 1247:           current_context)) != NULL)
 1248:     should_continue = func(current_context, arg);
 1249: 
 1250:   if(current_context)
 1251:     CertFreeCertificateContext(current_context);
 1252: }
 1253: 
 1254: static bool
 1255: cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
 1256: {
 1257:   if(valid_cert_encoding(ccert_context))
 1258:     (*(int *)certs_count)++;
 1259:   return true;
 1260: }
 1261: 
 1262: struct Adder_args
 1263: {
 1264:   struct connectdata *conn;
 1265:   CURLcode result;
 1266:   int idx;
 1267:   int certs_count;
 1268: };
 1269: 
 1270: static bool
 1271: add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
 1272: {
 1273:   struct Adder_args *args = (struct Adder_args*)raw_arg;
 1274:   args->result = CURLE_OK;
 1275:   if(valid_cert_encoding(ccert_context)) {
 1276:     const char *beg = (const char *) ccert_context->pbCertEncoded;
 1277:     const char *end = beg + ccert_context->cbCertEncoded;
 1278:     int insert_index = (args->certs_count - 1) - args->idx;
 1279:     args->result = Curl_extract_certinfo(args->conn, insert_index, beg, end);
 1280:     args->idx++;
 1281:   }
 1282:   return args->result == CURLE_OK;
 1283: }
 1284: 
 1285: static CURLcode
 1286: schannel_connect_step3(struct connectdata *conn, int sockindex)
 1287: {
 1288:   CURLcode result = CURLE_OK;
 1289:   struct Curl_easy *data = conn->data;
 1290:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 1291:   SECURITY_STATUS sspi_status = SEC_E_OK;
 1292:   CERT_CONTEXT *ccert_context = NULL;
 1293: #ifdef DEBUGBUILD
 1294:   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
 1295:     conn->host.name;
 1296: #endif
 1297: #ifdef HAS_ALPN
 1298:   SecPkgContext_ApplicationProtocol alpn_result;
 1299: #endif
 1300: 
 1301:   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 1302: 
 1303:   DEBUGF(infof(data,
 1304:                "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
 1305:                hostname, conn->remote_port));
 1306: 
 1307:   if(!BACKEND->cred)
 1308:     return CURLE_SSL_CONNECT_ERROR;
 1309: 
 1310:   /* check if the required context attributes are met */
 1311:   if(BACKEND->ret_flags != BACKEND->req_flags) {
 1312:     if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
 1313:       failf(data, "schannel: failed to setup sequence detection");
 1314:     if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
 1315:       failf(data, "schannel: failed to setup replay detection");
 1316:     if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
 1317:       failf(data, "schannel: failed to setup confidentiality");
 1318:     if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
 1319:       failf(data, "schannel: failed to setup memory allocation");
 1320:     if(!(BACKEND->ret_flags & ISC_RET_STREAM))
 1321:       failf(data, "schannel: failed to setup stream orientation");
 1322:     return CURLE_SSL_CONNECT_ERROR;
 1323:   }
 1324: 
 1325: #ifdef HAS_ALPN
 1326:   if(BACKEND->use_alpn) {
 1327:     sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
 1328:       SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
 1329: 
 1330:     if(sspi_status != SEC_E_OK) {
 1331:       failf(data, "schannel: failed to retrieve ALPN result");
 1332:       return CURLE_SSL_CONNECT_ERROR;
 1333:     }
 1334: 
 1335:     if(alpn_result.ProtoNegoStatus ==
 1336:        SecApplicationProtocolNegotiationStatus_Success) {
 1337: 
 1338:       infof(data, "schannel: ALPN, server accepted to use %.*s\n",
 1339:         alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
 1340: 
 1341: #ifdef USE_NGHTTP2
 1342:       if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
 1343:          !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
 1344:           NGHTTP2_PROTO_VERSION_ID_LEN)) {
 1345:         conn->negnpn = CURL_HTTP_VERSION_2;
 1346:       }
 1347:       else
 1348: #endif
 1349:       if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
 1350:          !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
 1351:            ALPN_HTTP_1_1_LENGTH)) {
 1352:         conn->negnpn = CURL_HTTP_VERSION_1_1;
 1353:       }
 1354:     }
 1355:     else
 1356:       infof(data, "ALPN, server did not agree to a protocol\n");
 1357:     Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
 1358:                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
 1359:   }
 1360: #endif
 1361: 
 1362:   /* save the current session data for possible re-use */
 1363:   if(SSL_SET_OPTION(primary.sessionid)) {
 1364:     bool incache;
 1365:     struct curl_schannel_cred *old_cred = NULL;
 1366: 
 1367:     Curl_ssl_sessionid_lock(conn);
 1368:     incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
 1369:                                       sockindex));
 1370:     if(incache) {
 1371:       if(old_cred != BACKEND->cred) {
 1372:         DEBUGF(infof(data,
 1373:                      "schannel: old credential handle is stale, removing\n"));
 1374:         /* we're not taking old_cred ownership here, no refcount++ is needed */
 1375:         Curl_ssl_delsessionid(conn, (void *)old_cred);
 1376:         incache = FALSE;
 1377:       }
 1378:     }
 1379:     if(!incache) {
 1380:       result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred,
 1381:                                      sizeof(struct curl_schannel_cred),
 1382:                                      sockindex);
 1383:       if(result) {
 1384:         Curl_ssl_sessionid_unlock(conn);
 1385:         failf(data, "schannel: failed to store credential handle");
 1386:         return result;
 1387:       }
 1388:       else {
 1389:         /* this cred session is now also referenced by sessionid cache */
 1390:         BACKEND->cred->refcount++;
 1391:         DEBUGF(infof(data,
 1392:                      "schannel: stored credential handle in session cache\n"));
 1393:       }
 1394:     }
 1395:     Curl_ssl_sessionid_unlock(conn);
 1396:   }
 1397: 
 1398:   if(data->set.ssl.certinfo) {
 1399:     int certs_count = 0;
 1400:     sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
 1401:       SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
 1402: 
 1403:     if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
 1404:       failf(data, "schannel: failed to retrieve remote cert context");
 1405:       return CURLE_PEER_FAILED_VERIFICATION;
 1406:     }
 1407: 
 1408:     traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
 1409: 
 1410:     result = Curl_ssl_init_certinfo(data, certs_count);
 1411:     if(!result) {
 1412:       struct Adder_args args;
 1413:       args.conn = conn;
 1414:       args.idx = 0;
 1415:       args.certs_count = certs_count;
 1416:       traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
 1417:       result = args.result;
 1418:     }
 1419:     CertFreeCertificateContext(ccert_context);
 1420:     if(result)
 1421:       return result;
 1422:   }
 1423: 
 1424:   connssl->connecting_state = ssl_connect_done;
 1425: 
 1426:   return CURLE_OK;
 1427: }
 1428: 
 1429: static CURLcode
 1430: schannel_connect_common(struct connectdata *conn, int sockindex,
 1431:                         bool nonblocking, bool *done)
 1432: {
 1433:   CURLcode result;
 1434:   struct Curl_easy *data = conn->data;
 1435:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 1436:   curl_socket_t sockfd = conn->sock[sockindex];
 1437:   timediff_t timeout_ms;
 1438:   int what;
 1439: 
 1440:   /* check if the connection has already been established */
 1441:   if(ssl_connection_complete == connssl->state) {
 1442:     *done = TRUE;
 1443:     return CURLE_OK;
 1444:   }
 1445: 
 1446:   if(ssl_connect_1 == connssl->connecting_state) {
 1447:     /* check out how much more time we're allowed */
 1448:     timeout_ms = Curl_timeleft(data, NULL, TRUE);
 1449: 
 1450:     if(timeout_ms < 0) {
 1451:       /* no need to continue if time already is up */
 1452:       failf(data, "SSL/TLS connection timeout");
 1453:       return CURLE_OPERATION_TIMEDOUT;
 1454:     }
 1455: 
 1456:     result = schannel_connect_step1(conn, sockindex);
 1457:     if(result)
 1458:       return result;
 1459:   }
 1460: 
 1461:   while(ssl_connect_2 == connssl->connecting_state ||
 1462:         ssl_connect_2_reading == connssl->connecting_state ||
 1463:         ssl_connect_2_writing == connssl->connecting_state) {
 1464: 
 1465:     /* check out how much more time we're allowed */
 1466:     timeout_ms = Curl_timeleft(data, NULL, TRUE);
 1467: 
 1468:     if(timeout_ms < 0) {
 1469:       /* no need to continue if time already is up */
 1470:       failf(data, "SSL/TLS connection timeout");
 1471:       return CURLE_OPERATION_TIMEDOUT;
 1472:     }
 1473: 
 1474:     /* if ssl is expecting something, check if it's available. */
 1475:     if(connssl->connecting_state == ssl_connect_2_reading
 1476:        || connssl->connecting_state == ssl_connect_2_writing) {
 1477: 
 1478:       curl_socket_t writefd = ssl_connect_2_writing ==
 1479:         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
 1480:       curl_socket_t readfd = ssl_connect_2_reading ==
 1481:         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
 1482: 
 1483:       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
 1484:                                nonblocking ? 0 : (time_t)timeout_ms);
 1485:       if(what < 0) {
 1486:         /* fatal error */
 1487:         failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
 1488:         return CURLE_SSL_CONNECT_ERROR;
 1489:       }
 1490:       else if(0 == what) {
 1491:         if(nonblocking) {
 1492:           *done = FALSE;
 1493:           return CURLE_OK;
 1494:         }
 1495:         else {
 1496:           /* timeout */
 1497:           failf(data, "SSL/TLS connection timeout");
 1498:           return CURLE_OPERATION_TIMEDOUT;
 1499:         }
 1500:       }
 1501:       /* socket is readable or writable */
 1502:     }
 1503: 
 1504:     /* Run transaction, and return to the caller if it failed or if
 1505:      * this connection is part of a multi handle and this loop would
 1506:      * execute again. This permits the owner of a multi handle to
 1507:      * abort a connection attempt before step2 has completed while
 1508:      * ensuring that a client using select() or epoll() will always
 1509:      * have a valid fdset to wait on.
 1510:      */
 1511:     result = schannel_connect_step2(conn, sockindex);
 1512:     if(result || (nonblocking &&
 1513:                   (ssl_connect_2 == connssl->connecting_state ||
 1514:                    ssl_connect_2_reading == connssl->connecting_state ||
 1515:                    ssl_connect_2_writing == connssl->connecting_state)))
 1516:       return result;
 1517: 
 1518:   } /* repeat step2 until all transactions are done. */
 1519: 
 1520:   if(ssl_connect_3 == connssl->connecting_state) {
 1521:     result = schannel_connect_step3(conn, sockindex);
 1522:     if(result)
 1523:       return result;
 1524:   }
 1525: 
 1526:   if(ssl_connect_done == connssl->connecting_state) {
 1527:     connssl->state = ssl_connection_complete;
 1528:     conn->recv[sockindex] = schannel_recv;
 1529:     conn->send[sockindex] = schannel_send;
 1530: 
 1531: #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
 1532:     /* When SSPI is used in combination with Schannel
 1533:      * we need the Schannel context to create the Schannel
 1534:      * binding to pass the IIS extended protection checks.
 1535:      * Available on Windows 7 or later.
 1536:      */
 1537:     conn->sslContext = &BACKEND->ctxt->ctxt_handle;
 1538: #endif
 1539: 
 1540:     *done = TRUE;
 1541:   }
 1542:   else
 1543:     *done = FALSE;
 1544: 
 1545:   /* reset our connection state machine */
 1546:   connssl->connecting_state = ssl_connect_1;
 1547: 
 1548:   return CURLE_OK;
 1549: }
 1550: 
 1551: static ssize_t
 1552: schannel_send(struct connectdata *conn, int sockindex,
 1553:               const void *buf, size_t len, CURLcode *err)
 1554: {
 1555:   ssize_t written = -1;
 1556:   size_t data_len = 0;
 1557:   unsigned char *data = NULL;
 1558:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 1559:   SecBuffer outbuf[4];
 1560:   SecBufferDesc outbuf_desc;
 1561:   SECURITY_STATUS sspi_status = SEC_E_OK;
 1562:   CURLcode result;
 1563: 
 1564:   /* check if the maximum stream sizes were queried */
 1565:   if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
 1566:     sspi_status = s_pSecFn->QueryContextAttributes(
 1567:       &BACKEND->ctxt->ctxt_handle,
 1568:       SECPKG_ATTR_STREAM_SIZES,
 1569:       &BACKEND->stream_sizes);
 1570:     if(sspi_status != SEC_E_OK) {
 1571:       *err = CURLE_SEND_ERROR;
 1572:       return -1;
 1573:     }
 1574:   }
 1575: 
 1576:   /* check if the buffer is longer than the maximum message length */
 1577:   if(len > BACKEND->stream_sizes.cbMaximumMessage) {
 1578:     len = BACKEND->stream_sizes.cbMaximumMessage;
 1579:   }
 1580: 
 1581:   /* calculate the complete message length and allocate a buffer for it */
 1582:   data_len = BACKEND->stream_sizes.cbHeader + len +
 1583:     BACKEND->stream_sizes.cbTrailer;
 1584:   data = (unsigned char *) malloc(data_len);
 1585:   if(data == NULL) {
 1586:     *err = CURLE_OUT_OF_MEMORY;
 1587:     return -1;
 1588:   }
 1589: 
 1590:   /* setup output buffers (header, data, trailer, empty) */
 1591:   InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
 1592:                 data, BACKEND->stream_sizes.cbHeader);
 1593:   InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
 1594:                 data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
 1595:   InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
 1596:                 data + BACKEND->stream_sizes.cbHeader + len,
 1597:                 BACKEND->stream_sizes.cbTrailer);
 1598:   InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
 1599:   InitSecBufferDesc(&outbuf_desc, outbuf, 4);
 1600: 
 1601:   /* copy data into output buffer */
 1602:   memcpy(outbuf[1].pvBuffer, buf, len);
 1603: 
 1604:   /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
 1605:   sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
 1606:                                          &outbuf_desc, 0);
 1607: 
 1608:   /* check if the message was encrypted */
 1609:   if(sspi_status == SEC_E_OK) {
 1610:     written = 0;
 1611: 
 1612:     /* send the encrypted message including header, data and trailer */
 1613:     len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
 1614: 
 1615:     /*
 1616:       It's important to send the full message which includes the header,
 1617:       encrypted payload, and trailer.  Until the client receives all the
 1618:       data a coherent message has not been delivered and the client
 1619:       can't read any of it.
 1620: 
 1621:       If we wanted to buffer the unwritten encrypted bytes, we would
 1622:       tell the client that all data it has requested to be sent has been
 1623:       sent. The unwritten encrypted bytes would be the first bytes to
 1624:       send on the next invocation.
 1625:       Here's the catch with this - if we tell the client that all the
 1626:       bytes have been sent, will the client call this method again to
 1627:       send the buffered data?  Looking at who calls this function, it
 1628:       seems the answer is NO.
 1629:     */
 1630: 
 1631:     /* send entire message or fail */
 1632:     while(len > (size_t)written) {
 1633:       ssize_t this_write;
 1634:       timediff_t timeout_ms;
 1635:       int what;
 1636: 
 1637:       this_write = 0;
 1638: 
 1639:       timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
 1640:       if(timeout_ms < 0) {
 1641:         /* we already got the timeout */
 1642:         failf(conn->data, "schannel: timed out sending data "
 1643:               "(bytes sent: %zd)", written);
 1644:         *err = CURLE_OPERATION_TIMEDOUT;
 1645:         written = -1;
 1646:         break;
 1647:       }
 1648:       if(!timeout_ms)
 1649:         timeout_ms = TIMEDIFF_T_MAX;
 1650:       what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms);
 1651:       if(what < 0) {
 1652:         /* fatal error */
 1653:         failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
 1654:         *err = CURLE_SEND_ERROR;
 1655:         written = -1;
 1656:         break;
 1657:       }
 1658:       else if(0 == what) {
 1659:         failf(conn->data, "schannel: timed out sending data "
 1660:               "(bytes sent: %zd)", written);
 1661:         *err = CURLE_OPERATION_TIMEDOUT;
 1662:         written = -1;
 1663:         break;
 1664:       }
 1665:       /* socket is writable */
 1666: 
 1667:       result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
 1668:                                 len - written, &this_write);
 1669:       if(result == CURLE_AGAIN)
 1670:         continue;
 1671:       else if(result != CURLE_OK) {
 1672:         *err = result;
 1673:         written = -1;
 1674:         break;
 1675:       }
 1676: 
 1677:       written += this_write;
 1678:     }
 1679:   }
 1680:   else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
 1681:     *err = CURLE_OUT_OF_MEMORY;
 1682:   }
 1683:   else{
 1684:     *err = CURLE_SEND_ERROR;
 1685:   }
 1686: 
 1687:   Curl_safefree(data);
 1688: 
 1689:   if(len == (size_t)written)
 1690:     /* Encrypted message including header, data and trailer entirely sent.
 1691:        The return value is the number of unencrypted bytes that were sent. */
 1692:     written = outbuf[1].cbBuffer;
 1693: 
 1694:   return written;
 1695: }
 1696: 
 1697: static ssize_t
 1698: schannel_recv(struct connectdata *conn, int sockindex,
 1699:               char *buf, size_t len, CURLcode *err)
 1700: {
 1701:   size_t size = 0;
 1702:   ssize_t nread = -1;
 1703:   struct Curl_easy *data = conn->data;
 1704:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 1705:   unsigned char *reallocated_buffer;
 1706:   size_t reallocated_length;
 1707:   bool done = FALSE;
 1708:   SecBuffer inbuf[4];
 1709:   SecBufferDesc inbuf_desc;
 1710:   SECURITY_STATUS sspi_status = SEC_E_OK;
 1711:   /* we want the length of the encrypted buffer to be at least large enough
 1712:      that it can hold all the bytes requested and some TLS record overhead. */
 1713:   size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
 1714: 
 1715:   /****************************************************************************
 1716:    * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup.
 1717:    * The pattern for return error is set *err, optional infof, goto cleanup.
 1718:    *
 1719:    * Our priority is to always return as much decrypted data to the caller as
 1720:    * possible, even if an error occurs. The state of the decrypted buffer must
 1721:    * always be valid. Transfer of decrypted data to the caller's buffer is
 1722:    * handled in the cleanup.
 1723:    */
 1724: 
 1725:   DEBUGF(infof(data, "schannel: client wants to read %zu bytes\n", len));
 1726:   *err = CURLE_OK;
 1727: 
 1728:   if(len && len <= BACKEND->decdata_offset) {
 1729:     infof(data, "schannel: enough decrypted data is already available\n");
 1730:     goto cleanup;
 1731:   }
 1732:   else if(BACKEND->recv_unrecoverable_err) {
 1733:     *err = BACKEND->recv_unrecoverable_err;
 1734:     infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
 1735:     goto cleanup;
 1736:   }
 1737:   else if(BACKEND->recv_sspi_close_notify) {
 1738:     /* once a server has indicated shutdown there is no more encrypted data */
 1739:     infof(data, "schannel: server indicated shutdown in a prior call\n");
 1740:     goto cleanup;
 1741:   }
 1742:   else if(!len) {
 1743:     /* It's debatable what to return when !len. Regardless we can't return
 1744:     immediately because there may be data to decrypt (in the case we want to
 1745:     decrypt all encrypted cached data) so handle !len later in cleanup.
 1746:     */
 1747:     ; /* do nothing */
 1748:   }
 1749:   else if(!BACKEND->recv_connection_closed) {
 1750:     /* increase enc buffer in order to fit the requested amount of data */
 1751:     size = BACKEND->encdata_length - BACKEND->encdata_offset;
 1752:     if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
 1753:        BACKEND->encdata_length < min_encdata_length) {
 1754:       reallocated_length = BACKEND->encdata_offset +
 1755:                            CURL_SCHANNEL_BUFFER_FREE_SIZE;
 1756:       if(reallocated_length < min_encdata_length) {
 1757:         reallocated_length = min_encdata_length;
 1758:       }
 1759:       reallocated_buffer = realloc(BACKEND->encdata_buffer,
 1760:                                    reallocated_length);
 1761:       if(reallocated_buffer == NULL) {
 1762:         *err = CURLE_OUT_OF_MEMORY;
 1763:         failf(data, "schannel: unable to re-allocate memory");
 1764:         goto cleanup;
 1765:       }
 1766: 
 1767:       BACKEND->encdata_buffer = reallocated_buffer;
 1768:       BACKEND->encdata_length = reallocated_length;
 1769:       size = BACKEND->encdata_length - BACKEND->encdata_offset;
 1770:       DEBUGF(infof(data, "schannel: encdata_buffer resized %zu\n",
 1771:                    BACKEND->encdata_length));
 1772:     }
 1773: 
 1774:     DEBUGF(infof(data,
 1775:                  "schannel: encrypted data buffer: offset %zu length %zu\n",
 1776:                  BACKEND->encdata_offset, BACKEND->encdata_length));
 1777: 
 1778:     /* read encrypted data from socket */
 1779:     *err = Curl_read_plain(conn->sock[sockindex],
 1780:                            (char *)(BACKEND->encdata_buffer +
 1781:                                     BACKEND->encdata_offset),
 1782:                            size, &nread);
 1783:     if(*err) {
 1784:       nread = -1;
 1785:       if(*err == CURLE_AGAIN)
 1786:         DEBUGF(infof(data,
 1787:                      "schannel: Curl_read_plain returned CURLE_AGAIN\n"));
 1788:       else if(*err == CURLE_RECV_ERROR)
 1789:         infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
 1790:       else
 1791:         infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
 1792:     }
 1793:     else if(nread == 0) {
 1794:       BACKEND->recv_connection_closed = true;
 1795:       DEBUGF(infof(data, "schannel: server closed the connection\n"));
 1796:     }
 1797:     else if(nread > 0) {
 1798:       BACKEND->encdata_offset += (size_t)nread;
 1799:       BACKEND->encdata_is_incomplete = false;
 1800:       DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
 1801:     }
 1802:   }
 1803: 
 1804:   DEBUGF(infof(data,
 1805:                "schannel: encrypted data buffer: offset %zu length %zu\n",
 1806:                BACKEND->encdata_offset, BACKEND->encdata_length));
 1807: 
 1808:   /* decrypt loop */
 1809:   while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
 1810:         (!len || BACKEND->decdata_offset < len ||
 1811:          BACKEND->recv_connection_closed)) {
 1812:     /* prepare data buffer for DecryptMessage call */
 1813:     InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
 1814:                   curlx_uztoul(BACKEND->encdata_offset));
 1815: 
 1816:     /* we need 3 more empty input buffers for possible output */
 1817:     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
 1818:     InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
 1819:     InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
 1820:     InitSecBufferDesc(&inbuf_desc, inbuf, 4);
 1821: 
 1822:     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
 1823:        */
 1824:     sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
 1825:                                            &inbuf_desc, 0, NULL);
 1826: 
 1827:     /* check if everything went fine (server may want to renegotiate
 1828:        or shutdown the connection context) */
 1829:     if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
 1830:        sspi_status == SEC_I_CONTEXT_EXPIRED) {
 1831:       /* check for successfully decrypted data, even before actual
 1832:          renegotiation or shutdown of the connection context */
 1833:       if(inbuf[1].BufferType == SECBUFFER_DATA) {
 1834:         DEBUGF(infof(data, "schannel: decrypted data length: %lu\n",
 1835:                      inbuf[1].cbBuffer));
 1836: 
 1837:         /* increase buffer in order to fit the received amount of data */
 1838:         size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
 1839:                inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
 1840:         if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
 1841:            BACKEND->decdata_length < len) {
 1842:           /* increase internal decrypted data buffer */
 1843:           reallocated_length = BACKEND->decdata_offset + size;
 1844:           /* make sure that the requested amount of data fits */
 1845:           if(reallocated_length < len) {
 1846:             reallocated_length = len;
 1847:           }
 1848:           reallocated_buffer = realloc(BACKEND->decdata_buffer,
 1849:                                        reallocated_length);
 1850:           if(reallocated_buffer == NULL) {
 1851:             *err = CURLE_OUT_OF_MEMORY;
 1852:             failf(data, "schannel: unable to re-allocate memory");
 1853:             goto cleanup;
 1854:           }
 1855:           BACKEND->decdata_buffer = reallocated_buffer;
 1856:           BACKEND->decdata_length = reallocated_length;
 1857:         }
 1858: 
 1859:         /* copy decrypted data to internal buffer */
 1860:         size = inbuf[1].cbBuffer;
 1861:         if(size) {
 1862:           memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
 1863:                  inbuf[1].pvBuffer, size);
 1864:           BACKEND->decdata_offset += size;
 1865:         }
 1866: 
 1867:         DEBUGF(infof(data, "schannel: decrypted data added: %zu\n", size));
 1868:         DEBUGF(infof(data,
 1869:                      "schannel: decrypted cached: offset %zu length %zu\n",
 1870:                      BACKEND->decdata_offset, BACKEND->decdata_length));
 1871:       }
 1872: 
 1873:       /* check for remaining encrypted data */
 1874:       if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
 1875:         DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
 1876:                      inbuf[3].cbBuffer));
 1877: 
 1878:         /* check if the remaining data is less than the total amount
 1879:          * and therefore begins after the already processed data
 1880:          */
 1881:         if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
 1882:           /* move remaining encrypted data forward to the beginning of
 1883:              buffer */
 1884:           memmove(BACKEND->encdata_buffer,
 1885:                   (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
 1886:                   inbuf[3].cbBuffer, inbuf[3].cbBuffer);
 1887:           BACKEND->encdata_offset = inbuf[3].cbBuffer;
 1888:         }
 1889: 
 1890:         DEBUGF(infof(data,
 1891:                      "schannel: encrypted cached: offset %zu length %zu\n",
 1892:                      BACKEND->encdata_offset, BACKEND->encdata_length));
 1893:       }
 1894:       else {
 1895:         /* reset encrypted buffer offset, because there is no data remaining */
 1896:         BACKEND->encdata_offset = 0;
 1897:       }
 1898: 
 1899:       /* check if server wants to renegotiate the connection context */
 1900:       if(sspi_status == SEC_I_RENEGOTIATE) {
 1901:         infof(data, "schannel: remote party requests renegotiation\n");
 1902:         if(*err && *err != CURLE_AGAIN) {
 1903:           infof(data, "schannel: can't renogotiate, an error is pending\n");
 1904:           goto cleanup;
 1905:         }
 1906:         if(BACKEND->encdata_offset) {
 1907:           *err = CURLE_RECV_ERROR;
 1908:           infof(data, "schannel: can't renogotiate, "
 1909:                       "encrypted data available\n");
 1910:           goto cleanup;
 1911:         }
 1912:         /* begin renegotiation */
 1913:         infof(data, "schannel: renegotiating SSL/TLS connection\n");
 1914:         connssl->state = ssl_connection_negotiating;
 1915:         connssl->connecting_state = ssl_connect_2_writing;
 1916:         *err = schannel_connect_common(conn, sockindex, FALSE, &done);
 1917:         if(*err) {
 1918:           infof(data, "schannel: renegotiation failed\n");
 1919:           goto cleanup;
 1920:         }
 1921:         /* now retry receiving data */
 1922:         sspi_status = SEC_E_OK;
 1923:         infof(data, "schannel: SSL/TLS connection renegotiated\n");
 1924:         continue;
 1925:       }
 1926:       /* check if the server closed the connection */
 1927:       else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
 1928:         /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
 1929:            returned so we have to work around that in cleanup. */
 1930:         BACKEND->recv_sspi_close_notify = true;
 1931:         if(!BACKEND->recv_connection_closed) {
 1932:           BACKEND->recv_connection_closed = true;
 1933:           infof(data, "schannel: server closed the connection\n");
 1934:         }
 1935:         goto cleanup;
 1936:       }
 1937:     }
 1938:     else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
 1939:       BACKEND->encdata_is_incomplete = true;
 1940:       if(!*err)
 1941:         *err = CURLE_AGAIN;
 1942:       infof(data, "schannel: failed to decrypt data, need more data\n");
 1943:       goto cleanup;
 1944:     }
 1945:     else {
 1946: #ifndef CURL_DISABLE_VERBOSE_STRINGS
 1947:       char buffer[STRERROR_LEN];
 1948: #endif
 1949:       *err = CURLE_RECV_ERROR;
 1950:       infof(data, "schannel: failed to read data from server: %s\n",
 1951:             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
 1952:       goto cleanup;
 1953:     }
 1954:   }
 1955: 
 1956:   DEBUGF(infof(data,
 1957:                "schannel: encrypted data buffer: offset %zu length %zu\n",
 1958:                BACKEND->encdata_offset, BACKEND->encdata_length));
 1959: 
 1960:   DEBUGF(infof(data,
 1961:                "schannel: decrypted data buffer: offset %zu length %zu\n",
 1962:                BACKEND->decdata_offset, BACKEND->decdata_length));
 1963: 
 1964: cleanup:
 1965:   /* Warning- there is no guarantee the encdata state is valid at this point */
 1966:   DEBUGF(infof(data, "schannel: schannel_recv cleanup\n"));
 1967: 
 1968:   /* Error if the connection has closed without a close_notify.
 1969:   Behavior here is a matter of debate. We don't want to be vulnerable to a
 1970:   truncation attack however there's some browser precedent for ignoring the
 1971:   close_notify for compatibility reasons.
 1972:   Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
 1973:   return close_notify. In that case if the connection was closed we assume it
 1974:   was graceful (close_notify) since there doesn't seem to be a way to tell.
 1975:   */
 1976:   if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
 1977:      !BACKEND->recv_sspi_close_notify) {
 1978:     bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
 1979:                                                VERSION_EQUAL);
 1980: 
 1981:     if(isWin2k && sspi_status == SEC_E_OK)
 1982:       BACKEND->recv_sspi_close_notify = true;
 1983:     else {
 1984:       *err = CURLE_RECV_ERROR;
 1985:       infof(data, "schannel: server closed abruptly (missing close_notify)\n");
 1986:     }
 1987:   }
 1988: 
 1989:   /* Any error other than CURLE_AGAIN is an unrecoverable error. */
 1990:   if(*err && *err != CURLE_AGAIN)
 1991:       BACKEND->recv_unrecoverable_err = *err;
 1992: 
 1993:   size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
 1994:   if(size) {
 1995:     memcpy(buf, BACKEND->decdata_buffer, size);
 1996:     memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
 1997:             BACKEND->decdata_offset - size);
 1998:     BACKEND->decdata_offset -= size;
 1999:     DEBUGF(infof(data, "schannel: decrypted data returned %zu\n", size));
 2000:     DEBUGF(infof(data,
 2001:                  "schannel: decrypted data buffer: offset %zu length %zu\n",
 2002:                  BACKEND->decdata_offset, BACKEND->decdata_length));
 2003:     *err = CURLE_OK;
 2004:     return (ssize_t)size;
 2005:   }
 2006: 
 2007:   if(!*err && !BACKEND->recv_connection_closed)
 2008:       *err = CURLE_AGAIN;
 2009: 
 2010:   /* It's debatable what to return when !len. We could return whatever error we
 2011:   got from decryption but instead we override here so the return is consistent.
 2012:   */
 2013:   if(!len)
 2014:     *err = CURLE_OK;
 2015: 
 2016:   return *err ? -1 : 0;
 2017: }
 2018: 
 2019: static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
 2020:                                                   int sockindex, bool *done)
 2021: {
 2022:   return schannel_connect_common(conn, sockindex, TRUE, done);
 2023: }
 2024: 
 2025: static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
 2026: {
 2027:   CURLcode result;
 2028:   bool done = FALSE;
 2029: 
 2030:   result = schannel_connect_common(conn, sockindex, FALSE, &done);
 2031:   if(result)
 2032:     return result;
 2033: 
 2034:   DEBUGASSERT(done);
 2035: 
 2036:   return CURLE_OK;
 2037: }
 2038: 
 2039: static bool Curl_schannel_data_pending(const struct connectdata *conn,
 2040:                                        int sockindex)
 2041: {
 2042:   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 2043: 
 2044:   if(connssl->use) /* SSL/TLS is in use */
 2045:     return (BACKEND->decdata_offset > 0 ||
 2046:             (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
 2047:   else
 2048:     return FALSE;
 2049: }
 2050: 
 2051: static void Curl_schannel_close(struct connectdata *conn, int sockindex)
 2052: {
 2053:   if(conn->ssl[sockindex].use)
 2054:     /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
 2055:     Curl_ssl_shutdown(conn, sockindex);
 2056: }
 2057: 
 2058: static void Curl_schannel_session_free(void *ptr)
 2059: {
 2060:   /* this is expected to be called under sessionid lock */
 2061:   struct curl_schannel_cred *cred = ptr;
 2062: 
 2063:   cred->refcount--;
 2064:   if(cred->refcount == 0) {
 2065:     s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
 2066:     Curl_safefree(cred);
 2067:   }
 2068: }
 2069: 
 2070: static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
 2071: {
 2072:   /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
 2073:    * Shutting Down an Schannel Connection
 2074:    */
 2075:   struct Curl_easy *data = conn->data;
 2076:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 2077:   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
 2078:     conn->host.name;
 2079: 
 2080:   DEBUGASSERT(data);
 2081: 
 2082:   infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
 2083:         hostname, conn->remote_port);
 2084: 
 2085:   if(BACKEND->cred && BACKEND->ctxt) {
 2086:     SecBufferDesc BuffDesc;
 2087:     SecBuffer Buffer;
 2088:     SECURITY_STATUS sspi_status;
 2089:     SecBuffer outbuf;
 2090:     SecBufferDesc outbuf_desc;
 2091:     CURLcode result;
 2092:     TCHAR *host_name;
 2093:     DWORD dwshut = SCHANNEL_SHUTDOWN;
 2094: 
 2095:     InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
 2096:     InitSecBufferDesc(&BuffDesc, &Buffer, 1);
 2097: 
 2098:     sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
 2099:                                               &BuffDesc);
 2100: 
 2101:     if(sspi_status != SEC_E_OK) {
 2102:       char buffer[STRERROR_LEN];
 2103:       failf(data, "schannel: ApplyControlToken failure: %s",
 2104:             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
 2105:     }
 2106: 
 2107:     host_name = Curl_convert_UTF8_to_tchar(hostname);
 2108:     if(!host_name)
 2109:       return CURLE_OUT_OF_MEMORY;
 2110: 
 2111:     /* setup output buffer */
 2112:     InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
 2113:     InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
 2114: 
 2115:     sspi_status = s_pSecFn->InitializeSecurityContext(
 2116:       &BACKEND->cred->cred_handle,
 2117:       &BACKEND->ctxt->ctxt_handle,
 2118:       host_name,
 2119:       BACKEND->req_flags,
 2120:       0,
 2121:       0,
 2122:       NULL,
 2123:       0,
 2124:       &BACKEND->ctxt->ctxt_handle,
 2125:       &outbuf_desc,
 2126:       &BACKEND->ret_flags,
 2127:       &BACKEND->ctxt->time_stamp);
 2128: 
 2129:     Curl_unicodefree(host_name);
 2130: 
 2131:     if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
 2132:       /* send close message which is in output buffer */
 2133:       ssize_t written;
 2134:       result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
 2135:                                 outbuf.cbBuffer, &written);
 2136: 
 2137:       s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
 2138:       if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
 2139:         infof(data, "schannel: failed to send close msg: %s"
 2140:               " (bytes written: %zd)\n", curl_easy_strerror(result), written);
 2141:       }
 2142:     }
 2143:   }
 2144: 
 2145:   /* free SSPI Schannel API security context handle */
 2146:   if(BACKEND->ctxt) {
 2147:     DEBUGF(infof(data, "schannel: clear security context handle\n"));
 2148:     s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
 2149:     Curl_safefree(BACKEND->ctxt);
 2150:   }
 2151: 
 2152:   /* free SSPI Schannel API credential handle */
 2153:   if(BACKEND->cred) {
 2154:     /*
 2155:      * When this function is called from Curl_schannel_close() the connection
 2156:      * might not have an associated transfer so the check for conn->data is
 2157:      * necessary.
 2158:      */
 2159:     Curl_ssl_sessionid_lock(conn);
 2160:     Curl_schannel_session_free(BACKEND->cred);
 2161:     Curl_ssl_sessionid_unlock(conn);
 2162:     BACKEND->cred = NULL;
 2163:   }
 2164: 
 2165:   /* free internal buffer for received encrypted data */
 2166:   if(BACKEND->encdata_buffer != NULL) {
 2167:     Curl_safefree(BACKEND->encdata_buffer);
 2168:     BACKEND->encdata_length = 0;
 2169:     BACKEND->encdata_offset = 0;
 2170:     BACKEND->encdata_is_incomplete = false;
 2171:   }
 2172: 
 2173:   /* free internal buffer for received decrypted data */
 2174:   if(BACKEND->decdata_buffer != NULL) {
 2175:     Curl_safefree(BACKEND->decdata_buffer);
 2176:     BACKEND->decdata_length = 0;
 2177:     BACKEND->decdata_offset = 0;
 2178:   }
 2179: 
 2180:   return CURLE_OK;
 2181: }
 2182: 
 2183: static int Curl_schannel_init(void)
 2184: {
 2185:   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
 2186: }
 2187: 
 2188: static void Curl_schannel_cleanup(void)
 2189: {
 2190:   Curl_sspi_global_cleanup();
 2191: }
 2192: 
 2193: static size_t Curl_schannel_version(char *buffer, size_t size)
 2194: {
 2195:   size = msnprintf(buffer, size, "Schannel");
 2196: 
 2197:   return size;
 2198: }
 2199: 
 2200: static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
 2201:                                      unsigned char *entropy, size_t length)
 2202: {
 2203:   HCRYPTPROV hCryptProv = 0;
 2204: 
 2205:   (void)data;
 2206: 
 2207:   if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
 2208:                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
 2209:     return CURLE_FAILED_INIT;
 2210: 
 2211:   if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
 2212:     CryptReleaseContext(hCryptProv, 0UL);
 2213:     return CURLE_FAILED_INIT;
 2214:   }
 2215: 
 2216:   CryptReleaseContext(hCryptProv, 0UL);
 2217:   return CURLE_OK;
 2218: }
 2219: 
 2220: static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
 2221:                                     const char *pinnedpubkey)
 2222: {
 2223:   struct Curl_easy *data = conn->data;
 2224:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 2225:   CERT_CONTEXT *pCertContextServer = NULL;
 2226: 
 2227:   /* Result is returned to caller */
 2228:   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
 2229: 
 2230:   /* if a path wasn't specified, don't pin */
 2231:   if(!pinnedpubkey)
 2232:     return CURLE_OK;
 2233: 
 2234:   do {
 2235:     SECURITY_STATUS sspi_status;
 2236:     const char *x509_der;
 2237:     DWORD x509_der_len;
 2238:     curl_X509certificate x509_parsed;
 2239:     curl_asn1Element *pubkey;
 2240: 
 2241:     sspi_status =
 2242:       s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
 2243:                                        SECPKG_ATTR_REMOTE_CERT_CONTEXT,
 2244:                                        &pCertContextServer);
 2245: 
 2246:     if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) {
 2247:       char buffer[STRERROR_LEN];
 2248:       failf(data, "schannel: Failed to read remote certificate context: %s",
 2249:             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
 2250:       break; /* failed */
 2251:     }
 2252: 
 2253: 
 2254:     if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
 2255:        (pCertContextServer->cbCertEncoded > 0)))
 2256:       break;
 2257: 
 2258:     x509_der = (const char *)pCertContextServer->pbCertEncoded;
 2259:     x509_der_len = pCertContextServer->cbCertEncoded;
 2260:     memset(&x509_parsed, 0, sizeof(x509_parsed));
 2261:     if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
 2262:       break;
 2263: 
 2264:     pubkey = &x509_parsed.subjectPublicKeyInfo;
 2265:     if(!pubkey->header || pubkey->end <= pubkey->header) {
 2266:       failf(data, "SSL: failed retrieving public key from server certificate");
 2267:       break;
 2268:     }
 2269: 
 2270:     result = Curl_pin_peer_pubkey(data,
 2271:                                   pinnedpubkey,
 2272:                                   (const unsigned char *)pubkey->header,
 2273:                                   (size_t)(pubkey->end - pubkey->header));
 2274:     if(result) {
 2275:       failf(data, "SSL: public key does not match pinned public key!");
 2276:     }
 2277:   } while(0);
 2278: 
 2279:   if(pCertContextServer)
 2280:     CertFreeCertificateContext(pCertContextServer);
 2281: 
 2282:   return result;
 2283: }
 2284: 
 2285: static void Curl_schannel_checksum(const unsigned char *input,
 2286:                                    size_t inputlen,
 2287:                                    unsigned char *checksum,
 2288:                                    size_t checksumlen,
 2289:                                    DWORD provType,
 2290:                                    const unsigned int algId)
 2291: {
 2292:   HCRYPTPROV hProv = 0;
 2293:   HCRYPTHASH hHash = 0;
 2294:   DWORD cbHashSize = 0;
 2295:   DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
 2296:   DWORD dwChecksumLen = (DWORD)checksumlen;
 2297: 
 2298:   /* since this can fail in multiple ways, zero memory first so we never
 2299:    * return old data
 2300:    */
 2301:   memset(checksum, 0, checksumlen);
 2302: 
 2303:   if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
 2304:                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
 2305:     return; /* failed */
 2306: 
 2307:   do {
 2308:     if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
 2309:       break; /* failed */
 2310: 
 2311:     /* workaround for original MinGW, should be (const BYTE*) */
 2312:     if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0))
 2313:       break; /* failed */
 2314: 
 2315:     /* get hash size */
 2316:     if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
 2317:                           &dwHashSizeLen, 0))
 2318:       break; /* failed */
 2319: 
 2320:     /* check hash size */
 2321:     if(checksumlen < cbHashSize)
 2322:       break; /* failed */
 2323: 
 2324:     if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
 2325:       break; /* failed */
 2326:   } while(0);
 2327: 
 2328:   if(hHash)
 2329:     CryptDestroyHash(hHash);
 2330: 
 2331:   if(hProv)
 2332:     CryptReleaseContext(hProv, 0);
 2333: }
 2334: 
 2335: static CURLcode Curl_schannel_md5sum(unsigned char *input,
 2336:                                      size_t inputlen,
 2337:                                      unsigned char *md5sum,
 2338:                                      size_t md5len)
 2339: {
 2340:   Curl_schannel_checksum(input, inputlen, md5sum, md5len,
 2341:                          PROV_RSA_FULL, CALG_MD5);
 2342:   return CURLE_OK;
 2343: }
 2344: 
 2345: static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
 2346:                                     size_t inputlen,
 2347:                                     unsigned char *sha256sum,
 2348:                                     size_t sha256len)
 2349: {
 2350:   Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
 2351:                          PROV_RSA_AES, CALG_SHA_256);
 2352:   return CURLE_OK;
 2353: }
 2354: 
 2355: static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
 2356:                                          CURLINFO info UNUSED_PARAM)
 2357: {
 2358:   (void)info;
 2359:   return &BACKEND->ctxt->ctxt_handle;
 2360: }
 2361: 
 2362: const struct Curl_ssl Curl_ssl_schannel = {
 2363:   { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
 2364: 
 2365:   SSLSUPP_CERTINFO |
 2366:   SSLSUPP_PINNEDPUBKEY,
 2367: 
 2368:   sizeof(struct ssl_backend_data),
 2369: 
 2370:   Curl_schannel_init,                /* init */
 2371:   Curl_schannel_cleanup,             /* cleanup */
 2372:   Curl_schannel_version,             /* version */
 2373:   Curl_none_check_cxn,               /* check_cxn */
 2374:   Curl_schannel_shutdown,            /* shutdown */
 2375:   Curl_schannel_data_pending,        /* data_pending */
 2376:   Curl_schannel_random,              /* random */
 2377:   Curl_none_cert_status_request,     /* cert_status_request */
 2378:   Curl_schannel_connect,             /* connect */
 2379:   Curl_schannel_connect_nonblocking, /* connect_nonblocking */
 2380:   Curl_schannel_get_internals,       /* get_internals */
 2381:   Curl_schannel_close,               /* close_one */
 2382:   Curl_none_close_all,               /* close_all */
 2383:   Curl_schannel_session_free,        /* session_free */
 2384:   Curl_none_set_engine,              /* set_engine */
 2385:   Curl_none_set_engine_default,      /* set_engine_default */
 2386:   Curl_none_engines_list,            /* engines_list */
 2387:   Curl_none_false_start,             /* false_start */
 2388:   Curl_schannel_md5sum,              /* md5sum */
 2389:   Curl_schannel_sha256sum            /* sha256sum */
 2390: };
 2391: 
 2392: #endif /* USE_SCHANNEL */

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