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