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