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