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