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