Home | History | Annotate | Download | only in cups
      1 /*
      2  * TLS support for CUPS on Windows using the Security Support Provider
      3  * Interface (SSPI).
      4  *
      5  * Copyright 2010-2017 by Apple Inc.
      6  *
      7  * These coded instructions, statements, and computer programs are the
      8  * property of Apple Inc. and are protected by Federal copyright
      9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     10  * which should have been included with this file.  If this file is
     11  * missing or damaged, see the license at "http://www.cups.org/".
     12  *
     13  * This file is subject to the Apple OS-Developed Software exception.
     14  */
     15 
     16 /**** This file is included from tls.c ****/
     17 
     18 /*
     19  * Include necessary headers...
     20  */
     21 
     22 #include "debug-private.h"
     23 
     24 
     25 /*
     26  * Include necessary libraries...
     27  */
     28 
     29 #pragma comment(lib, "Crypt32.lib")
     30 #pragma comment(lib, "Secur32.lib")
     31 #pragma comment(lib, "Ws2_32.lib")
     32 
     33 
     34 /*
     35  * Constants...
     36  */
     37 
     38 #ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA
     39 #  define SECURITY_FLAG_IGNORE_UNKNOWN_CA         0x00000100 /* Untrusted root */
     40 #endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */
     41 
     42 #ifndef SECURITY_FLAG_IGNORE_CERT_CN_INVALID
     43 #  define SECURITY_FLAG_IGNORE_CERT_CN_INVALID	  0x00001000 /* Common name does not match */
     44 #endif /* !SECURITY_FLAG_IGNORE_CERT_CN_INVALID */
     45 
     46 #ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
     47 #  define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID  0x00002000 /* Expired X509 Cert. */
     48 #endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */
     49 
     50 
     51 /*
     52  * Local globals...
     53  */
     54 
     55 static int		tls_options = -1;/* Options for TLS connections */
     56 
     57 
     58 /*
     59  * Local functions...
     60  */
     61 
     62 static _http_sspi_t *http_sspi_alloc(void);
     63 static int	http_sspi_client(http_t *http, const char *hostname);
     64 static PCCERT_CONTEXT http_sspi_create_credential(http_credential_t *cred);
     65 static BOOL	http_sspi_find_credentials(http_t *http, const LPWSTR containerName, const char *common_name);
     66 static void	http_sspi_free(_http_sspi_t *sspi);
     67 static BOOL	http_sspi_make_credentials(_http_sspi_t *sspi, const LPWSTR containerName, const char *common_name, _http_mode_t mode, int years);
     68 static int	http_sspi_server(http_t *http, const char *hostname);
     69 static void	http_sspi_set_allows_any_root(_http_sspi_t *sspi, BOOL allow);
     70 static void	http_sspi_set_allows_expired_certs(_http_sspi_t *sspi, BOOL allow);
     71 static const char *http_sspi_strerror(char *buffer, size_t bufsize, DWORD code);
     72 static DWORD	http_sspi_verify(PCCERT_CONTEXT cert, const char *common_name, DWORD dwCertFlags);
     73 
     74 
     75 /*
     76  * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
     77  *
     78  * @since CUPS 2.0/OS 10.10@
     79  */
     80 
     81 int					/* O - 1 on success, 0 on failure */
     82 cupsMakeServerCredentials(
     83     const char *path,			/* I - Keychain path or @code NULL@ for default */
     84     const char *common_name,		/* I - Common name */
     85     int        num_alt_names,		/* I - Number of subject alternate names */
     86     const char **alt_names,		/* I - Subject Alternate Names */
     87     time_t     expiration_date)		/* I - Expiration date */
     88 {
     89   _http_sspi_t	*sspi;			/* SSPI data */
     90   int		ret;			/* Return value */
     91 
     92 
     93   DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date));
     94 
     95   (void)path;
     96   (void)num_alt_names;
     97   (void)alt_names;
     98 
     99   sspi = http_sspi_alloc();
    100   ret  = http_sspi_make_credentials(sspi, L"ServerContainer", common_name, _HTTP_MODE_SERVER, (int)((expiration_date - time(NULL) + 86399) / 86400 / 365));
    101 
    102   http_sspi_free(sspi);
    103 
    104   return (ret);
    105 }
    106 
    107 
    108 /*
    109  * 'cupsSetServerCredentials()' - Set the default server credentials.
    110  *
    111  * Note: The server credentials are used by all threads in the running process.
    112  * This function is threadsafe.
    113  *
    114  * @since CUPS 2.0/OS 10.10@
    115  */
    116 
    117 int					/* O - 1 on success, 0 on failure */
    118 cupsSetServerCredentials(
    119     const char *path,			/* I - Keychain path or @code NULL@ for default */
    120     const char *common_name,		/* I - Default common name for server */
    121     int        auto_create)		/* I - 1 = automatically create self-signed certificates */
    122 {
    123   DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create));
    124 
    125   (void)path;
    126   (void)common_name;
    127   (void)auto_create;
    128 
    129   return (0);
    130 }
    131 
    132 
    133 /*
    134  * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
    135  *                           an encrypted connection.
    136  *
    137  * @since CUPS 1.5/macOS 10.7@
    138  */
    139 
    140 int					/* O - Status of call (0 = success) */
    141 httpCopyCredentials(
    142     http_t	 *http,			/* I - Connection to server */
    143     cups_array_t **credentials)		/* O - Array of credentials */
    144 {
    145   DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials));
    146 
    147   if (!http || !http->tls || !http->tls->remoteCert || !credentials)
    148   {
    149     if (credentials)
    150       *credentials = NULL;
    151 
    152     return (-1);
    153   }
    154 
    155   *credentials = cupsArrayNew(NULL, NULL);
    156   httpAddCredential(*credentials, http->tls->remoteCert->pbCertEncoded, http->tls->remoteCert->cbCertEncoded);
    157 
    158   return (0);
    159 }
    160 
    161 
    162 /*
    163  * '_httpCreateCredentials()' - Create credentials in the internal format.
    164  */
    165 
    166 http_tls_credentials_t			/* O - Internal credentials */
    167 _httpCreateCredentials(
    168     cups_array_t *credentials)		/* I - Array of credentials */
    169 {
    170   return (http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)));
    171 }
    172 
    173 
    174 /*
    175  * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
    176  *
    177  * @since CUPS 2.0/OS 10.10@
    178  */
    179 
    180 int					/* O - 1 if valid, 0 otherwise */
    181 httpCredentialsAreValidForName(
    182     cups_array_t *credentials,		/* I - Credentials */
    183     const char   *common_name)		/* I - Name to check */
    184 {
    185   int		valid = 1;		/* Valid name? */
    186   PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
    187 					/* Certificate */
    188   char		cert_name[1024];	/* Name from certificate */
    189 
    190 
    191   if (cert)
    192   {
    193     if (CertNameToStr(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name)))
    194     {
    195      /*
    196       * Extract common name at end...
    197       */
    198 
    199       char  *ptr = strrchr(cert_name, ',');
    200       if (ptr && ptr[1])
    201         _cups_strcpy(cert_name, ptr + 2);
    202     }
    203     else
    204       strlcpy(cert_name, "unknown", sizeof(cert_name));
    205 
    206     CertFreeCertificateContext(cert);
    207   }
    208   else
    209     strlcpy(cert_name, "unknown", sizeof(cert_name));
    210 
    211  /*
    212   * Compare the common names...
    213   */
    214 
    215   if (_cups_strcasecmp(common_name, cert_name))
    216   {
    217    /*
    218     * Not an exact match for the common name, check for wildcard certs...
    219     */
    220 
    221     const char	*domain = strchr(common_name, '.');
    222 					/* Domain in common name */
    223 
    224     if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1))
    225     {
    226      /*
    227       * Not a wildcard match.
    228       */
    229 
    230       /* TODO: Check subject alternate names */
    231       valid = 0;
    232     }
    233   }
    234 
    235   return (valid);
    236 }
    237 
    238 
    239 /*
    240  * 'httpCredentialsGetTrust()' - Return the trust of credentials.
    241  *
    242  * @since CUPS 2.0/OS 10.10@
    243  */
    244 
    245 http_trust_t				/* O - Level of trust */
    246 httpCredentialsGetTrust(
    247     cups_array_t *credentials,		/* I - Credentials */
    248     const char   *common_name)		/* I - Common name for trust lookup */
    249 {
    250   http_trust_t	trust = HTTP_TRUST_OK;	/* Level of trust */
    251   PCCERT_CONTEXT cert = NULL;		/* Certificate to validate */
    252   DWORD		certFlags = 0;		/* Cert verification flags */
    253   _cups_globals_t *cg = _cupsGlobals();	/* Per-thread global data */
    254 
    255 
    256   if (!common_name)
    257     return (HTTP_TRUST_UNKNOWN);
    258 
    259   cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
    260   if (!cert)
    261     return (HTTP_TRUST_UNKNOWN);
    262 
    263   if (cg->any_root < 0)
    264     _cupsSetDefaults();
    265 
    266   if (cg->any_root)
    267     certFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
    268 
    269   if (cg->expired_certs)
    270     certFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
    271 
    272   if (!cg->validate_certs)
    273     certFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
    274 
    275   if (http_sspi_verify(cert, common_name, certFlags) != SEC_E_OK)
    276     trust = HTTP_TRUST_INVALID;
    277 
    278   CertFreeCertificateContext(cert);
    279 
    280   return (trust);
    281 }
    282 
    283 
    284 /*
    285  * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
    286  *
    287  * @since CUPS 2.0/OS 10.10@
    288  */
    289 
    290 time_t					/* O - Expiration date of credentials */
    291 httpCredentialsGetExpiration(
    292     cups_array_t *credentials)		/* I - Credentials */
    293 {
    294   time_t	expiration_date = 0;	/* Expiration data of credentials */
    295   PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
    296 					/* Certificate */
    297 
    298   if (cert)
    299   {
    300     SYSTEMTIME	systime;		/* System time */
    301     struct tm	tm;			/* UNIX date/time */
    302 
    303     FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
    304 
    305     tm.tm_year = systime.wYear - 1900;
    306     tm.tm_mon  = systime.wMonth - 1;
    307     tm.tm_mday = systime.wDay;
    308     tm.tm_hour = systime.wHour;
    309     tm.tm_min  = systime.wMinute;
    310     tm.tm_sec  = systime.wSecond;
    311 
    312     expiration_date = mktime(&tm);
    313 
    314     CertFreeCertificateContext(cert);
    315   }
    316 
    317   return (expiration_date);
    318 }
    319 
    320 
    321 /*
    322  * 'httpCredentialsString()' - Return a string representing the credentials.
    323  *
    324  * @since CUPS 2.0/OS 10.10@
    325  */
    326 
    327 size_t					/* O - Total size of credentials string */
    328 httpCredentialsString(
    329     cups_array_t *credentials,		/* I - Credentials */
    330     char         *buffer,		/* I - Buffer or @code NULL@ */
    331     size_t       bufsize)		/* I - Size of buffer */
    332 {
    333   http_credential_t	*first = (http_credential_t *)cupsArrayFirst(credentials);
    334 					/* First certificate */
    335   PCCERT_CONTEXT 	cert;		/* Certificate */
    336 
    337 
    338   DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize));
    339 
    340   if (!buffer)
    341     return (0);
    342 
    343   if (buffer && bufsize > 0)
    344     *buffer = '\0';
    345 
    346   cert = http_sspi_create_credential(first);
    347 
    348   if (cert)
    349   {
    350     char		cert_name[256];	/* Common name */
    351     SYSTEMTIME		systime;	/* System time */
    352     struct tm		tm;		/* UNIX date/time */
    353     time_t		expiration;	/* Expiration date of cert */
    354     _cups_md5_state_t	md5_state;	/* MD5 state */
    355     unsigned char	md5_digest[16];	/* MD5 result */
    356 
    357     FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
    358 
    359     tm.tm_year = systime.wYear - 1900;
    360     tm.tm_mon  = systime.wMonth - 1;
    361     tm.tm_mday = systime.wDay;
    362     tm.tm_hour = systime.wHour;
    363     tm.tm_min  = systime.wMinute;
    364     tm.tm_sec  = systime.wSecond;
    365 
    366     expiration = mktime(&tm);
    367 
    368     if (CertNameToStr(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name)))
    369     {
    370      /*
    371       * Extract common name at end...
    372       */
    373 
    374       char  *ptr = strrchr(cert_name, ',');
    375       if (ptr && ptr[1])
    376         _cups_strcpy(cert_name, ptr + 2);
    377     }
    378     else
    379       strlcpy(cert_name, "unknown", sizeof(cert_name));
    380 
    381     _cupsMD5Init(&md5_state);
    382     _cupsMD5Append(&md5_state, first->data, (int)first->datalen);
    383     _cupsMD5Finish(&md5_state, md5_digest);
    384 
    385     snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", cert_name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]);
    386 
    387     CertFreeCertificateContext(cert);
    388   }
    389 
    390   DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer));
    391 
    392   return (strlen(buffer));
    393 }
    394 
    395 
    396 /*
    397  * '_httpFreeCredentials()' - Free internal credentials.
    398  */
    399 
    400 void
    401 _httpFreeCredentials(
    402     http_tls_credentials_t credentials)	/* I - Internal credentials */
    403 {
    404   if (!credentials)
    405     return;
    406 
    407   CertFreeCertificateContext(credentials);
    408 }
    409 
    410 
    411 /*
    412  * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
    413  *
    414  * @since CUPS 2.0/OS 10.10@
    415  */
    416 
    417 int					/* O - 0 on success, -1 on error */
    418 httpLoadCredentials(
    419     const char   *path,			/* I  - Keychain path or @code NULL@ for default */
    420     cups_array_t **credentials,		/* IO - Credentials */
    421     const char   *common_name)		/* I  - Common name for credentials */
    422 {
    423   HCERTSTORE	store = NULL;		/* Certificate store */
    424   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
    425   DWORD		dwSize = 0; 		/* 32 bit size */
    426   PBYTE		p = NULL;		/* Temporary storage */
    427   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
    428 					/* Handle to a CSP */
    429   CERT_NAME_BLOB sib;			/* Arbitrary array of bytes */
    430 #ifdef DEBUG
    431   char		error[1024];		/* Error message buffer */
    432 #endif /* DEBUG */
    433 
    434 
    435   DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
    436 
    437   (void)path;
    438 
    439   if (credentials)
    440   {
    441     *credentials = NULL;
    442   }
    443   else
    444   {
    445     DEBUG_puts("1httpLoadCredentials: NULL credentials pointer, returning -1.");
    446     return (-1);
    447   }
    448 
    449   if (!common_name)
    450   {
    451     DEBUG_puts("1httpLoadCredentials: Bad common name, returning -1.");
    452     return (-1);
    453   }
    454 
    455   if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
    456   {
    457     if (GetLastError() == NTE_EXISTS)
    458     {
    459       if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
    460       {
    461         DEBUG_printf(("1httpLoadCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    462         goto cleanup;
    463       }
    464     }
    465   }
    466 
    467   store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
    468 
    469   if (!store)
    470   {
    471     DEBUG_printf(("1httpLoadCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    472     goto cleanup;
    473   }
    474 
    475   dwSize = 0;
    476 
    477   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
    478   {
    479     DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    480     goto cleanup;
    481   }
    482 
    483   p = (PBYTE)malloc(dwSize);
    484 
    485   if (!p)
    486   {
    487     DEBUG_printf(("1httpLoadCredentials: malloc failed for %d bytes.", dwSize));
    488     goto cleanup;
    489   }
    490 
    491   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
    492   {
    493     DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    494     goto cleanup;
    495   }
    496 
    497   sib.cbData = dwSize;
    498   sib.pbData = p;
    499 
    500   storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
    501 
    502   if (!storedContext)
    503   {
    504     DEBUG_printf(("1httpLoadCredentials: Unable to find credentials for \"%s\".", common_name));
    505     goto cleanup;
    506   }
    507 
    508   *credentials = cupsArrayNew(NULL, NULL);
    509   httpAddCredential(*credentials, storedContext->pbCertEncoded, storedContext->cbCertEncoded);
    510 
    511 cleanup:
    512 
    513  /*
    514   * Cleanup
    515   */
    516 
    517   if (storedContext)
    518     CertFreeCertificateContext(storedContext);
    519 
    520   if (p)
    521     free(p);
    522 
    523   if (store)
    524     CertCloseStore(store, 0);
    525 
    526   if (hProv)
    527     CryptReleaseContext(hProv, 0);
    528 
    529   DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1));
    530 
    531   return (*credentials ? 0 : -1);
    532 }
    533 
    534 
    535 /*
    536  * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
    537  *
    538  * @since CUPS 2.0/OS 10.10@
    539  */
    540 
    541 int					/* O - -1 on error, 0 on success */
    542 httpSaveCredentials(
    543     const char   *path,			/* I - Keychain path or @code NULL@ for default */
    544     cups_array_t *credentials,		/* I - Credentials */
    545     const char   *common_name)		/* I - Common name for credentials */
    546 {
    547   HCERTSTORE	store = NULL;		/* Certificate store */
    548   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
    549   PCCERT_CONTEXT createdContext = NULL;	/* Context created by us */
    550   DWORD		dwSize = 0; 		/* 32 bit size */
    551   PBYTE		p = NULL;		/* Temporary storage */
    552   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
    553 					/* Handle to a CSP */
    554   CRYPT_KEY_PROV_INFO ckp;		/* Handle to crypto key */
    555   int		ret = -1;		/* Return value */
    556 #ifdef DEBUG
    557   char		error[1024];		/* Error message buffer */
    558 #endif /* DEBUG */
    559 
    560 
    561   DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
    562 
    563   (void)path;
    564 
    565   if (!common_name)
    566   {
    567     DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1.");
    568     return (-1);
    569   }
    570 
    571   createdContext = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
    572   if (!createdContext)
    573   {
    574     DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1.");
    575     return (-1);
    576   }
    577 
    578   if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
    579   {
    580     if (GetLastError() == NTE_EXISTS)
    581     {
    582       if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
    583       {
    584         DEBUG_printf(("1httpSaveCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    585         goto cleanup;
    586       }
    587     }
    588   }
    589 
    590   store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
    591 
    592   if (!store)
    593   {
    594     DEBUG_printf(("1httpSaveCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    595     goto cleanup;
    596   }
    597 
    598   dwSize = 0;
    599 
    600   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
    601   {
    602     DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    603     goto cleanup;
    604   }
    605 
    606   p = (PBYTE)malloc(dwSize);
    607 
    608   if (!p)
    609   {
    610     DEBUG_printf(("1httpSaveCredentials: malloc failed for %d bytes.", dwSize));
    611     goto cleanup;
    612   }
    613 
    614   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
    615   {
    616     DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    617     goto cleanup;
    618   }
    619 
    620  /*
    621   * Add the created context to the named store, and associate it with the named
    622   * container...
    623   */
    624 
    625   if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
    626   {
    627     DEBUG_printf(("1httpSaveCredentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    628     goto cleanup;
    629   }
    630 
    631   ZeroMemory(&ckp, sizeof(ckp));
    632   ckp.pwszContainerName = L"RememberedContainer";
    633   ckp.pwszProvName      = MS_DEF_PROV_W;
    634   ckp.dwProvType        = PROV_RSA_FULL;
    635   ckp.dwFlags           = CRYPT_MACHINE_KEYSET;
    636   ckp.dwKeySpec         = AT_KEYEXCHANGE;
    637 
    638   if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
    639   {
    640     DEBUG_printf(("1httpSaveCredentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
    641     goto cleanup;
    642   }
    643 
    644   ret = 0;
    645 
    646 cleanup:
    647 
    648  /*
    649   * Cleanup
    650   */
    651 
    652   if (createdContext)
    653     CertFreeCertificateContext(createdContext);
    654 
    655   if (storedContext)
    656     CertFreeCertificateContext(storedContext);
    657 
    658   if (p)
    659     free(p);
    660 
    661   if (store)
    662     CertCloseStore(store, 0);
    663 
    664   if (hProv)
    665     CryptReleaseContext(hProv, 0);
    666 
    667   DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret));
    668   return (ret);
    669 }
    670 
    671 
    672 /*
    673  * '_httpTLSInitialize()' - Initialize the TLS stack.
    674  */
    675 
    676 void
    677 _httpTLSInitialize(void)
    678 {
    679  /*
    680   * Nothing to do...
    681   */
    682 }
    683 
    684 
    685 /*
    686  * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
    687  */
    688 
    689 size_t					/* O - Bytes available */
    690 _httpTLSPending(http_t *http)		/* I - HTTP connection */
    691 {
    692   if (http->tls)
    693     return (http->tls->readBufferUsed);
    694   else
    695     return (0);
    696 }
    697 
    698 
    699 /*
    700  * '_httpTLSRead()' - Read from a SSL/TLS connection.
    701  */
    702 
    703 int					/* O - Bytes read */
    704 _httpTLSRead(http_t *http,		/* I - HTTP connection */
    705 	     char   *buf,		/* I - Buffer to store data */
    706 	     int    len)		/* I - Length of buffer */
    707 {
    708   int		i;			/* Looping var */
    709   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
    710   SecBufferDesc	message;		/* Array of SecBuffer struct */
    711   SecBuffer	buffers[4] = { 0 };	/* Security package buffer */
    712   int		num = 0;		/* Return value */
    713   PSecBuffer	pDataBuffer;		/* Data buffer */
    714   PSecBuffer	pExtraBuffer;		/* Excess data buffer */
    715   SECURITY_STATUS scRet;		/* SSPI status */
    716 
    717 
    718   DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http, buf, len));
    719 
    720  /*
    721   * If there are bytes that have already been decrypted and have not yet been
    722   * read, return those...
    723   */
    724 
    725   if (sspi->readBufferUsed > 0)
    726   {
    727     int bytesToCopy = min(sspi->readBufferUsed, len);
    728 					/* Number of bytes to copy */
    729 
    730     memcpy(buf, sspi->readBuffer, bytesToCopy);
    731     sspi->readBufferUsed -= bytesToCopy;
    732 
    733     if (sspi->readBufferUsed > 0)
    734       memmove(sspi->readBuffer, sspi->readBuffer + bytesToCopy, sspi->readBufferUsed);
    735 
    736     DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy));
    737 
    738     return (bytesToCopy);
    739   }
    740 
    741  /*
    742   * Initialize security buffer structs
    743   */
    744 
    745   message.ulVersion = SECBUFFER_VERSION;
    746   message.cBuffers  = 4;
    747   message.pBuffers  = buffers;
    748 
    749   do
    750   {
    751    /*
    752     * If there is not enough space in the buffer, then increase its size...
    753     */
    754 
    755     if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
    756     {
    757       BYTE *temp;			/* New buffer */
    758 
    759       if (sspi->decryptBufferLength >= 262144)
    760       {
    761 	WSASetLastError(E_OUTOFMEMORY);
    762         DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)");
    763 	return (-1);
    764       }
    765 
    766       if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
    767       {
    768 	DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi->decryptBufferLength + 4096));
    769 	WSASetLastError(E_OUTOFMEMORY);
    770 	return (-1);
    771       }
    772 
    773       sspi->decryptBufferLength += 4096;
    774       sspi->decryptBuffer       = temp;
    775 
    776       DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi->decryptBufferLength));
    777     }
    778 
    779     buffers[0].pvBuffer	  = sspi->decryptBuffer;
    780     buffers[0].cbBuffer	  = (unsigned long)sspi->decryptBufferUsed;
    781     buffers[0].BufferType = SECBUFFER_DATA;
    782     buffers[1].BufferType = SECBUFFER_EMPTY;
    783     buffers[2].BufferType = SECBUFFER_EMPTY;
    784     buffers[3].BufferType = SECBUFFER_EMPTY;
    785 
    786     DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi->decryptBufferUsed));
    787 
    788     scRet = DecryptMessage(&sspi->context, &message, 0, NULL);
    789 
    790     if (scRet == SEC_E_INCOMPLETE_MESSAGE)
    791     {
    792       num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
    793       if (num < 0)
    794       {
    795 	DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError()));
    796 	return (-1);
    797       }
    798       else if (num == 0)
    799       {
    800 	DEBUG_puts("5_httpTLSRead: Server disconnected.");
    801 	return (0);
    802       }
    803 
    804       DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num));
    805 
    806       sspi->decryptBufferUsed += num;
    807     }
    808   }
    809   while (scRet == SEC_E_INCOMPLETE_MESSAGE);
    810 
    811   if (scRet == SEC_I_CONTEXT_EXPIRED)
    812   {
    813     DEBUG_puts("5_httpTLSRead: Context expired.");
    814     WSASetLastError(WSAECONNRESET);
    815     return (-1);
    816   }
    817   else if (scRet != SEC_E_OK)
    818   {
    819     DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
    820     WSASetLastError(WSASYSCALLFAILURE);
    821     return (-1);
    822   }
    823 
    824  /*
    825   * The decryption worked.  Now, locate data buffer.
    826   */
    827 
    828   pDataBuffer  = NULL;
    829   pExtraBuffer = NULL;
    830 
    831   for (i = 1; i < 4; i++)
    832   {
    833     if (buffers[i].BufferType == SECBUFFER_DATA)
    834       pDataBuffer = &buffers[i];
    835     else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA))
    836       pExtraBuffer = &buffers[i];
    837   }
    838 
    839  /*
    840   * If a data buffer is found, then copy the decrypted bytes to the passed-in
    841   * buffer...
    842   */
    843 
    844   if (pDataBuffer)
    845   {
    846     int bytesToCopy = min((int)pDataBuffer->cbBuffer, len);
    847 				      /* Number of bytes to copy into buf */
    848     int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy;
    849 				      /* Number of bytes to save in our read buffer */
    850 
    851     if (bytesToCopy)
    852       memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy);
    853 
    854    /*
    855     * If there are more decrypted bytes than can be copied to the passed in
    856     * buffer, then save them...
    857     */
    858 
    859     if (bytesToSave)
    860     {
    861       if ((sspi->readBufferLength - sspi->readBufferUsed) < bytesToSave)
    862       {
    863         BYTE *temp;			/* New buffer pointer */
    864 
    865         if ((temp = realloc(sspi->readBuffer, sspi->readBufferUsed + bytesToSave)) == NULL)
    866 	{
    867 	  DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi->readBufferUsed + bytesToSave));
    868 	  WSASetLastError(E_OUTOFMEMORY);
    869 	  return (-1);
    870 	}
    871 
    872 	sspi->readBufferLength = sspi->readBufferUsed + bytesToSave;
    873 	sspi->readBuffer       = temp;
    874       }
    875 
    876       memcpy(((BYTE *)sspi->readBuffer) + sspi->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave);
    877 
    878       sspi->readBufferUsed += bytesToSave;
    879     }
    880 
    881     num = bytesToCopy;
    882   }
    883   else
    884   {
    885     DEBUG_puts("_httpTLSRead: Unable to find data buffer.");
    886     WSASetLastError(WSASYSCALLFAILURE);
    887     return (-1);
    888   }
    889 
    890  /*
    891   * If the decryption process left extra bytes, then save those back in
    892   * decryptBuffer.  They will be processed the next time through the loop.
    893   */
    894 
    895   if (pExtraBuffer)
    896   {
    897     memmove(sspi->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
    898     sspi->decryptBufferUsed = pExtraBuffer->cbBuffer;
    899   }
    900   else
    901   {
    902     sspi->decryptBufferUsed = 0;
    903   }
    904 
    905   return (num);
    906 }
    907 
    908 
    909 /*
    910  * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
    911  */
    912 
    913 void
    914 _httpTLSSetOptions(int options)		/* I - Options */
    915 {
    916   if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
    917     tls_options = options;
    918 }
    919 
    920 
    921 /*
    922  * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
    923  */
    924 
    925 int					/* O - 0 on success, -1 on failure */
    926 _httpTLSStart(http_t *http)		/* I - HTTP connection */
    927 {
    928   char	hostname[256],			/* Hostname */
    929 	*hostptr;			/* Pointer into hostname */
    930 
    931 
    932   DEBUG_printf(("3_httpTLSStart(http=%p)", http));
    933 
    934   if (tls_options < 0)
    935   {
    936     DEBUG_puts("4_httpTLSStart: Setting defaults.");
    937     _cupsSetDefaults();
    938     DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
    939   }
    940 
    941   if ((http->tls = http_sspi_alloc()) == NULL)
    942     return (-1);
    943 
    944   if (http->mode == _HTTP_MODE_CLIENT)
    945   {
    946    /*
    947     * Client: determine hostname...
    948     */
    949 
    950     if (httpAddrLocalhost(http->hostaddr))
    951     {
    952       strlcpy(hostname, "localhost", sizeof(hostname));
    953     }
    954     else
    955     {
    956      /*
    957       * Otherwise make sure the hostname we have does not end in a trailing dot.
    958       */
    959 
    960       strlcpy(hostname, http->hostname, sizeof(hostname));
    961       if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
    962 	  *hostptr == '.')
    963 	*hostptr = '\0';
    964     }
    965 
    966     return (http_sspi_client(http, hostname));
    967   }
    968   else
    969   {
    970    /*
    971     * Server: determine hostname to use...
    972     */
    973 
    974     if (http->fields[HTTP_FIELD_HOST][0])
    975     {
    976      /*
    977       * Use hostname for TLS upgrade...
    978       */
    979 
    980       strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
    981     }
    982     else
    983     {
    984      /*
    985       * Resolve hostname from connection address...
    986       */
    987 
    988       http_addr_t	addr;		/* Connection address */
    989       socklen_t		addrlen;	/* Length of address */
    990 
    991       addrlen = sizeof(addr);
    992       if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
    993       {
    994 	DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno)));
    995 	hostname[0] = '\0';
    996       }
    997       else if (httpAddrLocalhost(&addr))
    998 	hostname[0] = '\0';
    999       else
   1000       {
   1001 	httpAddrLookup(&addr, hostname, sizeof(hostname));
   1002         DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname));
   1003       }
   1004     }
   1005 
   1006     return (http_sspi_server(http, hostname));
   1007   }
   1008 }
   1009 
   1010 
   1011 /*
   1012  * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
   1013  */
   1014 
   1015 void
   1016 _httpTLSStop(http_t *http)		/* I - HTTP connection */
   1017 {
   1018   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
   1019 
   1020 
   1021   if (sspi->contextInitialized && http->fd >= 0)
   1022   {
   1023     SecBufferDesc	message;	/* Array of SecBuffer struct */
   1024     SecBuffer		buffers[1] = { 0 };
   1025 					/* Security package buffer */
   1026     DWORD		dwType;		/* Type */
   1027     DWORD		status;		/* Status */
   1028 
   1029   /*
   1030    * Notify schannel that we are about to close the connection.
   1031    */
   1032 
   1033    dwType = SCHANNEL_SHUTDOWN;
   1034 
   1035    buffers[0].pvBuffer   = &dwType;
   1036    buffers[0].BufferType = SECBUFFER_TOKEN;
   1037    buffers[0].cbBuffer   = sizeof(dwType);
   1038 
   1039    message.cBuffers  = 1;
   1040    message.pBuffers  = buffers;
   1041    message.ulVersion = SECBUFFER_VERSION;
   1042 
   1043    status = ApplyControlToken(&sspi->context, &message);
   1044 
   1045    if (SUCCEEDED(status))
   1046    {
   1047      PBYTE	pbMessage;		/* Message buffer */
   1048      DWORD	cbMessage;		/* Message buffer count */
   1049      DWORD	cbData;			/* Data count */
   1050      DWORD	dwSSPIFlags;		/* SSL attributes we requested */
   1051      DWORD	dwSSPIOutFlags;		/* SSL attributes we received */
   1052      TimeStamp	tsExpiry;		/* Time stamp */
   1053 
   1054      dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT     |
   1055                    ASC_REQ_REPLAY_DETECT       |
   1056                    ASC_REQ_CONFIDENTIALITY     |
   1057                    ASC_REQ_EXTENDED_ERROR      |
   1058                    ASC_REQ_ALLOCATE_MEMORY     |
   1059                    ASC_REQ_STREAM;
   1060 
   1061      buffers[0].pvBuffer   = NULL;
   1062      buffers[0].BufferType = SECBUFFER_TOKEN;
   1063      buffers[0].cbBuffer   = 0;
   1064 
   1065      message.cBuffers  = 1;
   1066      message.pBuffers  = buffers;
   1067      message.ulVersion = SECBUFFER_VERSION;
   1068 
   1069      status = AcceptSecurityContext(&sspi->creds, &sspi->context, NULL,
   1070                                     dwSSPIFlags, SECURITY_NATIVE_DREP, NULL,
   1071                                     &message, &dwSSPIOutFlags, &tsExpiry);
   1072 
   1073       if (SUCCEEDED(status))
   1074       {
   1075         pbMessage = buffers[0].pvBuffer;
   1076         cbMessage = buffers[0].cbBuffer;
   1077 
   1078        /*
   1079         * Send the close notify message to the client.
   1080         */
   1081 
   1082         if (pbMessage && cbMessage)
   1083         {
   1084           cbData = send(http->fd, pbMessage, cbMessage, 0);
   1085           if ((cbData == SOCKET_ERROR) || (cbData == 0))
   1086           {
   1087             status = WSAGetLastError();
   1088             DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status));
   1089           }
   1090           else
   1091           {
   1092             FreeContextBuffer(pbMessage);
   1093           }
   1094         }
   1095       }
   1096       else
   1097       {
   1098         DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
   1099       }
   1100     }
   1101     else
   1102     {
   1103       DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
   1104     }
   1105   }
   1106 
   1107   http_sspi_free(sspi);
   1108 
   1109   http->tls = NULL;
   1110 }
   1111 
   1112 
   1113 /*
   1114  * '_httpTLSWrite()' - Write to a SSL/TLS connection.
   1115  */
   1116 
   1117 int					/* O - Bytes written */
   1118 _httpTLSWrite(http_t     *http,		/* I - HTTP connection */
   1119 	      const char *buf,		/* I - Buffer holding data */
   1120 	      int        len)		/* I - Length of buffer */
   1121 {
   1122   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
   1123   SecBufferDesc	message;		/* Array of SecBuffer struct */
   1124   SecBuffer	buffers[4] = { 0 };	/* Security package buffer */
   1125   int		bufferLen;		/* Buffer length */
   1126   int		bytesLeft;		/* Bytes left to write */
   1127   const char	*bufptr;		/* Pointer into buffer */
   1128   int		num = 0;		/* Return value */
   1129 
   1130 
   1131   bufferLen = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer;
   1132 
   1133   if (bufferLen > sspi->writeBufferLength)
   1134   {
   1135     BYTE *temp;				/* New buffer pointer */
   1136 
   1137     if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL)
   1138     {
   1139       DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen));
   1140       WSASetLastError(E_OUTOFMEMORY);
   1141       return (-1);
   1142     }
   1143 
   1144     sspi->writeBuffer       = temp;
   1145     sspi->writeBufferLength = bufferLen;
   1146   }
   1147 
   1148   bytesLeft = len;
   1149   bufptr    = buf;
   1150 
   1151   while (bytesLeft)
   1152   {
   1153     int chunk = min((int)sspi->streamSizes.cbMaximumMessage, bytesLeft);
   1154 					/* Size of data to write */
   1155     SECURITY_STATUS scRet;		/* SSPI status */
   1156 
   1157    /*
   1158     * Copy user data into the buffer, starting just past the header...
   1159     */
   1160 
   1161     memcpy(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk);
   1162 
   1163    /*
   1164     * Setup the SSPI buffers
   1165     */
   1166 
   1167     message.ulVersion = SECBUFFER_VERSION;
   1168     message.cBuffers  = 4;
   1169     message.pBuffers  = buffers;
   1170 
   1171     buffers[0].pvBuffer   = sspi->writeBuffer;
   1172     buffers[0].cbBuffer   = sspi->streamSizes.cbHeader;
   1173     buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
   1174     buffers[1].pvBuffer   = sspi->writeBuffer + sspi->streamSizes.cbHeader;
   1175     buffers[1].cbBuffer   = (unsigned long) chunk;
   1176     buffers[1].BufferType = SECBUFFER_DATA;
   1177     buffers[2].pvBuffer   = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk;
   1178     buffers[2].cbBuffer   = sspi->streamSizes.cbTrailer;
   1179     buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
   1180     buffers[3].BufferType = SECBUFFER_EMPTY;
   1181 
   1182    /*
   1183     * Encrypt the data
   1184     */
   1185 
   1186     scRet = EncryptMessage(&sspi->context, 0, &message, 0);
   1187 
   1188     if (FAILED(scRet))
   1189     {
   1190       DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
   1191       WSASetLastError(WSASYSCALLFAILURE);
   1192       return (-1);
   1193     }
   1194 
   1195    /*
   1196     * Send the data. Remember the size of the total data to send is the size
   1197     * of the header, the size of the data the caller passed in and the size
   1198     * of the trailer...
   1199     */
   1200 
   1201     num = send(http->fd, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0);
   1202 
   1203     if (num <= 0)
   1204     {
   1205       DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError()));
   1206       return (num);
   1207     }
   1208 
   1209     bytesLeft -= chunk;
   1210     bufptr    += chunk;
   1211   }
   1212 
   1213   return (len);
   1214 }
   1215 
   1216 
   1217 #if 0
   1218 /*
   1219  * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
   1220  */
   1221 
   1222 static int				/* O - 0 on success, -1 on failure */
   1223 http_setup_ssl(http_t *http)		/* I - Connection to server */
   1224 {
   1225   char			hostname[256],	/* Hostname */
   1226 			*hostptr;	/* Pointer into hostname */
   1227 
   1228   TCHAR			username[256];	/* Username returned from GetUserName() */
   1229   TCHAR			commonName[256];/* Common name for certificate */
   1230   DWORD			dwSize;		/* 32 bit size */
   1231 
   1232 
   1233   DEBUG_printf(("7http_setup_ssl(http=%p)", http));
   1234 
   1235  /*
   1236   * Get the hostname to use for SSL...
   1237   */
   1238 
   1239   if (httpAddrLocalhost(http->hostaddr))
   1240   {
   1241     strlcpy(hostname, "localhost", sizeof(hostname));
   1242   }
   1243   else
   1244   {
   1245    /*
   1246     * Otherwise make sure the hostname we have does not end in a trailing dot.
   1247     */
   1248 
   1249     strlcpy(hostname, http->hostname, sizeof(hostname));
   1250     if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
   1251         *hostptr == '.')
   1252       *hostptr = '\0';
   1253   }
   1254 
   1255   http->tls = http_sspi_alloc();
   1256 
   1257   if (!http->tls)
   1258   {
   1259     _cupsSetHTTPError(HTTP_STATUS_ERROR);
   1260     return (-1);
   1261   }
   1262 
   1263   dwSize          = sizeof(username) / sizeof(TCHAR);
   1264   GetUserName(username, &dwSize);
   1265   _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR),
   1266                sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username);
   1267 
   1268   if (!_sspiGetCredentials(http->tls, L"ClientContainer",
   1269                            commonName, FALSE))
   1270   {
   1271     _sspiFree(http->tls);
   1272     http->tls = NULL;
   1273 
   1274     http->error  = EIO;
   1275     http->status = HTTP_STATUS_ERROR;
   1276 
   1277     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
   1278                   _("Unable to establish a secure connection to host."), 1);
   1279 
   1280     return (-1);
   1281   }
   1282 
   1283   _sspiSetAllowsAnyRoot(http->tls, TRUE);
   1284   _sspiSetAllowsExpiredCerts(http->tls, TRUE);
   1285 
   1286   if (!_sspiConnect(http->tls, hostname))
   1287   {
   1288     _sspiFree(http->tls);
   1289     http->tls = NULL;
   1290 
   1291     http->error  = EIO;
   1292     http->status = HTTP_STATUS_ERROR;
   1293 
   1294     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
   1295                   _("Unable to establish a secure connection to host."), 1);
   1296 
   1297     return (-1);
   1298   }
   1299 
   1300   return (0);
   1301 }
   1302 #endif // 0
   1303 
   1304 
   1305 /*
   1306  * 'http_sspi_alloc()' - Allocate SSPI object.
   1307  */
   1308 
   1309 static _http_sspi_t *			/* O  - New SSPI/SSL object */
   1310 http_sspi_alloc(void)
   1311 {
   1312   return ((_http_sspi_t *)calloc(sizeof(_http_sspi_t), 1));
   1313 }
   1314 
   1315 
   1316 /*
   1317  * 'http_sspi_client()' - Negotiate a TLS connection as a client.
   1318  */
   1319 
   1320 static int				/* O - 0 on success, -1 on failure */
   1321 http_sspi_client(http_t     *http,	/* I - Client connection */
   1322                  const char *hostname)	/* I - Server hostname */
   1323 {
   1324   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
   1325   DWORD		dwSize;			/* Size for buffer */
   1326   DWORD		dwSSPIFlags;		/* SSL connection attributes we want */
   1327   DWORD		dwSSPIOutFlags;		/* SSL connection attributes we got */
   1328   TimeStamp	tsExpiry;		/* Time stamp */
   1329   SECURITY_STATUS scRet;		/* Status */
   1330   int		cbData;			/* Data count */
   1331   SecBufferDesc	inBuffer;		/* Array of SecBuffer structs */
   1332   SecBuffer	inBuffers[2];		/* Security package buffer */
   1333   SecBufferDesc	outBuffer;		/* Array of SecBuffer structs */
   1334   SecBuffer	outBuffers[1];		/* Security package buffer */
   1335   int		ret = 0;		/* Return value */
   1336   char		username[1024],		/* Current username */
   1337 		common_name[1024];	/* CN=username */
   1338 
   1339 
   1340   DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname));
   1341 
   1342   dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT   |
   1343                 ISC_REQ_REPLAY_DETECT     |
   1344                 ISC_REQ_CONFIDENTIALITY   |
   1345                 ISC_RET_EXTENDED_ERROR    |
   1346                 ISC_REQ_ALLOCATE_MEMORY   |
   1347                 ISC_REQ_STREAM;
   1348 
   1349  /*
   1350   * Lookup the client certificate...
   1351   */
   1352 
   1353   dwSize = sizeof(username);
   1354   GetUserName(username, &dwSize);
   1355   snprintf(common_name, sizeof(common_name), "CN=%s", username);
   1356 
   1357   if (!http_sspi_find_credentials(http, L"ClientContainer", common_name))
   1358     if (!http_sspi_make_credentials(http->tls, L"ClientContainer", common_name, _HTTP_MODE_CLIENT, 10))
   1359     {
   1360       DEBUG_puts("5http_sspi_client: Unable to get client credentials.");
   1361       return (-1);
   1362     }
   1363 
   1364  /*
   1365   * Initiate a ClientHello message and generate a token.
   1366   */
   1367 
   1368   outBuffers[0].pvBuffer   = NULL;
   1369   outBuffers[0].BufferType = SECBUFFER_TOKEN;
   1370   outBuffers[0].cbBuffer   = 0;
   1371 
   1372   outBuffer.cBuffers  = 1;
   1373   outBuffer.pBuffers  = outBuffers;
   1374   outBuffer.ulVersion = SECBUFFER_VERSION;
   1375 
   1376   scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
   1377 
   1378   if (scRet != SEC_I_CONTINUE_NEEDED)
   1379   {
   1380     DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
   1381     return (-1);
   1382   }
   1383 
   1384  /*
   1385   * Send response to server if there is one.
   1386   */
   1387 
   1388   if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
   1389   {
   1390     if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0)
   1391     {
   1392       DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
   1393       FreeContextBuffer(outBuffers[0].pvBuffer);
   1394       DeleteSecurityContext(&sspi->context);
   1395       return (-1);
   1396     }
   1397 
   1398     DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
   1399 
   1400     FreeContextBuffer(outBuffers[0].pvBuffer);
   1401     outBuffers[0].pvBuffer = NULL;
   1402   }
   1403 
   1404   dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
   1405 		ISC_REQ_SEQUENCE_DETECT        |
   1406                 ISC_REQ_REPLAY_DETECT          |
   1407                 ISC_REQ_CONFIDENTIALITY        |
   1408                 ISC_RET_EXTENDED_ERROR         |
   1409                 ISC_REQ_ALLOCATE_MEMORY        |
   1410                 ISC_REQ_STREAM;
   1411 
   1412   sspi->decryptBufferUsed = 0;
   1413 
   1414  /*
   1415   * Loop until the handshake is finished or an error occurs.
   1416   */
   1417 
   1418   scRet = SEC_I_CONTINUE_NEEDED;
   1419 
   1420   while(scRet == SEC_I_CONTINUE_NEEDED        ||
   1421         scRet == SEC_E_INCOMPLETE_MESSAGE     ||
   1422         scRet == SEC_I_INCOMPLETE_CREDENTIALS)
   1423   {
   1424     if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
   1425     {
   1426       if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
   1427       {
   1428 	BYTE *temp;			/* New buffer */
   1429 
   1430 	if (sspi->decryptBufferLength >= 262144)
   1431 	{
   1432 	  WSASetLastError(E_OUTOFMEMORY);
   1433 	  DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)");
   1434 	  return (-1);
   1435 	}
   1436 
   1437 	if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
   1438 	{
   1439 	  DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
   1440 	  WSASetLastError(E_OUTOFMEMORY);
   1441 	  return (-1);
   1442 	}
   1443 
   1444 	sspi->decryptBufferLength += 4096;
   1445 	sspi->decryptBuffer       = temp;
   1446       }
   1447 
   1448       cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
   1449 
   1450       if (cbData < 0)
   1451       {
   1452         DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError()));
   1453         return (-1);
   1454       }
   1455       else if (cbData == 0)
   1456       {
   1457         DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected."));
   1458         return (-1);
   1459       }
   1460 
   1461       DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData));
   1462 
   1463       sspi->decryptBufferUsed += cbData;
   1464     }
   1465 
   1466    /*
   1467     * Set up the input buffers. Buffer 0 is used to pass in data received from
   1468     * the server.  Schannel will consume some or all of this.  Leftover data
   1469     * (if any) will be placed in buffer 1 and given a buffer type of
   1470     * SECBUFFER_EXTRA.
   1471     */
   1472 
   1473     inBuffers[0].pvBuffer   = sspi->decryptBuffer;
   1474     inBuffers[0].cbBuffer   = (unsigned long)sspi->decryptBufferUsed;
   1475     inBuffers[0].BufferType = SECBUFFER_TOKEN;
   1476 
   1477     inBuffers[1].pvBuffer   = NULL;
   1478     inBuffers[1].cbBuffer   = 0;
   1479     inBuffers[1].BufferType = SECBUFFER_EMPTY;
   1480 
   1481     inBuffer.cBuffers       = 2;
   1482     inBuffer.pBuffers       = inBuffers;
   1483     inBuffer.ulVersion      = SECBUFFER_VERSION;
   1484 
   1485    /*
   1486     * Set up the output buffers. These are initialized to NULL so as to make it
   1487     * less likely we'll attempt to free random garbage later.
   1488     */
   1489 
   1490     outBuffers[0].pvBuffer   = NULL;
   1491     outBuffers[0].BufferType = SECBUFFER_TOKEN;
   1492     outBuffers[0].cbBuffer   = 0;
   1493 
   1494     outBuffer.cBuffers       = 1;
   1495     outBuffer.pBuffers       = outBuffers;
   1496     outBuffer.ulVersion      = SECBUFFER_VERSION;
   1497 
   1498    /*
   1499     * Call InitializeSecurityContext.
   1500     */
   1501 
   1502     scRet = InitializeSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
   1503 
   1504    /*
   1505     * If InitializeSecurityContext was successful (or if the error was one of
   1506     * the special extended ones), send the contents of the output buffer to the
   1507     * server.
   1508     */
   1509 
   1510     if (scRet == SEC_E_OK                ||
   1511         scRet == SEC_I_CONTINUE_NEEDED   ||
   1512         FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
   1513     {
   1514       if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
   1515       {
   1516         cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
   1517 
   1518         if (cbData <= 0)
   1519         {
   1520           DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
   1521           FreeContextBuffer(outBuffers[0].pvBuffer);
   1522           DeleteSecurityContext(&sspi->context);
   1523           return (-1);
   1524         }
   1525 
   1526         DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
   1527 
   1528        /*
   1529         * Free output buffer.
   1530         */
   1531 
   1532         FreeContextBuffer(outBuffers[0].pvBuffer);
   1533         outBuffers[0].pvBuffer = NULL;
   1534       }
   1535     }
   1536 
   1537    /*
   1538     * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we
   1539     * need to read more data from the server and try again.
   1540     */
   1541 
   1542     if (scRet == SEC_E_INCOMPLETE_MESSAGE)
   1543       continue;
   1544 
   1545    /*
   1546     * If InitializeSecurityContext returned SEC_E_OK, then the handshake
   1547     * completed successfully.
   1548     */
   1549 
   1550     if (scRet == SEC_E_OK)
   1551     {
   1552      /*
   1553       * If the "extra" buffer contains data, this is encrypted application
   1554       * protocol layer stuff. It needs to be saved. The application layer will
   1555       * later decrypt it with DecryptMessage.
   1556       */
   1557 
   1558       DEBUG_puts("5http_sspi_client: Handshake was successful.");
   1559 
   1560       if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
   1561       {
   1562         memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
   1563 
   1564         sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
   1565 
   1566         DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed));
   1567       }
   1568       else
   1569         sspi->decryptBufferUsed = 0;
   1570 
   1571      /*
   1572       * Bail out to quit
   1573       */
   1574 
   1575       break;
   1576     }
   1577 
   1578    /*
   1579     * Check for fatal error.
   1580     */
   1581 
   1582     if (FAILED(scRet))
   1583     {
   1584       DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
   1585       ret = -1;
   1586       break;
   1587     }
   1588 
   1589    /*
   1590     * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
   1591     * then the server just requested client authentication.
   1592     */
   1593 
   1594     if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
   1595     {
   1596      /*
   1597       * Unimplemented
   1598       */
   1599 
   1600       DEBUG_printf(("5http_sspi_client: server requested client credentials."));
   1601       ret = -1;
   1602       break;
   1603     }
   1604 
   1605    /*
   1606     * Copy any leftover data from the "extra" buffer, and go around again.
   1607     */
   1608 
   1609     if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
   1610     {
   1611       memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
   1612 
   1613       sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
   1614     }
   1615     else
   1616     {
   1617       sspi->decryptBufferUsed = 0;
   1618     }
   1619   }
   1620 
   1621   if (!ret)
   1622   {
   1623    /*
   1624     * Success!  Get the server cert
   1625     */
   1626 
   1627     sspi->contextInitialized = TRUE;
   1628 
   1629     scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert));
   1630 
   1631     if (scRet != SEC_E_OK)
   1632     {
   1633       DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
   1634       return (-1);
   1635     }
   1636 
   1637    /*
   1638     * Find out how big the header/trailer will be:
   1639     */
   1640 
   1641     scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
   1642 
   1643     if (scRet != SEC_E_OK)
   1644     {
   1645       DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
   1646       ret = -1;
   1647     }
   1648   }
   1649 
   1650   return (ret);
   1651 }
   1652 
   1653 
   1654 /*
   1655  * 'http_sspi_create_credential()' - Create an SSPI certificate context.
   1656  */
   1657 
   1658 static PCCERT_CONTEXT			/* O - Certificate context */
   1659 http_sspi_create_credential(
   1660     http_credential_t *cred)		/* I - Credential */
   1661 {
   1662   if (cred)
   1663     return (CertCreateCertificateContext(X509_ASN_ENCODING, cred->data, cred->datalen));
   1664   else
   1665     return (NULL);
   1666 }
   1667 
   1668 
   1669 /*
   1670  * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store.
   1671  */
   1672 
   1673 static BOOL				/* O - 1 on success, 0 on failure */
   1674 http_sspi_find_credentials(
   1675     http_t       *http,			/* I - HTTP connection */
   1676     const LPWSTR container,		/* I - Cert container name */
   1677     const char   *common_name)		/* I - Common name of certificate */
   1678 {
   1679   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
   1680   HCERTSTORE	store = NULL;		/* Certificate store */
   1681   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
   1682   DWORD		dwSize = 0; 		/* 32 bit size */
   1683   PBYTE		p = NULL;		/* Temporary storage */
   1684   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
   1685 					/* Handle to a CSP */
   1686   CERT_NAME_BLOB sib;			/* Arbitrary array of bytes */
   1687   SCHANNEL_CRED	SchannelCred;		/* Schannel credential data */
   1688   TimeStamp	tsExpiry;		/* Time stamp */
   1689   SECURITY_STATUS Status;		/* Status */
   1690   BOOL		ok = TRUE;		/* Return value */
   1691 
   1692 
   1693   if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
   1694   {
   1695     if (GetLastError() == NTE_EXISTS)
   1696     {
   1697       if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
   1698       {
   1699         DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1700         ok = FALSE;
   1701         goto cleanup;
   1702       }
   1703     }
   1704   }
   1705 
   1706   store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
   1707 
   1708   if (!store)
   1709   {
   1710     DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1711     ok = FALSE;
   1712     goto cleanup;
   1713   }
   1714 
   1715   dwSize = 0;
   1716 
   1717   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
   1718   {
   1719     DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1720     ok = FALSE;
   1721     goto cleanup;
   1722   }
   1723 
   1724   p = (PBYTE)malloc(dwSize);
   1725 
   1726   if (!p)
   1727   {
   1728     DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize));
   1729     ok = FALSE;
   1730     goto cleanup;
   1731   }
   1732 
   1733   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
   1734   {
   1735     DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1736     ok = FALSE;
   1737     goto cleanup;
   1738   }
   1739 
   1740   sib.cbData = dwSize;
   1741   sib.pbData = p;
   1742 
   1743   storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
   1744 
   1745   if (!storedContext)
   1746   {
   1747     DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name));
   1748     ok = FALSE;
   1749     goto cleanup;
   1750   }
   1751 
   1752   ZeroMemory(&SchannelCred, sizeof(SchannelCred));
   1753 
   1754   SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
   1755   SchannelCred.cCreds    = 1;
   1756   SchannelCred.paCred    = &storedContext;
   1757 
   1758  /*
   1759   * Set supported protocols (can also be overriden in the registry...)
   1760   */
   1761 
   1762 #ifdef SP_PROT_TLS1_2_SERVER
   1763   if (http->mode == _HTTP_MODE_SERVER)
   1764   {
   1765     if (tls_options & _HTTP_TLS_DENY_TLS10)
   1766       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER;
   1767     else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
   1768       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER;
   1769     else
   1770       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER;
   1771   }
   1772   else
   1773   {
   1774     if (tls_options & _HTTP_TLS_DENY_TLS10)
   1775       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT;
   1776     else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
   1777       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT;
   1778     else
   1779       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT;
   1780   }
   1781 
   1782 #else
   1783   if (http->mode == _HTTP_MODE_SERVER)
   1784   {
   1785     if (tls_options & _HTTP_TLS_ALLOW_SSL3)
   1786       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER;
   1787     else
   1788       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER;
   1789   }
   1790   else
   1791   {
   1792     if (tls_options & _HTTP_TLS_ALLOW_SSL3)
   1793       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT;
   1794     else
   1795       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
   1796   }
   1797 #endif /* SP_PROT_TLS1_2_SERVER */
   1798 
   1799   /* TODO: Support _HTTP_TLS_ALLOW_RC4, _HTTP_TLS_ALLOW_DH, and _HTTP_TLS_DENY_CBC options; right now we'll rely on Windows registry to enable/disable RC4/DH/CBC... */
   1800 
   1801  /*
   1802   * Create an SSPI credential.
   1803   */
   1804 
   1805   Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
   1806   if (Status != SEC_E_OK)
   1807   {
   1808     DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
   1809     ok = FALSE;
   1810     goto cleanup;
   1811   }
   1812 
   1813 cleanup:
   1814 
   1815  /*
   1816   * Cleanup
   1817   */
   1818 
   1819   if (storedContext)
   1820     CertFreeCertificateContext(storedContext);
   1821 
   1822   if (p)
   1823     free(p);
   1824 
   1825   if (store)
   1826     CertCloseStore(store, 0);
   1827 
   1828   if (hProv)
   1829     CryptReleaseContext(hProv, 0);
   1830 
   1831   return (ok);
   1832 }
   1833 
   1834 
   1835 /*
   1836  * 'http_sspi_free()' - Close a connection and free resources.
   1837  */
   1838 
   1839 static void
   1840 http_sspi_free(_http_sspi_t *sspi)	/* I - SSPI data */
   1841 {
   1842   if (!sspi)
   1843     return;
   1844 
   1845   if (sspi->contextInitialized)
   1846     DeleteSecurityContext(&sspi->context);
   1847 
   1848   if (sspi->decryptBuffer)
   1849     free(sspi->decryptBuffer);
   1850 
   1851   if (sspi->readBuffer)
   1852     free(sspi->readBuffer);
   1853 
   1854   if (sspi->writeBuffer)
   1855     free(sspi->writeBuffer);
   1856 
   1857   if (sspi->localCert)
   1858     CertFreeCertificateContext(sspi->localCert);
   1859 
   1860   if (sspi->remoteCert)
   1861     CertFreeCertificateContext(sspi->remoteCert);
   1862 
   1863   free(sspi);
   1864 }
   1865 
   1866 
   1867 /*
   1868  * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store.
   1869  */
   1870 
   1871 static BOOL				/* O - 1 on success, 0 on failure */
   1872 http_sspi_make_credentials(
   1873     _http_sspi_t *sspi,			/* I - SSPI data */
   1874     const LPWSTR container,		/* I - Cert container name */
   1875     const char   *common_name,		/* I - Common name of certificate */
   1876     _http_mode_t mode,			/* I - Client or server? */
   1877     int          years)			/* I - Years until expiration */
   1878 {
   1879   HCERTSTORE	store = NULL;		/* Certificate store */
   1880   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
   1881   PCCERT_CONTEXT createdContext = NULL;	/* Context created by us */
   1882   DWORD		dwSize = 0; 		/* 32 bit size */
   1883   PBYTE		p = NULL;		/* Temporary storage */
   1884   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
   1885 					/* Handle to a CSP */
   1886   CERT_NAME_BLOB sib;			/* Arbitrary array of bytes */
   1887   SCHANNEL_CRED	SchannelCred;		/* Schannel credential data */
   1888   TimeStamp	tsExpiry;		/* Time stamp */
   1889   SECURITY_STATUS Status;		/* Status */
   1890   HCRYPTKEY	hKey = (HCRYPTKEY)NULL;	/* Handle to crypto key */
   1891   CRYPT_KEY_PROV_INFO kpi;		/* Key container info */
   1892   SYSTEMTIME	et;			/* System time */
   1893   CERT_EXTENSIONS exts;			/* Array of cert extensions */
   1894   CRYPT_KEY_PROV_INFO ckp;		/* Handle to crypto key */
   1895   BOOL		ok = TRUE;		/* Return value */
   1896 
   1897 
   1898   DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi, container, common_name, mode, years));
   1899 
   1900   if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
   1901   {
   1902     if (GetLastError() == NTE_EXISTS)
   1903     {
   1904       if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
   1905       {
   1906         DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1907         ok = FALSE;
   1908         goto cleanup;
   1909       }
   1910     }
   1911   }
   1912 
   1913   store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
   1914 
   1915   if (!store)
   1916   {
   1917     DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1918     ok = FALSE;
   1919     goto cleanup;
   1920   }
   1921 
   1922   dwSize = 0;
   1923 
   1924   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
   1925   {
   1926     DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1927     ok = FALSE;
   1928     goto cleanup;
   1929   }
   1930 
   1931   p = (PBYTE)malloc(dwSize);
   1932 
   1933   if (!p)
   1934   {
   1935     DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize));
   1936     ok = FALSE;
   1937     goto cleanup;
   1938   }
   1939 
   1940   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
   1941   {
   1942     DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1943     ok = FALSE;
   1944     goto cleanup;
   1945   }
   1946 
   1947  /*
   1948   * Create a private key and self-signed certificate...
   1949   */
   1950 
   1951   if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
   1952   {
   1953     DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1954     ok = FALSE;
   1955     goto cleanup;
   1956   }
   1957 
   1958   ZeroMemory(&kpi, sizeof(kpi));
   1959   kpi.pwszContainerName = (LPWSTR)container;
   1960   kpi.pwszProvName      = MS_DEF_PROV_W;
   1961   kpi.dwProvType        = PROV_RSA_FULL;
   1962   kpi.dwFlags           = CERT_SET_KEY_CONTEXT_PROP_ID;
   1963   kpi.dwKeySpec         = AT_KEYEXCHANGE;
   1964 
   1965   GetSystemTime(&et);
   1966   et.wYear += years;
   1967 
   1968   ZeroMemory(&exts, sizeof(exts));
   1969 
   1970   createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts);
   1971 
   1972   if (!createdContext)
   1973   {
   1974     DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1975     ok = FALSE;
   1976     goto cleanup;
   1977   }
   1978 
   1979  /*
   1980   * Add the created context to the named store, and associate it with the named
   1981   * container...
   1982   */
   1983 
   1984   if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
   1985   {
   1986     DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   1987     ok = FALSE;
   1988     goto cleanup;
   1989   }
   1990 
   1991   ZeroMemory(&ckp, sizeof(ckp));
   1992   ckp.pwszContainerName = (LPWSTR) container;
   1993   ckp.pwszProvName      = MS_DEF_PROV_W;
   1994   ckp.dwProvType        = PROV_RSA_FULL;
   1995   ckp.dwFlags           = CRYPT_MACHINE_KEYSET;
   1996   ckp.dwKeySpec         = AT_KEYEXCHANGE;
   1997 
   1998   if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
   1999   {
   2000     DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
   2001     ok = FALSE;
   2002     goto cleanup;
   2003   }
   2004 
   2005  /*
   2006   * Get a handle to use the certificate...
   2007   */
   2008 
   2009   ZeroMemory(&SchannelCred, sizeof(SchannelCred));
   2010 
   2011   SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
   2012   SchannelCred.cCreds    = 1;
   2013   SchannelCred.paCred    = &storedContext;
   2014 
   2015  /*
   2016   * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
   2017   */
   2018 
   2019   if (mode == _HTTP_MODE_SERVER)
   2020     SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
   2021 
   2022  /*
   2023   * Create an SSPI credential.
   2024   */
   2025 
   2026   Status = AcquireCredentialsHandle(NULL, UNISP_NAME, mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
   2027   if (Status != SEC_E_OK)
   2028   {
   2029     DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
   2030     ok = FALSE;
   2031     goto cleanup;
   2032   }
   2033 
   2034 cleanup:
   2035 
   2036  /*
   2037   * Cleanup
   2038   */
   2039 
   2040   if (hKey)
   2041     CryptDestroyKey(hKey);
   2042 
   2043   if (createdContext)
   2044     CertFreeCertificateContext(createdContext);
   2045 
   2046   if (storedContext)
   2047     CertFreeCertificateContext(storedContext);
   2048 
   2049   if (p)
   2050     free(p);
   2051 
   2052   if (store)
   2053     CertCloseStore(store, 0);
   2054 
   2055   if (hProv)
   2056     CryptReleaseContext(hProv, 0);
   2057 
   2058   return (ok);
   2059 }
   2060 
   2061 
   2062 /*
   2063  * 'http_sspi_server()' - Negotiate a TLS connection as a server.
   2064  */
   2065 
   2066 static int				/* O - 0 on success, -1 on failure */
   2067 http_sspi_server(http_t     *http,	/* I - HTTP connection */
   2068                  const char *hostname)	/* I - Hostname of server */
   2069 {
   2070   _http_sspi_t	*sspi = http->tls;	/* I - SSPI data */
   2071   char		common_name[512];	/* Common name for cert */
   2072   DWORD		dwSSPIFlags;		/* SSL connection attributes we want */
   2073   DWORD		dwSSPIOutFlags;		/* SSL connection attributes we got */
   2074   TimeStamp	tsExpiry;		/* Time stamp */
   2075   SECURITY_STATUS scRet;		/* SSPI Status */
   2076   SecBufferDesc	inBuffer;		/* Array of SecBuffer structs */
   2077   SecBuffer	inBuffers[2];		/* Security package buffer */
   2078   SecBufferDesc	outBuffer;		/* Array of SecBuffer structs */
   2079   SecBuffer	outBuffers[1];		/* Security package buffer */
   2080   int		num = 0;		/* 32 bit status value */
   2081   BOOL		fInitContext = TRUE;	/* Has the context been init'd? */
   2082   int		ret = 0;		/* Return value */
   2083 
   2084 
   2085   DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname));
   2086 
   2087   dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT  |
   2088                 ASC_REQ_REPLAY_DETECT    |
   2089                 ASC_REQ_CONFIDENTIALITY  |
   2090                 ASC_REQ_EXTENDED_ERROR   |
   2091                 ASC_REQ_ALLOCATE_MEMORY  |
   2092                 ASC_REQ_STREAM;
   2093 
   2094   sspi->decryptBufferUsed = 0;
   2095 
   2096  /*
   2097   * Lookup the server certificate...
   2098   */
   2099 
   2100   snprintf(common_name, sizeof(common_name), "CN=%s", hostname);
   2101 
   2102   if (!http_sspi_find_credentials(http, L"ServerContainer", common_name))
   2103     if (!http_sspi_make_credentials(http->tls, L"ServerContainer", common_name, _HTTP_MODE_SERVER, 10))
   2104     {
   2105       DEBUG_puts("5http_sspi_server: Unable to get server credentials.");
   2106       return (-1);
   2107     }
   2108 
   2109  /*
   2110   * Set OutBuffer for AcceptSecurityContext call
   2111   */
   2112 
   2113   outBuffer.cBuffers  = 1;
   2114   outBuffer.pBuffers  = outBuffers;
   2115   outBuffer.ulVersion = SECBUFFER_VERSION;
   2116 
   2117   scRet = SEC_I_CONTINUE_NEEDED;
   2118 
   2119   while (scRet == SEC_I_CONTINUE_NEEDED    ||
   2120          scRet == SEC_E_INCOMPLETE_MESSAGE ||
   2121          scRet == SEC_I_INCOMPLETE_CREDENTIALS)
   2122   {
   2123     if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
   2124     {
   2125       if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
   2126       {
   2127 	BYTE *temp;			/* New buffer */
   2128 
   2129 	if (sspi->decryptBufferLength >= 262144)
   2130 	{
   2131 	  WSASetLastError(E_OUTOFMEMORY);
   2132 	  DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)");
   2133 	  return (-1);
   2134 	}
   2135 
   2136 	if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
   2137 	{
   2138 	  DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
   2139 	  WSASetLastError(E_OUTOFMEMORY);
   2140 	  return (-1);
   2141 	}
   2142 
   2143 	sspi->decryptBufferLength += 4096;
   2144 	sspi->decryptBuffer       = temp;
   2145       }
   2146 
   2147       for (;;)
   2148       {
   2149         num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
   2150 
   2151         if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
   2152           Sleep(1);
   2153         else
   2154           break;
   2155       }
   2156 
   2157       if (num < 0)
   2158       {
   2159         DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError()));
   2160         return (-1);
   2161       }
   2162       else if (num == 0)
   2163       {
   2164         DEBUG_puts("5http_sspi_server: client disconnected");
   2165         return (-1);
   2166       }
   2167 
   2168       DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num));
   2169       sspi->decryptBufferUsed += num;
   2170     }
   2171 
   2172    /*
   2173     * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process
   2174     * on this run around the loop.
   2175     */
   2176 
   2177     inBuffers[0].pvBuffer   = sspi->decryptBuffer;
   2178     inBuffers[0].cbBuffer   = (unsigned long)sspi->decryptBufferUsed;
   2179     inBuffers[0].BufferType = SECBUFFER_TOKEN;
   2180 
   2181     inBuffers[1].pvBuffer   = NULL;
   2182     inBuffers[1].cbBuffer   = 0;
   2183     inBuffers[1].BufferType = SECBUFFER_EMPTY;
   2184 
   2185     inBuffer.cBuffers       = 2;
   2186     inBuffer.pBuffers       = inBuffers;
   2187     inBuffer.ulVersion      = SECBUFFER_VERSION;
   2188 
   2189    /*
   2190     * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to
   2191     * free random garbage at the quit.
   2192     */
   2193 
   2194     outBuffers[0].pvBuffer   = NULL;
   2195     outBuffers[0].BufferType = SECBUFFER_TOKEN;
   2196     outBuffers[0].cbBuffer   = 0;
   2197 
   2198     scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry);
   2199 
   2200     fInitContext = FALSE;
   2201 
   2202     if (scRet == SEC_E_OK              ||
   2203         scRet == SEC_I_CONTINUE_NEEDED ||
   2204         (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0)))
   2205     {
   2206       if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
   2207       {
   2208        /*
   2209         * Send response to server if there is one.
   2210         */
   2211 
   2212         num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
   2213 
   2214         if (num <= 0)
   2215         {
   2216           DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError()));
   2217 	  return (-1);
   2218         }
   2219 
   2220         DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer));
   2221 
   2222         FreeContextBuffer(outBuffers[0].pvBuffer);
   2223         outBuffers[0].pvBuffer = NULL;
   2224       }
   2225     }
   2226 
   2227     if (scRet == SEC_E_OK)
   2228     {
   2229      /*
   2230       * If there's extra data then save it for next time we go to decrypt.
   2231       */
   2232 
   2233       if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
   2234       {
   2235         memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
   2236         sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
   2237       }
   2238       else
   2239       {
   2240         sspi->decryptBufferUsed = 0;
   2241       }
   2242       break;
   2243     }
   2244     else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE)
   2245     {
   2246       DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
   2247       ret = -1;
   2248       break;
   2249     }
   2250 
   2251     if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
   2252         scRet != SEC_I_INCOMPLETE_CREDENTIALS)
   2253     {
   2254       if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
   2255       {
   2256         memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
   2257         sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
   2258       }
   2259       else
   2260       {
   2261         sspi->decryptBufferUsed = 0;
   2262       }
   2263     }
   2264   }
   2265 
   2266   if (!ret)
   2267   {
   2268     sspi->contextInitialized = TRUE;
   2269 
   2270    /*
   2271     * Find out how big the header will be:
   2272     */
   2273 
   2274     scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
   2275 
   2276     if (scRet != SEC_E_OK)
   2277     {
   2278       DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
   2279       ret = -1;
   2280     }
   2281   }
   2282 
   2283   return (ret);
   2284 }
   2285 
   2286 
   2287 /*
   2288  * 'http_sspi_strerror()' - Return a string for the specified error code.
   2289  */
   2290 
   2291 static const char *			/* O - String for error */
   2292 http_sspi_strerror(char   *buffer,	/* I - Error message buffer */
   2293                    size_t bufsize,	/* I - Size of buffer */
   2294                    DWORD  code)		/* I - Error code */
   2295 {
   2296   if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, bufsize, NULL))
   2297   {
   2298    /*
   2299     * Strip trailing CR + LF...
   2300     */
   2301 
   2302     char	*ptr;			/* Pointer into error message */
   2303 
   2304     for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --)
   2305       if (*ptr == '\n' || *ptr == '\r')
   2306         *ptr = '\0';
   2307       else
   2308         break;
   2309   }
   2310   else
   2311     snprintf(buffer, bufsize, "Unknown error %x", code);
   2312 
   2313   return (buffer);
   2314 }
   2315 
   2316 
   2317 /*
   2318  * 'http_sspi_verify()' - Verify a certificate.
   2319  */
   2320 
   2321 static DWORD				/* O - Error code (0 == No error) */
   2322 http_sspi_verify(
   2323     PCCERT_CONTEXT cert,		/* I - Server certificate */
   2324     const char     *common_name,	/* I - Common name */
   2325     DWORD          dwCertFlags)		/* I - Verification flags */
   2326 {
   2327   HTTPSPolicyCallbackData httpsPolicy;	/* HTTPS Policy Struct */
   2328   CERT_CHAIN_POLICY_PARA policyPara;	/* Cert chain policy parameters */
   2329   CERT_CHAIN_POLICY_STATUS policyStatus;/* Cert chain policy status */
   2330   CERT_CHAIN_PARA	chainPara;	/* Used for searching and matching criteria */
   2331   PCCERT_CHAIN_CONTEXT	chainContext = NULL;
   2332 					/* Certificate chain */
   2333   PWSTR			commonNameUnicode = NULL;
   2334 					/* Unicode common name */
   2335   LPSTR			rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
   2336                                          szOID_SERVER_GATED_CRYPTO,
   2337                                          szOID_SGC_NETSCAPE };
   2338 					/* How are we using this certificate? */
   2339   DWORD			cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
   2340 					/* Number of ites in rgszUsages */
   2341   DWORD			count;		/* 32 bit count variable */
   2342   DWORD			status;		/* Return value */
   2343 #ifdef DEBUG
   2344   char			error[1024];	/* Error message string */
   2345 #endif /* DEBUG */
   2346 
   2347 
   2348   if (!cert)
   2349     return (SEC_E_WRONG_PRINCIPAL);
   2350 
   2351  /*
   2352   * Convert common name to Unicode.
   2353   */
   2354 
   2355   if (!common_name || !*common_name)
   2356     return (SEC_E_WRONG_PRINCIPAL);
   2357 
   2358   count             = MultiByteToWideChar(CP_ACP, 0, common_name, -1, NULL, 0);
   2359   commonNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR));
   2360   if (!commonNameUnicode)
   2361     return (SEC_E_INSUFFICIENT_MEMORY);
   2362 
   2363   if (!MultiByteToWideChar(CP_ACP, 0, common_name, -1, commonNameUnicode, count))
   2364   {
   2365     LocalFree(commonNameUnicode);
   2366     return (SEC_E_WRONG_PRINCIPAL);
   2367   }
   2368 
   2369  /*
   2370   * Build certificate chain.
   2371   */
   2372 
   2373   ZeroMemory(&chainPara, sizeof(chainPara));
   2374 
   2375   chainPara.cbSize					= sizeof(chainPara);
   2376   chainPara.RequestedUsage.dwType			= USAGE_MATCH_TYPE_OR;
   2377   chainPara.RequestedUsage.Usage.cUsageIdentifier	= cUsages;
   2378   chainPara.RequestedUsage.Usage.rgpszUsageIdentifier	= rgszUsages;
   2379 
   2380   if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext))
   2381   {
   2382     status = GetLastError();
   2383 
   2384     DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status)));
   2385 
   2386     LocalFree(commonNameUnicode);
   2387     return (status);
   2388   }
   2389 
   2390  /*
   2391   * Validate certificate chain.
   2392   */
   2393 
   2394   ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
   2395   httpsPolicy.cbStruct		= sizeof(HTTPSPolicyCallbackData);
   2396   httpsPolicy.dwAuthType	= AUTHTYPE_SERVER;
   2397   httpsPolicy.fdwChecks		= dwCertFlags;
   2398   httpsPolicy.pwszServerName	= commonNameUnicode;
   2399 
   2400   memset(&policyPara, 0, sizeof(policyPara));
   2401   policyPara.cbSize		= sizeof(policyPara);
   2402   policyPara.pvExtraPolicyPara	= &httpsPolicy;
   2403 
   2404   memset(&policyStatus, 0, sizeof(policyStatus));
   2405   policyStatus.cbSize = sizeof(policyStatus);
   2406 
   2407   if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus))
   2408   {
   2409     status = GetLastError();
   2410 
   2411     DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status)));
   2412   }
   2413   else if (policyStatus.dwError)
   2414     status = policyStatus.dwError;
   2415   else
   2416     status = SEC_E_OK;
   2417 
   2418   if (chainContext)
   2419     CertFreeCertificateChain(chainContext);
   2420 
   2421   if (commonNameUnicode)
   2422     LocalFree(commonNameUnicode);
   2423 
   2424   return (status);
   2425 }
   2426