]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/tls-sspi.c
Implement httpLoadCredentials and httpSaveCredentials for SSPI.
[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 *
69 * @since CUPS 2.0@
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 *
105 * @since CUPS 2.0@
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 *
168 * @since CUPS 2.0@
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 *
233 * @since CUPS 2.0@
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 *
275 * @since CUPS 2.0@
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 *
312 * @since CUPS 2.0@
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 *
402 * @since CUPS 2.0@
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 *
526 * @since CUPS 2.0@
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 _http_sspi_t *sspi = http->tls; /* SSPI data */
536 HCERTSTORE store = NULL; /* Certificate store */
537 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
538 PCCERT_CONTEXT createdContext = NULL; /* Context created by us */
539 DWORD dwSize = 0; /* 32 bit size */
540 PBYTE p = NULL; /* Temporary storage */
541 HCRYPTPROV hProv = (HCRYPTPROV)NULL;
542 /* Handle to a CSP */
543 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
544 int ret = -1; /* Return value */
545#ifdef DEBUG
546 char error[1024]; /* Error message buffer */
547#endif /* DEBUG */
548
549
2ece34a9 550 DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
2c85b752 551
2ece34a9 552 (void)path;
2c85b752 553
52770f63
MS
554 if (!common_name)
555 {
556 DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1.");
557 return (-1);
558 }
559
560 createdContext = http_sspi_create_credential(credentials);
561 if (!createdContext)
562 {
563 DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1.");
564 return (-1);
565 }
566
567 if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
568 {
569 if (GetLastError() == NTE_EXISTS)
570 {
571 if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
572 {
573 DEBUG_printf(("1httpSaveCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
574 goto cleanup;
575 }
576 }
577 }
578
579 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");
580
581 if (!store)
582 {
583 DEBUG_printf(("1httpSaveCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
584 goto cleanup;
585 }
586
587 dwSize = 0;
588
589 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
590 {
591 DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
592 goto cleanup;
593 }
594
595 p = (PBYTE)malloc(dwSize);
596
597 if (!p)
598 {
599 DEBUG_printf(("1httpSaveCredentials: malloc failed for %d bytes.", dwSize));
600 goto cleanup;
601 }
602
603 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
604 {
605 DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
606 goto cleanup;
607 }
608
609 /*
610 * Add the created context to the named store, and associate it with the named
611 * container...
612 */
613
614 if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
615 {
616 DEBUG_printf(("1httpSaveCredentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
617 goto cleanup;
618 }
619
620 ZeroMemory(&ckp, sizeof(ckp));
621 ckp.pwszContainerName = L"RememberedContainer";
622 ckp.pwszProvName = MS_DEF_PROV_W;
623 ckp.dwProvType = PROV_RSA_FULL;
624 ckp.dwFlags = CRYPT_MACHINE_KEYSET;
625 ckp.dwKeySpec = AT_KEYEXCHANGE;
626
627 if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
628 {
629 DEBUG_printf(("1httpSaveCredentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
630 goto cleanup;
631 }
632
633 ret = 0;
634
635cleanup:
636
637 /*
638 * Cleanup
639 */
640
641 if (createdContext)
642 CertFreeCertificateContext(createdContext);
643
644 if (storedContext)
645 CertFreeCertificateContext(storedContext);
646
647 if (p)
648 free(p);
649
650 if (store)
651 CertCloseStore(store, 0);
652
653 if (hProv)
654 CryptReleaseContext(hProv, 0);
655
656 DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret));
657 return (ret);
2c85b752
MS
658}
659
660
661/*
2ece34a9 662 * '_httpTLSInitialize()' - Initialize the TLS stack.
2c85b752
MS
663 */
664
2ece34a9
MS
665void
666_httpTLSInitialize(void)
2c85b752 667{
2ece34a9
MS
668 /*
669 * Nothing to do...
670 */
671}
2c85b752 672
2c85b752 673
2ece34a9
MS
674/*
675 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
676 */
2c85b752 677
2ece34a9
MS
678size_t /* O - Bytes available */
679_httpTLSPending(http_t *http) /* I - HTTP connection */
680{
681 if (http->tls)
682 return (http->tls->readBufferUsed);
683 else
684 return (0);
685}
2c85b752 686
2c85b752 687
2ece34a9
MS
688/*
689 * '_httpTLSRead()' - Read from a SSL/TLS connection.
690 */
2c85b752 691
2ece34a9
MS
692int /* O - Bytes read */
693_httpTLSRead(http_t *http, /* I - HTTP connection */
694 char *buf, /* I - Buffer to store data */
695 int len) /* I - Length of buffer */
696{
697 int i; /* Looping var */
e32497ad 698 _http_sspi_t *sspi = http->tls; /* SSPI data */
2ece34a9
MS
699 SecBufferDesc message; /* Array of SecBuffer struct */
700 SecBuffer buffers[4] = { 0 }; /* Security package buffer */
701 int num = 0; /* Return value */
702 PSecBuffer pDataBuffer; /* Data buffer */
703 PSecBuffer pExtraBuffer; /* Excess data buffer */
704 SECURITY_STATUS scRet; /* SSPI status */
2c85b752 705
2c85b752 706
195c1f2d
MS
707 DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http, buf, len));
708
2ece34a9
MS
709 /*
710 * If there are bytes that have already been decrypted and have not yet been
711 * read, return those...
712 */
2c85b752 713
e32497ad 714 if (sspi->readBufferUsed > 0)
2ece34a9 715 {
e32497ad 716 int bytesToCopy = min(sspi->readBufferUsed, len);
2ece34a9 717 /* Number of bytes to copy */
2c85b752 718
e32497ad
MS
719 memcpy(buf, sspi->readBuffer, bytesToCopy);
720 sspi->readBufferUsed -= bytesToCopy;
2c85b752 721
e32497ad
MS
722 if (sspi->readBufferUsed > 0)
723 memmove(sspi->readBuffer, sspi->readBuffer + bytesToCopy, sspi->readBufferUsed);
2c85b752 724
195c1f2d
MS
725 DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy));
726
2ece34a9
MS
727 return (bytesToCopy);
728 }
2c85b752 729
2ece34a9
MS
730 /*
731 * Initialize security buffer structs
732 */
2c85b752 733
2ece34a9 734 message.ulVersion = SECBUFFER_VERSION;
195c1f2d
MS
735 message.cBuffers = 4;
736 message.pBuffers = buffers;
2c85b752 737
2ece34a9 738 do
2c85b752
MS
739 {
740 /*
2ece34a9 741 * If there is not enough space in the buffer, then increase its size...
2c85b752
MS
742 */
743
e32497ad 744 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
2c85b752 745 {
2ece34a9 746 BYTE *temp; /* New buffer */
2c85b752 747
e32497ad 748 if (sspi->decryptBufferLength >= 262144)
2ece34a9
MS
749 {
750 WSASetLastError(E_OUTOFMEMORY);
751 DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)");
752 return (-1);
753 }
2c85b752 754
e32497ad 755 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
2ece34a9 756 {
e32497ad 757 DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi->decryptBufferLength + 4096));
2ece34a9
MS
758 WSASetLastError(E_OUTOFMEMORY);
759 return (-1);
760 }
2c85b752 761
e32497ad
MS
762 sspi->decryptBufferLength += 4096;
763 sspi->decryptBuffer = temp;
195c1f2d 764
e32497ad 765 DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi->decryptBufferLength));
2ece34a9 766 }
2c85b752 767
e32497ad
MS
768 buffers[0].pvBuffer = sspi->decryptBuffer;
769 buffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
2ece34a9
MS
770 buffers[0].BufferType = SECBUFFER_DATA;
771 buffers[1].BufferType = SECBUFFER_EMPTY;
772 buffers[2].BufferType = SECBUFFER_EMPTY;
773 buffers[3].BufferType = SECBUFFER_EMPTY;
2c85b752 774
e32497ad 775 DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi->decryptBufferUsed));
195c1f2d 776
e32497ad 777 scRet = DecryptMessage(&sspi->context, &message, 0, NULL);
2c85b752 778
2ece34a9
MS
779 if (scRet == SEC_E_INCOMPLETE_MESSAGE)
780 {
e32497ad 781 num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
2ece34a9
MS
782 if (num < 0)
783 {
195c1f2d 784 DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError()));
2ece34a9
MS
785 return (-1);
786 }
787 else if (num == 0)
788 {
195c1f2d 789 DEBUG_puts("5_httpTLSRead: Server disconnected.");
2ece34a9
MS
790 return (0);
791 }
2c85b752 792
195c1f2d
MS
793 DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num));
794
e32497ad 795 sspi->decryptBufferUsed += num;
2ece34a9 796 }
2c85b752 797 }
2ece34a9 798 while (scRet == SEC_E_INCOMPLETE_MESSAGE);
2c85b752 799
2ece34a9
MS
800 if (scRet == SEC_I_CONTEXT_EXPIRED)
801 {
195c1f2d 802 DEBUG_puts("5_httpTLSRead: Context expired.");
2ece34a9
MS
803 WSASetLastError(WSAECONNRESET);
804 return (-1);
805 }
806 else if (scRet != SEC_E_OK)
807 {
52770f63 808 DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9
MS
809 WSASetLastError(WSASYSCALLFAILURE);
810 return (-1);
811 }
2c85b752 812
2ece34a9
MS
813 /*
814 * The decryption worked. Now, locate data buffer.
815 */
2c85b752 816
2ece34a9
MS
817 pDataBuffer = NULL;
818 pExtraBuffer = NULL;
2c85b752 819
2ece34a9
MS
820 for (i = 1; i < 4; i++)
821 {
822 if (buffers[i].BufferType == SECBUFFER_DATA)
823 pDataBuffer = &buffers[i];
824 else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA))
825 pExtraBuffer = &buffers[i];
826 }
2c85b752 827
2ece34a9
MS
828 /*
829 * If a data buffer is found, then copy the decrypted bytes to the passed-in
830 * buffer...
831 */
2c85b752 832
2ece34a9
MS
833 if (pDataBuffer)
834 {
33c9220c 835 int bytesToCopy = min((int)pDataBuffer->cbBuffer, len);
2ece34a9
MS
836 /* Number of bytes to copy into buf */
837 int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy;
838 /* Number of bytes to save in our read buffer */
2c85b752 839
2ece34a9
MS
840 if (bytesToCopy)
841 memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy);
2c85b752 842
2c85b752 843 /*
2ece34a9
MS
844 * If there are more decrypted bytes than can be copied to the passed in
845 * buffer, then save them...
2c85b752
MS
846 */
847
2ece34a9 848 if (bytesToSave)
2c85b752 849 {
e32497ad 850 if ((sspi->readBufferLength - sspi->readBufferUsed) < bytesToSave)
2ece34a9
MS
851 {
852 BYTE *temp; /* New buffer pointer */
2c85b752 853
e32497ad 854 if ((temp = realloc(sspi->readBuffer, sspi->readBufferUsed + bytesToSave)) == NULL)
2ece34a9 855 {
e32497ad 856 DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi->readBufferUsed + bytesToSave));
2ece34a9
MS
857 WSASetLastError(E_OUTOFMEMORY);
858 return (-1);
859 }
2c85b752 860
e32497ad
MS
861 sspi->readBufferLength = sspi->readBufferUsed + bytesToSave;
862 sspi->readBuffer = temp;
2ece34a9 863 }
2c85b752 864
e32497ad 865 memcpy(((BYTE *)sspi->readBuffer) + sspi->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave);
2c85b752 866
e32497ad 867 sspi->readBufferUsed += bytesToSave;
2ece34a9 868 }
2c85b752 869
adad9dd6 870 num = bytesToCopy;
2ece34a9
MS
871 }
872 else
873 {
33c9220c 874 DEBUG_puts("_httpTLSRead: Unable to find data buffer.");
2ece34a9
MS
875 WSASetLastError(WSASYSCALLFAILURE);
876 return (-1);
877 }
2c85b752 878
2ece34a9
MS
879 /*
880 * If the decryption process left extra bytes, then save those back in
881 * decryptBuffer. They will be processed the next time through the loop.
882 */
2c85b752 883
2ece34a9 884 if (pExtraBuffer)
2c85b752 885 {
e32497ad
MS
886 memmove(sspi->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
887 sspi->decryptBufferUsed = pExtraBuffer->cbBuffer;
2ece34a9
MS
888 }
889 else
890 {
e32497ad 891 sspi->decryptBufferUsed = 0;
2c85b752 892 }
2c85b752 893
adad9dd6 894 return (num);
2c85b752 895}
2c85b752
MS
896
897
cc754834 898/*
2ece34a9 899 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
cc754834 900 */
2ece34a9
MS
901
902int /* O - 0 on success, -1 on failure */
903_httpTLSStart(http_t *http) /* I - HTTP connection */
cc754834 904{
2ece34a9
MS
905 char hostname[256], /* Hostname */
906 *hostptr; /* Pointer into hostname */
cc754834 907
cc754834 908
2ece34a9
MS
909 DEBUG_printf(("7_httpTLSStart(http=%p)", http));
910
911 if ((http->tls = http_sspi_alloc()) == NULL)
912 return (-1);
cc754834 913
2ece34a9
MS
914 if (http->mode == _HTTP_MODE_CLIENT)
915 {
916 /*
917 * Client: determine hostname...
918 */
cc754834 919
2ece34a9
MS
920 if (httpAddrLocalhost(http->hostaddr))
921 {
922 strlcpy(hostname, "localhost", sizeof(hostname));
923 }
924 else
925 {
926 /*
927 * Otherwise make sure the hostname we have does not end in a trailing dot.
928 */
cc754834 929
2ece34a9
MS
930 strlcpy(hostname, http->hostname, sizeof(hostname));
931 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
932 *hostptr == '.')
933 *hostptr = '\0';
934 }
cc754834 935
2ece34a9
MS
936 return (http_sspi_client(http, hostname));
937 }
938 else
cc754834 939 {
2ece34a9
MS
940 /*
941 * Server: determine hostname to use...
942 */
943
944 if (http->fields[HTTP_FIELD_HOST][0])
cc754834 945 {
2ece34a9
MS
946 /*
947 * Use hostname for TLS upgrade...
948 */
949
950 strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
951 }
952 else
953 {
954 /*
955 * Resolve hostname from connection address...
956 */
957
958 http_addr_t addr; /* Connection address */
959 socklen_t addrlen; /* Length of address */
960
961 addrlen = sizeof(addr);
962 if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
cc754834 963 {
2ece34a9
MS
964 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno)));
965 hostname[0] = '\0';
966 }
967 else if (httpAddrLocalhost(&addr))
968 hostname[0] = '\0';
969 else
970 {
971 httpAddrLookup(&addr, hostname, sizeof(hostname));
972 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname));
cc754834
MS
973 }
974 }
cc754834 975
2ece34a9 976 return (http_sspi_server(http, hostname));
cc754834 977 }
2ece34a9 978}
cc754834 979
321d8d57 980
2ece34a9
MS
981/*
982 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
983 */
cc754834 984
2ece34a9
MS
985void
986_httpTLSStop(http_t *http) /* I - HTTP connection */
987{
e32497ad 988 _http_sspi_t *sspi = http->tls; /* SSPI data */
cc754834 989
cc754834 990
e32497ad 991 if (sspi->contextInitialized && http->fd >= 0)
cc754834 992 {
2ece34a9
MS
993 SecBufferDesc message; /* Array of SecBuffer struct */
994 SecBuffer buffers[1] = { 0 };
995 /* Security package buffer */
996 DWORD dwType; /* Type */
997 DWORD status; /* Status */
cc754834 998
2ece34a9
MS
999 /*
1000 * Notify schannel that we are about to close the connection.
1001 */
cc754834 1002
2ece34a9 1003 dwType = SCHANNEL_SHUTDOWN;
321d8d57 1004
2ece34a9
MS
1005 buffers[0].pvBuffer = &dwType;
1006 buffers[0].BufferType = SECBUFFER_TOKEN;
1007 buffers[0].cbBuffer = sizeof(dwType);
cc754834 1008
2ece34a9
MS
1009 message.cBuffers = 1;
1010 message.pBuffers = buffers;
1011 message.ulVersion = SECBUFFER_VERSION;
cc754834 1012
e32497ad 1013 status = ApplyControlToken(&sspi->context, &message);
cc754834 1014
2ece34a9
MS
1015 if (SUCCEEDED(status))
1016 {
1017 PBYTE pbMessage; /* Message buffer */
1018 DWORD cbMessage; /* Message buffer count */
1019 DWORD cbData; /* Data count */
1020 DWORD dwSSPIFlags; /* SSL attributes we requested */
1021 DWORD dwSSPIOutFlags; /* SSL attributes we received */
1022 TimeStamp tsExpiry; /* Time stamp */
cc754834 1023
2ece34a9
MS
1024 dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
1025 ASC_REQ_REPLAY_DETECT |
1026 ASC_REQ_CONFIDENTIALITY |
1027 ASC_REQ_EXTENDED_ERROR |
1028 ASC_REQ_ALLOCATE_MEMORY |
1029 ASC_REQ_STREAM;
321d8d57 1030
2ece34a9
MS
1031 buffers[0].pvBuffer = NULL;
1032 buffers[0].BufferType = SECBUFFER_TOKEN;
1033 buffers[0].cbBuffer = 0;
cc754834 1034
2ece34a9
MS
1035 message.cBuffers = 1;
1036 message.pBuffers = buffers;
1037 message.ulVersion = SECBUFFER_VERSION;
1038
e32497ad 1039 status = AcceptSecurityContext(&sspi->creds, &sspi->context, NULL,
2ece34a9
MS
1040 dwSSPIFlags, SECURITY_NATIVE_DREP, NULL,
1041 &message, &dwSSPIOutFlags, &tsExpiry);
1042
1043 if (SUCCEEDED(status))
1044 {
1045 pbMessage = buffers[0].pvBuffer;
1046 cbMessage = buffers[0].cbBuffer;
1047
1048 /*
1049 * Send the close notify message to the client.
1050 */
1051
1052 if (pbMessage && cbMessage)
1053 {
1054 cbData = send(http->fd, pbMessage, cbMessage, 0);
1055 if ((cbData == SOCKET_ERROR) || (cbData == 0))
1056 {
1057 status = WSAGetLastError();
1058 DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status));
1059 }
1060 else
1061 {
1062 FreeContextBuffer(pbMessage);
1063 }
1064 }
1065 }
1066 else
1067 {
52770f63 1068 DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
2ece34a9
MS
1069 }
1070 }
1071 else
1072 {
52770f63 1073 DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
cc754834 1074 }
2ece34a9 1075 }
cc754834 1076
e32497ad 1077 http_sspi_free(sspi);
cc754834 1078
2ece34a9
MS
1079 http->tls = NULL;
1080}
1081
1082
1083/*
1084 * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1085 */
1086
1087int /* O - Bytes written */
1088_httpTLSWrite(http_t *http, /* I - HTTP connection */
1089 const char *buf, /* I - Buffer holding data */
1090 int len) /* I - Length of buffer */
1091{
e32497ad 1092 _http_sspi_t *sspi = http->tls; /* SSPI data */
2ece34a9
MS
1093 SecBufferDesc message; /* Array of SecBuffer struct */
1094 SecBuffer buffers[4] = { 0 }; /* Security package buffer */
1095 int bufferLen; /* Buffer length */
1096 int bytesLeft; /* Bytes left to write */
1097 const char *bufptr; /* Pointer into buffer */
1098 int num = 0; /* Return value */
1099
1100
e32497ad 1101 bufferLen = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer;
2ece34a9 1102
e32497ad 1103 if (bufferLen > sspi->writeBufferLength)
2ece34a9
MS
1104 {
1105 BYTE *temp; /* New buffer pointer */
1106
e32497ad 1107 if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL)
cc754834 1108 {
2ece34a9
MS
1109 DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen));
1110 WSASetLastError(E_OUTOFMEMORY);
1111 return (-1);
cc754834 1112 }
2ece34a9 1113
e32497ad
MS
1114 sspi->writeBuffer = temp;
1115 sspi->writeBufferLength = bufferLen;
cc754834
MS
1116 }
1117
2ece34a9
MS
1118 bytesLeft = len;
1119 bufptr = buf;
cc754834 1120
2ece34a9
MS
1121 while (bytesLeft)
1122 {
e32497ad 1123 int chunk = min((int)sspi->streamSizes.cbMaximumMessage, bytesLeft);
2ece34a9
MS
1124 /* Size of data to write */
1125 SECURITY_STATUS scRet; /* SSPI status */
1126
1127 /*
1128 * Copy user data into the buffer, starting just past the header...
1129 */
1130
e32497ad 1131 memcpy(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk);
2ece34a9
MS
1132
1133 /*
1134 * Setup the SSPI buffers
1135 */
1136
1137 message.ulVersion = SECBUFFER_VERSION;
1138 message.cBuffers = 4;
1139 message.pBuffers = buffers;
1140
e32497ad
MS
1141 buffers[0].pvBuffer = sspi->writeBuffer;
1142 buffers[0].cbBuffer = sspi->streamSizes.cbHeader;
2ece34a9 1143 buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
e32497ad 1144 buffers[1].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader;
2ece34a9
MS
1145 buffers[1].cbBuffer = (unsigned long) chunk;
1146 buffers[1].BufferType = SECBUFFER_DATA;
e32497ad
MS
1147 buffers[2].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk;
1148 buffers[2].cbBuffer = sspi->streamSizes.cbTrailer;
2ece34a9
MS
1149 buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
1150 buffers[3].BufferType = SECBUFFER_EMPTY;
1151
1152 /*
1153 * Encrypt the data
1154 */
1155
e32497ad 1156 scRet = EncryptMessage(&sspi->context, 0, &message, 0);
2ece34a9
MS
1157
1158 if (FAILED(scRet))
1159 {
52770f63 1160 DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9
MS
1161 WSASetLastError(WSASYSCALLFAILURE);
1162 return (-1);
1163 }
1164
1165 /*
1166 * Send the data. Remember the size of the total data to send is the size
1167 * of the header, the size of the data the caller passed in and the size
1168 * of the trailer...
1169 */
1170
e32497ad 1171 num = send(http->fd, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0);
2ece34a9
MS
1172
1173 if (num <= 0)
1174 {
1175 DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError()));
1176 return (num);
1177 }
1178
1179 bytesLeft -= chunk;
1180 bufptr += chunk;
1181 }
1182
1183 return (len);
1184}
1185
1186
33c9220c 1187#if 0
2ece34a9
MS
1188/*
1189 * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
1190 */
1191
1192static int /* O - 0 on success, -1 on failure */
1193http_setup_ssl(http_t *http) /* I - Connection to server */
1194{
1195 char hostname[256], /* Hostname */
1196 *hostptr; /* Pointer into hostname */
1197
1198 TCHAR username[256]; /* Username returned from GetUserName() */
1199 TCHAR commonName[256];/* Common name for certificate */
1200 DWORD dwSize; /* 32 bit size */
cc754834 1201
2ece34a9
MS
1202
1203 DEBUG_printf(("7http_setup_ssl(http=%p)", http));
cc754834
MS
1204
1205 /*
2ece34a9 1206 * Get the hostname to use for SSL...
cc754834 1207 */
2ece34a9
MS
1208
1209 if (httpAddrLocalhost(http->hostaddr))
cc754834 1210 {
2ece34a9 1211 strlcpy(hostname, "localhost", sizeof(hostname));
cc754834 1212 }
2ece34a9
MS
1213 else
1214 {
1215 /*
1216 * Otherwise make sure the hostname we have does not end in a trailing dot.
1217 */
cc754834 1218
2ece34a9
MS
1219 strlcpy(hostname, http->hostname, sizeof(hostname));
1220 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
1221 *hostptr == '.')
1222 *hostptr = '\0';
1223 }
cc754834 1224
33c9220c 1225 http->tls = http_sspi_alloc();
cc754834 1226
2ece34a9
MS
1227 if (!http->tls)
1228 {
1229 _cupsSetHTTPError(HTTP_STATUS_ERROR);
1230 return (-1);
1231 }
cc754834 1232
2ece34a9
MS
1233 dwSize = sizeof(username) / sizeof(TCHAR);
1234 GetUserName(username, &dwSize);
1235 _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR),
1236 sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username);
cc754834 1237
2ece34a9
MS
1238 if (!_sspiGetCredentials(http->tls, L"ClientContainer",
1239 commonName, FALSE))
1240 {
1241 _sspiFree(http->tls);
1242 http->tls = NULL;
cc754834 1243
2ece34a9
MS
1244 http->error = EIO;
1245 http->status = HTTP_STATUS_ERROR;
cc754834 1246
2ece34a9
MS
1247 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
1248 _("Unable to establish a secure connection to host."), 1);
cc754834 1249
2ece34a9
MS
1250 return (-1);
1251 }
1252
1253 _sspiSetAllowsAnyRoot(http->tls, TRUE);
1254 _sspiSetAllowsExpiredCerts(http->tls, TRUE);
1255
1256 if (!_sspiConnect(http->tls, hostname))
1257 {
1258 _sspiFree(http->tls);
1259 http->tls = NULL;
1260
1261 http->error = EIO;
1262 http->status = HTTP_STATUS_ERROR;
1263
1264 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
1265 _("Unable to establish a secure connection to host."), 1);
1266
1267 return (-1);
1268 }
1269
1270 return (0);
cc754834 1271}
33c9220c 1272#endif // 0
cc754834
MS
1273
1274
1275/*
2ece34a9 1276 * 'http_sspi_alloc()' - Allocate SSPI object.
cc754834 1277 */
2ece34a9
MS
1278
1279static _http_sspi_t * /* O - New SSPI/SSL object */
1280http_sspi_alloc(void)
1281{
e32497ad 1282 return ((_http_sspi_t *)calloc(sizeof(_http_sspi_t), 1));
2ece34a9
MS
1283}
1284
1285
1286/*
1287 * 'http_sspi_client()' - Negotiate a TLS connection as a client.
1288 */
1289
1290static int /* O - 0 on success, -1 on failure */
1291http_sspi_client(http_t *http, /* I - Client connection */
1292 const char *hostname) /* I - Server hostname */
cc754834 1293{
e32497ad 1294 _http_sspi_t *sspi = http->tls; /* SSPI data */
9870d12b 1295 DWORD dwSize; /* Size for buffer */
33c9220c
MS
1296 DWORD dwSSPIFlags; /* SSL connection attributes we want */
1297 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
1298 TimeStamp tsExpiry; /* Time stamp */
1299 SECURITY_STATUS scRet; /* Status */
1300 int cbData; /* Data count */
1301 SecBufferDesc inBuffer; /* Array of SecBuffer structs */
1302 SecBuffer inBuffers[2]; /* Security package buffer */
1303 SecBufferDesc outBuffer; /* Array of SecBuffer structs */
1304 SecBuffer outBuffers[1]; /* Security package buffer */
1305 int ret = 0; /* Return value */
9870d12b
MS
1306 char username[1024], /* Current username */
1307 common_name[1024]; /* CN=username */
cc754834 1308
cc754834 1309
52770f63 1310 DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname));
2ece34a9 1311
cc754834
MS
1312 dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
1313 ISC_REQ_REPLAY_DETECT |
1314 ISC_REQ_CONFIDENTIALITY |
1315 ISC_RET_EXTENDED_ERROR |
1316 ISC_REQ_ALLOCATE_MEMORY |
1317 ISC_REQ_STREAM;
1318
9870d12b
MS
1319 /*
1320 * Lookup the client certificate...
1321 */
1322
1323 dwSize = sizeof(username);
1324 GetUserName(username, &dwSize);
1325 snprintf(common_name, sizeof(common_name), "CN=%s", username);
1326
e32497ad
MS
1327 if (!http_sspi_find_credentials(http, L"ClientContainer", common_name))
1328 if (!http_sspi_make_credentials(http->tls, L"ClientContainer", common_name, _HTTP_MODE_CLIENT, 10))
1329 {
52770f63 1330 DEBUG_puts("5http_sspi_client: Unable to get client credentials.");
e32497ad
MS
1331 return (-1);
1332 }
9870d12b 1333
cc754834
MS
1334 /*
1335 * Initiate a ClientHello message and generate a token.
1336 */
2ece34a9 1337
cc754834
MS
1338 outBuffers[0].pvBuffer = NULL;
1339 outBuffers[0].BufferType = SECBUFFER_TOKEN;
1340 outBuffers[0].cbBuffer = 0;
1341
2ece34a9
MS
1342 outBuffer.cBuffers = 1;
1343 outBuffer.pBuffers = outBuffers;
cc754834
MS
1344 outBuffer.ulVersion = SECBUFFER_VERSION;
1345
e32497ad 1346 scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
cc754834
MS
1347
1348 if (scRet != SEC_I_CONTINUE_NEEDED)
1349 {
52770f63 1350 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 1351 return (-1);
cc754834
MS
1352 }
1353
1354 /*
1355 * Send response to server if there is one.
1356 */
2ece34a9 1357
cc754834
MS
1358 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
1359 {
2ece34a9 1360 if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0)
cc754834 1361 {
52770f63 1362 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
cc754834 1363 FreeContextBuffer(outBuffers[0].pvBuffer);
e32497ad 1364 DeleteSecurityContext(&sspi->context);
2ece34a9 1365 return (-1);
cc754834
MS
1366 }
1367
52770f63 1368 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
cc754834 1369
cc754834
MS
1370 FreeContextBuffer(outBuffers[0].pvBuffer);
1371 outBuffers[0].pvBuffer = NULL;
1372 }
1373
1374 dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
2ece34a9 1375 ISC_REQ_SEQUENCE_DETECT |
cc754834
MS
1376 ISC_REQ_REPLAY_DETECT |
1377 ISC_REQ_CONFIDENTIALITY |
1378 ISC_RET_EXTENDED_ERROR |
1379 ISC_REQ_ALLOCATE_MEMORY |
1380 ISC_REQ_STREAM;
1381
e32497ad 1382 sspi->decryptBufferUsed = 0;
cc754834 1383
321d8d57 1384 /*
cc754834
MS
1385 * Loop until the handshake is finished or an error occurs.
1386 */
2ece34a9 1387
cc754834
MS
1388 scRet = SEC_I_CONTINUE_NEEDED;
1389
1390 while(scRet == SEC_I_CONTINUE_NEEDED ||
1391 scRet == SEC_E_INCOMPLETE_MESSAGE ||
321d8d57 1392 scRet == SEC_I_INCOMPLETE_CREDENTIALS)
cc754834 1393 {
e32497ad 1394 if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
cc754834 1395 {
e32497ad 1396 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
cc754834 1397 {
2ece34a9 1398 BYTE *temp; /* New buffer */
cc754834 1399
e32497ad 1400 if (sspi->decryptBufferLength >= 262144)
2ece34a9
MS
1401 {
1402 WSASetLastError(E_OUTOFMEMORY);
52770f63 1403 DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)");
2ece34a9
MS
1404 return (-1);
1405 }
1406
e32497ad 1407 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
2ece34a9 1408 {
52770f63 1409 DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
2ece34a9
MS
1410 WSASetLastError(E_OUTOFMEMORY);
1411 return (-1);
1412 }
1413
e32497ad
MS
1414 sspi->decryptBufferLength += 4096;
1415 sspi->decryptBuffer = temp;
cc754834 1416 }
321d8d57 1417
e32497ad 1418 cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
321d8d57 1419
2ece34a9 1420 if (cbData < 0)
cc754834 1421 {
52770f63 1422 DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError()));
2ece34a9 1423 return (-1);
cc754834
MS
1424 }
1425 else if (cbData == 0)
1426 {
52770f63 1427 DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected."));
2ece34a9 1428 return (-1);
cc754834
MS
1429 }
1430
52770f63 1431 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData));
cc754834 1432
e32497ad 1433 sspi->decryptBufferUsed += cbData;
cc754834
MS
1434 }
1435
1436 /*
2ece34a9
MS
1437 * Set up the input buffers. Buffer 0 is used to pass in data received from
1438 * the server. Schannel will consume some or all of this. Leftover data
1439 * (if any) will be placed in buffer 1 and given a buffer type of
1440 * SECBUFFER_EXTRA.
cc754834 1441 */
2ece34a9 1442
e32497ad
MS
1443 inBuffers[0].pvBuffer = sspi->decryptBuffer;
1444 inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
cc754834
MS
1445 inBuffers[0].BufferType = SECBUFFER_TOKEN;
1446
1447 inBuffers[1].pvBuffer = NULL;
1448 inBuffers[1].cbBuffer = 0;
1449 inBuffers[1].BufferType = SECBUFFER_EMPTY;
1450
1451 inBuffer.cBuffers = 2;
1452 inBuffer.pBuffers = inBuffers;
1453 inBuffer.ulVersion = SECBUFFER_VERSION;
1454
1455 /*
2ece34a9
MS
1456 * Set up the output buffers. These are initialized to NULL so as to make it
1457 * less likely we'll attempt to free random garbage later.
cc754834 1458 */
cc754834 1459
2ece34a9
MS
1460 outBuffers[0].pvBuffer = NULL;
1461 outBuffers[0].BufferType = SECBUFFER_TOKEN;
1462 outBuffers[0].cbBuffer = 0;
1463
1464 outBuffer.cBuffers = 1;
1465 outBuffer.pBuffers = outBuffers;
1466 outBuffer.ulVersion = SECBUFFER_VERSION;
cc754834
MS
1467
1468 /*
1469 * Call InitializeSecurityContext.
1470 */
2ece34a9 1471
e32497ad 1472 scRet = InitializeSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
cc754834
MS
1473
1474 /*
2ece34a9
MS
1475 * If InitializeSecurityContext was successful (or if the error was one of
1476 * the special extended ones), send the contents of the output buffer to the
1477 * server.
cc754834 1478 */
2ece34a9 1479
cc754834
MS
1480 if (scRet == SEC_E_OK ||
1481 scRet == SEC_I_CONTINUE_NEEDED ||
1482 FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
1483 {
1484 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
1485 {
2ece34a9 1486 cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
321d8d57 1487
2ece34a9 1488 if (cbData <= 0)
cc754834 1489 {
52770f63 1490 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
cc754834 1491 FreeContextBuffer(outBuffers[0].pvBuffer);
e32497ad 1492 DeleteSecurityContext(&sspi->context);
2ece34a9 1493 return (-1);
cc754834
MS
1494 }
1495
52770f63 1496 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
cc754834
MS
1497
1498 /*
1499 * Free output buffer.
1500 */
2ece34a9 1501
cc754834
MS
1502 FreeContextBuffer(outBuffers[0].pvBuffer);
1503 outBuffers[0].pvBuffer = NULL;
1504 }
1505 }
1506
1507 /*
2ece34a9
MS
1508 * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we
1509 * need to read more data from the server and try again.
cc754834 1510 */
2ece34a9 1511
cc754834
MS
1512 if (scRet == SEC_E_INCOMPLETE_MESSAGE)
1513 continue;
1514
1515 /*
2ece34a9
MS
1516 * If InitializeSecurityContext returned SEC_E_OK, then the handshake
1517 * completed successfully.
cc754834 1518 */
2ece34a9 1519
cc754834
MS
1520 if (scRet == SEC_E_OK)
1521 {
1522 /*
1523 * If the "extra" buffer contains data, this is encrypted application
2ece34a9
MS
1524 * protocol layer stuff. It needs to be saved. The application layer will
1525 * later decrypt it with DecryptMessage.
cc754834 1526 */
2ece34a9 1527
52770f63 1528 DEBUG_puts("5http_sspi_client: Handshake was successful.");
cc754834
MS
1529
1530 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1531 {
e32497ad 1532 memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
cc754834 1533
e32497ad 1534 sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
cc754834 1535
52770f63 1536 DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed));
cc754834
MS
1537 }
1538 else
e32497ad 1539 sspi->decryptBufferUsed = 0;
cc754834
MS
1540
1541 /*
1542 * Bail out to quit
1543 */
2ece34a9 1544
cc754834
MS
1545 break;
1546 }
1547
1548 /*
1549 * Check for fatal error.
1550 */
2ece34a9 1551
cc754834
MS
1552 if (FAILED(scRet))
1553 {
52770f63 1554 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 1555 ret = -1;
cc754834
MS
1556 break;
1557 }
1558
1559 /*
1560 * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
321d8d57 1561 * then the server just requested client authentication.
cc754834 1562 */
2ece34a9 1563
cc754834
MS
1564 if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
1565 {
1566 /*
1567 * Unimplemented
1568 */
2ece34a9 1569
52770f63 1570 DEBUG_printf(("5http_sspi_client: server requested client credentials."));
2ece34a9 1571 ret = -1;
cc754834
MS
1572 break;
1573 }
1574
1575 /*
2ece34a9 1576 * Copy any leftover data from the "extra" buffer, and go around again.
cc754834 1577 */
2ece34a9 1578
cc754834
MS
1579 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1580 {
e32497ad 1581 memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
cc754834 1582
e32497ad 1583 sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
cc754834
MS
1584 }
1585 else
1586 {
e32497ad 1587 sspi->decryptBufferUsed = 0;
cc754834
MS
1588 }
1589 }
1590
2ece34a9 1591 if (!ret)
cc754834 1592 {
cc754834 1593 /*
2ece34a9 1594 * Success! Get the server cert
cc754834 1595 */
2ece34a9 1596
e32497ad 1597 sspi->contextInitialized = TRUE;
2ece34a9 1598
e32497ad 1599 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert));
cc754834
MS
1600
1601 if (scRet != SEC_E_OK)
1602 {
52770f63 1603 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 1604 return (-1);
cc754834
MS
1605 }
1606
cc754834
MS
1607 /*
1608 * Find out how big the header/trailer will be:
1609 */
2ece34a9 1610
e32497ad 1611 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
cc754834
MS
1612
1613 if (scRet != SEC_E_OK)
1614 {
52770f63 1615 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 1616 ret = -1;
cc754834
MS
1617 }
1618 }
1619
2ece34a9
MS
1620 return (ret);
1621}
cc754834 1622
cc754834 1623
17eecbf1
MS
1624/*
1625 * 'http_sspi_create_credential()' - Create an SSPI certificate context.
1626 */
1627
1628static PCCERT_CONTEXT /* O - Certificate context */
1629http_sspi_create_credential(
1630 http_credential_t *cred) /* I - Credential */
1631{
1632 if (cred)
1633 return (CertCreateCertificateContext(X509_ASN_ENCODING, cred->data, cred->datalen));
1634 else
1635 return (NULL);
1636}
1637
1638
2ece34a9 1639/*
e32497ad 1640 * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store.
2ece34a9
MS
1641 */
1642
9870d12b 1643static BOOL /* O - 1 on success, 0 on failure */
e32497ad 1644http_sspi_find_credentials(
9870d12b
MS
1645 http_t *http, /* I - HTTP connection */
1646 const LPWSTR container, /* I - Cert container name */
e32497ad 1647 const char *common_name) /* I - Common name of certificate */
cc754834 1648{
e32497ad 1649 _http_sspi_t *sspi = http->tls; /* SSPI data */
9870d12b
MS
1650 HCERTSTORE store = NULL; /* Certificate store */
1651 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
9870d12b
MS
1652 DWORD dwSize = 0; /* 32 bit size */
1653 PBYTE p = NULL; /* Temporary storage */
1654 HCRYPTPROV hProv = (HCRYPTPROV)NULL;
2ece34a9 1655 /* Handle to a CSP */
9870d12b
MS
1656 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
1657 SCHANNEL_CRED SchannelCred; /* Schannel credential data */
1658 TimeStamp tsExpiry; /* Time stamp */
1659 SECURITY_STATUS Status; /* Status */
9870d12b 1660 BOOL ok = TRUE; /* Return value */
cc754834 1661
cc754834 1662
9870d12b 1663 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
cc754834 1664 {
2ece34a9 1665 if (GetLastError() == NTE_EXISTS)
cc754834 1666 {
9870d12b 1667 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
cc754834 1668 {
52770f63 1669 DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
cc754834
MS
1670 ok = FALSE;
1671 goto cleanup;
1672 }
cc754834 1673 }
2ece34a9 1674 }
cc754834 1675
9870d12b 1676 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 1677
2ece34a9
MS
1678 if (!store)
1679 {
52770f63 1680 DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
2ece34a9
MS
1681 ok = FALSE;
1682 goto cleanup;
1683 }
cc754834 1684
2ece34a9 1685 dwSize = 0;
cc754834 1686
9870d12b 1687 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
2ece34a9 1688 {
52770f63 1689 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
2ece34a9
MS
1690 ok = FALSE;
1691 goto cleanup;
1692 }
cc754834 1693
9870d12b 1694 p = (PBYTE)malloc(dwSize);
cc754834 1695
2ece34a9
MS
1696 if (!p)
1697 {
52770f63 1698 DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize));
2ece34a9
MS
1699 ok = FALSE;
1700 goto cleanup;
1701 }
cc754834 1702
9870d12b 1703 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
2ece34a9 1704 {
52770f63 1705 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
2ece34a9
MS
1706 ok = FALSE;
1707 goto cleanup;
1708 }
cc754834 1709
2ece34a9
MS
1710 sib.cbData = dwSize;
1711 sib.pbData = p;
cc754834 1712
9870d12b 1713 storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
cc754834 1714
2ece34a9
MS
1715 if (!storedContext)
1716 {
52770f63 1717 DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name));
e32497ad
MS
1718 ok = FALSE;
1719 goto cleanup;
cc754834
MS
1720 }
1721
2ece34a9 1722 ZeroMemory(&SchannelCred, sizeof(SchannelCred));
cc754834 1723
2ece34a9 1724 SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
9870d12b
MS
1725 SchannelCred.cCreds = 1;
1726 SchannelCred.paCred = &storedContext;
cc754834 1727
2ece34a9 1728 /*
9870d12b 1729 * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
2ece34a9 1730 */
9870d12b 1731
e32497ad 1732 if (http->mode == _HTTP_MODE_SERVER)
2ece34a9 1733 SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
cc754834 1734
2ece34a9
MS
1735 /*
1736 * Create an SSPI credential.
1737 */
9870d12b 1738
e32497ad 1739 Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
2ece34a9 1740 if (Status != SEC_E_OK)
cc754834 1741 {
52770f63 1742 DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
2ece34a9 1743 ok = FALSE;
cc754834
MS
1744 goto cleanup;
1745 }
1746
2ece34a9 1747cleanup:
cc754834 1748
2ece34a9
MS
1749 /*
1750 * Cleanup
1751 */
9870d12b 1752
2ece34a9
MS
1753 if (storedContext)
1754 CertFreeCertificateContext(storedContext);
cc754834 1755
2ece34a9
MS
1756 if (p)
1757 free(p);
cc754834 1758
2ece34a9
MS
1759 if (store)
1760 CertCloseStore(store, 0);
cc754834 1761
2ece34a9
MS
1762 if (hProv)
1763 CryptReleaseContext(hProv, 0);
cc754834 1764
2ece34a9 1765 return (ok);
cc754834 1766}
9870d12b
MS
1767
1768
1769/*
1770 * 'http_sspi_free()' - Close a connection and free resources.
1771 */
1772
1773static void
e32497ad 1774http_sspi_free(_http_sspi_t *sspi) /* I - SSPI data */
9870d12b 1775{
e32497ad 1776 if (!sspi)
9870d12b
MS
1777 return;
1778
e32497ad
MS
1779 if (sspi->contextInitialized)
1780 DeleteSecurityContext(&sspi->context);
1781
1782 if (sspi->decryptBuffer)
1783 free(sspi->decryptBuffer);
1784
1785 if (sspi->readBuffer)
1786 free(sspi->readBuffer);
1787
1788 if (sspi->writeBuffer)
1789 free(sspi->writeBuffer);
1790
1791 if (sspi->localCert)
1792 CertFreeCertificateContext(sspi->localCert);
1793
1794 if (sspi->remoteCert)
1795 CertFreeCertificateContext(sspi->remoteCert);
1796
1797 free(sspi);
1798}
1799
1800
1801/*
1802 * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store.
1803 */
1804
1805static BOOL /* O - 1 on success, 0 on failure */
1806http_sspi_make_credentials(
1807 _http_sspi_t *sspi, /* I - SSPI data */
1808 const LPWSTR container, /* I - Cert container name */
1809 const char *common_name, /* I - Common name of certificate */
1810 _http_mode_t mode, /* I - Client or server? */
1811 int years) /* I - Years until expiration */
1812{
1813 HCERTSTORE store = NULL; /* Certificate store */
1814 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
1815 PCCERT_CONTEXT createdContext = NULL; /* Context created by us */
1816 DWORD dwSize = 0; /* 32 bit size */
1817 PBYTE p = NULL; /* Temporary storage */
1818 HCRYPTPROV hProv = (HCRYPTPROV)NULL;
1819 /* Handle to a CSP */
1820 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
1821 SCHANNEL_CRED SchannelCred; /* Schannel credential data */
1822 TimeStamp tsExpiry; /* Time stamp */
1823 SECURITY_STATUS Status; /* Status */
1824 HCRYPTKEY hKey = (HCRYPTKEY)NULL; /* Handle to crypto key */
1825 CRYPT_KEY_PROV_INFO kpi; /* Key container info */
1826 SYSTEMTIME et; /* System time */
1827 CERT_EXTENSIONS exts; /* Array of cert extensions */
1828 CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
1829 BOOL ok = TRUE; /* Return value */
1830
1831
1832 DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi, container, common_name, mode, years));
1833
1834 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
1835 {
1836 if (GetLastError() == NTE_EXISTS)
1837 {
1838 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
1839 {
52770f63 1840 DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1841 ok = FALSE;
1842 goto cleanup;
1843 }
1844 }
1845 }
1846
1847 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");
1848
1849 if (!store)
1850 {
52770f63 1851 DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1852 ok = FALSE;
1853 goto cleanup;
1854 }
1855
1856 dwSize = 0;
1857
1858 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
1859 {
52770f63 1860 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1861 ok = FALSE;
1862 goto cleanup;
1863 }
1864
1865 p = (PBYTE)malloc(dwSize);
1866
1867 if (!p)
1868 {
52770f63 1869 DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize));
e32497ad
MS
1870 ok = FALSE;
1871 goto cleanup;
1872 }
1873
1874 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
1875 {
52770f63 1876 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1877 ok = FALSE;
1878 goto cleanup;
1879 }
1880
1881 /*
52770f63 1882 * Create a private key and self-signed certificate...
e32497ad 1883 */
9870d12b 1884
e32497ad
MS
1885 if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
1886 {
52770f63 1887 DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1888 ok = FALSE;
1889 goto cleanup;
1890 }
1891
1892 ZeroMemory(&kpi, sizeof(kpi));
1893 kpi.pwszContainerName = (LPWSTR)container;
1894 kpi.pwszProvName = MS_DEF_PROV_W;
1895 kpi.dwProvType = PROV_RSA_FULL;
1896 kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
1897 kpi.dwKeySpec = AT_KEYEXCHANGE;
1898
1899 GetSystemTime(&et);
1900 et.wYear += years;
9870d12b 1901
e32497ad 1902 ZeroMemory(&exts, sizeof(exts));
9870d12b 1903
e32497ad 1904 createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts);
9870d12b 1905
e32497ad
MS
1906 if (!createdContext)
1907 {
52770f63 1908 DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1909 ok = FALSE;
1910 goto cleanup;
1911 }
9870d12b 1912
52770f63
MS
1913 /*
1914 * Add the created context to the named store, and associate it with the named
1915 * container...
1916 */
1917
e32497ad
MS
1918 if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
1919 {
52770f63 1920 DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1921 ok = FALSE;
1922 goto cleanup;
1923 }
1924
1925 ZeroMemory(&ckp, sizeof(ckp));
1926 ckp.pwszContainerName = (LPWSTR) container;
1927 ckp.pwszProvName = MS_DEF_PROV_W;
1928 ckp.dwProvType = PROV_RSA_FULL;
1929 ckp.dwFlags = CRYPT_MACHINE_KEYSET;
1930 ckp.dwKeySpec = AT_KEYEXCHANGE;
1931
1932 if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
1933 {
52770f63 1934 DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
e32497ad
MS
1935 ok = FALSE;
1936 goto cleanup;
1937 }
1938
52770f63
MS
1939 /*
1940 * Get a handle to use the certificate...
1941 */
e32497ad
MS
1942
1943 ZeroMemory(&SchannelCred, sizeof(SchannelCred));
1944
1945 SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
1946 SchannelCred.cCreds = 1;
1947 SchannelCred.paCred = &storedContext;
1948
1949 /*
1950 * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
1951 */
1952
1953 if (mode == _HTTP_MODE_SERVER)
1954 SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
1955
1956 /*
1957 * Create an SSPI credential.
1958 */
1959
1960 Status = AcquireCredentialsHandle(NULL, UNISP_NAME, mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
1961 if (Status != SEC_E_OK)
1962 {
52770f63 1963 DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
e32497ad
MS
1964 ok = FALSE;
1965 goto cleanup;
1966 }
1967
1968cleanup:
1969
1970 /*
1971 * Cleanup
1972 */
1973
1974 if (hKey)
1975 CryptDestroyKey(hKey);
1976
1977 if (createdContext)
1978 CertFreeCertificateContext(createdContext);
1979
1980 if (storedContext)
1981 CertFreeCertificateContext(storedContext);
9870d12b 1982
e32497ad
MS
1983 if (p)
1984 free(p);
1985
1986 if (store)
1987 CertCloseStore(store, 0);
1988
1989 if (hProv)
1990 CryptReleaseContext(hProv, 0);
1991
1992 return (ok);
9870d12b 1993}
cc754834
MS
1994
1995
1996/*
2ece34a9 1997 * 'http_sspi_server()' - Negotiate a TLS connection as a server.
cc754834 1998 */
2ece34a9
MS
1999
2000static int /* O - 0 on success, -1 on failure */
2001http_sspi_server(http_t *http, /* I - HTTP connection */
2002 const char *hostname) /* I - Hostname of server */
cc754834 2003{
e32497ad
MS
2004 _http_sspi_t *sspi = http->tls; /* I - SSPI data */
2005 char common_name[512]; /* Common name for cert */
2ece34a9
MS
2006 DWORD dwSSPIFlags; /* SSL connection attributes we want */
2007 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
2008 TimeStamp tsExpiry; /* Time stamp */
2009 SECURITY_STATUS scRet; /* SSPI Status */
2010 SecBufferDesc inBuffer; /* Array of SecBuffer structs */
2011 SecBuffer inBuffers[2]; /* Security package buffer */
2012 SecBufferDesc outBuffer; /* Array of SecBuffer structs */
2013 SecBuffer outBuffers[1]; /* Security package buffer */
2014 int num = 0; /* 32 bit status value */
2015 BOOL fInitContext = TRUE; /* Has the context been init'd? */
2016 int ret = 0; /* Return value */
2017
2018
52770f63 2019 DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname));
cc754834 2020
2ece34a9
MS
2021 dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
2022 ASC_REQ_REPLAY_DETECT |
2023 ASC_REQ_CONFIDENTIALITY |
2024 ASC_REQ_EXTENDED_ERROR |
2025 ASC_REQ_ALLOCATE_MEMORY |
2026 ASC_REQ_STREAM;
2027
e32497ad
MS
2028 sspi->decryptBufferUsed = 0;
2029
2030 /*
2031 * Lookup the server certificate...
2032 */
2033
2034 snprintf(common_name, sizeof(common_name), "CN=%s", hostname);
2035
2036 if (!http_sspi_find_credentials(http, L"ServerContainer", common_name))
2037 if (!http_sspi_make_credentials(http->tls, L"ServerContainer", common_name, _HTTP_MODE_SERVER, 10))
2038 {
52770f63 2039 DEBUG_puts("5http_sspi_server: Unable to get server credentials.");
e32497ad
MS
2040 return (-1);
2041 }
cc754834
MS
2042
2043 /*
2ece34a9 2044 * Set OutBuffer for AcceptSecurityContext call
cc754834 2045 */
cc754834 2046
2ece34a9
MS
2047 outBuffer.cBuffers = 1;
2048 outBuffer.pBuffers = outBuffers;
2049 outBuffer.ulVersion = SECBUFFER_VERSION;
cc754834 2050
2ece34a9 2051 scRet = SEC_I_CONTINUE_NEEDED;
cc754834 2052
2ece34a9
MS
2053 while (scRet == SEC_I_CONTINUE_NEEDED ||
2054 scRet == SEC_E_INCOMPLETE_MESSAGE ||
2055 scRet == SEC_I_INCOMPLETE_CREDENTIALS)
cc754834 2056 {
e32497ad 2057 if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
cc754834 2058 {
e32497ad 2059 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
cc754834 2060 {
2ece34a9 2061 BYTE *temp; /* New buffer */
cc754834 2062
e32497ad 2063 if (sspi->decryptBufferLength >= 262144)
2ece34a9
MS
2064 {
2065 WSASetLastError(E_OUTOFMEMORY);
52770f63 2066 DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)");
2ece34a9
MS
2067 return (-1);
2068 }
cc754834 2069
e32497ad 2070 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
2ece34a9 2071 {
52770f63 2072 DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
2ece34a9
MS
2073 WSASetLastError(E_OUTOFMEMORY);
2074 return (-1);
2075 }
cc754834 2076
e32497ad
MS
2077 sspi->decryptBufferLength += 4096;
2078 sspi->decryptBuffer = temp;
2ece34a9 2079 }
cc754834 2080
2ece34a9 2081 for (;;)
cc754834 2082 {
e32497ad 2083 num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
cc754834 2084
33c9220c 2085 if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
2ece34a9 2086 Sleep(1);
cc754834 2087 else
2ece34a9 2088 break;
cc754834 2089 }
cc754834 2090
2ece34a9
MS
2091 if (num < 0)
2092 {
52770f63 2093 DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError()));
2ece34a9
MS
2094 return (-1);
2095 }
2096 else if (num == 0)
2097 {
52770f63 2098 DEBUG_puts("5http_sspi_server: client disconnected");
2ece34a9
MS
2099 return (-1);
2100 }
2101
52770f63 2102 DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num));
e32497ad 2103 sspi->decryptBufferUsed += num;
cc754834
MS
2104 }
2105
2106 /*
2ece34a9
MS
2107 * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process
2108 * on this run around the loop.
cc754834 2109 */
2ece34a9 2110
e32497ad
MS
2111 inBuffers[0].pvBuffer = sspi->decryptBuffer;
2112 inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
2ece34a9
MS
2113 inBuffers[0].BufferType = SECBUFFER_TOKEN;
2114
2115 inBuffers[1].pvBuffer = NULL;
2116 inBuffers[1].cbBuffer = 0;
2117 inBuffers[1].BufferType = SECBUFFER_EMPTY;
2118
2119 inBuffer.cBuffers = 2;
2120 inBuffer.pBuffers = inBuffers;
2121 inBuffer.ulVersion = SECBUFFER_VERSION;
cc754834
MS
2122
2123 /*
2ece34a9
MS
2124 * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to
2125 * free random garbage at the quit.
cc754834 2126 */
cc754834 2127
2ece34a9
MS
2128 outBuffers[0].pvBuffer = NULL;
2129 outBuffers[0].BufferType = SECBUFFER_TOKEN;
2130 outBuffers[0].cbBuffer = 0;
2131
e32497ad 2132 scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry);
cc754834 2133
2ece34a9
MS
2134 fInitContext = FALSE;
2135
2136 if (scRet == SEC_E_OK ||
2137 scRet == SEC_I_CONTINUE_NEEDED ||
2138 (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0)))
2139 {
2140 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
cc754834 2141 {
2ece34a9
MS
2142 /*
2143 * Send response to server if there is one.
2144 */
cc754834 2145
2ece34a9
MS
2146 num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
2147
2148 if (num <= 0)
2149 {
52770f63 2150 DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError()));
2ece34a9 2151 return (-1);
cc754834
MS
2152 }
2153
52770f63 2154 DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer));
cc754834 2155
2ece34a9
MS
2156 FreeContextBuffer(outBuffers[0].pvBuffer);
2157 outBuffers[0].pvBuffer = NULL;
cc754834 2158 }
2ece34a9
MS
2159 }
2160
2161 if (scRet == SEC_E_OK)
2162 {
2163 /*
2164 * If there's extra data then save it for next time we go to decrypt.
2165 */
cc754834 2166
2ece34a9
MS
2167 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
2168 {
e32497ad
MS
2169 memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
2170 sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
2ece34a9
MS
2171 }
2172 else
2173 {
e32497ad 2174 sspi->decryptBufferUsed = 0;
2ece34a9
MS
2175 }
2176 break;
cc754834 2177 }
2ece34a9 2178 else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE)
cc754834 2179 {
52770f63 2180 DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9
MS
2181 ret = -1;
2182 break;
cc754834
MS
2183 }
2184
2ece34a9
MS
2185 if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
2186 scRet != SEC_I_INCOMPLETE_CREDENTIALS)
cc754834 2187 {
2ece34a9
MS
2188 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
2189 {
e32497ad
MS
2190 memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
2191 sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
2ece34a9
MS
2192 }
2193 else
2194 {
e32497ad 2195 sspi->decryptBufferUsed = 0;
2ece34a9 2196 }
cc754834 2197 }
2ece34a9
MS
2198 }
2199
2200 if (!ret)
2201 {
e32497ad 2202 sspi->contextInitialized = TRUE;
2ece34a9
MS
2203
2204 /*
2205 * Find out how big the header will be:
2206 */
2207
e32497ad 2208 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
2ece34a9
MS
2209
2210 if (scRet != SEC_E_OK)
cc754834 2211 {
52770f63 2212 DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
2ece34a9 2213 ret = -1;
cc754834
MS
2214 }
2215 }
2216
2ece34a9 2217 return (ret);
cc754834
MS
2218}
2219
2220
adad9dd6
MS
2221/*
2222 * 'http_sspi_strerror()' - Return a string for the specified error code.
2223 */
2224
2225static const char * /* O - String for error */
52770f63
MS
2226http_sspi_strerror(char *buffer, /* I - Error message buffer */
2227 size_t bufsize, /* I - Size of buffer */
2228 DWORD code) /* I - Error code */
adad9dd6 2229{
52770f63 2230 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, bufsize, NULL))
adad9dd6
MS
2231 {
2232 /*
2233 * Strip trailing CR + LF...
2234 */
2235
2236 char *ptr; /* Pointer into error message */
2237
52770f63 2238 for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --)
adad9dd6
MS
2239 if (*ptr == '\n' || *ptr == '\r')
2240 *ptr = '\0';
2241 else
2242 break;
2243 }
2244 else
52770f63 2245 snprintf(buffer, bufsize, "Unknown error %x", code);
cc754834 2246
52770f63 2247 return (buffer);
cc754834
MS
2248}
2249
2250
2251/*
2ece34a9 2252 * 'http_sspi_verify()' - Verify a certificate.
cc754834 2253 */
2ece34a9
MS
2254
2255static DWORD /* O - Error code (0 == No error) */
2256http_sspi_verify(
2257 PCCERT_CONTEXT cert, /* I - Server certificate */
2258 const char *common_name, /* I - Common name */
2259 DWORD dwCertFlags) /* I - Verification flags */
cc754834 2260{
2ece34a9
MS
2261 HTTPSPolicyCallbackData httpsPolicy; /* HTTPS Policy Struct */
2262 CERT_CHAIN_POLICY_PARA policyPara; /* Cert chain policy parameters */
2263 CERT_CHAIN_POLICY_STATUS policyStatus;/* Cert chain policy status */
2264 CERT_CHAIN_PARA chainPara; /* Used for searching and matching criteria */
2265 PCCERT_CHAIN_CONTEXT chainContext = NULL;
cc754834 2266 /* Certificate chain */
2ece34a9
MS
2267 PWSTR commonNameUnicode = NULL;
2268 /* Unicode common name */
2269 LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
2270 szOID_SERVER_GATED_CRYPTO,
2271 szOID_SGC_NETSCAPE };
cc754834 2272 /* How are we using this certificate? */
2ece34a9 2273 DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
cc754834 2274 /* Number of ites in rgszUsages */
2ece34a9
MS
2275 DWORD count; /* 32 bit count variable */
2276 DWORD status; /* Return value */
cc754834 2277
2ece34a9
MS
2278
2279 if (!cert)
2280 return (SEC_E_WRONG_PRINCIPAL);
cc754834
MS
2281
2282 /*
2ece34a9 2283 * Convert common name to Unicode.
cc754834 2284 */
cc754834 2285
2ece34a9
MS
2286 if (!common_name || !*common_name)
2287 return (SEC_E_WRONG_PRINCIPAL);
2288
2289 count = MultiByteToWideChar(CP_ACP, 0, common_name, -1, NULL, 0);
2290 commonNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR));
2291 if (!commonNameUnicode)
2292 return (SEC_E_INSUFFICIENT_MEMORY);
2293
2294 if (!MultiByteToWideChar(CP_ACP, 0, common_name, -1, commonNameUnicode, count))
cc754834 2295 {
2ece34a9
MS
2296 LocalFree(commonNameUnicode);
2297 return (SEC_E_WRONG_PRINCIPAL);
cc754834
MS
2298 }
2299
2300 /*
2301 * Build certificate chain.
2302 */
2ece34a9 2303
cc754834 2304 ZeroMemory(&chainPara, sizeof(chainPara));
2ece34a9 2305
cc754834
MS
2306 chainPara.cbSize = sizeof(chainPara);
2307 chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
2308 chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
2309 chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
2310
2ece34a9 2311 if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext))
cc754834
MS
2312 {
2313 status = GetLastError();
52770f63
MS
2314
2315#ifdef DEBUG
2316 char error[1024]; /* Error message string */
2317
2318 DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status)));
2319#endif /* DEBUG */
2ece34a9
MS
2320
2321 LocalFree(commonNameUnicode);
2322 return (status);
cc754834
MS
2323 }
2324
2325 /*
2326 * Validate certificate chain.
321d8d57 2327 */
2ece34a9 2328
cc754834
MS
2329 ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
2330 httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData);
2331 httpsPolicy.dwAuthType = AUTHTYPE_SERVER;
2332 httpsPolicy.fdwChecks = dwCertFlags;
2ece34a9 2333 httpsPolicy.pwszServerName = commonNameUnicode;
cc754834
MS
2334
2335 memset(&policyPara, 0, sizeof(policyPara));
2336 policyPara.cbSize = sizeof(policyPara);
2337 policyPara.pvExtraPolicyPara = &httpsPolicy;
2338
2339 memset(&policyStatus, 0, sizeof(policyStatus));
2340 policyStatus.cbSize = sizeof(policyStatus);
2341
2ece34a9 2342 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus))
cc754834
MS
2343 {
2344 status = GetLastError();
52770f63
MS
2345
2346#ifdef DEBUG
2347 char error[1024]; /* Error message string */
2348
2349 DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status)));
2350#endif /* DEBUG */
cc754834 2351 }
2ece34a9 2352 else if (policyStatus.dwError)
cc754834 2353 status = policyStatus.dwError;
2ece34a9
MS
2354 else
2355 status = SEC_E_OK;
cc754834
MS
2356
2357 if (chainContext)
2358 CertFreeCertificateChain(chainContext);
2359
2ece34a9
MS
2360 if (commonNameUnicode)
2361 LocalFree(commonNameUnicode);
cc754834
MS
2362
2363 return (status);
2364}
e32497ad
MS
2365
2366
321d8d57
MS
2367/*
2368 * End of "$Id$".
2369 */