]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/tls-sspi.c
Update "since CUPS 2.0" into to mention OS X 10.10.
[thirdparty/cups.git] / cups / tls-sspi.c
CommitLineData
cc754834 1/*
321d8d57 2 * "$Id$"
cc754834 3 *
2c85b752 4 * TLS support for CUPS on Windows using SSPI.
321d8d57 5 *
2ece34a9 6 * Copyright 2010-2014 by Apple Inc.
cc754834 7 *
2c85b752
MS
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/".
cc754834 13 *
2c85b752 14 * This file is subject to the Apple OS-Developed Software exception.
cc754834
MS
15 */
16
17/*
18 * Include necessary headers...
19 */
20
cc754834 21#include "debug-private.h"
321d8d57 22
cc754834 23
2ece34a9
MS
24/*
25 * Include necessary libraries...
26 */
27
cc754834
MS
28#pragma comment(lib, "Crypt32.lib")
29#pragma comment(lib, "Secur32.lib")
30#pragma comment(lib, "Ws2_32.lib")
31
32
2ece34a9
MS
33/*
34 * Constants...
35 */
36
37#ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA
cc754834 38# define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */
2ece34a9 39#endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */
cc754834 40
9041146f
MS
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
2ece34a9 45#ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
cc754834 46# define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */
2ece34a9
MS
47#endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */
48
49/*
50 * Local functions...
51 */
cc754834 52
2ece34a9
MS
53static _http_sspi_t *http_sspi_alloc(void);
54static int http_sspi_client(http_t *http, const char *hostname);
17eecbf1 55static PCCERT_CONTEXT http_sspi_create_credential(http_credential_t *cred);
e32497ad
MS
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);
2ece34a9 59static int http_sspi_server(http_t *http, const char *hostname);
e32497ad
MS
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);
52770f63 62static const char *http_sspi_strerror(char *buffer, size_t bufsize, DWORD code);
2ece34a9 63static DWORD http_sspi_verify(PCCERT_CONTEXT cert, const char *common_name, DWORD dwCertFlags);
cc754834
MS
64
65
2c85b752 66/*
2ece34a9
MS
67 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
68 *
e1f19878 69 * @since CUPS 2.0/OS 10.10@
2c85b752
MS
70 */
71
2ece34a9
MS
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 */
2c85b752 79{
e32497ad
MS
80 _http_sspi_t *sspi; /* SSPI data */
81 int ret; /* Return value */
82
83
2ece34a9 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));
2c85b752 85
2ece34a9 86 (void)path;
2ece34a9
MS
87 (void)num_alt_names;
88 (void)alt_names;
2c85b752 89
e32497ad
MS
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);
2ece34a9 96}
2c85b752 97
2c85b752 98
2ece34a9
MS
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 *
e1f19878 105 * @since CUPS 2.0/OS 10.10@
2ece34a9 106 */
2c85b752 107
2ece34a9
MS
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));
2c85b752 115
2ece34a9
MS
116 (void)path;
117 (void)common_name;
118 (void)auto_create;
2c85b752 119
2ece34a9 120 return (0);
2c85b752
MS
121}
122
123
2c85b752 124/*
2ece34a9
MS
125 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
126 * an encrypted connection.
127 *
128 * @since CUPS 1.5/OS X 10.7@
2c85b752
MS
129 */
130
2ece34a9
MS
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 */
2c85b752 135{
2ece34a9 136 DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials));
2c85b752 137
9041146f
MS
138 if (!http || !http->tls || !http->tls->remoteCert || !credentials)
139 {
140 if (credentials)
141 *credentials = NULL;
142
143 return (-1);
144 }
2c85b752 145
9041146f
MS
146 *credentials = cupsArrayNew(NULL, NULL);
147 httpAddCredential(*credentials, http->tls->remoteCert->pbCertEncoded, http->tls->remoteCert->cbCertEncoded);
2c85b752 148
9041146f 149 return (0);
2ece34a9 150}
2c85b752 151
2c85b752 152
2ece34a9
MS
153/*
154 * '_httpCreateCredentials()' - Create credentials in the internal format.
155 */
2c85b752 156
2ece34a9
MS
157http_tls_credentials_t /* O - Internal credentials */
158_httpCreateCredentials(
159 cups_array_t *credentials) /* I - Array of credentials */
160{
17eecbf1 161 return (http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)));
2ece34a9 162}
2c85b752 163
2c85b752 164
2ece34a9
MS
165/*
166 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
167 *
e1f19878 168 * @since CUPS 2.0/OS 10.10@
2ece34a9 169 */
2c85b752 170
2ece34a9
MS
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{
17eecbf1
MS
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 {
9041146f
MS
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
17eecbf1
MS
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 }
2c85b752 225
17eecbf1 226 return (valid);
2c85b752 227}
2c85b752
MS
228
229
2c85b752 230/*
2ece34a9
MS
231 * 'httpCredentialsGetTrust()' - Return the trust of credentials.
232 *
e1f19878 233 * @since CUPS 2.0/OS 10.10@
2c85b752
MS
234 */
235
2ece34a9
MS
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 */
2c85b752 240{
17eecbf1
MS
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 */
2c85b752
MS
245
246
2ece34a9
MS
247 if (!common_name)
248 return (HTTP_TRUST_UNKNOWN);
2c85b752 249
17eecbf1
MS
250 cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
251 if (!cert)
252 return (HTTP_TRUST_UNKNOWN);
2c85b752 253
17eecbf1
MS
254 if (cg->any_root)
255 certFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
2c85b752 256
17eecbf1
MS
257 if (cg->expired_certs)
258 certFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
2c85b752 259
17eecbf1
MS
260 if (!cg->validate_certs)
261 certFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
2c85b752 262
17eecbf1 263 if (http_sspi_verify(cert, common_name, certFlags) != SEC_E_OK)
2ece34a9 264 trust = HTTP_TRUST_INVALID;
2c85b752 265
17eecbf1 266 CertFreeCertificateContext(cert);
2c85b752 267
2ece34a9
MS
268 return (trust);
269}
2c85b752 270
2c85b752 271
2ece34a9
MS
272/*
273 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
274 *
e1f19878 275 * @since CUPS 2.0/OS 10.10@
2ece34a9 276 */
2c85b752 277
2ece34a9
MS
278time_t /* O - Expiration date of credentials */
279httpCredentialsGetExpiration(
280 cups_array_t *credentials) /* I - Credentials */
281{
17eecbf1
MS
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 */
2c85b752 285
17eecbf1
MS
286 if (cert)
287 {
288 SYSTEMTIME systime; /* System time */
289 struct tm tm; /* UNIX date/time */
290
9041146f 291 FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
17eecbf1
MS
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);
2ece34a9 306}
2c85b752 307
2c85b752 308
2ece34a9
MS
309/*
310 * 'httpCredentialsString()' - Return a string representing the credentials.
311 *
e1f19878 312 * @since CUPS 2.0/OS 10.10@
2ece34a9 313 */
2c85b752 314
2ece34a9
MS
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{
17eecbf1
MS
321 http_credential_t *first = (http_credential_t *)cupsArrayFirst(credentials);
322 /* First certificate */
323 PCCERT_CONTEXT cert; /* Certificate */
324
325
2ece34a9 326 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize));
2c85b752 327
2ece34a9
MS
328 if (!buffer)
329 return (0);
2c85b752 330
2ece34a9
MS
331 if (buffer && bufsize > 0)
332 *buffer = '\0';
2c85b752 333
17eecbf1 334 cert = http_sspi_create_credential(first);
2c85b752 335
17eecbf1 336 if (cert)
2c85b752 337 {
17eecbf1
MS
338 char cert_name[256]; /* Common name */
339 SYSTEMTIME systime; /* System time */
340 struct tm tm; /* UNIX date/time */
2ece34a9
MS
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 */
2c85b752 344
9041146f 345 FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
17eecbf1
MS
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);
2c85b752 355
9041146f
MS
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
17eecbf1 367 strlcpy(cert_name, "unknown", sizeof(cert_name));
2c85b752 368
2ece34a9
MS
369 _cupsMD5Init(&md5_state);
370 _cupsMD5Append(&md5_state, first->data, (int)first->datalen);
371 _cupsMD5Finish(&md5_state, md5_digest);
2c85b752 372
17eecbf1 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]);
2c85b752 374
17eecbf1 375 CertFreeCertificateContext(cert);
2c85b752
MS
376 }
377
2ece34a9 378 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer));
2c85b752 379
2ece34a9
MS
380 return (strlen(buffer));
381}
2c85b752 382
2c85b752 383
2ece34a9
MS
384/*
385 * '_httpFreeCredentials()' - Free internal credentials.
386 */
2c85b752 387
2ece34a9
MS
388void
389_httpFreeCredentials(
390 http_tls_credentials_t credentials) /* I - Internal credentials */
391{
392 if (!credentials)
393 return;
17eecbf1
MS
394
395 CertFreeCertificateContext(credentials);
2ece34a9 396}
2c85b752 397
2c85b752 398
2ece34a9
MS
399/*
400 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
401 *
e1f19878 402 * @since CUPS 2.0/OS 10.10@
2ece34a9 403 */
2c85b752 404
2ece34a9
MS
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{
52770f63
MS
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
2ece34a9 423 DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
2c85b752 424
2ece34a9 425 (void)path;
2c85b752 426
2ece34a9 427 if (credentials)
52770f63 428 {
2ece34a9 429 *credentials = NULL;
52770f63
MS
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);
2c85b752 516
2ece34a9 517 DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1));
2c85b752 518
2ece34a9
MS
519 return (*credentials ? 0 : -1);
520}
2c85b752 521
2c85b752 522
2ece34a9
MS
523/*
524 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
525 *
e1f19878 526 * @since CUPS 2.0/OS 10.10@
2ece34a9 527 */
2c85b752 528
2ece34a9
MS
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{
52770f63
MS
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 */
74ac5fe7 542 CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
52770f63
MS
543 int ret = -1; /* Return value */
544#ifdef DEBUG
545 char error[1024]; /* Error message buffer */
546#endif /* DEBUG */
547
548
2ece34a9 549 DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
2c85b752 550
2ece34a9 551 (void)path;
2c85b752 552
52770f63
MS
553 if (!common_name)
554 {
555 DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1.");
556 return (-1);
557 }
558
74ac5fe7 559 createdContext = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
52770f63
MS
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);
2c85b752
MS
657}
658
659
660/*
2ece34a9 661 * '_httpTLSInitialize()' - Initialize the TLS stack.
2c85b752
MS
662 */
663
2ece34a9
MS
664void
665_httpTLSInitialize(void)
2c85b752 666{
2ece34a9
MS
667 /*
668 * Nothing to do...
669 */
670}
2c85b752 671
2c85b752 672
2ece34a9
MS
673/*
674 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
675 */
2c85b752 676
2ece34a9
MS
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}
2c85b752 685
2c85b752 686
2ece34a9
MS
687/*
688 * '_httpTLSRead()' - Read from a SSL/TLS connection.
689 */
2c85b752 690
2ece34a9
MS
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 */
e32497ad 697 _http_sspi_t *sspi = http->tls; /* SSPI data */
2ece34a9
MS
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 */
2c85b752 704
2c85b752 705
195c1f2d
MS
706 DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http, buf, len));
707
2ece34a9
MS
708 /*
709 * If there are bytes that have already been decrypted and have not yet been
710 * read, return those...
711 */
2c85b752 712
e32497ad 713 if (sspi->readBufferUsed > 0)
2ece34a9 714 {
e32497ad 715 int bytesToCopy = min(sspi->readBufferUsed, len);
2ece34a9 716 /* Number of bytes to copy */
2c85b752 717
e32497ad
MS
718 memcpy(buf, sspi->readBuffer, bytesToCopy);
719 sspi->readBufferUsed -= bytesToCopy;
2c85b752 720
e32497ad
MS
721 if (sspi->readBufferUsed > 0)
722 memmove(sspi->readBuffer, sspi->readBuffer + bytesToCopy, sspi->readBufferUsed);
2c85b752 723
195c1f2d
MS
724 DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy));
725
2ece34a9
MS
726 return (bytesToCopy);
727 }
2c85b752 728
2ece34a9
MS
729 /*
730 * Initialize security buffer structs
731 */
2c85b752 732
2ece34a9 733 message.ulVersion = SECBUFFER_VERSION;
195c1f2d
MS
734 message.cBuffers = 4;
735 message.pBuffers = buffers;
2c85b752 736
2ece34a9 737 do
2c85b752
MS
738 {
739 /*
2ece34a9 740 * If there is not enough space in the buffer, then increase its size...
2c85b752
MS
741 */
742
e32497ad 743 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
2c85b752 744 {
2ece34a9 745 BYTE *temp; /* New buffer */
2c85b752 746
e32497ad 747 if (sspi->decryptBufferLength >= 262144)
2ece34a9
MS
748 {
749 WSASetLastError(E_OUTOFMEMORY);
750 DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)");
751 return (-1);
752 }
2c85b752 753
e32497ad 754 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
2ece34a9 755 {
e32497ad 756 DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi->decryptBufferLength + 4096));
2ece34a9
MS
757 WSASetLastError(E_OUTOFMEMORY);
758 return (-1);
759 }
2c85b752 760
e32497ad
MS
761 sspi->decryptBufferLength += 4096;
762 sspi->decryptBuffer = temp;
195c1f2d 763
e32497ad 764 DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi->decryptBufferLength));
2ece34a9 765 }
2c85b752 766
e32497ad
MS
767 buffers[0].pvBuffer = sspi->decryptBuffer;
768 buffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
2ece34a9
MS
769 buffers[0].BufferType = SECBUFFER_DATA;
770 buffers[1].BufferType = SECBUFFER_EMPTY;
771 buffers[2].BufferType = SECBUFFER_EMPTY;
772 buffers[3].BufferType = SECBUFFER_EMPTY;
2c85b752 773
e32497ad 774 DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi->decryptBufferUsed));
195c1f2d 775
e32497ad 776 scRet = DecryptMessage(&sspi->context, &message, 0, NULL);
2c85b752 777
2ece34a9
MS
778 if (scRet == SEC_E_INCOMPLETE_MESSAGE)
779 {
e32497ad 780 num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
2ece34a9
MS
781 if (num < 0)
782 {
195c1f2d 783 DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError()));
2ece34a9
MS
784 return (-1);
785 }
786 else if (num == 0)
787 {
195c1f2d 788 DEBUG_puts("5_httpTLSRead: Server disconnected.");
2ece34a9
MS
789 return (0);
790 }
2c85b752 791
195c1f2d
MS
792 DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num));
793
e32497ad 794 sspi->decryptBufferUsed += num;
2ece34a9 795 }
2c85b752 796 }
2ece34a9 797 while (scRet == SEC_E_INCOMPLETE_MESSAGE);
2c85b752 798
2ece34a9
MS
799 if (scRet == SEC_I_CONTEXT_EXPIRED)
800 {
195c1f2d 801 DEBUG_puts("5_httpTLSRead: Context expired.");
2ece34a9
MS
802 WSASetLastError(WSAECONNRESET);
803 return (-1);
804 }
805 else if (scRet != SEC_E_OK)
806 {
52770f63 807 DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9
MS
808 WSASetLastError(WSASYSCALLFAILURE);
809 return (-1);
810 }
2c85b752 811
2ece34a9
MS
812 /*
813 * The decryption worked. Now, locate data buffer.
814 */
2c85b752 815
2ece34a9
MS
816 pDataBuffer = NULL;
817 pExtraBuffer = NULL;
2c85b752 818
2ece34a9
MS
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 }
2c85b752 826
2ece34a9
MS
827 /*
828 * If a data buffer is found, then copy the decrypted bytes to the passed-in
829 * buffer...
830 */
2c85b752 831
2ece34a9
MS
832 if (pDataBuffer)
833 {
33c9220c 834 int bytesToCopy = min((int)pDataBuffer->cbBuffer, len);
2ece34a9
MS
835 /* Number of bytes to copy into buf */
836 int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy;
837 /* Number of bytes to save in our read buffer */
2c85b752 838
2ece34a9
MS
839 if (bytesToCopy)
840 memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy);
2c85b752 841
2c85b752 842 /*
2ece34a9
MS
843 * If there are more decrypted bytes than can be copied to the passed in
844 * buffer, then save them...
2c85b752
MS
845 */
846
2ece34a9 847 if (bytesToSave)
2c85b752 848 {
e32497ad 849 if ((sspi->readBufferLength - sspi->readBufferUsed) < bytesToSave)
2ece34a9
MS
850 {
851 BYTE *temp; /* New buffer pointer */
2c85b752 852
e32497ad 853 if ((temp = realloc(sspi->readBuffer, sspi->readBufferUsed + bytesToSave)) == NULL)
2ece34a9 854 {
e32497ad 855 DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi->readBufferUsed + bytesToSave));
2ece34a9
MS
856 WSASetLastError(E_OUTOFMEMORY);
857 return (-1);
858 }
2c85b752 859
e32497ad
MS
860 sspi->readBufferLength = sspi->readBufferUsed + bytesToSave;
861 sspi->readBuffer = temp;
2ece34a9 862 }
2c85b752 863
e32497ad 864 memcpy(((BYTE *)sspi->readBuffer) + sspi->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave);
2c85b752 865
e32497ad 866 sspi->readBufferUsed += bytesToSave;
2ece34a9 867 }
2c85b752 868
adad9dd6 869 num = bytesToCopy;
2ece34a9
MS
870 }
871 else
872 {
33c9220c 873 DEBUG_puts("_httpTLSRead: Unable to find data buffer.");
2ece34a9
MS
874 WSASetLastError(WSASYSCALLFAILURE);
875 return (-1);
876 }
2c85b752 877
2ece34a9
MS
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 */
2c85b752 882
2ece34a9 883 if (pExtraBuffer)
2c85b752 884 {
e32497ad
MS
885 memmove(sspi->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
886 sspi->decryptBufferUsed = pExtraBuffer->cbBuffer;
2ece34a9
MS
887 }
888 else
889 {
e32497ad 890 sspi->decryptBufferUsed = 0;
2c85b752 891 }
2c85b752 892
adad9dd6 893 return (num);
2c85b752 894}
2c85b752
MS
895
896
cc754834 897/*
2ece34a9 898 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
cc754834 899 */
2ece34a9
MS
900
901int /* O - 0 on success, -1 on failure */
902_httpTLSStart(http_t *http) /* I - HTTP connection */
cc754834 903{
2ece34a9
MS
904 char hostname[256], /* Hostname */
905 *hostptr; /* Pointer into hostname */
cc754834 906
cc754834 907
2ece34a9
MS
908 DEBUG_printf(("7_httpTLSStart(http=%p)", http));
909
910 if ((http->tls = http_sspi_alloc()) == NULL)
911 return (-1);
cc754834 912
2ece34a9
MS
913 if (http->mode == _HTTP_MODE_CLIENT)
914 {
915 /*
916 * Client: determine hostname...
917 */
cc754834 918
2ece34a9
MS
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 */
cc754834 928
2ece34a9
MS
929 strlcpy(hostname, http->hostname, sizeof(hostname));
930 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
931 *hostptr == '.')
932 *hostptr = '\0';
933 }
cc754834 934
2ece34a9
MS
935 return (http_sspi_client(http, hostname));
936 }
937 else
cc754834 938 {
2ece34a9
MS
939 /*
940 * Server: determine hostname to use...
941 */
942
943 if (http->fields[HTTP_FIELD_HOST][0])
cc754834 944 {
2ece34a9
MS
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))
cc754834 962 {
2ece34a9
MS
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));
cc754834
MS
972 }
973 }
cc754834 974
2ece34a9 975 return (http_sspi_server(http, hostname));
cc754834 976 }
2ece34a9 977}
cc754834 978
321d8d57 979
2ece34a9
MS
980/*
981 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
982 */
cc754834 983
2ece34a9
MS
984void
985_httpTLSStop(http_t *http) /* I - HTTP connection */
986{
e32497ad 987 _http_sspi_t *sspi = http->tls; /* SSPI data */
cc754834 988
cc754834 989
e32497ad 990 if (sspi->contextInitialized && http->fd >= 0)
cc754834 991 {
2ece34a9
MS
992 SecBufferDesc message; /* Array of SecBuffer struct */
993 SecBuffer buffers[1] = { 0 };
994 /* Security package buffer */
995 DWORD dwType; /* Type */
996 DWORD status; /* Status */
cc754834 997
2ece34a9
MS
998 /*
999 * Notify schannel that we are about to close the connection.
1000 */
cc754834 1001
2ece34a9 1002 dwType = SCHANNEL_SHUTDOWN;
321d8d57 1003
2ece34a9
MS
1004 buffers[0].pvBuffer = &dwType;
1005 buffers[0].BufferType = SECBUFFER_TOKEN;
1006 buffers[0].cbBuffer = sizeof(dwType);
cc754834 1007
2ece34a9
MS
1008 message.cBuffers = 1;
1009 message.pBuffers = buffers;
1010 message.ulVersion = SECBUFFER_VERSION;
cc754834 1011
e32497ad 1012 status = ApplyControlToken(&sspi->context, &message);
cc754834 1013
2ece34a9
MS
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 */
cc754834 1022
2ece34a9
MS
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;
321d8d57 1029
2ece34a9
MS
1030 buffers[0].pvBuffer = NULL;
1031 buffers[0].BufferType = SECBUFFER_TOKEN;
1032 buffers[0].cbBuffer = 0;
cc754834 1033
2ece34a9
MS
1034 message.cBuffers = 1;
1035 message.pBuffers = buffers;
1036 message.ulVersion = SECBUFFER_VERSION;
1037
e32497ad 1038 status = AcceptSecurityContext(&sspi->creds, &sspi->context, NULL,
2ece34a9
MS
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 {
52770f63 1067 DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
2ece34a9
MS
1068 }
1069 }
1070 else
1071 {
52770f63 1072 DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
cc754834 1073 }
2ece34a9 1074 }
cc754834 1075
e32497ad 1076 http_sspi_free(sspi);
cc754834 1077
2ece34a9
MS
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{
e32497ad 1091 _http_sspi_t *sspi = http->tls; /* SSPI data */
2ece34a9
MS
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
e32497ad 1100 bufferLen = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer;
2ece34a9 1101
e32497ad 1102 if (bufferLen > sspi->writeBufferLength)
2ece34a9
MS
1103 {
1104 BYTE *temp; /* New buffer pointer */
1105
e32497ad 1106 if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL)
cc754834 1107 {
2ece34a9
MS
1108 DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen));
1109 WSASetLastError(E_OUTOFMEMORY);
1110 return (-1);
cc754834 1111 }
2ece34a9 1112
e32497ad
MS
1113 sspi->writeBuffer = temp;
1114 sspi->writeBufferLength = bufferLen;
cc754834
MS
1115 }
1116
2ece34a9
MS
1117 bytesLeft = len;
1118 bufptr = buf;
cc754834 1119
2ece34a9
MS
1120 while (bytesLeft)
1121 {
e32497ad 1122 int chunk = min((int)sspi->streamSizes.cbMaximumMessage, bytesLeft);
2ece34a9
MS
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
e32497ad 1130 memcpy(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk);
2ece34a9
MS
1131
1132 /*
1133 * Setup the SSPI buffers
1134 */
1135
1136 message.ulVersion = SECBUFFER_VERSION;
1137 message.cBuffers = 4;
1138 message.pBuffers = buffers;
1139
e32497ad
MS
1140 buffers[0].pvBuffer = sspi->writeBuffer;
1141 buffers[0].cbBuffer = sspi->streamSizes.cbHeader;
2ece34a9 1142 buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
e32497ad 1143 buffers[1].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader;
2ece34a9
MS
1144 buffers[1].cbBuffer = (unsigned long) chunk;
1145 buffers[1].BufferType = SECBUFFER_DATA;
e32497ad
MS
1146 buffers[2].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk;
1147 buffers[2].cbBuffer = sspi->streamSizes.cbTrailer;
2ece34a9
MS
1148 buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
1149 buffers[3].BufferType = SECBUFFER_EMPTY;
1150
1151 /*
1152 * Encrypt the data
1153 */
1154
e32497ad 1155 scRet = EncryptMessage(&sspi->context, 0, &message, 0);
2ece34a9
MS
1156
1157 if (FAILED(scRet))
1158 {
52770f63 1159 DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9
MS
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
e32497ad 1170 num = send(http->fd, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0);
2ece34a9
MS
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
33c9220c 1186#if 0
2ece34a9
MS
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 */
cc754834 1200
2ece34a9
MS
1201
1202 DEBUG_printf(("7http_setup_ssl(http=%p)", http));
cc754834
MS
1203
1204 /*
2ece34a9 1205 * Get the hostname to use for SSL...
cc754834 1206 */
2ece34a9
MS
1207
1208 if (httpAddrLocalhost(http->hostaddr))
cc754834 1209 {
2ece34a9 1210 strlcpy(hostname, "localhost", sizeof(hostname));
cc754834 1211 }
2ece34a9
MS
1212 else
1213 {
1214 /*
1215 * Otherwise make sure the hostname we have does not end in a trailing dot.
1216 */
cc754834 1217
2ece34a9
MS
1218 strlcpy(hostname, http->hostname, sizeof(hostname));
1219 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
1220 *hostptr == '.')
1221 *hostptr = '\0';
1222 }
cc754834 1223
33c9220c 1224 http->tls = http_sspi_alloc();
cc754834 1225
2ece34a9
MS
1226 if (!http->tls)
1227 {
1228 _cupsSetHTTPError(HTTP_STATUS_ERROR);
1229 return (-1);
1230 }
cc754834 1231
2ece34a9
MS
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);
cc754834 1236
2ece34a9
MS
1237 if (!_sspiGetCredentials(http->tls, L"ClientContainer",
1238 commonName, FALSE))
1239 {
1240 _sspiFree(http->tls);
1241 http->tls = NULL;
cc754834 1242
2ece34a9
MS
1243 http->error = EIO;
1244 http->status = HTTP_STATUS_ERROR;
cc754834 1245
2ece34a9
MS
1246 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
1247 _("Unable to establish a secure connection to host."), 1);
cc754834 1248
2ece34a9
MS
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);
cc754834 1270}
33c9220c 1271#endif // 0
cc754834
MS
1272
1273
1274/*
2ece34a9 1275 * 'http_sspi_alloc()' - Allocate SSPI object.
cc754834 1276 */
2ece34a9
MS
1277
1278static _http_sspi_t * /* O - New SSPI/SSL object */
1279http_sspi_alloc(void)
1280{
e32497ad 1281 return ((_http_sspi_t *)calloc(sizeof(_http_sspi_t), 1));
2ece34a9
MS
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 */
cc754834 1292{
e32497ad 1293 _http_sspi_t *sspi = http->tls; /* SSPI data */
9870d12b 1294 DWORD dwSize; /* Size for buffer */
33c9220c
MS
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 */
9870d12b
MS
1305 char username[1024], /* Current username */
1306 common_name[1024]; /* CN=username */
cc754834 1307
cc754834 1308
52770f63 1309 DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname));
2ece34a9 1310
cc754834
MS
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
9870d12b
MS
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
e32497ad
MS
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 {
52770f63 1329 DEBUG_puts("5http_sspi_client: Unable to get client credentials.");
e32497ad
MS
1330 return (-1);
1331 }
9870d12b 1332
cc754834
MS
1333 /*
1334 * Initiate a ClientHello message and generate a token.
1335 */
2ece34a9 1336
cc754834
MS
1337 outBuffers[0].pvBuffer = NULL;
1338 outBuffers[0].BufferType = SECBUFFER_TOKEN;
1339 outBuffers[0].cbBuffer = 0;
1340
2ece34a9
MS
1341 outBuffer.cBuffers = 1;
1342 outBuffer.pBuffers = outBuffers;
cc754834
MS
1343 outBuffer.ulVersion = SECBUFFER_VERSION;
1344
e32497ad 1345 scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
cc754834
MS
1346
1347 if (scRet != SEC_I_CONTINUE_NEEDED)
1348 {
52770f63 1349 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 1350 return (-1);
cc754834
MS
1351 }
1352
1353 /*
1354 * Send response to server if there is one.
1355 */
2ece34a9 1356
cc754834
MS
1357 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
1358 {
2ece34a9 1359 if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0)
cc754834 1360 {
52770f63 1361 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
cc754834 1362 FreeContextBuffer(outBuffers[0].pvBuffer);
e32497ad 1363 DeleteSecurityContext(&sspi->context);
2ece34a9 1364 return (-1);
cc754834
MS
1365 }
1366
52770f63 1367 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
cc754834 1368
cc754834
MS
1369 FreeContextBuffer(outBuffers[0].pvBuffer);
1370 outBuffers[0].pvBuffer = NULL;
1371 }
1372
1373 dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
2ece34a9 1374 ISC_REQ_SEQUENCE_DETECT |
cc754834
MS
1375 ISC_REQ_REPLAY_DETECT |
1376 ISC_REQ_CONFIDENTIALITY |
1377 ISC_RET_EXTENDED_ERROR |
1378 ISC_REQ_ALLOCATE_MEMORY |
1379 ISC_REQ_STREAM;
1380
e32497ad 1381 sspi->decryptBufferUsed = 0;
cc754834 1382
321d8d57 1383 /*
cc754834
MS
1384 * Loop until the handshake is finished or an error occurs.
1385 */
2ece34a9 1386
cc754834
MS
1387 scRet = SEC_I_CONTINUE_NEEDED;
1388
1389 while(scRet == SEC_I_CONTINUE_NEEDED ||
1390 scRet == SEC_E_INCOMPLETE_MESSAGE ||
321d8d57 1391 scRet == SEC_I_INCOMPLETE_CREDENTIALS)
cc754834 1392 {
e32497ad 1393 if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
cc754834 1394 {
e32497ad 1395 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
cc754834 1396 {
2ece34a9 1397 BYTE *temp; /* New buffer */
cc754834 1398
e32497ad 1399 if (sspi->decryptBufferLength >= 262144)
2ece34a9
MS
1400 {
1401 WSASetLastError(E_OUTOFMEMORY);
52770f63 1402 DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)");
2ece34a9
MS
1403 return (-1);
1404 }
1405
e32497ad 1406 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
2ece34a9 1407 {
52770f63 1408 DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
2ece34a9
MS
1409 WSASetLastError(E_OUTOFMEMORY);
1410 return (-1);
1411 }
1412
e32497ad
MS
1413 sspi->decryptBufferLength += 4096;
1414 sspi->decryptBuffer = temp;
cc754834 1415 }
321d8d57 1416
e32497ad 1417 cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
321d8d57 1418
2ece34a9 1419 if (cbData < 0)
cc754834 1420 {
52770f63 1421 DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError()));
2ece34a9 1422 return (-1);
cc754834
MS
1423 }
1424 else if (cbData == 0)
1425 {
52770f63 1426 DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected."));
2ece34a9 1427 return (-1);
cc754834
MS
1428 }
1429
52770f63 1430 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData));
cc754834 1431
e32497ad 1432 sspi->decryptBufferUsed += cbData;
cc754834
MS
1433 }
1434
1435 /*
2ece34a9
MS
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.
cc754834 1440 */
2ece34a9 1441
e32497ad
MS
1442 inBuffers[0].pvBuffer = sspi->decryptBuffer;
1443 inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
cc754834
MS
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 /*
2ece34a9
MS
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.
cc754834 1457 */
cc754834 1458
2ece34a9
MS
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;
cc754834
MS
1466
1467 /*
1468 * Call InitializeSecurityContext.
1469 */
2ece34a9 1470
e32497ad 1471 scRet = InitializeSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
cc754834
MS
1472
1473 /*
2ece34a9
MS
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.
cc754834 1477 */
2ece34a9 1478
cc754834
MS
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 {
2ece34a9 1485 cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
321d8d57 1486
2ece34a9 1487 if (cbData <= 0)
cc754834 1488 {
52770f63 1489 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
cc754834 1490 FreeContextBuffer(outBuffers[0].pvBuffer);
e32497ad 1491 DeleteSecurityContext(&sspi->context);
2ece34a9 1492 return (-1);
cc754834
MS
1493 }
1494
52770f63 1495 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
cc754834
MS
1496
1497 /*
1498 * Free output buffer.
1499 */
2ece34a9 1500
cc754834
MS
1501 FreeContextBuffer(outBuffers[0].pvBuffer);
1502 outBuffers[0].pvBuffer = NULL;
1503 }
1504 }
1505
1506 /*
2ece34a9
MS
1507 * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we
1508 * need to read more data from the server and try again.
cc754834 1509 */
2ece34a9 1510
cc754834
MS
1511 if (scRet == SEC_E_INCOMPLETE_MESSAGE)
1512 continue;
1513
1514 /*
2ece34a9
MS
1515 * If InitializeSecurityContext returned SEC_E_OK, then the handshake
1516 * completed successfully.
cc754834 1517 */
2ece34a9 1518
cc754834
MS
1519 if (scRet == SEC_E_OK)
1520 {
1521 /*
1522 * If the "extra" buffer contains data, this is encrypted application
2ece34a9
MS
1523 * protocol layer stuff. It needs to be saved. The application layer will
1524 * later decrypt it with DecryptMessage.
cc754834 1525 */
2ece34a9 1526
52770f63 1527 DEBUG_puts("5http_sspi_client: Handshake was successful.");
cc754834
MS
1528
1529 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1530 {
e32497ad 1531 memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
cc754834 1532
e32497ad 1533 sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
cc754834 1534
52770f63 1535 DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed));
cc754834
MS
1536 }
1537 else
e32497ad 1538 sspi->decryptBufferUsed = 0;
cc754834
MS
1539
1540 /*
1541 * Bail out to quit
1542 */
2ece34a9 1543
cc754834
MS
1544 break;
1545 }
1546
1547 /*
1548 * Check for fatal error.
1549 */
2ece34a9 1550
cc754834
MS
1551 if (FAILED(scRet))
1552 {
52770f63 1553 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 1554 ret = -1;
cc754834
MS
1555 break;
1556 }
1557
1558 /*
1559 * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
321d8d57 1560 * then the server just requested client authentication.
cc754834 1561 */
2ece34a9 1562
cc754834
MS
1563 if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
1564 {
1565 /*
1566 * Unimplemented
1567 */
2ece34a9 1568
52770f63 1569 DEBUG_printf(("5http_sspi_client: server requested client credentials."));
2ece34a9 1570 ret = -1;
cc754834
MS
1571 break;
1572 }
1573
1574 /*
2ece34a9 1575 * Copy any leftover data from the "extra" buffer, and go around again.
cc754834 1576 */
2ece34a9 1577
cc754834
MS
1578 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1579 {
e32497ad 1580 memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
cc754834 1581
e32497ad 1582 sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
cc754834
MS
1583 }
1584 else
1585 {
e32497ad 1586 sspi->decryptBufferUsed = 0;
cc754834
MS
1587 }
1588 }
1589
2ece34a9 1590 if (!ret)
cc754834 1591 {
cc754834 1592 /*
2ece34a9 1593 * Success! Get the server cert
cc754834 1594 */
2ece34a9 1595
e32497ad 1596 sspi->contextInitialized = TRUE;
2ece34a9 1597
e32497ad 1598 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert));
cc754834
MS
1599
1600 if (scRet != SEC_E_OK)
1601 {
52770f63 1602 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 1603 return (-1);
cc754834
MS
1604 }
1605
cc754834
MS
1606 /*
1607 * Find out how big the header/trailer will be:
1608 */
2ece34a9 1609
e32497ad 1610 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
cc754834
MS
1611
1612 if (scRet != SEC_E_OK)
1613 {
52770f63 1614 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 1615 ret = -1;
cc754834
MS
1616 }
1617 }
1618
2ece34a9
MS
1619 return (ret);
1620}
cc754834 1621
cc754834 1622
17eecbf1
MS
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
2ece34a9 1638/*
e32497ad 1639 * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store.
2ece34a9
MS
1640 */
1641
9870d12b 1642static BOOL /* O - 1 on success, 0 on failure */
e32497ad 1643http_sspi_find_credentials(
9870d12b
MS
1644 http_t *http, /* I - HTTP connection */
1645 const LPWSTR container, /* I - Cert container name */
e32497ad 1646 const char *common_name) /* I - Common name of certificate */
cc754834 1647{
e32497ad 1648 _http_sspi_t *sspi = http->tls; /* SSPI data */
9870d12b
MS
1649 HCERTSTORE store = NULL; /* Certificate store */
1650 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
9870d12b
MS
1651 DWORD dwSize = 0; /* 32 bit size */
1652 PBYTE p = NULL; /* Temporary storage */
1653 HCRYPTPROV hProv = (HCRYPTPROV)NULL;
2ece34a9 1654 /* Handle to a CSP */
9870d12b
MS
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 */
9870d12b 1659 BOOL ok = TRUE; /* Return value */
cc754834 1660
cc754834 1661
9870d12b 1662 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
cc754834 1663 {
2ece34a9 1664 if (GetLastError() == NTE_EXISTS)
cc754834 1665 {
9870d12b 1666 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
cc754834 1667 {
52770f63 1668 DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
cc754834
MS
1669 ok = FALSE;
1670 goto cleanup;
1671 }
cc754834 1672 }
2ece34a9 1673 }
cc754834 1674
9870d12b 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");
cc754834 1676
2ece34a9
MS
1677 if (!store)
1678 {
52770f63 1679 DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
2ece34a9
MS
1680 ok = FALSE;
1681 goto cleanup;
1682 }
cc754834 1683
2ece34a9 1684 dwSize = 0;
cc754834 1685
9870d12b 1686 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
2ece34a9 1687 {
52770f63 1688 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
2ece34a9
MS
1689 ok = FALSE;
1690 goto cleanup;
1691 }
cc754834 1692
9870d12b 1693 p = (PBYTE)malloc(dwSize);
cc754834 1694
2ece34a9
MS
1695 if (!p)
1696 {
52770f63 1697 DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize));
2ece34a9
MS
1698 ok = FALSE;
1699 goto cleanup;
1700 }
cc754834 1701
9870d12b 1702 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
2ece34a9 1703 {
52770f63 1704 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
2ece34a9
MS
1705 ok = FALSE;
1706 goto cleanup;
1707 }
cc754834 1708
2ece34a9
MS
1709 sib.cbData = dwSize;
1710 sib.pbData = p;
cc754834 1711
9870d12b 1712 storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
cc754834 1713
2ece34a9
MS
1714 if (!storedContext)
1715 {
52770f63 1716 DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name));
e32497ad
MS
1717 ok = FALSE;
1718 goto cleanup;
cc754834
MS
1719 }
1720
2ece34a9 1721 ZeroMemory(&SchannelCred, sizeof(SchannelCred));
cc754834 1722
2ece34a9 1723 SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
9870d12b
MS
1724 SchannelCred.cCreds = 1;
1725 SchannelCred.paCred = &storedContext;
cc754834 1726
2ece34a9 1727 /*
9870d12b 1728 * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
2ece34a9 1729 */
9870d12b 1730
e32497ad 1731 if (http->mode == _HTTP_MODE_SERVER)
2ece34a9 1732 SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
cc754834 1733
2ece34a9
MS
1734 /*
1735 * Create an SSPI credential.
1736 */
9870d12b 1737
e32497ad 1738 Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
2ece34a9 1739 if (Status != SEC_E_OK)
cc754834 1740 {
52770f63 1741 DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
2ece34a9 1742 ok = FALSE;
cc754834
MS
1743 goto cleanup;
1744 }
1745
2ece34a9 1746cleanup:
cc754834 1747
2ece34a9
MS
1748 /*
1749 * Cleanup
1750 */
9870d12b 1751
2ece34a9
MS
1752 if (storedContext)
1753 CertFreeCertificateContext(storedContext);
cc754834 1754
2ece34a9
MS
1755 if (p)
1756 free(p);
cc754834 1757
2ece34a9
MS
1758 if (store)
1759 CertCloseStore(store, 0);
cc754834 1760
2ece34a9
MS
1761 if (hProv)
1762 CryptReleaseContext(hProv, 0);
cc754834 1763
2ece34a9 1764 return (ok);
cc754834 1765}
9870d12b
MS
1766
1767
1768/*
1769 * 'http_sspi_free()' - Close a connection and free resources.
1770 */
1771
1772static void
e32497ad 1773http_sspi_free(_http_sspi_t *sspi) /* I - SSPI data */
9870d12b 1774{
e32497ad 1775 if (!sspi)
9870d12b
MS
1776 return;
1777
e32497ad
MS
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 {
52770f63 1839 DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
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 {
52770f63 1850 DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
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 {
52770f63 1859 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1860 ok = FALSE;
1861 goto cleanup;
1862 }
1863
1864 p = (PBYTE)malloc(dwSize);
1865
1866 if (!p)
1867 {
52770f63 1868 DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize));
e32497ad
MS
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 {
52770f63 1875 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1876 ok = FALSE;
1877 goto cleanup;
1878 }
1879
1880 /*
52770f63 1881 * Create a private key and self-signed certificate...
e32497ad 1882 */
9870d12b 1883
e32497ad
MS
1884 if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
1885 {
52770f63 1886 DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
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;
9870d12b 1900
e32497ad 1901 ZeroMemory(&exts, sizeof(exts));
9870d12b 1902
e32497ad 1903 createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts);
9870d12b 1904
e32497ad
MS
1905 if (!createdContext)
1906 {
52770f63 1907 DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1908 ok = FALSE;
1909 goto cleanup;
1910 }
9870d12b 1911
52770f63
MS
1912 /*
1913 * Add the created context to the named store, and associate it with the named
1914 * container...
1915 */
1916
e32497ad
MS
1917 if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
1918 {
52770f63 1919 DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
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 {
52770f63 1933 DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1934 ok = FALSE;
1935 goto cleanup;
1936 }
1937
52770f63
MS
1938 /*
1939 * Get a handle to use the certificate...
1940 */
e32497ad
MS
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 {
52770f63 1962 DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
e32497ad
MS
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);
9870d12b 1981
e32497ad
MS
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);
9870d12b 1992}
cc754834
MS
1993
1994
1995/*
2ece34a9 1996 * 'http_sspi_server()' - Negotiate a TLS connection as a server.
cc754834 1997 */
2ece34a9
MS
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 */
cc754834 2002{
e32497ad
MS
2003 _http_sspi_t *sspi = http->tls; /* I - SSPI data */
2004 char common_name[512]; /* Common name for cert */
2ece34a9
MS
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
52770f63 2018 DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname));
cc754834 2019
2ece34a9
MS
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
e32497ad
MS
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 {
52770f63 2038 DEBUG_puts("5http_sspi_server: Unable to get server credentials.");
e32497ad
MS
2039 return (-1);
2040 }
cc754834
MS
2041
2042 /*
2ece34a9 2043 * Set OutBuffer for AcceptSecurityContext call
cc754834 2044 */
cc754834 2045
2ece34a9
MS
2046 outBuffer.cBuffers = 1;
2047 outBuffer.pBuffers = outBuffers;
2048 outBuffer.ulVersion = SECBUFFER_VERSION;
cc754834 2049
2ece34a9 2050 scRet = SEC_I_CONTINUE_NEEDED;
cc754834 2051
2ece34a9
MS
2052 while (scRet == SEC_I_CONTINUE_NEEDED ||
2053 scRet == SEC_E_INCOMPLETE_MESSAGE ||
2054 scRet == SEC_I_INCOMPLETE_CREDENTIALS)
cc754834 2055 {
e32497ad 2056 if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
cc754834 2057 {
e32497ad 2058 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
cc754834 2059 {
2ece34a9 2060 BYTE *temp; /* New buffer */
cc754834 2061
e32497ad 2062 if (sspi->decryptBufferLength >= 262144)
2ece34a9
MS
2063 {
2064 WSASetLastError(E_OUTOFMEMORY);
52770f63 2065 DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)");
2ece34a9
MS
2066 return (-1);
2067 }
cc754834 2068
e32497ad 2069 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
2ece34a9 2070 {
52770f63 2071 DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
2ece34a9
MS
2072 WSASetLastError(E_OUTOFMEMORY);
2073 return (-1);
2074 }
cc754834 2075
e32497ad
MS
2076 sspi->decryptBufferLength += 4096;
2077 sspi->decryptBuffer = temp;
2ece34a9 2078 }
cc754834 2079
2ece34a9 2080 for (;;)
cc754834 2081 {
e32497ad 2082 num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
cc754834 2083
33c9220c 2084 if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
2ece34a9 2085 Sleep(1);
cc754834 2086 else
2ece34a9 2087 break;
cc754834 2088 }
cc754834 2089
2ece34a9
MS
2090 if (num < 0)
2091 {
52770f63 2092 DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError()));
2ece34a9
MS
2093 return (-1);
2094 }
2095 else if (num == 0)
2096 {
52770f63 2097 DEBUG_puts("5http_sspi_server: client disconnected");
2ece34a9
MS
2098 return (-1);
2099 }
2100
52770f63 2101 DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num));
e32497ad 2102 sspi->decryptBufferUsed += num;
cc754834
MS
2103 }
2104
2105 /*
2ece34a9
MS
2106 * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process
2107 * on this run around the loop.
cc754834 2108 */
2ece34a9 2109
e32497ad
MS
2110 inBuffers[0].pvBuffer = sspi->decryptBuffer;
2111 inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
2ece34a9
MS
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;
cc754834
MS
2121
2122 /*
2ece34a9
MS
2123 * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to
2124 * free random garbage at the quit.
cc754834 2125 */
cc754834 2126
2ece34a9
MS
2127 outBuffers[0].pvBuffer = NULL;
2128 outBuffers[0].BufferType = SECBUFFER_TOKEN;
2129 outBuffers[0].cbBuffer = 0;
2130
e32497ad 2131 scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry);
cc754834 2132
2ece34a9
MS
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)
cc754834 2140 {
2ece34a9
MS
2141 /*
2142 * Send response to server if there is one.
2143 */
cc754834 2144
2ece34a9
MS
2145 num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
2146
2147 if (num <= 0)
2148 {
52770f63 2149 DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError()));
2ece34a9 2150 return (-1);
cc754834
MS
2151 }
2152
52770f63 2153 DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer));
cc754834 2154
2ece34a9
MS
2155 FreeContextBuffer(outBuffers[0].pvBuffer);
2156 outBuffers[0].pvBuffer = NULL;
cc754834 2157 }
2ece34a9
MS
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 */
cc754834 2165
2ece34a9
MS
2166 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
2167 {
e32497ad
MS
2168 memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
2169 sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
2ece34a9
MS
2170 }
2171 else
2172 {
e32497ad 2173 sspi->decryptBufferUsed = 0;
2ece34a9
MS
2174 }
2175 break;
cc754834 2176 }
2ece34a9 2177 else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE)
cc754834 2178 {
52770f63 2179 DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9
MS
2180 ret = -1;
2181 break;
cc754834
MS
2182 }
2183
2ece34a9
MS
2184 if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
2185 scRet != SEC_I_INCOMPLETE_CREDENTIALS)
cc754834 2186 {
2ece34a9
MS
2187 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
2188 {
e32497ad
MS
2189 memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
2190 sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
2ece34a9
MS
2191 }
2192 else
2193 {
e32497ad 2194 sspi->decryptBufferUsed = 0;
2ece34a9 2195 }
cc754834 2196 }
2ece34a9
MS
2197 }
2198
2199 if (!ret)
2200 {
e32497ad 2201 sspi->contextInitialized = TRUE;
2ece34a9
MS
2202
2203 /*
2204 * Find out how big the header will be:
2205 */
2206
e32497ad 2207 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
2ece34a9
MS
2208
2209 if (scRet != SEC_E_OK)
cc754834 2210 {
52770f63 2211 DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 2212 ret = -1;
cc754834
MS
2213 }
2214 }
2215
2ece34a9 2216 return (ret);
cc754834
MS
2217}
2218
2219
adad9dd6
MS
2220/*
2221 * 'http_sspi_strerror()' - Return a string for the specified error code.
2222 */
2223
2224static const char * /* O - String for error */
52770f63
MS
2225http_sspi_strerror(char *buffer, /* I - Error message buffer */
2226 size_t bufsize, /* I - Size of buffer */
2227 DWORD code) /* I - Error code */
adad9dd6 2228{
52770f63 2229 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, bufsize, NULL))
adad9dd6
MS
2230 {
2231 /*
2232 * Strip trailing CR + LF...
2233 */
2234
2235 char *ptr; /* Pointer into error message */
2236
52770f63 2237 for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --)
adad9dd6
MS
2238 if (*ptr == '\n' || *ptr == '\r')
2239 *ptr = '\0';
2240 else
2241 break;
2242 }
2243 else
52770f63 2244 snprintf(buffer, bufsize, "Unknown error %x", code);
cc754834 2245
52770f63 2246 return (buffer);
cc754834
MS
2247}
2248
2249
2250/*
2ece34a9 2251 * 'http_sspi_verify()' - Verify a certificate.
cc754834 2252 */
2ece34a9
MS
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 */
cc754834 2259{
2ece34a9
MS
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;
cc754834 2265 /* Certificate chain */
2ece34a9
MS
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 };
cc754834 2271 /* How are we using this certificate? */
2ece34a9 2272 DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
cc754834 2273 /* Number of ites in rgszUsages */
2ece34a9
MS
2274 DWORD count; /* 32 bit count variable */
2275 DWORD status; /* Return value */
74ac5fe7
MS
2276#ifdef DEBUG
2277 char error[1024]; /* Error message string */
2278#endif /* DEBUG */
cc754834 2279
2ece34a9
MS
2280
2281 if (!cert)
2282 return (SEC_E_WRONG_PRINCIPAL);
cc754834
MS
2283
2284 /*
2ece34a9 2285 * Convert common name to Unicode.
cc754834 2286 */
cc754834 2287
2ece34a9
MS
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))
cc754834 2297 {
2ece34a9
MS
2298 LocalFree(commonNameUnicode);
2299 return (SEC_E_WRONG_PRINCIPAL);
cc754834
MS
2300 }
2301
2302 /*
2303 * Build certificate chain.
2304 */
2ece34a9 2305
cc754834 2306 ZeroMemory(&chainPara, sizeof(chainPara));
2ece34a9 2307
cc754834
MS
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
2ece34a9 2313 if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext))
cc754834
MS
2314 {
2315 status = GetLastError();
52770f63 2316
52770f63 2317 DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status)));
2ece34a9
MS
2318
2319 LocalFree(commonNameUnicode);
2320 return (status);
cc754834
MS
2321 }
2322
2323 /*
2324 * Validate certificate chain.
321d8d57 2325 */
2ece34a9 2326
cc754834
MS
2327 ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
2328 httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData);
2329 httpsPolicy.dwAuthType = AUTHTYPE_SERVER;
2330 httpsPolicy.fdwChecks = dwCertFlags;
2ece34a9 2331 httpsPolicy.pwszServerName = commonNameUnicode;
cc754834
MS
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
2ece34a9 2340 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus))
cc754834
MS
2341 {
2342 status = GetLastError();
52770f63 2343
52770f63 2344 DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status)));
cc754834 2345 }
2ece34a9 2346 else if (policyStatus.dwError)
cc754834 2347 status = policyStatus.dwError;
2ece34a9
MS
2348 else
2349 status = SEC_E_OK;
cc754834
MS
2350
2351 if (chainContext)
2352 CertFreeCertificateChain(chainContext);
2353
2ece34a9
MS
2354 if (commonNameUnicode)
2355 LocalFree(commonNameUnicode);
cc754834
MS
2356
2357 return (status);
2358}
e32497ad
MS
2359
2360
321d8d57
MS
2361/*
2362 * End of "$Id$".
2363 */