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