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