zoukankan      html  css  js  c++  java
  • Windows C++ TLS 实现连接163邮箱

      1 // Compiles with Visual Studio 2008 for Windows
      2 
      3 // This C example is designed as more of a guide than a library to be plugged into an application
      4 // That module required a couple of major re-writes and is available upon request
      5 // The Basic example has tips to the direction you should take
      6 // This will work with connections on port 587 that upgrade a plain text session to an encrypted session with STARTTLS as covered here.
      7 
      8 // TLSclient.c - SSPI Schannel gmail TLS connection example
      9 
     10 #define _CRT_SECURE_NO_WARNINGS
     11 
     12 #define SECURITY_WIN32
     13 #define IO_BUFFER_SIZE  0x10000
     14 #define DLL_NAME TEXT("Secur32.dll")
     15 #define NT4_DLL_NAME TEXT("Security.dll")
     16 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <windows.h>
     20 #include <winsock.h>
     21 #include <wincrypt.h>
     22 #include <wintrust.h>
     23 #include <schannel.h>
     24 #include <security.h>
     25 #include <sspi.h>
     26 
     27 #pragma comment(lib, "WSock32.Lib")
     28 #pragma comment(lib, "Crypt32.Lib")
     29 #pragma comment(lib, "user32.lib")
     30 #pragma comment(lib, "MSVCRTD.lib")
     31 
     32 // Globals.
     33 BOOL    fVerbose = FALSE; // FALSE; // TRUE;
     34 
     35 
     36 INT     iPortNumber = 465; // gmail TLS
     37 LPCSTR   pszServerName = "smtp.163.com"; // DNS name of server
     38 LPCSTR   pszUser = 0; // if specified, a certificate in "MY" store is searched for
     39 
     40 DWORD   dwProtocol = SP_PROT_TLS1; // SP_PROT_TLS1; // SP_PROT_PCT1; SP_PROT_SSL2; SP_PROT_SSL3; 0=default
     41 ALG_ID  aiKeyExch = 0; // = default; CALG_DH_EPHEM; CALG_RSA_KEYX;
     42 
     43 BOOL    fUseProxy = FALSE;
     44 LPCSTR   pszProxyServer = "proxy";
     45 INT     iProxyPort = 80;
     46 
     47 HCERTSTORE hMyCertStore = NULL;
     48 HMODULE g_hSecurity = NULL;
     49 
     50 SCHANNEL_CRED SchannelCred;
     51 PSecurityFunctionTable g_pSSPI;
     52 
     53 
     54 
     55 /*****************************************************************************/
     56 static void DisplayWinVerifyTrustError(DWORD Status)
     57 {
     58     LPCSTR pszName = NULL;
     59 
     60     switch (Status)
     61     {
     62     case CERT_E_EXPIRED:                pszName = "CERT_E_EXPIRED";                 break;
     63     case CERT_E_VALIDITYPERIODNESTING:  pszName = "CERT_E_VALIDITYPERIODNESTING";   break;
     64     case CERT_E_ROLE:                   pszName = "CERT_E_ROLE";                    break;
     65     case CERT_E_PATHLENCONST:           pszName = "CERT_E_PATHLENCONST";            break;
     66     case CERT_E_CRITICAL:               pszName = "CERT_E_CRITICAL";                break;
     67     case CERT_E_PURPOSE:                pszName = "CERT_E_PURPOSE";                 break;
     68     case CERT_E_ISSUERCHAINING:         pszName = "CERT_E_ISSUERCHAINING";          break;
     69     case CERT_E_MALFORMED:              pszName = "CERT_E_MALFORMED";               break;
     70     case CERT_E_UNTRUSTEDROOT:          pszName = "CERT_E_UNTRUSTEDROOT";           break;
     71     case CERT_E_CHAINING:               pszName = "CERT_E_CHAINING";                break;
     72     case TRUST_E_FAIL:                  pszName = "TRUST_E_FAIL";                   break;
     73     case CERT_E_REVOKED:                pszName = "CERT_E_REVOKED";                 break;
     74     case CERT_E_UNTRUSTEDTESTROOT:      pszName = "CERT_E_UNTRUSTEDTESTROOT";       break;
     75     case CERT_E_REVOCATION_FAILURE:     pszName = "CERT_E_REVOCATION_FAILURE";      break;
     76     case CERT_E_CN_NO_MATCH:            pszName = "CERT_E_CN_NO_MATCH";             break;
     77     case CERT_E_WRONG_USAGE:            pszName = "CERT_E_WRONG_USAGE";             break;
     78     default:                            pszName = "(unknown)";                      break;
     79     }
     80     printf("Error 0x%x (%s) returned by CertVerifyCertificateChainPolicy!
    ", Status, pszName);
     81 }
     82 
     83 
     84 /*****************************************************************************/
     85 static void DisplayWinSockError(DWORD ErrCode)
     86 {
     87     LPCSTR pszName = NULL; // http://www.sockets.com/err_lst1.htm#WSANO_DATA
     88 
     89     switch (ErrCode) // http://msdn.microsoft.com/en-us/library/ms740668(VS.85).aspx
     90     {
     91     case     10035:  pszName = "WSAEWOULDBLOCK    "; break;
     92     case     10036:  pszName = "WSAEINPROGRESS    "; break;
     93     case     10037:  pszName = "WSAEALREADY       "; break;
     94     case     10038:  pszName = "WSAENOTSOCK       "; break;
     95     case     10039:  pszName = "WSAEDESTADDRREQ   "; break;
     96     case     10040:  pszName = "WSAEMSGSIZE       "; break;
     97     case     10041:  pszName = "WSAEPROTOTYPE     "; break;
     98     case     10042:  pszName = "WSAENOPROTOOPT    "; break;
     99     case  10043:  pszName = "WSAEPROTONOSUPPORT"; break;
    100     case  10044:  pszName = "WSAESOCKTNOSUPPORT"; break;
    101     case     10045:  pszName = "WSAEOPNOTSUPP     "; break;
    102     case     10046:  pszName = "WSAEPFNOSUPPORT   "; break;
    103     case     10047:  pszName = "WSAEAFNOSUPPORT   "; break;
    104     case     10048:  pszName = "WSAEADDRINUSE     "; break;
    105     case     10049:  pszName = "WSAEADDRNOTAVAIL  "; break;
    106     case     10050:  pszName = "WSAENETDOWN       "; break;
    107     case     10051:  pszName = "WSAENETUNREACH    "; break;
    108     case     10052:  pszName = "WSAENETRESET      "; break;
    109     case     10053:  pszName = "WSAECONNABORTED   "; break;
    110     case     10054:  pszName = "WSAECONNRESET     "; break;
    111     case     10055:  pszName = "WSAENOBUFS        "; break;
    112     case     10056:  pszName = "WSAEISCONN        "; break;
    113     case     10057:  pszName = "WSAENOTCONN       "; break;
    114     case     10058:  pszName = "WSAESHUTDOWN      "; break;
    115     case     10059:  pszName = "WSAETOOMANYREFS   "; break;
    116     case     10060:  pszName = "WSAETIMEDOUT      "; break;
    117     case     10061:  pszName = "WSAECONNREFUSED   "; break;
    118     case     10062:  pszName = "WSAELOOP          "; break;
    119     case     10063:  pszName = "WSAENAMETOOLONG   "; break;
    120     case     10064:  pszName = "WSAEHOSTDOWN      "; break;
    121     case     10065:  pszName = "WSAEHOSTUNREACH   "; break;
    122     case     10066:  pszName = "WSAENOTEMPTY      "; break;
    123     case     10067:  pszName = "WSAEPROCLIM       "; break;
    124     case     10068:  pszName = "WSAEUSERS         "; break;
    125     case     10069:  pszName = "WSAEDQUOT         "; break;
    126     case     10070:  pszName = "WSAESTALE         "; break;
    127     case     10071:  pszName = "WSAEREMOTE        "; break;
    128     case     10091:  pszName = "WSASYSNOTREADY    "; break;
    129     case  10092:  pszName = "WSAVERNOTSUPPORTED"; break;
    130     case     10093:  pszName = "WSANOTINITIALISED "; break;
    131     case     11001:  pszName = "WSAHOST_NOT_FOUND "; break;
    132     case     11002:  pszName = "WSATRY_AGAIN      "; break;
    133     case     11003:  pszName = "WSANO_RECOVERY    "; break;
    134     case     11004:  pszName = "WSANO_DATA        "; break;
    135     }
    136     printf("Error 0x%x (%s)
    ", ErrCode, pszName);
    137 }
    138 
    139 /*****************************************************************************/
    140 static void DisplaySECError(DWORD ErrCode)
    141 {
    142     LPCSTR pszName = NULL; // WinError.h
    143 
    144     switch (ErrCode)
    145     {
    146     case     SEC_E_BUFFER_TOO_SMALL:
    147         pszName = "SEC_E_BUFFER_TOO_SMALL - The message buffer is too small. Used with the Digest SSP.";
    148         break;
    149 
    150     case     SEC_E_CRYPTO_SYSTEM_INVALID:
    151         pszName = "SEC_E_CRYPTO_SYSTEM_INVALID - The cipher chosen for the security context is not supported. Used with the Digest SSP.";
    152         break;
    153     case     SEC_E_INCOMPLETE_MESSAGE:
    154         pszName = "SEC_E_INCOMPLETE_MESSAGE - The data in the input buffer is incomplete. The application needs to read more data from the server and call DecryptMessage (General) again.";
    155         break;
    156 
    157     case     SEC_E_INVALID_HANDLE:
    158         pszName = "SEC_E_INVALID_HANDLE - A context handle that is not valid was specified in the phContext parameter. Used with the Digest and Schannel SSPs.";
    159         break;
    160 
    161     case     SEC_E_INVALID_TOKEN:
    162         pszName = "SEC_E_INVALID_TOKEN - The buffers are of the wrong type or no buffer of type SECBUFFER_DATA was found. Used with the Schannel SSP.";
    163         break;
    164 
    165     case     SEC_E_MESSAGE_ALTERED:
    166         pszName = "SEC_E_MESSAGE_ALTERED - The message has been altered. Used with the Digest and Schannel SSPs.";
    167         break;
    168 
    169     case     SEC_E_OUT_OF_SEQUENCE:
    170         pszName = "SEC_E_OUT_OF_SEQUENCE - The message was not received in the correct sequence.";
    171         break;
    172 
    173     case     SEC_E_QOP_NOT_SUPPORTED:
    174         pszName = "SEC_E_QOP_NOT_SUPPORTED - Neither confidentiality nor integrity are supported by the security context. Used with the Digest SSP.";
    175         break;
    176 
    177     case     SEC_I_CONTEXT_EXPIRED:
    178         pszName = "SEC_I_CONTEXT_EXPIRED - The message sender has finished using the connection and has initiated a shutdown.";
    179         break;
    180 
    181     case     SEC_I_RENEGOTIATE:
    182         pszName = "SEC_I_RENEGOTIATE - The remote party requires a new handshake sequence or the application has just initiated a shutdown.";
    183         break;
    184 
    185     case     SEC_E_ENCRYPT_FAILURE:
    186         pszName = "SEC_E_ENCRYPT_FAILURE - The specified data could not be encrypted.";
    187         break;
    188 
    189     case     SEC_E_DECRYPT_FAILURE:
    190         pszName = "SEC_E_DECRYPT_FAILURE - The specified data could not be decrypted.";
    191         break;
    192 
    193     }
    194     printf("Error 0x%x %s 
    ", ErrCode, pszName);
    195 }
    196 
    197 
    198 
    199 /*****************************************************************************/
    200 static void DisplayCertChain(PCCERT_CONTEXT  pServerCert, BOOL fLocal)
    201 {
    202     CHAR szName[1000];
    203     PCCERT_CONTEXT pCurrentCert, pIssuerCert;
    204     DWORD dwVerificationFlags;
    205 
    206     printf("
    ");
    207 
    208     // display leaf name
    209     if (!CertNameToStr(pServerCert->dwCertEncodingType,
    210         &pServerCert->pCertInfo->Subject,
    211         CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
    212         szName, sizeof(szName)))
    213     {
    214         printf("**** Error 0x%x building subject name
    ", GetLastError());
    215     }
    216 
    217     if (fLocal) printf("Client subject: %s
    ", szName);
    218     else printf("Server subject: %s
    ", szName);
    219 
    220     if (!CertNameToStr(pServerCert->dwCertEncodingType,
    221         &pServerCert->pCertInfo->Issuer,
    222         CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
    223         szName, sizeof(szName)))
    224     {
    225         printf("**** Error 0x%x building issuer name
    ", GetLastError());
    226     }
    227 
    228     if (fLocal) printf("Client issuer: %s
    ", szName);
    229     else printf("Server issuer: %s
    
    ", szName);
    230 
    231 
    232     // display certificate chain
    233     pCurrentCert = pServerCert;
    234     while (pCurrentCert != NULL)
    235     {
    236         dwVerificationFlags = 0;
    237         pIssuerCert = CertGetIssuerCertificateFromStore(pServerCert->hCertStore, pCurrentCert, NULL, &dwVerificationFlags);
    238         if (pIssuerCert == NULL)
    239         {
    240             if (pCurrentCert != pServerCert) CertFreeCertificateContext(pCurrentCert);
    241             break;
    242         }
    243 
    244         if (!CertNameToStr(pIssuerCert->dwCertEncodingType,
    245             &pIssuerCert->pCertInfo->Subject,
    246             CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
    247             szName, sizeof(szName)))
    248         {
    249             printf("**** Error 0x%x building subject name
    ", GetLastError());
    250         }
    251 
    252         printf("CA subject: %s
    ", szName);
    253 
    254         if (!CertNameToStr(pIssuerCert->dwCertEncodingType,
    255             &pIssuerCert->pCertInfo->Issuer,
    256             CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
    257             szName, sizeof(szName)))
    258         {
    259             printf("**** Error 0x%x building issuer name
    ", GetLastError());
    260         }
    261 
    262         printf("CA issuer: %s
    
    ", szName);
    263 
    264         if (pCurrentCert != pServerCert) CertFreeCertificateContext(pCurrentCert);
    265         pCurrentCert = pIssuerCert;
    266         pIssuerCert = NULL;
    267     }
    268 }
    269 
    270 /*****************************************************************************/
    271 static void DisplayConnectionInfo(CtxtHandle *phContext)
    272 {
    273 
    274     SECURITY_STATUS Status;
    275     SecPkgContext_ConnectionInfo ConnectionInfo;
    276 
    277     Status = g_pSSPI->QueryContextAttributes(phContext, SECPKG_ATTR_CONNECTION_INFO, (PVOID)&ConnectionInfo);
    278     if (Status != SEC_E_OK) { printf("Error 0x%x querying connection info
    ", Status); return; }
    279 
    280     printf("
    ");
    281 
    282     switch (ConnectionInfo.dwProtocol)
    283     {
    284     case SP_PROT_TLS1_CLIENT:
    285         printf("Protocol: TLS1
    ");
    286         break;
    287 
    288     case SP_PROT_SSL3_CLIENT:
    289         printf("Protocol: SSL3
    ");
    290         break;
    291 
    292     case SP_PROT_PCT1_CLIENT:
    293         printf("Protocol: PCT
    ");
    294         break;
    295 
    296     case SP_PROT_SSL2_CLIENT:
    297         printf("Protocol: SSL2
    ");
    298         break;
    299 
    300     default:
    301         printf("Protocol: 0x%x
    ", ConnectionInfo.dwProtocol);
    302     }
    303 
    304     switch (ConnectionInfo.aiCipher)
    305     {
    306     case CALG_RC4:
    307         printf("Cipher: RC4
    ");
    308         break;
    309 
    310     case CALG_3DES:
    311         printf("Cipher: Triple DES
    ");
    312         break;
    313 
    314     case CALG_RC2:
    315         printf("Cipher: RC2
    ");
    316         break;
    317 
    318     case CALG_DES:
    319     case CALG_CYLINK_MEK:
    320         printf("Cipher: DES
    ");
    321         break;
    322 
    323     case CALG_SKIPJACK:
    324         printf("Cipher: Skipjack
    ");
    325         break;
    326 
    327     default:
    328         printf("Cipher: 0x%x
    ", ConnectionInfo.aiCipher);
    329     }
    330 
    331     printf("Cipher strength: %d
    ", ConnectionInfo.dwCipherStrength);
    332 
    333     switch (ConnectionInfo.aiHash)
    334     {
    335     case CALG_MD5:
    336         printf("Hash: MD5
    ");
    337         break;
    338 
    339     case CALG_SHA:
    340         printf("Hash: SHA
    ");
    341         break;
    342 
    343     default:
    344         printf("Hash: 0x%x
    ", ConnectionInfo.aiHash);
    345     }
    346 
    347     printf("Hash strength: %d
    ", ConnectionInfo.dwHashStrength);
    348 
    349     switch (ConnectionInfo.aiExch)
    350     {
    351     case CALG_RSA_KEYX:
    352     case CALG_RSA_SIGN:
    353         printf("Key exchange: RSA
    ");
    354         break;
    355 
    356     case CALG_KEA_KEYX:
    357         printf("Key exchange: KEA
    ");
    358         break;
    359 
    360     case CALG_DH_EPHEM:
    361         printf("Key exchange: DH Ephemeral
    ");
    362         break;
    363 
    364     default:
    365         printf("Key exchange: 0x%x
    ", ConnectionInfo.aiExch);
    366     }
    367 
    368     printf("Key exchange strength: %d
    ", ConnectionInfo.dwExchStrength);
    369 }
    370 
    371 
    372 /*****************************************************************************/
    373 static void PrintHexDump(DWORD length, PBYTE buffer)
    374 {
    375     DWORD i, count, index;
    376     CHAR rgbDigits[] = "0123456789abcdef";
    377     CHAR rgbLine[100];
    378     char cbLine;
    379 
    380     for (index = 0; length; length -= count, buffer += count, index += count)
    381     {
    382         count = (length > 16) ? 16 : length;
    383         sprintf(rgbLine, "%4.4x  ", index);
    384         cbLine = 6;
    385 
    386         for (i = 0; i < count; i++)
    387         {
    388             rgbLine[cbLine++] = rgbDigits[buffer[i] >> 4];
    389             rgbLine[cbLine++] = rgbDigits[buffer[i] & 0x0f];
    390             if (i == 7) rgbLine[cbLine++] = ':';
    391             else rgbLine[cbLine++] = ' ';
    392         }
    393         for (; i < 16; i++)
    394         {
    395             rgbLine[cbLine++] = ' ';
    396             rgbLine[cbLine++] = ' ';
    397             rgbLine[cbLine++] = ' ';
    398         }
    399         rgbLine[cbLine++] = ' ';
    400 
    401         for (i = 0; i < count; i++)
    402         {
    403             if (buffer[i] < 32 || buffer[i] > 126 || buffer[i] == '%') rgbLine[cbLine++] = '.';
    404             else rgbLine[cbLine++] = buffer[i];
    405         }
    406         rgbLine[cbLine++] = 0;
    407         printf("%s
    ", rgbLine);
    408     }
    409 }
    410 
    411 /*****************************************************************************/
    412 static void PrintText(DWORD length, PBYTE buffer) // handle unprintable charaters
    413 {
    414     int i; //
    415 
    416     printf("
    "); // "length = %d bytes 
    ", length);
    417     for (i = 0; i < (int)length; i++)
    418     {
    419         if (buffer[i] == 10 || buffer[i] == 13)
    420             printf("%c", (char)buffer[i]);
    421         else if (buffer[i] < 32 || buffer[i] > 126 || buffer[i] == '%')
    422             printf("%c", '.');
    423         else
    424             printf("%c", (char)buffer[i]);
    425     }
    426     printf("
    ");
    427 }
    428 
    429 
    430 
    431 /*****************************************************************************/
    432 static void WriteDataToFile(PSTR pszData, PBYTE pbData, DWORD cbData)
    433 {
    434     FILE *file;
    435 
    436     file = fopen(pszData, "wb");
    437     if (file == NULL)
    438     {
    439         printf("**** Error opening file '%s'
    ", pszData); return;
    440     }
    441 
    442     if (fwrite(pbData, 1, cbData, file) != cbData)
    443     {
    444         printf("**** Error writing to file
    "); return;
    445     }
    446 
    447     fclose(file);
    448 }
    449 
    450 
    451 
    452 
    453 
    454 /*****************************************************************************/
    455 BOOL LoadSecurityLibrary(void) // load SSPI.DLL, set up a special table - PSecurityFunctionTable
    456 {
    457     INIT_SECURITY_INTERFACE pInitSecurityInterface;
    458     //  QUERY_CREDENTIALS_ATTRIBUTES_FN pQueryCredentialsAttributes;
    459     OSVERSIONINFO VerInfo;
    460     UCHAR lpszDLL[MAX_PATH];
    461 
    462 
    463     //  Find out which security DLL to use, depending on
    464     //  whether we are on Win2K, NT or Win9x
    465     VerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    466 
    467     if (!GetVersionEx(&VerInfo)) return FALSE;
    468 
    469     if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && VerInfo.dwMajorVersion == 4)
    470     {
    471         strcpy((char*)lpszDLL, NT4_DLL_NAME); // NT4_DLL_NAME TEXT("Security.dll")
    472     }
    473     else if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ||
    474         VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
    475     {
    476         strcpy((char*)lpszDLL, DLL_NAME); // DLL_NAME TEXT("Secur32.dll")
    477     }
    478     else
    479     {
    480         printf("System not recognized
    "); return FALSE;
    481     }
    482 
    483 
    484     //  Load Security DLL
    485     g_hSecurity = LoadLibrary((char*)lpszDLL);
    486     if (g_hSecurity == NULL) { printf("Error 0x%x loading %s.
    ", GetLastError(), lpszDLL); return FALSE; }
    487 
    488     pInitSecurityInterface = (INIT_SECURITY_INTERFACE)GetProcAddress(g_hSecurity, "InitSecurityInterfaceA");
    489     if (pInitSecurityInterface == NULL) { printf("Error 0x%x reading InitSecurityInterface entry point.
    ", GetLastError()); return FALSE; }
    490 
    491     g_pSSPI = pInitSecurityInterface(); // call InitSecurityInterfaceA(void);
    492     if (g_pSSPI == NULL) { printf("Error 0x%x reading security interface.
    ", GetLastError()); return FALSE; }
    493 
    494     return TRUE; // and PSecurityFunctionTable
    495 }
    496 
    497 
    498 /*****************************************************************************/
    499 void UnloadSecurityLibrary(void)
    500 {
    501     FreeLibrary(g_hSecurity);
    502     g_hSecurity = NULL;
    503 }
    504 
    505 
    506 /*****************************************************************************/
    507 static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PSTR pszServerName, DWORD dwCertFlags)
    508 {
    509     HTTPSPolicyCallbackData  polHttps;
    510     CERT_CHAIN_POLICY_PARA   PolicyPara;
    511     CERT_CHAIN_POLICY_STATUS PolicyStatus;
    512     CERT_CHAIN_PARA          ChainPara;
    513     PCCERT_CHAIN_CONTEXT     pChainContext = NULL;
    514     DWORD                                         cchServerName, Status;
    515     LPSTR rgszUsages[] = { (char*)szOID_PKIX_KP_SERVER_AUTH,
    516                                (char*)szOID_SERVER_GATED_CRYPTO,
    517                                (char*)szOID_SGC_NETSCAPE };
    518 
    519     DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
    520 
    521     PWSTR   pwszServerName = NULL;
    522 
    523 
    524     if (pServerCert == NULL)
    525     {
    526         Status = SEC_E_WRONG_PRINCIPAL; goto cleanup;
    527     }
    528 
    529     // Convert server name to unicode.
    530     if (pszServerName == NULL || strlen(pszServerName) == 0)
    531     {
    532         Status = SEC_E_WRONG_PRINCIPAL; goto cleanup;
    533     }
    534 
    535     cchServerName = MultiByteToWideChar(CP_ACP, 0, pszServerName, -1, NULL, 0);
    536     pwszServerName = (PWSTR)LocalAlloc(LMEM_FIXED, cchServerName * sizeof(WCHAR));
    537     if (pwszServerName == NULL)
    538     {
    539         Status = SEC_E_INSUFFICIENT_MEMORY; goto cleanup;
    540     }
    541 
    542     cchServerName = MultiByteToWideChar(CP_ACP, 0, pszServerName, -1, pwszServerName, cchServerName);
    543     if (cchServerName == 0)
    544     {
    545         Status = SEC_E_WRONG_PRINCIPAL; goto cleanup;
    546     }
    547 
    548 
    549     // Build certificate chain.
    550     ZeroMemory(&ChainPara, sizeof(ChainPara));
    551     ChainPara.cbSize = sizeof(ChainPara);
    552     ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
    553     ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
    554     ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
    555 
    556     if (!CertGetCertificateChain(NULL,
    557         pServerCert,
    558         NULL,
    559         pServerCert->hCertStore,
    560         &ChainPara,
    561         0,
    562         NULL,
    563         &pChainContext))
    564     {
    565         Status = GetLastError();
    566         printf("Error 0x%x returned by CertGetCertificateChain!
    ", Status);
    567         goto cleanup;
    568     }
    569 
    570 
    571     // Validate certificate chain.
    572     ZeroMemory(&polHttps, sizeof(HTTPSPolicyCallbackData));
    573     polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
    574     polHttps.dwAuthType = AUTHTYPE_SERVER;
    575     polHttps.fdwChecks = dwCertFlags;
    576     polHttps.pwszServerName = pwszServerName;
    577 
    578     memset(&PolicyPara, 0, sizeof(PolicyPara));
    579     PolicyPara.cbSize = sizeof(PolicyPara);
    580     PolicyPara.pvExtraPolicyPara = &polHttps;
    581 
    582     memset(&PolicyStatus, 0, sizeof(PolicyStatus));
    583     PolicyStatus.cbSize = sizeof(PolicyStatus);
    584 
    585     if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
    586         pChainContext,
    587         &PolicyPara,
    588         &PolicyStatus))
    589     {
    590         Status = GetLastError();
    591         printf("Error 0x%x returned by CertVerifyCertificateChainPolicy!
    ", Status);
    592         goto cleanup;
    593     }
    594 
    595     if (PolicyStatus.dwError)
    596     {
    597         Status = PolicyStatus.dwError;
    598         DisplayWinVerifyTrustError(Status);
    599         goto cleanup;
    600     }
    601 
    602     Status = SEC_E_OK;
    603 
    604 
    605 cleanup:
    606     if (pChainContext)  CertFreeCertificateChain(pChainContext);
    607     if (pwszServerName) LocalFree(pwszServerName);
    608 
    609     return Status;
    610 }
    611 
    612 
    613 /*****************************************************************************/
    614 static SECURITY_STATUS CreateCredentials(LPSTR pszUser, PCredHandle phCreds)
    615 { //                                                in                     out
    616     TimeStamp        tsExpiry;
    617     SECURITY_STATUS  Status;
    618     DWORD            cSupportedAlgs = 0;
    619     ALG_ID           rgbSupportedAlgs[16];
    620     PCCERT_CONTEXT   pCertContext = NULL;
    621 
    622 
    623     // Open the "MY" certificate store, where IE stores client certificates.
    624         // Windows maintains 4 stores -- MY, CA, ROOT, SPC.
    625     if (hMyCertStore == NULL)
    626     {
    627         hMyCertStore = CertOpenSystemStore(0, "MY");
    628         if (!hMyCertStore)
    629         {
    630             printf("**** Error 0x%x returned by CertOpenSystemStore
    ", GetLastError());
    631             return SEC_E_NO_CREDENTIALS;
    632         }
    633     }
    634 
    635 
    636     // If a user name is specified, then attempt to find a client
    637     // certificate. Otherwise, just create a NULL credential.
    638     if (pszUser)
    639     {
    640         // Find client certificate. Note that this sample just searches for a
    641         // certificate that contains the user name somewhere in the subject name.
    642         // A real application should be a bit less casual.
    643         pCertContext = CertFindCertificateInStore(hMyCertStore,                     // hCertStore
    644             X509_ASN_ENCODING,             // dwCertEncodingType
    645             0,                                             // dwFindFlags
    646             CERT_FIND_SUBJECT_STR_A,// dwFindType
    647             pszUser,                         // *pvFindPara
    648             NULL);                                 // pPrevCertContext
    649 
    650 
    651         if (pCertContext == NULL)
    652         {
    653             printf("**** Error 0x%x returned by CertFindCertificateInStore
    ", GetLastError());
    654             if (GetLastError() == CRYPT_E_NOT_FOUND) printf("CRYPT_E_NOT_FOUND - property doesn't exist
    ");
    655             return SEC_E_NO_CREDENTIALS;
    656         }
    657     }
    658 
    659 
    660     // Build Schannel credential structure. Currently, this sample only
    661     // specifies the protocol to be used (and optionally the certificate,
    662     // of course). Real applications may wish to specify other parameters as well.
    663     ZeroMemory(&SchannelCred, sizeof(SchannelCred));
    664 
    665     SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
    666     if (pCertContext)
    667     {
    668         SchannelCred.cCreds = 1;
    669         SchannelCred.paCred = &pCertContext;
    670     }
    671 
    672     SchannelCred.grbitEnabledProtocols = dwProtocol;
    673 
    674     if (aiKeyExch) rgbSupportedAlgs[cSupportedAlgs++] = aiKeyExch;
    675 
    676     if (cSupportedAlgs)
    677     {
    678         SchannelCred.cSupportedAlgs = cSupportedAlgs;
    679         SchannelCred.palgSupportedAlgs = rgbSupportedAlgs;
    680     }
    681 
    682     SchannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
    683 
    684     // The SCH_CRED_MANUAL_CRED_VALIDATION flag is specified because
    685     // this sample verifies the server certificate manually.
    686     // Applications that expect to run on WinNT, Win9x, or WinME
    687     // should specify this flag and also manually verify the server
    688     // certificate. Applications running on newer versions of Windows can
    689     // leave off this flag, in which case the InitializeSecurityContext
    690     // function will validate the server certificate automatically.
    691     SchannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
    692 
    693 
    694     // Create an SSPI credential.
    695     Status = g_pSSPI->AcquireCredentialsHandleA(NULL,                 // Name of principal    
    696         (char*)UNISP_NAME_A,         // Name of package
    697         SECPKG_CRED_OUTBOUND, // Flags indicating use
    698         NULL,                 // Pointer to logon ID
    699         &SchannelCred,        // Package specific data
    700         NULL,                 // Pointer to GetKey() func
    701         NULL,                 // Value to pass to GetKey()
    702         phCreds,              // (out) Cred Handle
    703         &tsExpiry);          // (out) Lifetime (optional)
    704 
    705     if (Status != SEC_E_OK) printf("**** Error 0x%x returned by AcquireCredentialsHandle
    ", Status);
    706 
    707     // cleanup: Free the certificate context. Schannel has already made its own copy.
    708     if (pCertContext) CertFreeCertificateContext(pCertContext);
    709 
    710     return Status;
    711 }
    712 
    713 /*****************************************************************************/
    714 static INT ConnectToServer(LPSTR pszServerName, INT iPortNumber, SOCKET * pSocket)
    715 { //                                    in                in                 out
    716     SOCKET Socket;
    717     struct sockaddr_in sin;
    718     struct hostent *hp;
    719 
    720 
    721     Socket = socket(PF_INET, SOCK_STREAM, 0);
    722     if (Socket == INVALID_SOCKET)
    723     {
    724         printf("**** Error %d creating socket
    ", WSAGetLastError());
    725         DisplayWinSockError(WSAGetLastError());
    726         return WSAGetLastError();
    727     }
    728 
    729 
    730     if (fUseProxy)
    731     {
    732         sin.sin_family = AF_INET;
    733         sin.sin_port = ntohs((u_short)iProxyPort);
    734         if ((hp = gethostbyname(pszProxyServer)) == NULL)
    735         {
    736             printf("**** Error %d returned by gethostbyname using Proxy
    ", WSAGetLastError());
    737             DisplayWinSockError(WSAGetLastError());
    738             return WSAGetLastError();
    739         }
    740         else
    741             memcpy(&sin.sin_addr, hp->h_addr, 4);
    742     }
    743 
    744     else // No proxy used
    745     {
    746         sin.sin_family = AF_INET;
    747         sin.sin_port = htons((u_short)iPortNumber);
    748         if ((hp = gethostbyname(pszServerName)) == NULL)
    749         {
    750             printf("**** Error returned by gethostbyname
    ");
    751             DisplayWinSockError(WSAGetLastError());
    752             return WSAGetLastError();
    753         }
    754         else
    755             memcpy(&sin.sin_addr, hp->h_addr, 4);
    756     }
    757 
    758 
    759     if (connect(Socket, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
    760     {
    761         printf("**** Error %d connecting to "%s" (%s)
    ", WSAGetLastError(), pszServerName, inet_ntoa(sin.sin_addr));
    762         closesocket(Socket);
    763         DisplayWinSockError(WSAGetLastError());
    764         return WSAGetLastError();
    765     }
    766 
    767 
    768     if (fUseProxy)
    769     {
    770         BYTE  pbMessage[200];
    771         DWORD cbMessage;
    772 
    773         // Build message for proxy server
    774         strcpy((char*)pbMessage, "CONNECT ");
    775         strcat((char*)pbMessage, pszServerName);
    776         strcat((char*)pbMessage, ":");
    777         _itoa(iPortNumber, (char*)pbMessage + strlen((char*)pbMessage), 10);
    778         strcat((char*)pbMessage, " HTTP/1.0
    User-Agent: webclient
    
    ");
    779         cbMessage = (DWORD)strlen((char*)pbMessage);
    780 
    781         // Send message to proxy server
    782         if (send(Socket, (char*)pbMessage, cbMessage, 0) == SOCKET_ERROR)
    783         {
    784             printf("**** Error %d sending message to proxy!
    ", WSAGetLastError());
    785             DisplayWinSockError(WSAGetLastError());
    786             return WSAGetLastError();
    787         }
    788 
    789         // Receive message from proxy server
    790         cbMessage = recv(Socket, (char*)pbMessage, 200, 0);
    791         if (cbMessage == SOCKET_ERROR)
    792         {
    793             printf("**** Error %d receiving message from proxy
    ", WSAGetLastError());
    794             DisplayWinSockError(WSAGetLastError());
    795             return WSAGetLastError();
    796         }
    797         // this sample is limited but in normal use it
    798         // should continue to receive until CR LF CR LF is received
    799     }
    800     *pSocket = Socket;
    801 
    802     return SEC_E_OK;
    803 }
    804 
    805 /*****************************************************************************/
    806 static LONG DisconnectFromServer(SOCKET Socket, PCredHandle phCreds, CtxtHandle * phContext)
    807 {
    808     PBYTE                    pbMessage;
    809     DWORD                    dwType, dwSSPIFlags, dwSSPIOutFlags, cbMessage, cbData, Status;
    810     SecBufferDesc OutBuffer;
    811     SecBuffer     OutBuffers[1];
    812     TimeStamp     tsExpiry;
    813 
    814 
    815     dwType = SCHANNEL_SHUTDOWN; // Notify schannel that we are about to close the connection.
    816 
    817     OutBuffers[0].pvBuffer = &dwType;
    818     OutBuffers[0].BufferType = SECBUFFER_TOKEN;
    819     OutBuffers[0].cbBuffer = sizeof(dwType);
    820 
    821     OutBuffer.cBuffers = 1;
    822     OutBuffer.pBuffers = OutBuffers;
    823     OutBuffer.ulVersion = SECBUFFER_VERSION;
    824 
    825     Status = g_pSSPI->ApplyControlToken(phContext, &OutBuffer);
    826     if (FAILED(Status)) { printf("**** Error 0x%x returned by ApplyControlToken
    ", Status); goto cleanup; }
    827 
    828 
    829     // Build an SSL close notify message.
    830     dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
    831         ISC_REQ_REPLAY_DETECT |
    832         ISC_REQ_CONFIDENTIALITY |
    833         ISC_RET_EXTENDED_ERROR |
    834         ISC_REQ_ALLOCATE_MEMORY |
    835         ISC_REQ_STREAM;
    836 
    837     OutBuffers[0].pvBuffer = NULL;
    838     OutBuffers[0].BufferType = SECBUFFER_TOKEN;
    839     OutBuffers[0].cbBuffer = 0;
    840 
    841     OutBuffer.cBuffers = 1;
    842     OutBuffer.pBuffers = OutBuffers;
    843     OutBuffer.ulVersion = SECBUFFER_VERSION;
    844 
    845     Status = g_pSSPI->InitializeSecurityContextA(phCreds,
    846         phContext,
    847         NULL,
    848         dwSSPIFlags,
    849         0,
    850         SECURITY_NATIVE_DREP,
    851         NULL,
    852         0,
    853         phContext,
    854         &OutBuffer,
    855         &dwSSPIOutFlags,
    856         &tsExpiry);
    857 
    858     if (FAILED(Status)) { printf("**** Error 0x%x returned by InitializeSecurityContext
    ", Status); goto cleanup; }
    859 
    860     pbMessage = (PBYTE)OutBuffers[0].pvBuffer;
    861     cbMessage = OutBuffers[0].cbBuffer;
    862 
    863 
    864     // Send the close notify message to the server.
    865     if (pbMessage != NULL && cbMessage != 0)
    866     {
    867         cbData = send(Socket, (char*)pbMessage, cbMessage, 0);
    868         if (cbData == SOCKET_ERROR || cbData == 0)
    869         {
    870             Status = WSAGetLastError();
    871             printf("**** Error %d sending close notify
    ", Status);
    872             DisplayWinSockError(WSAGetLastError());
    873             goto cleanup;
    874         }
    875         printf("Sending Close Notify
    ");
    876         printf("%d bytes of handshake data sent
    ", cbData);
    877         if (fVerbose) { PrintHexDump(cbData, pbMessage); printf("
    "); }
    878         g_pSSPI->FreeContextBuffer(pbMessage); // Free output buffer.
    879     }
    880 
    881 
    882 cleanup:
    883     g_pSSPI->DeleteSecurityContext(phContext); // Free the security context.
    884     closesocket(Socket); // Close the socket.
    885 
    886     return Status;
    887 }
    888 
    889 
    890 
    891 /*****************************************************************************/
    892 static void GetNewClientCredentials(CredHandle *phCreds, CtxtHandle *phContext)
    893 {
    894 
    895     CredHandle                                            hCreds;
    896     SecPkgContext_IssuerListInfoEx    IssuerListInfo;
    897     PCCERT_CHAIN_CONTEXT                        pChainContext;
    898     CERT_CHAIN_FIND_BY_ISSUER_PARA    FindByIssuerPara;
    899     PCCERT_CONTEXT                                    pCertContext;
    900     TimeStamp                                                tsExpiry;
    901     SECURITY_STATUS                                    Status;
    902 
    903 
    904     // Read list of trusted issuers from schannel.
    905     Status = g_pSSPI->QueryContextAttributes(phContext, SECPKG_ATTR_ISSUER_LIST_EX, (PVOID)&IssuerListInfo);
    906     if (Status != SEC_E_OK) { printf("Error 0x%x querying issuer list info
    ", Status); return; }
    907 
    908     // Enumerate the client certificates.
    909     ZeroMemory(&FindByIssuerPara, sizeof(FindByIssuerPara));
    910 
    911     FindByIssuerPara.cbSize = sizeof(FindByIssuerPara);
    912     FindByIssuerPara.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH;
    913     FindByIssuerPara.dwKeySpec = 0;
    914     FindByIssuerPara.cIssuer = IssuerListInfo.cIssuers;
    915     FindByIssuerPara.rgIssuer = IssuerListInfo.aIssuers;
    916 
    917     pChainContext = NULL;
    918 
    919     while (TRUE)
    920     {   // Find a certificate chain.
    921         pChainContext = CertFindChainInStore(hMyCertStore,
    922             X509_ASN_ENCODING,
    923             0,
    924             CERT_CHAIN_FIND_BY_ISSUER,
    925             &FindByIssuerPara,
    926             pChainContext);
    927         if (pChainContext == NULL) { printf("Error 0x%x finding cert chain
    ", GetLastError()); break; }
    928 
    929         printf("
    certificate chain found
    ");
    930 
    931         // Get pointer to leaf certificate context.
    932         pCertContext = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext;
    933 
    934         // Create schannel credential.
    935         SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
    936         SchannelCred.cCreds = 1;
    937         SchannelCred.paCred = &pCertContext;
    938 
    939         Status = g_pSSPI->AcquireCredentialsHandleA(NULL,                   // Name of principal
    940             (char*)UNISP_NAME_A,           // Name of package
    941             SECPKG_CRED_OUTBOUND,   // Flags indicating use
    942             NULL,                   // Pointer to logon ID
    943             &SchannelCred,          // Package specific data
    944             NULL,                   // Pointer to GetKey() func
    945             NULL,                   // Value to pass to GetKey()
    946             &hCreds,                // (out) Cred Handle
    947             &tsExpiry);            // (out) Lifetime (optional)
    948 
    949         if (Status != SEC_E_OK) { printf("**** Error 0x%x returned by AcquireCredentialsHandle
    ", Status); continue; }
    950 
    951         printf("
    new schannel credential created
    ");
    952 
    953         g_pSSPI->FreeCredentialsHandle(phCreds); // Destroy the old credentials.
    954 
    955         *phCreds = hCreds;
    956 
    957     }
    958 }
    959 
    960 /*****************************************************************************/
    961 static SECURITY_STATUS ClientHandshakeLoop(SOCKET          Socket,         // in
    962     PCredHandle     phCreds,        // in
    963     CtxtHandle *    phContext,      // in, out
    964     BOOL            fDoInitialRead, // in
    965     SecBuffer *     pExtraData)    // out
    966 
    967 {
    968 
    969     SecBufferDesc   OutBuffer, InBuffer;
    970     SecBuffer       InBuffers[2], OutBuffers[1];
    971     DWORD           dwSSPIFlags, dwSSPIOutFlags, cbData, cbIoBuffer;
    972     TimeStamp       tsExpiry;
    973     SECURITY_STATUS scRet;
    974     PUCHAR          IoBuffer;
    975     BOOL            fDoRead;
    976 
    977 
    978     dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY |
    979         ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
    980 
    981 
    982     // Allocate data buffer.
    983     IoBuffer = (PUCHAR)LocalAlloc(LMEM_FIXED, IO_BUFFER_SIZE);
    984     if (IoBuffer == NULL) { printf("**** Out of memory (1)
    "); return SEC_E_INTERNAL_ERROR; }
    985     cbIoBuffer = 0;
    986     fDoRead = fDoInitialRead;
    987 
    988 
    989 
    990     // Loop until the handshake is finished or an error occurs.
    991     scRet = SEC_I_CONTINUE_NEEDED;
    992 
    993     while (scRet == SEC_I_CONTINUE_NEEDED ||
    994         scRet == SEC_E_INCOMPLETE_MESSAGE ||
    995         scRet == SEC_I_INCOMPLETE_CREDENTIALS)
    996     {
    997         if (0 == cbIoBuffer || scRet == SEC_E_INCOMPLETE_MESSAGE) // Read data from server.
    998         {
    999             if (fDoRead)
    1000             {
    1001                 cbData = recv(Socket, (char*)IoBuffer + cbIoBuffer, IO_BUFFER_SIZE - cbIoBuffer, 0);
    1002                 if (cbData == SOCKET_ERROR)
    1003                 {
    1004                     printf("**** Error %d reading data from server
    ", WSAGetLastError());
    1005                     scRet = SEC_E_INTERNAL_ERROR;
    1006                     break;
    1007                 }
    1008                 else if (cbData == 0)
    1009                 {
    1010                     printf("**** Server unexpectedly disconnected
    ");
    1011                     scRet = SEC_E_INTERNAL_ERROR;
    1012                     break;
    1013                 }
    1014                 printf("%d bytes of handshake data received
    ", cbData);
    1015                 if (fVerbose) { PrintHexDump(cbData, IoBuffer + cbIoBuffer); printf("
    "); }
    1016                 cbIoBuffer += cbData;
    1017             }
    1018             else
    1019                 fDoRead = TRUE;
    1020         }
    1021 
    1022 
    1023 
    1024         // Set up the input buffers. Buffer 0 is used to pass in data
    1025         // received from the server. Schannel will consume some or all
    1026         // of this. Leftover data (if any) will be placed in buffer 1 and
    1027         // given a buffer type of SECBUFFER_EXTRA.
    1028         InBuffers[0].pvBuffer = IoBuffer;
    1029         InBuffers[0].cbBuffer = cbIoBuffer;
    1030         InBuffers[0].BufferType = SECBUFFER_TOKEN;
    1031 
    1032         InBuffers[1].pvBuffer = NULL;
    1033         InBuffers[1].cbBuffer = 0;
    1034         InBuffers[1].BufferType = SECBUFFER_EMPTY;
    1035 
    1036         InBuffer.cBuffers = 2;
    1037         InBuffer.pBuffers = InBuffers;
    1038         InBuffer.ulVersion = SECBUFFER_VERSION;
    1039 
    1040 
    1041         // Set up the output buffers. These are initialized to NULL
    1042         // so as to make it less likely we'll attempt to free random
    1043         // garbage later.
    1044         OutBuffers[0].pvBuffer = NULL;
    1045         OutBuffers[0].BufferType = SECBUFFER_TOKEN;
    1046         OutBuffers[0].cbBuffer = 0;
    1047 
    1048         OutBuffer.cBuffers = 1;
    1049         OutBuffer.pBuffers = OutBuffers;
    1050         OutBuffer.ulVersion = SECBUFFER_VERSION;
    1051 
    1052 
    1053         // Call InitializeSecurityContext.
    1054         scRet = g_pSSPI->InitializeSecurityContextA(phCreds,
    1055             phContext,
    1056             NULL,
    1057             dwSSPIFlags,
    1058             0,
    1059             SECURITY_NATIVE_DREP,
    1060             &InBuffer,
    1061             0,
    1062             NULL,
    1063             &OutBuffer,
    1064             &dwSSPIOutFlags,
    1065             &tsExpiry);
    1066 
    1067 
    1068         // If InitializeSecurityContext was successful (or if the error was
    1069         // one of the special extended ones), send the contends of the output
    1070         // buffer to the server.
    1071         if (scRet == SEC_E_OK ||
    1072             scRet == SEC_I_CONTINUE_NEEDED ||
    1073             FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
    1074         {
    1075             if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
    1076             {
    1077                 cbData = send(Socket, (char*)OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
    1078                 if (cbData == SOCKET_ERROR || cbData == 0)
    1079                 {
    1080                     printf("**** Error %d sending data to server (2)
    ", WSAGetLastError());
    1081                     DisplayWinSockError(WSAGetLastError());
    1082                     g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
    1083                     g_pSSPI->DeleteSecurityContext(phContext);
    1084                     return SEC_E_INTERNAL_ERROR;
    1085                 }
    1086                 printf("%d bytes of handshake data sent
    ", cbData);
    1087                 if (fVerbose) { PrintHexDump(cbData, (PBYTE)OutBuffers[0].pvBuffer); printf("
    "); }
    1088 
    1089                 // Free output buffer.
    1090                 g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
    1091                 OutBuffers[0].pvBuffer = NULL;
    1092             }
    1093         }
    1094 
    1095 
    1096 
    1097         // If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE,
    1098         // then we need to read more data from the server and try again.
    1099         if (scRet == SEC_E_INCOMPLETE_MESSAGE) continue;
    1100 
    1101 
    1102         // If InitializeSecurityContext returned SEC_E_OK, then the
    1103         // handshake completed successfully.
    1104         if (scRet == SEC_E_OK)
    1105         {
    1106             // If the "extra" buffer contains data, this is encrypted application
    1107             // protocol layer stuff. It needs to be saved. The application layer
    1108             // will later decrypt it with DecryptMessage.
    1109             printf("Handshake was successful
    ");
    1110 
    1111             if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
    1112             {
    1113                 pExtraData->pvBuffer = LocalAlloc(LMEM_FIXED, InBuffers[1].cbBuffer);
    1114                 if (pExtraData->pvBuffer == NULL) { printf("**** Out of memory (2)
    "); return SEC_E_INTERNAL_ERROR; }
    1115 
    1116                 MoveMemory(pExtraData->pvBuffer,
    1117                     IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer),
    1118                     InBuffers[1].cbBuffer);
    1119 
    1120                 pExtraData->cbBuffer = InBuffers[1].cbBuffer;
    1121                 pExtraData->BufferType = SECBUFFER_TOKEN;
    1122 
    1123                 printf("%d bytes of app data was bundled with handshake data
    ", pExtraData->cbBuffer);
    1124             }
    1125             else
    1126             {
    1127                 pExtraData->pvBuffer = NULL;
    1128                 pExtraData->cbBuffer = 0;
    1129                 pExtraData->BufferType = SECBUFFER_EMPTY;
    1130             }
    1131             break; // Bail out to quit
    1132         }
    1133 
    1134 
    1135 
    1136         // Check for fatal error.
    1137         if (FAILED(scRet)) { printf("**** Error 0x%x returned by InitializeSecurityContext (2)
    ", scRet); break; }
    1138 
    1139         // If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
    1140         // then the server just requested client authentication.
    1141         if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
    1142         {
    1143             // Busted. The server has requested client authentication and
    1144             // the credential we supplied didn't contain a client certificate.
    1145             // This function will read the list of trusted certificate
    1146             // authorities ("issuers") that was received from the server
    1147             // and attempt to find a suitable client certificate that
    1148             // was issued by one of these. If this function is successful,
    1149             // then we will connect using the new certificate. Otherwise,
    1150             // we will attempt to connect anonymously (using our current credentials).
    1151             GetNewClientCredentials(phCreds, phContext);
    1152 
    1153             // Go around again.
    1154             fDoRead = FALSE;
    1155             scRet = SEC_I_CONTINUE_NEEDED;
    1156             continue;
    1157         }
    1158 
    1159         // Copy any leftover data from the "extra" buffer, and go around again.
    1160         if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
    1161         {
    1162             MoveMemory(IoBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer);
    1163             cbIoBuffer = InBuffers[1].cbBuffer;
    1164         }
    1165         else
    1166             cbIoBuffer = 0;
    1167     }
    1168 
    1169     // Delete the security context in the case of a fatal error.
    1170     if (FAILED(scRet)) g_pSSPI->DeleteSecurityContext(phContext);
    1171     LocalFree(IoBuffer);
    1172 
    1173     return scRet;
    1174 }
    1175 
    1176 
    1177 /*****************************************************************************/
    1178 static SECURITY_STATUS PerformClientHandshake(SOCKET          Socket,        // in
    1179     PCredHandle     phCreds,       // in
    1180     LPSTR           pszServerName, // in
    1181     CtxtHandle *    phContext,     // out
    1182     SecBuffer *     pExtraData)   // out
    1183 {
    1184 
    1185     SecBufferDesc   OutBuffer;
    1186     SecBuffer       OutBuffers[1];
    1187     DWORD           dwSSPIFlags, dwSSPIOutFlags, cbData;
    1188     TimeStamp       tsExpiry;
    1189     SECURITY_STATUS scRet;
    1190 
    1191 
    1192     dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY |
    1193         ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
    1194 
    1195 
    1196     //  Initiate a ClientHello message and generate a token.
    1197     OutBuffers[0].pvBuffer = NULL;
    1198     OutBuffers[0].BufferType = SECBUFFER_TOKEN;
    1199     OutBuffers[0].cbBuffer = 0;
    1200 
    1201     OutBuffer.cBuffers = 1;
    1202     OutBuffer.pBuffers = OutBuffers;
    1203     OutBuffer.ulVersion = SECBUFFER_VERSION;
    1204 
    1205     scRet = g_pSSPI->InitializeSecurityContextA(phCreds,
    1206         NULL,
    1207         pszServerName,
    1208         dwSSPIFlags,
    1209         0,
    1210         SECURITY_NATIVE_DREP,
    1211         NULL,
    1212         0,
    1213         phContext,
    1214         &OutBuffer,
    1215         &dwSSPIOutFlags,
    1216         &tsExpiry);
    1217 
    1218     if (scRet != SEC_I_CONTINUE_NEEDED) { printf("**** Error %d returned by InitializeSecurityContext (1)
    ", scRet); return scRet; }
    1219 
    1220     // Send response to server if there is one.
    1221     if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
    1222     {
    1223         cbData = send(Socket, (CHAR*)OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
    1224         if (cbData == SOCKET_ERROR || cbData == 0)
    1225         {
    1226             printf("**** Error %d sending data to server (1)
    ", WSAGetLastError());
    1227             g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
    1228             g_pSSPI->DeleteSecurityContext(phContext);
    1229             return SEC_E_INTERNAL_ERROR;
    1230         }
    1231         printf("%d bytes of handshake data sent
    ", cbData);
    1232         if (fVerbose) { PrintHexDump(cbData, (PBYTE)OutBuffers[0].pvBuffer); printf("
    "); }
    1233         g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer); // Free output buffer.
    1234         OutBuffers[0].pvBuffer = NULL;
    1235     }
    1236 
    1237     return ClientHandshakeLoop(Socket, phCreds, phContext, TRUE, pExtraData);
    1238 }
    1239 
    1240 
    1241 
    1242 /*****************************************************************************/
    1243 static DWORD EncryptSend(SOCKET Socket, CtxtHandle * phContext, PBYTE pbIoBuffer, SecPkgContext_StreamSizes Sizes)
    1244 // http://msdn.microsoft.com/en-us/library/aa375378(VS.85).aspx
    1245 // The encrypted message is encrypted in place, overwriting the original contents of its buffer.
    1246 {
    1247     SECURITY_STATUS    scRet;            // unsigned long cbBuffer;    // Size of the buffer, in bytes
    1248     SecBufferDesc        Message;        // unsigned long BufferType;  // Type of the buffer (below)
    1249     SecBuffer                Buffers[4];    // void    SEC_FAR * pvBuffer;   // Pointer to the buffer
    1250     DWORD                        cbMessage, cbData;
    1251     PBYTE                        pbMessage;
    1252 
    1253 
    1254     pbMessage = pbIoBuffer + Sizes.cbHeader; // Offset by "header size"
    1255     cbMessage = (DWORD)strlen((const char*)pbMessage);
    1256     printf("Sending %d bytes of plaintext:", cbMessage); PrintText(cbMessage, pbMessage);
    1257     if (fVerbose) { PrintHexDump(cbMessage, pbMessage); printf("
    "); }
    1258 
    1259 
    1260     // Encrypt the HTTP request.
    1261     Buffers[0].pvBuffer = pbIoBuffer;                                // Pointer to buffer 1
    1262     Buffers[0].cbBuffer = Sizes.cbHeader;                        // length of header
    1263     Buffers[0].BufferType = SECBUFFER_STREAM_HEADER;    // Type of the buffer
    1264 
    1265     Buffers[1].pvBuffer = pbMessage;                                // Pointer to buffer 2
    1266     Buffers[1].cbBuffer = cbMessage;                                // length of the message
    1267     Buffers[1].BufferType = SECBUFFER_DATA;                        // Type of the buffer
    1268 
    1269     Buffers[2].pvBuffer = pbMessage + cbMessage;        // Pointer to buffer 3
    1270     Buffers[2].cbBuffer = Sizes.cbTrailer;                    // length of the trailor
    1271     Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;    // Type of the buffer
    1272 
    1273     Buffers[3].pvBuffer = SECBUFFER_EMPTY;                    // Pointer to buffer 4
    1274     Buffers[3].cbBuffer = SECBUFFER_EMPTY;                    // length of buffer 4
    1275     Buffers[3].BufferType = SECBUFFER_EMPTY;                    // Type of the buffer 4
    1276 
    1277 
    1278     Message.ulVersion = SECBUFFER_VERSION;    // Version number
    1279     Message.cBuffers = 4;                                    // Number of buffers - must contain four SecBuffer structures.
    1280     Message.pBuffers = Buffers;                        // Pointer to array of buffers
    1281     scRet = g_pSSPI->EncryptMessage(phContext, 0, &Message, 0); // must contain four SecBuffer structures.
    1282     if (FAILED(scRet)) { printf("**** Error 0x%x returned by EncryptMessage
    ", scRet); return scRet; }
    1283 
    1284 
    1285     // Send the encrypted data to the server.                                            len                                                                         flags
    1286     cbData = send(Socket, (const char*)pbIoBuffer, Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer, 0);
    1287 
    1288     printf("%d bytes of encrypted data sent
    ", cbData);
    1289     if (fVerbose) { PrintHexDump(cbData, pbIoBuffer); printf("
    "); }
    1290 
    1291     return cbData; // send( Socket, pbIoBuffer,    Sizes.cbHeader + strlen(pbMessage) + Sizes.cbTrailer,  0 );
    1292 
    1293 }
    1294 
    1295 
    1296 /*****************************************************************************/
    1297 static SECURITY_STATUS ReadDecrypt(SOCKET Socket, PCredHandle phCreds, CtxtHandle * phContext, PBYTE pbIoBuffer, DWORD    cbIoBufferLength)
    1298 
    1299 // calls recv() - blocking socket read
    1300 // http://msdn.microsoft.com/en-us/library/ms740121(VS.85).aspx
    1301 
    1302 // The encrypted message is decrypted in place, overwriting the original contents of its buffer.
    1303 // http://msdn.microsoft.com/en-us/library/aa375211(VS.85).aspx
    1304 
    1305 {
    1306     SecBuffer                ExtraBuffer;
    1307     SecBuffer                *pDataBuffer, *pExtraBuffer;
    1308 
    1309     SECURITY_STATUS    scRet;            // unsigned long cbBuffer;    // Size of the buffer, in bytes
    1310     SecBufferDesc        Message;        // unsigned long BufferType;  // Type of the buffer (below)
    1311     SecBuffer                Buffers[4];    // void    SEC_FAR * pvBuffer;   // Pointer to the buffer
    1312 
    1313     DWORD                        cbIoBuffer, cbData, length;
    1314     PBYTE                        buff;
    1315     int i;
    1316 
    1317 
    1318 
    1319     // Read data from server until done.
    1320     cbIoBuffer = 0;
    1321     scRet = 0;
    1322     while (TRUE) // Read some data.
    1323     {
    1324         if (cbIoBuffer == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE) // get the data
    1325         {
    1326             cbData = recv(Socket, (char*)pbIoBuffer + cbIoBuffer, cbIoBufferLength - cbIoBuffer, 0);
    1327             if (cbData == SOCKET_ERROR)
    1328             {
    1329                 printf("**** Error %d reading data from server
    ", WSAGetLastError());
    1330                 scRet = SEC_E_INTERNAL_ERROR;
    1331                 break;
    1332             }
    1333             else if (cbData == 0) // Server disconnected.
    1334             {
    1335                 if (cbIoBuffer)
    1336                 {
    1337                     printf("**** Server unexpectedly disconnected
    ");
    1338                     scRet = SEC_E_INTERNAL_ERROR;
    1339                     return scRet;
    1340                 }
    1341                 else
    1342                     break; // All Done
    1343             }
    1344             else // success
    1345             {
    1346                 printf("%d bytes of (encrypted) application data received
    ", cbData);
    1347                 if (fVerbose) { PrintHexDump(cbData, pbIoBuffer + cbIoBuffer); printf("
    "); }
    1348                 cbIoBuffer += cbData;
    1349             }
    1350         }
    1351 
    1352 
    1353         // Decrypt the received data.
    1354         Buffers[0].pvBuffer = pbIoBuffer;
    1355         Buffers[0].cbBuffer = cbIoBuffer;
    1356         Buffers[0].BufferType = SECBUFFER_DATA;  // Initial Type of the buffer 1
    1357         Buffers[1].BufferType = SECBUFFER_EMPTY; // Initial Type of the buffer 2
    1358         Buffers[2].BufferType = SECBUFFER_EMPTY; // Initial Type of the buffer 3
    1359         Buffers[3].BufferType = SECBUFFER_EMPTY; // Initial Type of the buffer 4
    1360 
    1361         Message.ulVersion = SECBUFFER_VERSION;    // Version number
    1362         Message.cBuffers = 4;                                    // Number of buffers - must contain four SecBuffer structures.
    1363         Message.pBuffers = Buffers;                        // Pointer to array of buffers
    1364         scRet = g_pSSPI->DecryptMessage(phContext, &Message, 0, NULL);
    1365         if (scRet == SEC_I_CONTEXT_EXPIRED) break; // Server signalled end of session
    1366 //      if( scRet == SEC_E_INCOMPLETE_MESSAGE - Input buffer has partial encrypted record, read more
    1367         if (scRet != SEC_E_OK &&
    1368             scRet != SEC_I_RENEGOTIATE &&
    1369             scRet != SEC_I_CONTEXT_EXPIRED)
    1370         {
    1371             printf("**** DecryptMessage ");
    1372             DisplaySECError((DWORD)scRet);
    1373             return scRet;
    1374         }
    1375 
    1376 
    1377 
    1378         // Locate data and (optional) extra buffers.
    1379         pDataBuffer = NULL;
    1380         pExtraBuffer = NULL;
    1381         for (i = 1; i < 4; i++)
    1382         {
    1383             if (pDataBuffer == NULL && Buffers[i].BufferType == SECBUFFER_DATA) pDataBuffer = &Buffers[i];
    1384             if (pExtraBuffer == NULL && Buffers[i].BufferType == SECBUFFER_EXTRA) pExtraBuffer = &Buffers[i];
    1385         }
    1386 
    1387 
    1388         // Display the decrypted data.
    1389         if (pDataBuffer)
    1390         {
    1391             length = pDataBuffer->cbBuffer;
    1392             if (length) // check if last two chars are CR LF
    1393             {
    1394                 buff = (PBYTE)pDataBuffer->pvBuffer; // printf( "n-2= %d, n-1= %d 
    ", buff[length-2], buff[length-1] );
    1395                 printf("Decrypted data: %d bytes", length); PrintText(length, buff);
    1396                 if (fVerbose) { PrintHexDump(length, buff); printf("
    "); }
    1397                 if (buff[length - 2] == 13 && buff[length - 1] == 10) break; // printf("Found CRLF
    ");
    1398             }
    1399         }
    1400 
    1401 
    1402 
    1403         // Move any "extra" data to the input buffer.
    1404         if (pExtraBuffer)
    1405         {
    1406             MoveMemory(pbIoBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
    1407             cbIoBuffer = pExtraBuffer->cbBuffer; // printf("cbIoBuffer= %d  
    ", cbIoBuffer);
    1408         }
    1409         else
    1410             cbIoBuffer = 0;
    1411 
    1412 
    1413         // The server wants to perform another handshake sequence.
    1414         if (scRet == SEC_I_RENEGOTIATE)
    1415         {
    1416             printf("Server requested renegotiate!
    ");
    1417             scRet = ClientHandshakeLoop(Socket, phCreds, phContext, FALSE, &ExtraBuffer);
    1418             if (scRet != SEC_E_OK) return scRet;
    1419 
    1420             if (ExtraBuffer.pvBuffer) // Move any "extra" data to the input buffer.
    1421             {
    1422                 MoveMemory(pbIoBuffer, ExtraBuffer.pvBuffer, ExtraBuffer.cbBuffer);
    1423                 cbIoBuffer = ExtraBuffer.cbBuffer;
    1424             }
    1425         }
    1426     } // Loop till CRLF is found at the end of the data
    1427 
    1428     return SEC_E_OK;
    1429 }
    1430 
    1431 
    1432 
    1433 /*****************************************************************************/
    1434 static SECURITY_STATUS SMTPsession(SOCKET          Socket,     // in
    1435     PCredHandle     phCreds,    // in
    1436     CtxtHandle *    phContext)  // in
    1437 {
    1438     SecPkgContext_StreamSizes Sizes;            // unsigned long cbBuffer;    // Size of the buffer, in bytes
    1439     SECURITY_STATUS                        scRet;            // unsigned long BufferType;  // Type of the buffer (below)        
    1440     PBYTE                                            pbIoBuffer; // void    SEC_FAR * pvBuffer;   // Pointer to the buffer
    1441     DWORD                                            cbIoBufferLength, cbData;
    1442 
    1443 
    1444     // Read stream encryption properties.
    1445     scRet = g_pSSPI->QueryContextAttributes(phContext, SECPKG_ATTR_STREAM_SIZES, &Sizes);
    1446     if (scRet != SEC_E_OK)
    1447     {
    1448         printf("**** Error 0x%x reading SECPKG_ATTR_STREAM_SIZES
    ", scRet); return scRet;
    1449     }
    1450 
    1451 
    1452     // Create a buffer.
    1453     cbIoBufferLength = Sizes.cbHeader + Sizes.cbMaximumMessage + Sizes.cbTrailer;
    1454     pbIoBuffer = (PBYTE)LocalAlloc(LMEM_FIXED, cbIoBufferLength);
    1455     if (pbIoBuffer == NULL) { printf("**** Out of memory (2)
    "); return SEC_E_INTERNAL_ERROR; }
    1456 
    1457 
    1458     // Receive a Response
    1459     scRet = ReadDecrypt(Socket, phCreds, phContext, pbIoBuffer, cbIoBufferLength);
    1460     if (scRet != SEC_E_OK) return scRet;
    1461 
    1462 
    1463     // Build the request - must be < maximum message size
    1464     sprintf((char*)pbIoBuffer + Sizes.cbHeader, "%s", "EHLO 
    "); // message begins after the header
    1465 
    1466 
    1467     // Send a request.
    1468     cbData = EncryptSend(Socket, phContext, pbIoBuffer, Sizes);
    1469     if (cbData == SOCKET_ERROR || cbData == 0)
    1470     {
    1471         printf("**** Error %d sending data to server (3)
    ", WSAGetLastError()); return SEC_E_INTERNAL_ERROR;
    1472     }
    1473 
    1474 
    1475     // Receive a Response
    1476     scRet = ReadDecrypt(Socket, phCreds, phContext, pbIoBuffer, cbIoBufferLength);
    1477     if (scRet != SEC_E_OK) return scRet;
    1478 
    1479 
    1480 
    1481 
    1482     // Build the request - must be < maximum message size
    1483     sprintf((char*)pbIoBuffer + Sizes.cbHeader, "%s", "QUIT 
    "); // message begins after the header
    1484 
    1485 
    1486     // Send a request.
    1487     cbData = EncryptSend(Socket, phContext, pbIoBuffer, Sizes);
    1488     if (cbData == SOCKET_ERROR || cbData == 0)
    1489     {
    1490         printf("**** Error %d sending data to server (3)
    ", WSAGetLastError()); return SEC_E_INTERNAL_ERROR;
    1491     }
    1492 
    1493 
    1494     // Receive a Response
    1495     scRet = ReadDecrypt(Socket, phCreds, phContext, pbIoBuffer, cbIoBufferLength);
    1496     if (scRet != SEC_E_OK) return scRet;
    1497 
    1498 
    1499     return SEC_E_OK;
    1500 }
    1501 
    1502 
    1503 /*****************************************************************************/
    1504 void _cdecl main(int argc, char *argv[])
    1505 {
    1506     WSADATA WsaData;
    1507     SOCKET  Socket = INVALID_SOCKET;
    1508 
    1509     CredHandle hClientCreds;
    1510     CtxtHandle hContext;
    1511     BOOL fCredsInitialized = FALSE;
    1512     BOOL fContextInitialized = FALSE;
    1513 
    1514     SecBuffer  ExtraData;
    1515     SECURITY_STATUS Status;
    1516 
    1517     PCCERT_CONTEXT pRemoteCertContext = NULL;
    1518 
    1519 
    1520 
    1521     if (!LoadSecurityLibrary())
    1522     {
    1523         printf("Error initializing the security library
    "); goto cleanup;
    1524     } //
    1525     printf("----- SSPI Initialized
    ");
    1526 
    1527 
    1528     // Initialize the WinSock subsystem.
    1529     if (WSAStartup(0x0101, &WsaData) == SOCKET_ERROR) // Winsock.h
    1530     {
    1531         printf("Error %d returned by WSAStartup
    ", GetLastError()); goto cleanup;
    1532     } //
    1533     printf("----- WinSock Initialized
    ");
    1534 
    1535 
    1536     // Create credentials.
    1537     if (CreateCredentials((char*)pszUser, &hClientCreds))
    1538     {
    1539         printf("Error creating credentials
    "); goto cleanup;
    1540     }
    1541     fCredsInitialized = TRUE; //
    1542     printf("----- Credentials Initialized
    ");
    1543 
    1544 
    1545     // Connect to server.
    1546     if (ConnectToServer((char*)pszServerName, iPortNumber, &Socket))
    1547     {
    1548         printf("Error connecting to server
    "); goto cleanup;
    1549     } //
    1550     printf("----- Connectd To Server
    ");
    1551 
    1552 
    1553 
    1554     // Perform handshake
    1555     if (PerformClientHandshake(Socket, &hClientCreds, (char*)pszServerName, &hContext, &ExtraData))
    1556     {
    1557         printf("Error performing handshake
    "); goto cleanup;
    1558     }
    1559     fContextInitialized = TRUE; //
    1560     printf("----- Client Handshake Performed
    ");
    1561 
    1562 
    1563     // Authenticate server's credentials. Get server's certificate.
    1564     Status = g_pSSPI->QueryContextAttributes(&hContext, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext);
    1565     if (Status != SEC_E_OK)
    1566     {
    1567         printf("Error 0x%x querying remote certificate
    ", Status); goto cleanup;
    1568     } //
    1569     printf("----- Server Credentials Authenticated 
    ");
    1570 
    1571 
    1572     // Display server certificate chain.
    1573     DisplayCertChain(pRemoteCertContext, FALSE); //
    1574     printf("----- Certificate Chain Displayed 
    ");
    1575 
    1576 
    1577     // Attempt to validate server certificate.
    1578     Status = VerifyServerCertificate(pRemoteCertContext, (char*)pszServerName, 0);
    1579     if (Status) { printf("**** Error 0x%x authenticating server credentials!
    ", Status); goto cleanup; }
    1580     // The server certificate did not validate correctly. At this point, we cannot tell
    1581     // if we are connecting to the correct server, or if we are connecting to a
    1582     // "man in the middle" attack server - Best to just abort the connection.
    1583     printf("----- Server Certificate Verified
    ");
    1584 
    1585 
    1586 
    1587     // Free the server certificate context.
    1588     CertFreeCertificateContext(pRemoteCertContext);
    1589     pRemoteCertContext = NULL; //
    1590     printf("----- Server certificate context released 
    ");
    1591 
    1592 
    1593     // Display connection info.
    1594     DisplayConnectionInfo(&hContext); //
    1595     printf("----- Secure Connection Info
    ");
    1596 
    1597 
    1598 
    1599     // Send Request, recover response. LPSTR pszRequest = "EHLO";
    1600     if (SMTPsession(Socket, &hClientCreds, &hContext))
    1601     {
    1602         printf("Error SMTP Session 
    "); goto cleanup;
    1603     } //
    1604     printf("----- SMTP session Complete 
    ");
    1605 
    1606 
    1607     // Send a close_notify alert to the server and close down the connection.
    1608     if (DisconnectFromServer(Socket, &hClientCreds, &hContext))
    1609     {
    1610         printf("Error disconnecting from server
    "); goto cleanup;
    1611     }
    1612     fContextInitialized = FALSE;
    1613     Socket = INVALID_SOCKET; //
    1614     printf("----- Disconnected From Server
    ");
    1615 
    1616 
    1617 
    1618 
    1619 cleanup: //
    1620     printf("----- Begin Cleanup
    ");
    1621 
    1622     // Free the server certificate context.
    1623     if (pRemoteCertContext)
    1624     {
    1625         CertFreeCertificateContext(pRemoteCertContext);
    1626         pRemoteCertContext = NULL;
    1627     }
    1628 
    1629     // Free SSPI context handle.
    1630     if (fContextInitialized)
    1631     {
    1632         g_pSSPI->DeleteSecurityContext(&hContext);
    1633         fContextInitialized = FALSE;
    1634     }
    1635 
    1636     // Free SSPI credentials handle.
    1637     if (fCredsInitialized)
    1638     {
    1639         g_pSSPI->FreeCredentialsHandle(&hClientCreds);
    1640         fCredsInitialized = FALSE;
    1641     }
    1642 
    1643     // Close socket.
    1644     if (Socket != INVALID_SOCKET) closesocket(Socket);
    1645 
    1646     // Shutdown WinSock subsystem.
    1647     WSACleanup();
    1648 
    1649     // Close "MY" certificate store.
    1650     if (hMyCertStore) CertCloseStore(hMyCertStore, 0);
    1651 
    1652     UnloadSecurityLibrary();
    1653 
    1654 
    1655     printf("----- All Done ----- 
    ");
    1656 
    1657 }
    1658 
    1659 
    PS:会笑的人,运气通常都会比别人好。
  • 相关阅读:
    九九乘法表及双色球
    错误 “SCRIPT7002: XMLHttpRequest: 网络错误 0x2ef3, ie浏览器兼容问题
    隐藏ie input的X和眼睛图标
    vue-cli解决兼容ie的es6+api问题
    git 本地tag和远程tag对应不上 vscode里pull不下代码
    git 计算commit
    git 查看对比的方法log diff
    git 版本回退方法
    git rebase的使用
    git 常规操作
  • 原文地址:https://www.cnblogs.com/thinkinc999/p/13786291.html
Copyright © 2011-2022 走看看