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