1 /*
2  * TLS support for CUPS on Windows using the Security Support Provider
3  * Interface (SSPI).
4  *
5  * Copyright 2010-2015 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   tls_options = options;
917 }
918 
919 
920 /*
921  * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
922  */
923 
924 int					/* O - 0 on success, -1 on failure */
_httpTLSStart(http_t * http)925 _httpTLSStart(http_t *http)		/* I - HTTP connection */
926 {
927   char	hostname[256],			/* Hostname */
928 	*hostptr;			/* Pointer into hostname */
929 
930 
931   DEBUG_printf(("3_httpTLSStart(http=%p)", http));
932 
933   if (tls_options < 0)
934   {
935     DEBUG_puts("4_httpTLSStart: Setting defaults.");
936     _cupsSetDefaults();
937     DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
938   }
939 
940   if ((http->tls = http_sspi_alloc()) == NULL)
941     return (-1);
942 
943   if (http->mode == _HTTP_MODE_CLIENT)
944   {
945    /*
946     * Client: determine hostname...
947     */
948 
949     if (httpAddrLocalhost(http->hostaddr))
950     {
951       strlcpy(hostname, "localhost", sizeof(hostname));
952     }
953     else
954     {
955      /*
956       * Otherwise make sure the hostname we have does not end in a trailing dot.
957       */
958 
959       strlcpy(hostname, http->hostname, sizeof(hostname));
960       if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
961 	  *hostptr == '.')
962 	*hostptr = '\0';
963     }
964 
965     return (http_sspi_client(http, hostname));
966   }
967   else
968   {
969    /*
970     * Server: determine hostname to use...
971     */
972 
973     if (http->fields[HTTP_FIELD_HOST][0])
974     {
975      /*
976       * Use hostname for TLS upgrade...
977       */
978 
979       strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
980     }
981     else
982     {
983      /*
984       * Resolve hostname from connection address...
985       */
986 
987       http_addr_t	addr;		/* Connection address */
988       socklen_t		addrlen;	/* Length of address */
989 
990       addrlen = sizeof(addr);
991       if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
992       {
993 	DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno)));
994 	hostname[0] = '\0';
995       }
996       else if (httpAddrLocalhost(&addr))
997 	hostname[0] = '\0';
998       else
999       {
1000 	httpAddrLookup(&addr, hostname, sizeof(hostname));
1001         DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname));
1002       }
1003     }
1004 
1005     return (http_sspi_server(http, hostname));
1006   }
1007 }
1008 
1009 
1010 /*
1011  * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
1012  */
1013 
1014 void
_httpTLSStop(http_t * http)1015 _httpTLSStop(http_t *http)		/* I - HTTP connection */
1016 {
1017   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
1018 
1019 
1020   if (sspi->contextInitialized && http->fd >= 0)
1021   {
1022     SecBufferDesc	message;	/* Array of SecBuffer struct */
1023     SecBuffer		buffers[1] = { 0 };
1024 					/* Security package buffer */
1025     DWORD		dwType;		/* Type */
1026     DWORD		status;		/* Status */
1027 
1028   /*
1029    * Notify schannel that we are about to close the connection.
1030    */
1031 
1032    dwType = SCHANNEL_SHUTDOWN;
1033 
1034    buffers[0].pvBuffer   = &dwType;
1035    buffers[0].BufferType = SECBUFFER_TOKEN;
1036    buffers[0].cbBuffer   = sizeof(dwType);
1037 
1038    message.cBuffers  = 1;
1039    message.pBuffers  = buffers;
1040    message.ulVersion = SECBUFFER_VERSION;
1041 
1042    status = ApplyControlToken(&sspi->context, &message);
1043 
1044    if (SUCCEEDED(status))
1045    {
1046      PBYTE	pbMessage;		/* Message buffer */
1047      DWORD	cbMessage;		/* Message buffer count */
1048      DWORD	cbData;			/* Data count */
1049      DWORD	dwSSPIFlags;		/* SSL attributes we requested */
1050      DWORD	dwSSPIOutFlags;		/* SSL attributes we received */
1051      TimeStamp	tsExpiry;		/* Time stamp */
1052 
1053      dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT     |
1054                    ASC_REQ_REPLAY_DETECT       |
1055                    ASC_REQ_CONFIDENTIALITY     |
1056                    ASC_REQ_EXTENDED_ERROR      |
1057                    ASC_REQ_ALLOCATE_MEMORY     |
1058                    ASC_REQ_STREAM;
1059 
1060      buffers[0].pvBuffer   = NULL;
1061      buffers[0].BufferType = SECBUFFER_TOKEN;
1062      buffers[0].cbBuffer   = 0;
1063 
1064      message.cBuffers  = 1;
1065      message.pBuffers  = buffers;
1066      message.ulVersion = SECBUFFER_VERSION;
1067 
1068      status = AcceptSecurityContext(&sspi->creds, &sspi->context, NULL,
1069                                     dwSSPIFlags, SECURITY_NATIVE_DREP, NULL,
1070                                     &message, &dwSSPIOutFlags, &tsExpiry);
1071 
1072       if (SUCCEEDED(status))
1073       {
1074         pbMessage = buffers[0].pvBuffer;
1075         cbMessage = buffers[0].cbBuffer;
1076 
1077        /*
1078         * Send the close notify message to the client.
1079         */
1080 
1081         if (pbMessage && cbMessage)
1082         {
1083           cbData = send(http->fd, pbMessage, cbMessage, 0);
1084           if ((cbData == SOCKET_ERROR) || (cbData == 0))
1085           {
1086             status = WSAGetLastError();
1087             DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status));
1088           }
1089           else
1090           {
1091             FreeContextBuffer(pbMessage);
1092           }
1093         }
1094       }
1095       else
1096       {
1097         DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
1098       }
1099     }
1100     else
1101     {
1102       DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
1103     }
1104   }
1105 
1106   http_sspi_free(sspi);
1107 
1108   http->tls = NULL;
1109 }
1110 
1111 
1112 /*
1113  * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1114  */
1115 
1116 int					/* O - Bytes written */
_httpTLSWrite(http_t * http,const char * buf,int len)1117 _httpTLSWrite(http_t     *http,		/* I - HTTP connection */
1118 	      const char *buf,		/* I - Buffer holding data */
1119 	      int        len)		/* I - Length of buffer */
1120 {
1121   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
1122   SecBufferDesc	message;		/* Array of SecBuffer struct */
1123   SecBuffer	buffers[4] = { 0 };	/* Security package buffer */
1124   int		bufferLen;		/* Buffer length */
1125   int		bytesLeft;		/* Bytes left to write */
1126   const char	*bufptr;		/* Pointer into buffer */
1127   int		num = 0;		/* Return value */
1128 
1129 
1130   bufferLen = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer;
1131 
1132   if (bufferLen > sspi->writeBufferLength)
1133   {
1134     BYTE *temp;				/* New buffer pointer */
1135 
1136     if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL)
1137     {
1138       DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen));
1139       WSASetLastError(E_OUTOFMEMORY);
1140       return (-1);
1141     }
1142 
1143     sspi->writeBuffer       = temp;
1144     sspi->writeBufferLength = bufferLen;
1145   }
1146 
1147   bytesLeft = len;
1148   bufptr    = buf;
1149 
1150   while (bytesLeft)
1151   {
1152     int chunk = min((int)sspi->streamSizes.cbMaximumMessage, bytesLeft);
1153 					/* Size of data to write */
1154     SECURITY_STATUS scRet;		/* SSPI status */
1155 
1156    /*
1157     * Copy user data into the buffer, starting just past the header...
1158     */
1159 
1160     memcpy(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk);
1161 
1162    /*
1163     * Setup the SSPI buffers
1164     */
1165 
1166     message.ulVersion = SECBUFFER_VERSION;
1167     message.cBuffers  = 4;
1168     message.pBuffers  = buffers;
1169 
1170     buffers[0].pvBuffer   = sspi->writeBuffer;
1171     buffers[0].cbBuffer   = sspi->streamSizes.cbHeader;
1172     buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
1173     buffers[1].pvBuffer   = sspi->writeBuffer + sspi->streamSizes.cbHeader;
1174     buffers[1].cbBuffer   = (unsigned long) chunk;
1175     buffers[1].BufferType = SECBUFFER_DATA;
1176     buffers[2].pvBuffer   = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk;
1177     buffers[2].cbBuffer   = sspi->streamSizes.cbTrailer;
1178     buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
1179     buffers[3].BufferType = SECBUFFER_EMPTY;
1180 
1181    /*
1182     * Encrypt the data
1183     */
1184 
1185     scRet = EncryptMessage(&sspi->context, 0, &message, 0);
1186 
1187     if (FAILED(scRet))
1188     {
1189       DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1190       WSASetLastError(WSASYSCALLFAILURE);
1191       return (-1);
1192     }
1193 
1194    /*
1195     * Send the data. Remember the size of the total data to send is the size
1196     * of the header, the size of the data the caller passed in and the size
1197     * of the trailer...
1198     */
1199 
1200     num = send(http->fd, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0);
1201 
1202     if (num <= 0)
1203     {
1204       DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError()));
1205       return (num);
1206     }
1207 
1208     bytesLeft -= chunk;
1209     bufptr    += chunk;
1210   }
1211 
1212   return (len);
1213 }
1214 
1215 
1216 #if 0
1217 /*
1218  * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
1219  */
1220 
1221 static int				/* O - 0 on success, -1 on failure */
1222 http_setup_ssl(http_t *http)		/* I - Connection to server */
1223 {
1224   char			hostname[256],	/* Hostname */
1225 			*hostptr;	/* Pointer into hostname */
1226 
1227   TCHAR			username[256];	/* Username returned from GetUserName() */
1228   TCHAR			commonName[256];/* Common name for certificate */
1229   DWORD			dwSize;		/* 32 bit size */
1230 
1231 
1232   DEBUG_printf(("7http_setup_ssl(http=%p)", http));
1233 
1234  /*
1235   * Get the hostname to use for SSL...
1236   */
1237 
1238   if (httpAddrLocalhost(http->hostaddr))
1239   {
1240     strlcpy(hostname, "localhost", sizeof(hostname));
1241   }
1242   else
1243   {
1244    /*
1245     * Otherwise make sure the hostname we have does not end in a trailing dot.
1246     */
1247 
1248     strlcpy(hostname, http->hostname, sizeof(hostname));
1249     if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
1250         *hostptr == '.')
1251       *hostptr = '\0';
1252   }
1253 
1254   http->tls = http_sspi_alloc();
1255 
1256   if (!http->tls)
1257   {
1258     _cupsSetHTTPError(HTTP_STATUS_ERROR);
1259     return (-1);
1260   }
1261 
1262   dwSize          = sizeof(username) / sizeof(TCHAR);
1263   GetUserName(username, &dwSize);
1264   _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR),
1265                sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username);
1266 
1267   if (!_sspiGetCredentials(http->tls, L"ClientContainer",
1268                            commonName, FALSE))
1269   {
1270     _sspiFree(http->tls);
1271     http->tls = NULL;
1272 
1273     http->error  = EIO;
1274     http->status = HTTP_STATUS_ERROR;
1275 
1276     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
1277                   _("Unable to establish a secure connection to host."), 1);
1278 
1279     return (-1);
1280   }
1281 
1282   _sspiSetAllowsAnyRoot(http->tls, TRUE);
1283   _sspiSetAllowsExpiredCerts(http->tls, TRUE);
1284 
1285   if (!_sspiConnect(http->tls, hostname))
1286   {
1287     _sspiFree(http->tls);
1288     http->tls = NULL;
1289 
1290     http->error  = EIO;
1291     http->status = HTTP_STATUS_ERROR;
1292 
1293     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
1294                   _("Unable to establish a secure connection to host."), 1);
1295 
1296     return (-1);
1297   }
1298 
1299   return (0);
1300 }
1301 #endif // 0
1302 
1303 
1304 /*
1305  * 'http_sspi_alloc()' - Allocate SSPI object.
1306  */
1307 
1308 static _http_sspi_t *			/* O  - New SSPI/SSL object */
http_sspi_alloc(void)1309 http_sspi_alloc(void)
1310 {
1311   return ((_http_sspi_t *)calloc(sizeof(_http_sspi_t), 1));
1312 }
1313 
1314 
1315 /*
1316  * 'http_sspi_client()' - Negotiate a TLS connection as a client.
1317  */
1318 
1319 static int				/* O - 0 on success, -1 on failure */
http_sspi_client(http_t * http,const char * hostname)1320 http_sspi_client(http_t     *http,	/* I - Client connection */
1321                  const char *hostname)	/* I - Server hostname */
1322 {
1323   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
1324   DWORD		dwSize;			/* Size for buffer */
1325   DWORD		dwSSPIFlags;		/* SSL connection attributes we want */
1326   DWORD		dwSSPIOutFlags;		/* SSL connection attributes we got */
1327   TimeStamp	tsExpiry;		/* Time stamp */
1328   SECURITY_STATUS scRet;		/* Status */
1329   int		cbData;			/* Data count */
1330   SecBufferDesc	inBuffer;		/* Array of SecBuffer structs */
1331   SecBuffer	inBuffers[2];		/* Security package buffer */
1332   SecBufferDesc	outBuffer;		/* Array of SecBuffer structs */
1333   SecBuffer	outBuffers[1];		/* Security package buffer */
1334   int		ret = 0;		/* Return value */
1335   char		username[1024],		/* Current username */
1336 		common_name[1024];	/* CN=username */
1337 
1338 
1339   DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname));
1340 
1341   dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT   |
1342                 ISC_REQ_REPLAY_DETECT     |
1343                 ISC_REQ_CONFIDENTIALITY   |
1344                 ISC_RET_EXTENDED_ERROR    |
1345                 ISC_REQ_ALLOCATE_MEMORY   |
1346                 ISC_REQ_STREAM;
1347 
1348  /*
1349   * Lookup the client certificate...
1350   */
1351 
1352   dwSize = sizeof(username);
1353   GetUserName(username, &dwSize);
1354   snprintf(common_name, sizeof(common_name), "CN=%s", username);
1355 
1356   if (!http_sspi_find_credentials(http, L"ClientContainer", common_name))
1357     if (!http_sspi_make_credentials(http->tls, L"ClientContainer", common_name, _HTTP_MODE_CLIENT, 10))
1358     {
1359       DEBUG_puts("5http_sspi_client: Unable to get client credentials.");
1360       return (-1);
1361     }
1362 
1363  /*
1364   * Initiate a ClientHello message and generate a token.
1365   */
1366 
1367   outBuffers[0].pvBuffer   = NULL;
1368   outBuffers[0].BufferType = SECBUFFER_TOKEN;
1369   outBuffers[0].cbBuffer   = 0;
1370 
1371   outBuffer.cBuffers  = 1;
1372   outBuffer.pBuffers  = outBuffers;
1373   outBuffer.ulVersion = SECBUFFER_VERSION;
1374 
1375   scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
1376 
1377   if (scRet != SEC_I_CONTINUE_NEEDED)
1378   {
1379     DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1380     return (-1);
1381   }
1382 
1383  /*
1384   * Send response to server if there is one.
1385   */
1386 
1387   if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
1388   {
1389     if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0)
1390     {
1391       DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
1392       FreeContextBuffer(outBuffers[0].pvBuffer);
1393       DeleteSecurityContext(&sspi->context);
1394       return (-1);
1395     }
1396 
1397     DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
1398 
1399     FreeContextBuffer(outBuffers[0].pvBuffer);
1400     outBuffers[0].pvBuffer = NULL;
1401   }
1402 
1403   dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
1404 		ISC_REQ_SEQUENCE_DETECT        |
1405                 ISC_REQ_REPLAY_DETECT          |
1406                 ISC_REQ_CONFIDENTIALITY        |
1407                 ISC_RET_EXTENDED_ERROR         |
1408                 ISC_REQ_ALLOCATE_MEMORY        |
1409                 ISC_REQ_STREAM;
1410 
1411   sspi->decryptBufferUsed = 0;
1412 
1413  /*
1414   * Loop until the handshake is finished or an error occurs.
1415   */
1416 
1417   scRet = SEC_I_CONTINUE_NEEDED;
1418 
1419   while(scRet == SEC_I_CONTINUE_NEEDED        ||
1420         scRet == SEC_E_INCOMPLETE_MESSAGE     ||
1421         scRet == SEC_I_INCOMPLETE_CREDENTIALS)
1422   {
1423     if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
1424     {
1425       if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
1426       {
1427 	BYTE *temp;			/* New buffer */
1428 
1429 	if (sspi->decryptBufferLength >= 262144)
1430 	{
1431 	  WSASetLastError(E_OUTOFMEMORY);
1432 	  DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)");
1433 	  return (-1);
1434 	}
1435 
1436 	if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
1437 	{
1438 	  DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
1439 	  WSASetLastError(E_OUTOFMEMORY);
1440 	  return (-1);
1441 	}
1442 
1443 	sspi->decryptBufferLength += 4096;
1444 	sspi->decryptBuffer       = temp;
1445       }
1446 
1447       cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
1448 
1449       if (cbData < 0)
1450       {
1451         DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError()));
1452         return (-1);
1453       }
1454       else if (cbData == 0)
1455       {
1456         DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected."));
1457         return (-1);
1458       }
1459 
1460       DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData));
1461 
1462       sspi->decryptBufferUsed += cbData;
1463     }
1464 
1465    /*
1466     * Set up the input buffers. Buffer 0 is used to pass in data received from
1467     * the server.  Schannel will consume some or all of this.  Leftover data
1468     * (if any) will be placed in buffer 1 and given a buffer type of
1469     * SECBUFFER_EXTRA.
1470     */
1471 
1472     inBuffers[0].pvBuffer   = sspi->decryptBuffer;
1473     inBuffers[0].cbBuffer   = (unsigned long)sspi->decryptBufferUsed;
1474     inBuffers[0].BufferType = SECBUFFER_TOKEN;
1475 
1476     inBuffers[1].pvBuffer   = NULL;
1477     inBuffers[1].cbBuffer   = 0;
1478     inBuffers[1].BufferType = SECBUFFER_EMPTY;
1479 
1480     inBuffer.cBuffers       = 2;
1481     inBuffer.pBuffers       = inBuffers;
1482     inBuffer.ulVersion      = SECBUFFER_VERSION;
1483 
1484    /*
1485     * Set up the output buffers. These are initialized to NULL so as to make it
1486     * less likely we'll attempt to free random garbage later.
1487     */
1488 
1489     outBuffers[0].pvBuffer   = NULL;
1490     outBuffers[0].BufferType = SECBUFFER_TOKEN;
1491     outBuffers[0].cbBuffer   = 0;
1492 
1493     outBuffer.cBuffers       = 1;
1494     outBuffer.pBuffers       = outBuffers;
1495     outBuffer.ulVersion      = SECBUFFER_VERSION;
1496 
1497    /*
1498     * Call InitializeSecurityContext.
1499     */
1500 
1501     scRet = InitializeSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
1502 
1503    /*
1504     * If InitializeSecurityContext was successful (or if the error was one of
1505     * the special extended ones), send the contents of the output buffer to the
1506     * server.
1507     */
1508 
1509     if (scRet == SEC_E_OK                ||
1510         scRet == SEC_I_CONTINUE_NEEDED   ||
1511         FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
1512     {
1513       if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
1514       {
1515         cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
1516 
1517         if (cbData <= 0)
1518         {
1519           DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
1520           FreeContextBuffer(outBuffers[0].pvBuffer);
1521           DeleteSecurityContext(&sspi->context);
1522           return (-1);
1523         }
1524 
1525         DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
1526 
1527        /*
1528         * Free output buffer.
1529         */
1530 
1531         FreeContextBuffer(outBuffers[0].pvBuffer);
1532         outBuffers[0].pvBuffer = NULL;
1533       }
1534     }
1535 
1536    /*
1537     * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we
1538     * need to read more data from the server and try again.
1539     */
1540 
1541     if (scRet == SEC_E_INCOMPLETE_MESSAGE)
1542       continue;
1543 
1544    /*
1545     * If InitializeSecurityContext returned SEC_E_OK, then the handshake
1546     * completed successfully.
1547     */
1548 
1549     if (scRet == SEC_E_OK)
1550     {
1551      /*
1552       * If the "extra" buffer contains data, this is encrypted application
1553       * protocol layer stuff. It needs to be saved. The application layer will
1554       * later decrypt it with DecryptMessage.
1555       */
1556 
1557       DEBUG_puts("5http_sspi_client: Handshake was successful.");
1558 
1559       if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1560       {
1561         memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
1562 
1563         sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
1564 
1565         DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed));
1566       }
1567       else
1568         sspi->decryptBufferUsed = 0;
1569 
1570      /*
1571       * Bail out to quit
1572       */
1573 
1574       break;
1575     }
1576 
1577    /*
1578     * Check for fatal error.
1579     */
1580 
1581     if (FAILED(scRet))
1582     {
1583       DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1584       ret = -1;
1585       break;
1586     }
1587 
1588    /*
1589     * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
1590     * then the server just requested client authentication.
1591     */
1592 
1593     if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
1594     {
1595      /*
1596       * Unimplemented
1597       */
1598 
1599       DEBUG_printf(("5http_sspi_client: server requested client credentials."));
1600       ret = -1;
1601       break;
1602     }
1603 
1604    /*
1605     * Copy any leftover data from the "extra" buffer, and go around again.
1606     */
1607 
1608     if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1609     {
1610       memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
1611 
1612       sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
1613     }
1614     else
1615     {
1616       sspi->decryptBufferUsed = 0;
1617     }
1618   }
1619 
1620   if (!ret)
1621   {
1622    /*
1623     * Success!  Get the server cert
1624     */
1625 
1626     sspi->contextInitialized = TRUE;
1627 
1628     scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert));
1629 
1630     if (scRet != SEC_E_OK)
1631     {
1632       DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1633       return (-1);
1634     }
1635 
1636    /*
1637     * Find out how big the header/trailer will be:
1638     */
1639 
1640     scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
1641 
1642     if (scRet != SEC_E_OK)
1643     {
1644       DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
1645       ret = -1;
1646     }
1647   }
1648 
1649   return (ret);
1650 }
1651 
1652 
1653 /*
1654  * 'http_sspi_create_credential()' - Create an SSPI certificate context.
1655  */
1656 
1657 static PCCERT_CONTEXT			/* O - Certificate context */
http_sspi_create_credential(http_credential_t * cred)1658 http_sspi_create_credential(
1659     http_credential_t *cred)		/* I - Credential */
1660 {
1661   if (cred)
1662     return (CertCreateCertificateContext(X509_ASN_ENCODING, cred->data, cred->datalen));
1663   else
1664     return (NULL);
1665 }
1666 
1667 
1668 /*
1669  * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store.
1670  */
1671 
1672 static BOOL				/* O - 1 on success, 0 on failure */
http_sspi_find_credentials(http_t * http,const LPWSTR container,const char * common_name)1673 http_sspi_find_credentials(
1674     http_t       *http,			/* I - HTTP connection */
1675     const LPWSTR container,		/* I - Cert container name */
1676     const char   *common_name)		/* I - Common name of certificate */
1677 {
1678   _http_sspi_t	*sspi = http->tls;	/* SSPI data */
1679   HCERTSTORE	store = NULL;		/* Certificate store */
1680   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
1681   DWORD		dwSize = 0; 		/* 32 bit size */
1682   PBYTE		p = NULL;		/* Temporary storage */
1683   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
1684 					/* Handle to a CSP */
1685   CERT_NAME_BLOB sib;			/* Arbitrary array of bytes */
1686   SCHANNEL_CRED	SchannelCred;		/* Schannel credential data */
1687   TimeStamp	tsExpiry;		/* Time stamp */
1688   SECURITY_STATUS Status;		/* Status */
1689   BOOL		ok = TRUE;		/* Return value */
1690 
1691 
1692   if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
1693   {
1694     if (GetLastError() == NTE_EXISTS)
1695     {
1696       if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
1697       {
1698         DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1699         ok = FALSE;
1700         goto cleanup;
1701       }
1702     }
1703   }
1704 
1705   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");
1706 
1707   if (!store)
1708   {
1709     DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1710     ok = FALSE;
1711     goto cleanup;
1712   }
1713 
1714   dwSize = 0;
1715 
1716   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
1717   {
1718     DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1719     ok = FALSE;
1720     goto cleanup;
1721   }
1722 
1723   p = (PBYTE)malloc(dwSize);
1724 
1725   if (!p)
1726   {
1727     DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize));
1728     ok = FALSE;
1729     goto cleanup;
1730   }
1731 
1732   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
1733   {
1734     DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1735     ok = FALSE;
1736     goto cleanup;
1737   }
1738 
1739   sib.cbData = dwSize;
1740   sib.pbData = p;
1741 
1742   storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
1743 
1744   if (!storedContext)
1745   {
1746     DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name));
1747     ok = FALSE;
1748     goto cleanup;
1749   }
1750 
1751   ZeroMemory(&SchannelCred, sizeof(SchannelCred));
1752 
1753   SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
1754   SchannelCred.cCreds    = 1;
1755   SchannelCred.paCred    = &storedContext;
1756 
1757  /*
1758   * Set supported protocols (can also be overriden in the registry...)
1759   */
1760 
1761 #ifdef SP_PROT_TLS1_2_SERVER
1762   if (http->mode == _HTTP_MODE_SERVER)
1763   {
1764     if (tls_options & _HTTP_TLS_DENY_TLS10)
1765       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER;
1766     else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
1767       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER;
1768     else
1769       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER;
1770   }
1771   else
1772   {
1773     if (tls_options & _HTTP_TLS_DENY_TLS10)
1774       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT;
1775     else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
1776       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT;
1777     else
1778       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT;
1779   }
1780 
1781 #else
1782   if (http->mode == _HTTP_MODE_SERVER)
1783   {
1784     if (tls_options & _HTTP_TLS_ALLOW_SSL3)
1785       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER;
1786     else
1787       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER;
1788   }
1789   else
1790   {
1791     if (tls_options & _HTTP_TLS_ALLOW_SSL3)
1792       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT;
1793     else
1794       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
1795   }
1796 #endif /* SP_PROT_TLS1_2_SERVER */
1797 
1798   /* TODO: Support _HTTP_TLS_ALLOW_RC4 and _HTTP_TLS_ALLOW_DH options; right now we'll rely on Windows registry to enable/disable RC4/DH... */
1799 
1800  /*
1801   * Create an SSPI credential.
1802   */
1803 
1804   Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
1805   if (Status != SEC_E_OK)
1806   {
1807     DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
1808     ok = FALSE;
1809     goto cleanup;
1810   }
1811 
1812 cleanup:
1813 
1814  /*
1815   * Cleanup
1816   */
1817 
1818   if (storedContext)
1819     CertFreeCertificateContext(storedContext);
1820 
1821   if (p)
1822     free(p);
1823 
1824   if (store)
1825     CertCloseStore(store, 0);
1826 
1827   if (hProv)
1828     CryptReleaseContext(hProv, 0);
1829 
1830   return (ok);
1831 }
1832 
1833 
1834 /*
1835  * 'http_sspi_free()' - Close a connection and free resources.
1836  */
1837 
1838 static void
http_sspi_free(_http_sspi_t * sspi)1839 http_sspi_free(_http_sspi_t *sspi)	/* I - SSPI data */
1840 {
1841   if (!sspi)
1842     return;
1843 
1844   if (sspi->contextInitialized)
1845     DeleteSecurityContext(&sspi->context);
1846 
1847   if (sspi->decryptBuffer)
1848     free(sspi->decryptBuffer);
1849 
1850   if (sspi->readBuffer)
1851     free(sspi->readBuffer);
1852 
1853   if (sspi->writeBuffer)
1854     free(sspi->writeBuffer);
1855 
1856   if (sspi->localCert)
1857     CertFreeCertificateContext(sspi->localCert);
1858 
1859   if (sspi->remoteCert)
1860     CertFreeCertificateContext(sspi->remoteCert);
1861 
1862   free(sspi);
1863 }
1864 
1865 
1866 /*
1867  * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store.
1868  */
1869 
1870 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)1871 http_sspi_make_credentials(
1872     _http_sspi_t *sspi,			/* I - SSPI data */
1873     const LPWSTR container,		/* I - Cert container name */
1874     const char   *common_name,		/* I - Common name of certificate */
1875     _http_mode_t mode,			/* I - Client or server? */
1876     int          years)			/* I - Years until expiration */
1877 {
1878   HCERTSTORE	store = NULL;		/* Certificate store */
1879   PCCERT_CONTEXT storedContext = NULL;	/* Context created from the store */
1880   PCCERT_CONTEXT createdContext = NULL;	/* Context created by us */
1881   DWORD		dwSize = 0; 		/* 32 bit size */
1882   PBYTE		p = NULL;		/* Temporary storage */
1883   HCRYPTPROV	hProv = (HCRYPTPROV)NULL;
1884 					/* Handle to a CSP */
1885   CERT_NAME_BLOB sib;			/* Arbitrary array of bytes */
1886   SCHANNEL_CRED	SchannelCred;		/* Schannel credential data */
1887   TimeStamp	tsExpiry;		/* Time stamp */
1888   SECURITY_STATUS Status;		/* Status */
1889   HCRYPTKEY	hKey = (HCRYPTKEY)NULL;	/* Handle to crypto key */
1890   CRYPT_KEY_PROV_INFO kpi;		/* Key container info */
1891   SYSTEMTIME	et;			/* System time */
1892   CERT_EXTENSIONS exts;			/* Array of cert extensions */
1893   CRYPT_KEY_PROV_INFO ckp;		/* Handle to crypto key */
1894   BOOL		ok = TRUE;		/* Return value */
1895 
1896 
1897   DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi, container, common_name, mode, years));
1898 
1899   if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
1900   {
1901     if (GetLastError() == NTE_EXISTS)
1902     {
1903       if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
1904       {
1905         DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1906         ok = FALSE;
1907         goto cleanup;
1908       }
1909     }
1910   }
1911 
1912   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");
1913 
1914   if (!store)
1915   {
1916     DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1917     ok = FALSE;
1918     goto cleanup;
1919   }
1920 
1921   dwSize = 0;
1922 
1923   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
1924   {
1925     DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1926     ok = FALSE;
1927     goto cleanup;
1928   }
1929 
1930   p = (PBYTE)malloc(dwSize);
1931 
1932   if (!p)
1933   {
1934     DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize));
1935     ok = FALSE;
1936     goto cleanup;
1937   }
1938 
1939   if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
1940   {
1941     DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1942     ok = FALSE;
1943     goto cleanup;
1944   }
1945 
1946  /*
1947   * Create a private key and self-signed certificate...
1948   */
1949 
1950   if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
1951   {
1952     DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1953     ok = FALSE;
1954     goto cleanup;
1955   }
1956 
1957   ZeroMemory(&kpi, sizeof(kpi));
1958   kpi.pwszContainerName = (LPWSTR)container;
1959   kpi.pwszProvName      = MS_DEF_PROV_W;
1960   kpi.dwProvType        = PROV_RSA_FULL;
1961   kpi.dwFlags           = CERT_SET_KEY_CONTEXT_PROP_ID;
1962   kpi.dwKeySpec         = AT_KEYEXCHANGE;
1963 
1964   GetSystemTime(&et);
1965   et.wYear += years;
1966 
1967   ZeroMemory(&exts, sizeof(exts));
1968 
1969   createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts);
1970 
1971   if (!createdContext)
1972   {
1973     DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1974     ok = FALSE;
1975     goto cleanup;
1976   }
1977 
1978  /*
1979   * Add the created context to the named store, and associate it with the named
1980   * container...
1981   */
1982 
1983   if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
1984   {
1985     DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
1986     ok = FALSE;
1987     goto cleanup;
1988   }
1989 
1990   ZeroMemory(&ckp, sizeof(ckp));
1991   ckp.pwszContainerName = (LPWSTR) container;
1992   ckp.pwszProvName      = MS_DEF_PROV_W;
1993   ckp.dwProvType        = PROV_RSA_FULL;
1994   ckp.dwFlags           = CRYPT_MACHINE_KEYSET;
1995   ckp.dwKeySpec         = AT_KEYEXCHANGE;
1996 
1997   if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
1998   {
1999     DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
2000     ok = FALSE;
2001     goto cleanup;
2002   }
2003 
2004  /*
2005   * Get a handle to use the certificate...
2006   */
2007 
2008   ZeroMemory(&SchannelCred, sizeof(SchannelCred));
2009 
2010   SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
2011   SchannelCred.cCreds    = 1;
2012   SchannelCred.paCred    = &storedContext;
2013 
2014  /*
2015   * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
2016   */
2017 
2018   if (mode == _HTTP_MODE_SERVER)
2019     SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
2020 
2021  /*
2022   * Create an SSPI credential.
2023   */
2024 
2025   Status = AcquireCredentialsHandle(NULL, UNISP_NAME, mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
2026   if (Status != SEC_E_OK)
2027   {
2028     DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
2029     ok = FALSE;
2030     goto cleanup;
2031   }
2032 
2033 cleanup:
2034 
2035  /*
2036   * Cleanup
2037   */
2038 
2039   if (hKey)
2040     CryptDestroyKey(hKey);
2041 
2042   if (createdContext)
2043     CertFreeCertificateContext(createdContext);
2044 
2045   if (storedContext)
2046     CertFreeCertificateContext(storedContext);
2047 
2048   if (p)
2049     free(p);
2050 
2051   if (store)
2052     CertCloseStore(store, 0);
2053 
2054   if (hProv)
2055     CryptReleaseContext(hProv, 0);
2056 
2057   return (ok);
2058 }
2059 
2060 
2061 /*
2062  * 'http_sspi_server()' - Negotiate a TLS connection as a server.
2063  */
2064 
2065 static int				/* O - 0 on success, -1 on failure */
http_sspi_server(http_t * http,const char * hostname)2066 http_sspi_server(http_t     *http,	/* I - HTTP connection */
2067                  const char *hostname)	/* I - Hostname of server */
2068 {
2069   _http_sspi_t	*sspi = http->tls;	/* I - SSPI data */
2070   char		common_name[512];	/* Common name for cert */
2071   DWORD		dwSSPIFlags;		/* SSL connection attributes we want */
2072   DWORD		dwSSPIOutFlags;		/* SSL connection attributes we got */
2073   TimeStamp	tsExpiry;		/* Time stamp */
2074   SECURITY_STATUS scRet;		/* SSPI Status */
2075   SecBufferDesc	inBuffer;		/* Array of SecBuffer structs */
2076   SecBuffer	inBuffers[2];		/* Security package buffer */
2077   SecBufferDesc	outBuffer;		/* Array of SecBuffer structs */
2078   SecBuffer	outBuffers[1];		/* Security package buffer */
2079   int		num = 0;		/* 32 bit status value */
2080   BOOL		fInitContext = TRUE;	/* Has the context been init'd? */
2081   int		ret = 0;		/* Return value */
2082 
2083 
2084   DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname));
2085 
2086   dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT  |
2087                 ASC_REQ_REPLAY_DETECT    |
2088                 ASC_REQ_CONFIDENTIALITY  |
2089                 ASC_REQ_EXTENDED_ERROR   |
2090                 ASC_REQ_ALLOCATE_MEMORY  |
2091                 ASC_REQ_STREAM;
2092 
2093   sspi->decryptBufferUsed = 0;
2094 
2095  /*
2096   * Lookup the server certificate...
2097   */
2098 
2099   snprintf(common_name, sizeof(common_name), "CN=%s", hostname);
2100 
2101   if (!http_sspi_find_credentials(http, L"ServerContainer", common_name))
2102     if (!http_sspi_make_credentials(http->tls, L"ServerContainer", common_name, _HTTP_MODE_SERVER, 10))
2103     {
2104       DEBUG_puts("5http_sspi_server: Unable to get server credentials.");
2105       return (-1);
2106     }
2107 
2108  /*
2109   * Set OutBuffer for AcceptSecurityContext call
2110   */
2111 
2112   outBuffer.cBuffers  = 1;
2113   outBuffer.pBuffers  = outBuffers;
2114   outBuffer.ulVersion = SECBUFFER_VERSION;
2115 
2116   scRet = SEC_I_CONTINUE_NEEDED;
2117 
2118   while (scRet == SEC_I_CONTINUE_NEEDED    ||
2119          scRet == SEC_E_INCOMPLETE_MESSAGE ||
2120          scRet == SEC_I_INCOMPLETE_CREDENTIALS)
2121   {
2122     if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
2123     {
2124       if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
2125       {
2126 	BYTE *temp;			/* New buffer */
2127 
2128 	if (sspi->decryptBufferLength >= 262144)
2129 	{
2130 	  WSASetLastError(E_OUTOFMEMORY);
2131 	  DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)");
2132 	  return (-1);
2133 	}
2134 
2135 	if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
2136 	{
2137 	  DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
2138 	  WSASetLastError(E_OUTOFMEMORY);
2139 	  return (-1);
2140 	}
2141 
2142 	sspi->decryptBufferLength += 4096;
2143 	sspi->decryptBuffer       = temp;
2144       }
2145 
2146       for (;;)
2147       {
2148         num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
2149 
2150         if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
2151           Sleep(1);
2152         else
2153           break;
2154       }
2155 
2156       if (num < 0)
2157       {
2158         DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError()));
2159         return (-1);
2160       }
2161       else if (num == 0)
2162       {
2163         DEBUG_puts("5http_sspi_server: client disconnected");
2164         return (-1);
2165       }
2166 
2167       DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num));
2168       sspi->decryptBufferUsed += num;
2169     }
2170 
2171    /*
2172     * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process
2173     * on this run around the loop.
2174     */
2175 
2176     inBuffers[0].pvBuffer   = sspi->decryptBuffer;
2177     inBuffers[0].cbBuffer   = (unsigned long)sspi->decryptBufferUsed;
2178     inBuffers[0].BufferType = SECBUFFER_TOKEN;
2179 
2180     inBuffers[1].pvBuffer   = NULL;
2181     inBuffers[1].cbBuffer   = 0;
2182     inBuffers[1].BufferType = SECBUFFER_EMPTY;
2183 
2184     inBuffer.cBuffers       = 2;
2185     inBuffer.pBuffers       = inBuffers;
2186     inBuffer.ulVersion      = SECBUFFER_VERSION;
2187 
2188    /*
2189     * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to
2190     * free random garbage at the quit.
2191     */
2192 
2193     outBuffers[0].pvBuffer   = NULL;
2194     outBuffers[0].BufferType = SECBUFFER_TOKEN;
2195     outBuffers[0].cbBuffer   = 0;
2196 
2197     scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry);
2198 
2199     fInitContext = FALSE;
2200 
2201     if (scRet == SEC_E_OK              ||
2202         scRet == SEC_I_CONTINUE_NEEDED ||
2203         (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0)))
2204     {
2205       if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
2206       {
2207        /*
2208         * Send response to server if there is one.
2209         */
2210 
2211         num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
2212 
2213         if (num <= 0)
2214         {
2215           DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError()));
2216 	  return (-1);
2217         }
2218 
2219         DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer));
2220 
2221         FreeContextBuffer(outBuffers[0].pvBuffer);
2222         outBuffers[0].pvBuffer = NULL;
2223       }
2224     }
2225 
2226     if (scRet == SEC_E_OK)
2227     {
2228      /*
2229       * If there's extra data then save it for next time we go to decrypt.
2230       */
2231 
2232       if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
2233       {
2234         memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
2235         sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
2236       }
2237       else
2238       {
2239         sspi->decryptBufferUsed = 0;
2240       }
2241       break;
2242     }
2243     else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE)
2244     {
2245       DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2246       ret = -1;
2247       break;
2248     }
2249 
2250     if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
2251         scRet != SEC_I_INCOMPLETE_CREDENTIALS)
2252     {
2253       if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
2254       {
2255         memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
2256         sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
2257       }
2258       else
2259       {
2260         sspi->decryptBufferUsed = 0;
2261       }
2262     }
2263   }
2264 
2265   if (!ret)
2266   {
2267     sspi->contextInitialized = TRUE;
2268 
2269    /*
2270     * Find out how big the header will be:
2271     */
2272 
2273     scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
2274 
2275     if (scRet != SEC_E_OK)
2276     {
2277       DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2278       ret = -1;
2279     }
2280   }
2281 
2282   return (ret);
2283 }
2284 
2285 
2286 /*
2287  * 'http_sspi_strerror()' - Return a string for the specified error code.
2288  */
2289 
2290 static const char *			/* O - String for error */
http_sspi_strerror(char * buffer,size_t bufsize,DWORD code)2291 http_sspi_strerror(char   *buffer,	/* I - Error message buffer */
2292                    size_t bufsize,	/* I - Size of buffer */
2293                    DWORD  code)		/* I - Error code */
2294 {
2295   if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, bufsize, NULL))
2296   {
2297    /*
2298     * Strip trailing CR + LF...
2299     */
2300 
2301     char	*ptr;			/* Pointer into error message */
2302 
2303     for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --)
2304       if (*ptr == '\n' || *ptr == '\r')
2305         *ptr = '\0';
2306       else
2307         break;
2308   }
2309   else
2310     snprintf(buffer, bufsize, "Unknown error %x", code);
2311 
2312   return (buffer);
2313 }
2314 
2315 
2316 /*
2317  * 'http_sspi_verify()' - Verify a certificate.
2318  */
2319 
2320 static DWORD				/* O - Error code (0 == No error) */
http_sspi_verify(PCCERT_CONTEXT cert,const char * common_name,DWORD dwCertFlags)2321 http_sspi_verify(
2322     PCCERT_CONTEXT cert,		/* I - Server certificate */
2323     const char     *common_name,	/* I - Common name */
2324     DWORD          dwCertFlags)		/* I - Verification flags */
2325 {
2326   HTTPSPolicyCallbackData httpsPolicy;	/* HTTPS Policy Struct */
2327   CERT_CHAIN_POLICY_PARA policyPara;	/* Cert chain policy parameters */
2328   CERT_CHAIN_POLICY_STATUS policyStatus;/* Cert chain policy status */
2329   CERT_CHAIN_PARA	chainPara;	/* Used for searching and matching criteria */
2330   PCCERT_CHAIN_CONTEXT	chainContext = NULL;
2331 					/* Certificate chain */
2332   PWSTR			commonNameUnicode = NULL;
2333 					/* Unicode common name */
2334   LPSTR			rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
2335                                          szOID_SERVER_GATED_CRYPTO,
2336                                          szOID_SGC_NETSCAPE };
2337 					/* How are we using this certificate? */
2338   DWORD			cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
2339 					/* Number of ites in rgszUsages */
2340   DWORD			count;		/* 32 bit count variable */
2341   DWORD			status;		/* Return value */
2342 #ifdef DEBUG
2343   char			error[1024];	/* Error message string */
2344 #endif /* DEBUG */
2345 
2346 
2347   if (!cert)
2348     return (SEC_E_WRONG_PRINCIPAL);
2349 
2350  /*
2351   * Convert common name to Unicode.
2352   */
2353 
2354   if (!common_name || !*common_name)
2355     return (SEC_E_WRONG_PRINCIPAL);
2356 
2357   count             = MultiByteToWideChar(CP_ACP, 0, common_name, -1, NULL, 0);
2358   commonNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR));
2359   if (!commonNameUnicode)
2360     return (SEC_E_INSUFFICIENT_MEMORY);
2361 
2362   if (!MultiByteToWideChar(CP_ACP, 0, common_name, -1, commonNameUnicode, count))
2363   {
2364     LocalFree(commonNameUnicode);
2365     return (SEC_E_WRONG_PRINCIPAL);
2366   }
2367 
2368  /*
2369   * Build certificate chain.
2370   */
2371 
2372   ZeroMemory(&chainPara, sizeof(chainPara));
2373 
2374   chainPara.cbSize					= sizeof(chainPara);
2375   chainPara.RequestedUsage.dwType			= USAGE_MATCH_TYPE_OR;
2376   chainPara.RequestedUsage.Usage.cUsageIdentifier	= cUsages;
2377   chainPara.RequestedUsage.Usage.rgpszUsageIdentifier	= rgszUsages;
2378 
2379   if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext))
2380   {
2381     status = GetLastError();
2382 
2383     DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status)));
2384 
2385     LocalFree(commonNameUnicode);
2386     return (status);
2387   }
2388 
2389  /*
2390   * Validate certificate chain.
2391   */
2392 
2393   ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
2394   httpsPolicy.cbStruct		= sizeof(HTTPSPolicyCallbackData);
2395   httpsPolicy.dwAuthType	= AUTHTYPE_SERVER;
2396   httpsPolicy.fdwChecks		= dwCertFlags;
2397   httpsPolicy.pwszServerName	= commonNameUnicode;
2398 
2399   memset(&policyPara, 0, sizeof(policyPara));
2400   policyPara.cbSize		= sizeof(policyPara);
2401   policyPara.pvExtraPolicyPara	= &httpsPolicy;
2402 
2403   memset(&policyStatus, 0, sizeof(policyStatus));
2404   policyStatus.cbSize = sizeof(policyStatus);
2405 
2406   if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus))
2407   {
2408     status = GetLastError();
2409 
2410     DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status)));
2411   }
2412   else if (policyStatus.dwError)
2413     status = policyStatus.dwError;
2414   else
2415     status = SEC_E_OK;
2416 
2417   if (chainContext)
2418     CertFreeCertificateChain(chainContext);
2419 
2420   if (commonNameUnicode)
2421     LocalFree(commonNameUnicode);
2422 
2423   return (status);
2424 }
2425