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
55static int		tls_options = -1;/* Options for TLS connections */
56
57
58/*
59 * Local functions...
60 */
61
62static _http_sspi_t *http_sspi_alloc(void);
63static int	http_sspi_client(http_t *http, const char *hostname);
64static PCCERT_CONTEXT http_sspi_create_credential(http_credential_t *cred);
65static BOOL	http_sspi_find_credentials(http_t *http, const LPWSTR containerName, const char *common_name);
66static void	http_sspi_free(_http_sspi_t *sspi);
67static BOOL	http_sspi_make_credentials(_http_sspi_t *sspi, const LPWSTR containerName, const char *common_name, _http_mode_t mode, int years);
68static int	http_sspi_server(http_t *http, const char *hostname);
69static void	http_sspi_set_allows_any_root(_http_sspi_t *sspi, BOOL allow);
70static void	http_sspi_set_allows_expired_certs(_http_sspi_t *sspi, BOOL allow);
71static const char *http_sspi_strerror(char *buffer, size_t bufsize, DWORD code);
72static 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
81int					/* O - 1 on success, 0 on failure */
82cupsMakeServerCredentials(
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
117int					/* O - 1 on success, 0 on failure */
118cupsSetServerCredentials(
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
140int					/* O - Status of call (0 = success) */
141httpCopyCredentials(
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
166http_tls_credentials_t			/* O - Internal credentials */
167_httpCreateCredentials(
168    cups_array_t *credentials)		/* I - Array of credentials */
169{
170  return (http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)));
171}
172
173
174/*
175 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
176 *
177 * @since CUPS 2.0/OS 10.10@
178 */
179
180int					/* O - 1 if valid, 0 otherwise */
181httpCredentialsAreValidForName(
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
245http_trust_t				/* O - Level of trust */
246httpCredentialsGetTrust(
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
290time_t					/* O - Expiration date of credentials */
291httpCredentialsGetExpiration(
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
327size_t					/* O - Total size of credentials string */
328httpCredentialsString(
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
400void
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
417int					/* O - 0 on success, -1 on error */
418httpLoadCredentials(
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
511cleanup:
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
541int					/* O - -1 on error, 0 on success */
542httpSaveCredentials(
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
646cleanup:
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
676void
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
689size_t					/* O - Bytes available */
690_httpTLSPending(http_t *http)		/* I - HTTP connection */
691{
692  if (http->tls)
693    return (http->tls->readBufferUsed);
694  else
695    return (0);
696}
697
698
699/*
700 * '_httpTLSRead()' - Read from a SSL/TLS connection.
701 */
702
703int					/* O - Bytes read */
704_httpTLSRead(http_t *http,		/* I - HTTP connection */
705	     char   *buf,		/* I - Buffer to store data */
706	     int    len)		/* I - Length of buffer */
707{
708  int		i;			/* Looping var */
709  _http_sspi_t	*sspi = http->tls;	/* SSPI data */
710  SecBufferDesc	message;		/* Array of SecBuffer struct */
711  SecBuffer	buffers[4] = { 0 };	/* Security package buffer */
712  int		num = 0;		/* Return value */
713  PSecBuffer	pDataBuffer;		/* Data buffer */
714  PSecBuffer	pExtraBuffer;		/* Excess data buffer */
715  SECURITY_STATUS scRet;		/* SSPI status */
716
717
718  DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http, buf, len));
719
720 /*
721  * If there are bytes that have already been decrypted and have not yet been
722  * read, return those...
723  */
724
725  if (sspi->readBufferUsed > 0)
726  {
727    int bytesToCopy = min(sspi->readBufferUsed, len);
728					/* Number of bytes to copy */
729
730    memcpy(buf, sspi->readBuffer, bytesToCopy);
731    sspi->readBufferUsed -= bytesToCopy;
732
733    if (sspi->readBufferUsed > 0)
734      memmove(sspi->readBuffer, sspi->readBuffer + bytesToCopy, sspi->readBufferUsed);
735
736    DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy));
737
738    return (bytesToCopy);
739  }
740
741 /*
742  * Initialize security buffer structs
743  */
744
745  message.ulVersion = SECBUFFER_VERSION;
746  message.cBuffers  = 4;
747  message.pBuffers  = buffers;
748
749  do
750  {
751   /*
752    * If there is not enough space in the buffer, then increase its size...
753    */
754
755    if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
756    {
757      BYTE *temp;			/* New buffer */
758
759      if (sspi->decryptBufferLength >= 262144)
760      {
761	WSASetLastError(E_OUTOFMEMORY);
762        DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)");
763	return (-1);
764      }
765
766      if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
767      {
768	DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi->decryptBufferLength + 4096));
769	WSASetLastError(E_OUTOFMEMORY);
770	return (-1);
771      }
772
773      sspi->decryptBufferLength += 4096;
774      sspi->decryptBuffer       = temp;
775
776      DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi->decryptBufferLength));
777    }
778
779    buffers[0].pvBuffer	  = sspi->decryptBuffer;
780    buffers[0].cbBuffer	  = (unsigned long)sspi->decryptBufferUsed;
781    buffers[0].BufferType = SECBUFFER_DATA;
782    buffers[1].BufferType = SECBUFFER_EMPTY;
783    buffers[2].BufferType = SECBUFFER_EMPTY;
784    buffers[3].BufferType = SECBUFFER_EMPTY;
785
786    DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi->decryptBufferUsed));
787
788    scRet = DecryptMessage(&sspi->context, &message, 0, NULL);
789
790    if (scRet == SEC_E_INCOMPLETE_MESSAGE)
791    {
792      num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
793      if (num < 0)
794      {
795	DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError()));
796	return (-1);
797      }
798      else if (num == 0)
799      {
800	DEBUG_puts("5_httpTLSRead: Server disconnected.");
801	return (0);
802      }
803
804      DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num));
805
806      sspi->decryptBufferUsed += num;
807    }
808  }
809  while (scRet == SEC_E_INCOMPLETE_MESSAGE);
810
811  if (scRet == SEC_I_CONTEXT_EXPIRED)
812  {
813    DEBUG_puts("5_httpTLSRead: Context expired.");
814    WSASetLastError(WSAECONNRESET);
815    return (-1);
816  }
817  else if (scRet != SEC_E_OK)
818  {
819    DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
820    WSASetLastError(WSASYSCALLFAILURE);
821    return (-1);
822  }
823
824 /*
825  * The decryption worked.  Now, locate data buffer.
826  */
827
828  pDataBuffer  = NULL;
829  pExtraBuffer = NULL;
830
831  for (i = 1; i < 4; i++)
832  {
833    if (buffers[i].BufferType == SECBUFFER_DATA)
834      pDataBuffer = &buffers[i];
835    else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA))
836      pExtraBuffer = &buffers[i];
837  }
838
839 /*
840  * If a data buffer is found, then copy the decrypted bytes to the passed-in
841  * buffer...
842  */
843
844  if (pDataBuffer)
845  {
846    int bytesToCopy = min((int)pDataBuffer->cbBuffer, len);
847				      /* Number of bytes to copy into buf */
848    int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy;
849				      /* Number of bytes to save in our read buffer */
850
851    if (bytesToCopy)
852      memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy);
853
854   /*
855    * If there are more decrypted bytes than can be copied to the passed in
856    * buffer, then save them...
857    */
858
859    if (bytesToSave)
860    {
861      if ((sspi->readBufferLength - sspi->readBufferUsed) < bytesToSave)
862      {
863        BYTE *temp;			/* New buffer pointer */
864
865        if ((temp = realloc(sspi->readBuffer, sspi->readBufferUsed + bytesToSave)) == NULL)
866	{
867	  DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi->readBufferUsed + bytesToSave));
868	  WSASetLastError(E_OUTOFMEMORY);
869	  return (-1);
870	}
871
872	sspi->readBufferLength = sspi->readBufferUsed + bytesToSave;
873	sspi->readBuffer       = temp;
874      }
875
876      memcpy(((BYTE *)sspi->readBuffer) + sspi->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave);
877
878      sspi->readBufferUsed += bytesToSave;
879    }
880
881    num = bytesToCopy;
882  }
883  else
884  {
885    DEBUG_puts("_httpTLSRead: Unable to find data buffer.");
886    WSASetLastError(WSASYSCALLFAILURE);
887    return (-1);
888  }
889
890 /*
891  * If the decryption process left extra bytes, then save those back in
892  * decryptBuffer.  They will be processed the next time through the loop.
893  */
894
895  if (pExtraBuffer)
896  {
897    memmove(sspi->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
898    sspi->decryptBufferUsed = pExtraBuffer->cbBuffer;
899  }
900  else
901  {
902    sspi->decryptBufferUsed = 0;
903  }
904
905  return (num);
906}
907
908
909/*
910 * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
911 */
912
913void
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
924int					/* O - 0 on success, -1 on failure */
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
1014void
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
1116int					/* O - Bytes written */
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
1221static int				/* O - 0 on success, -1 on failure */
1222http_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
1308static _http_sspi_t *			/* O  - New SSPI/SSL object */
1309http_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
1319static int				/* O - 0 on success, -1 on failure */
1320http_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
1657static PCCERT_CONTEXT			/* O - Certificate context */
1658http_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
1672static BOOL				/* O - 1 on success, 0 on failure */
1673http_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
1812cleanup:
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
1838static void
1839http_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
1870static BOOL				/* O - 1 on success, 0 on failure */
1871http_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
2033cleanup:
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
2065static int				/* O - 0 on success, -1 on failure */
2066http_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
2290static const char *			/* O - String for error */
2291http_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
2320static DWORD				/* O - Error code (0 == No error) */
2321http_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