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 */
cupsMakeServerCredentials(const char * path,const char * common_name,int num_alt_names,const char ** alt_names,time_t expiration_date)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 */
cupsSetServerCredentials(const char * path,const char * common_name,int auto_create)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) */
httpCopyCredentials(http_t * http,cups_array_t ** credentials)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 */
_httpCreateCredentials(cups_array_t * 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 */
httpCredentialsAreValidForName(cups_array_t * credentials,const char * common_name)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 */
httpCredentialsGetTrust(cups_array_t * credentials,const char * common_name)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 */
httpCredentialsGetExpiration(cups_array_t * 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 */
httpCredentialsString(cups_array_t * credentials,char * buffer,size_t bufsize)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
_httpFreeCredentials(http_tls_credentials_t credentials)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 */
httpLoadCredentials(const char * path,cups_array_t ** credentials,const char * common_name)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 */
httpSaveCredentials(const char * path,cups_array_t * credentials,const char * common_name)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
_httpTLSInitialize(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 */
_httpTLSPending(http_t * http)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 */
_httpTLSRead(http_t * http,char * buf,int len)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
_httpTLSSetOptions(int options)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 */
_httpTLSStart(http_t * http)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
_httpTLSStop(http_t * http)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 */
_httpTLSWrite(http_t * http,const char * buf,int len)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 */
http_sspi_alloc(void)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 */
http_sspi_client(http_t * http,const char * hostname)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 */
http_sspi_create_credential(http_credential_t * cred)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 */
http_sspi_find_credentials(http_t * http,const LPWSTR container,const char * common_name)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
http_sspi_free(_http_sspi_t * sspi)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 */
http_sspi_make_credentials(_http_sspi_t * sspi,const LPWSTR container,const char * common_name,_http_mode_t mode,int years)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 */
http_sspi_server(http_t * http,const char * hostname)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 */
http_sspi_strerror(char * buffer,size_t bufsize,DWORD code)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) */
http_sspi_verify(PCCERT_CONTEXT cert,const char * common_name,DWORD dwCertFlags)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