Annotation of embedaddon/curl/lib/vtls/schannel.c, revision 1.1

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