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