]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/tls-sspi.c
Bump shared library version.
[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);
51static void http_sspi_free(_http_sspi_t *conn);
52static BOOL http_sspi_get_credentials(_http_sspi_t *conn, const LPWSTR containerName, const TCHAR *commonName, BOOL server);
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 {
551 int bytesToCopy = min(pDataBuffer->cbBuffer, len);
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 {
590 DEBUG_puts("_httpTLSRead: Unable to find data buffer."));
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
819 if (bufferLen > conn->writeBufferLen)
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
MS
829
830 conn->writeBuffer = temp;
831 conn->writeBufferLen = bufferLen;
cc754834
MS
832 }
833
2ece34a9
MS
834 bytesLeft = len;
835 bufptr = buf;
cc754834 836
2ece34a9
MS
837 while (bytesLeft)
838 {
839 int chunk = min(conn->streamSizes.cbMaximumMessage, bytesLeft);
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
903#ifdef HAVE_SSL
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
2ece34a9 941 http->tls = _sspiAlloc();
cc754834 942
2ece34a9
MS
943 if (!http->tls)
944 {
945 _cupsSetHTTPError(HTTP_STATUS_ERROR);
946 return (-1);
947 }
cc754834 948
2ece34a9
MS
949 http->tls->sock = http->fd;
950 dwSize = sizeof(username) / sizeof(TCHAR);
951 GetUserName(username, &dwSize);
952 _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR),
953 sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username);
cc754834 954
2ece34a9
MS
955 if (!_sspiGetCredentials(http->tls, L"ClientContainer",
956 commonName, FALSE))
957 {
958 _sspiFree(http->tls);
959 http->tls = NULL;
cc754834 960
2ece34a9
MS
961 http->error = EIO;
962 http->status = HTTP_STATUS_ERROR;
cc754834 963
2ece34a9
MS
964 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
965 _("Unable to establish a secure connection to host."), 1);
cc754834 966
2ece34a9
MS
967 return (-1);
968 }
969
970 _sspiSetAllowsAnyRoot(http->tls, TRUE);
971 _sspiSetAllowsExpiredCerts(http->tls, TRUE);
972
973 if (!_sspiConnect(http->tls, hostname))
974 {
975 _sspiFree(http->tls);
976 http->tls = NULL;
977
978 http->error = EIO;
979 http->status = HTTP_STATUS_ERROR;
980
981 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
982 _("Unable to establish a secure connection to host."), 1);
983
984 return (-1);
985 }
986
987 return (0);
cc754834
MS
988}
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{
2ece34a9 1012 _http_sspi_t *conn; /* SSPI data */
cc754834
MS
1013 DWORD dwSSPIFlags; /* SSL connection attributes we want */
1014 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
1015 TimeStamp tsExpiry; /* Time stamp */
1016 SECURITY_STATUS scRet; /* Status */
2ece34a9 1017 int cbData; /* Data count */
cc754834
MS
1018 SecBufferDesc inBuffer; /* Array of SecBuffer structs */
1019 SecBuffer inBuffers[2]; /* Security package buffer */
1020 SecBufferDesc outBuffer; /* Array of SecBuffer structs */
1021 SecBuffer outBuffers[1]; /* Security package buffer */
2ece34a9 1022 int ret = 0; /* Return value */
cc754834 1023
cc754834 1024
2ece34a9
MS
1025 DEBUG_printf(("http_sspi_client(http=%p, hostname=\"%s\")", http, hostname));
1026
1027 serverCert = NULL;
cc754834
MS
1028 dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
1029 ISC_REQ_REPLAY_DETECT |
1030 ISC_REQ_CONFIDENTIALITY |
1031 ISC_RET_EXTENDED_ERROR |
1032 ISC_REQ_ALLOCATE_MEMORY |
1033 ISC_REQ_STREAM;
1034
1035 /*
1036 * Initiate a ClientHello message and generate a token.
1037 */
2ece34a9 1038
cc754834
MS
1039 outBuffers[0].pvBuffer = NULL;
1040 outBuffers[0].BufferType = SECBUFFER_TOKEN;
1041 outBuffers[0].cbBuffer = 0;
1042
2ece34a9
MS
1043 outBuffer.cBuffers = 1;
1044 outBuffer.pBuffers = outBuffers;
cc754834
MS
1045 outBuffer.ulVersion = SECBUFFER_VERSION;
1046
2ece34a9 1047 scRet = InitializeSecurityContext(&conn->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
cc754834
MS
1048
1049 if (scRet != SEC_I_CONTINUE_NEEDED)
1050 {
2ece34a9
MS
1051 DEBUG_printf(("http_sspi_client: InitializeSecurityContext(1) failed: %x", scRet));
1052 return (-1);
cc754834
MS
1053 }
1054
1055 /*
1056 * Send response to server if there is one.
1057 */
2ece34a9 1058
cc754834
MS
1059 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
1060 {
2ece34a9 1061 if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0)
cc754834 1062 {
2ece34a9 1063 DEBUG_printf(("http_sspi_client: send failed: %d", WSAGetLastError()));
cc754834
MS
1064 FreeContextBuffer(outBuffers[0].pvBuffer);
1065 DeleteSecurityContext(&conn->context);
2ece34a9 1066 return (-1);
cc754834
MS
1067 }
1068
2ece34a9 1069 DEBUG_printf(("http_sspi_client: %d bytes of handshake data sent.", cbData));
cc754834 1070
cc754834
MS
1071 FreeContextBuffer(outBuffers[0].pvBuffer);
1072 outBuffers[0].pvBuffer = NULL;
1073 }
1074
1075 dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
2ece34a9 1076 ISC_REQ_SEQUENCE_DETECT |
cc754834
MS
1077 ISC_REQ_REPLAY_DETECT |
1078 ISC_REQ_CONFIDENTIALITY |
1079 ISC_RET_EXTENDED_ERROR |
1080 ISC_REQ_ALLOCATE_MEMORY |
1081 ISC_REQ_STREAM;
1082
1083 conn->decryptBufferUsed = 0;
1084
321d8d57 1085 /*
cc754834
MS
1086 * Loop until the handshake is finished or an error occurs.
1087 */
2ece34a9 1088
cc754834
MS
1089 scRet = SEC_I_CONTINUE_NEEDED;
1090
1091 while(scRet == SEC_I_CONTINUE_NEEDED ||
1092 scRet == SEC_E_INCOMPLETE_MESSAGE ||
321d8d57 1093 scRet == SEC_I_INCOMPLETE_CREDENTIALS)
cc754834 1094 {
2ece34a9 1095 if (conn->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
cc754834 1096 {
321d8d57 1097 if (conn->decryptBufferLength <= conn->decryptBufferUsed)
cc754834 1098 {
2ece34a9 1099 BYTE *temp; /* New buffer */
cc754834 1100
2ece34a9
MS
1101 if (conn->decryptBufferLength >= 262144)
1102 {
1103 WSASetLastError(E_OUTOFMEMORY);
1104 DEBUG_puts("http_sspi_client: Decryption buffer too large (>256k)");
1105 return (-1);
1106 }
1107
1108 if ((temp = realloc(conn->decryptBuffer, conn->decryptBufferLength + 4096)) == NULL)
1109 {
1110 DEBUG_printf(("http_sspi_client: Unable to allocate %d byte buffer.", conn->decryptBufferLength + 4096));
1111 WSASetLastError(E_OUTOFMEMORY);
1112 return (-1);
1113 }
1114
1115 conn->decryptBufferLength += 4096;
1116 conn->decryptBuffer = temp;
cc754834 1117 }
321d8d57 1118
2ece34a9 1119 cbData = recv(http->fd, conn->decryptBuffer + conn->decryptBufferUsed, (int)(conn->decryptBufferLength - conn->decryptBufferUsed), 0);
321d8d57 1120
2ece34a9 1121 if (cbData < 0)
cc754834 1122 {
2ece34a9
MS
1123 DEBUG_printf(("http_sspi_client: recv failed: %d", WSAGetLastError()));
1124 return (-1);
cc754834
MS
1125 }
1126 else if (cbData == 0)
1127 {
2ece34a9
MS
1128 DEBUG_printf(("http_sspi_client: Server unexpectedly disconnected."));
1129 return (-1);
cc754834
MS
1130 }
1131
2ece34a9 1132 DEBUG_printf(("http_sspi_client: %d bytes of handshake data received", cbData));
cc754834
MS
1133
1134 conn->decryptBufferUsed += cbData;
1135 }
1136
1137 /*
2ece34a9
MS
1138 * Set up the input buffers. Buffer 0 is used to pass in data received from
1139 * the server. Schannel will consume some or all of this. Leftover data
1140 * (if any) will be placed in buffer 1 and given a buffer type of
1141 * SECBUFFER_EXTRA.
cc754834 1142 */
2ece34a9 1143
cc754834 1144 inBuffers[0].pvBuffer = conn->decryptBuffer;
2ece34a9 1145 inBuffers[0].cbBuffer = (unsigned long)conn->decryptBufferUsed;
cc754834
MS
1146 inBuffers[0].BufferType = SECBUFFER_TOKEN;
1147
1148 inBuffers[1].pvBuffer = NULL;
1149 inBuffers[1].cbBuffer = 0;
1150 inBuffers[1].BufferType = SECBUFFER_EMPTY;
1151
1152 inBuffer.cBuffers = 2;
1153 inBuffer.pBuffers = inBuffers;
1154 inBuffer.ulVersion = SECBUFFER_VERSION;
1155
1156 /*
2ece34a9
MS
1157 * Set up the output buffers. These are initialized to NULL so as to make it
1158 * less likely we'll attempt to free random garbage later.
cc754834 1159 */
cc754834 1160
2ece34a9
MS
1161 outBuffers[0].pvBuffer = NULL;
1162 outBuffers[0].BufferType = SECBUFFER_TOKEN;
1163 outBuffers[0].cbBuffer = 0;
1164
1165 outBuffer.cBuffers = 1;
1166 outBuffer.pBuffers = outBuffers;
1167 outBuffer.ulVersion = SECBUFFER_VERSION;
cc754834
MS
1168
1169 /*
1170 * Call InitializeSecurityContext.
1171 */
2ece34a9
MS
1172
1173 scRet = InitializeSecurityContext(&conn->creds, &conn->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
cc754834
MS
1174
1175 /*
2ece34a9
MS
1176 * If InitializeSecurityContext was successful (or if the error was one of
1177 * the special extended ones), send the contents of the output buffer to the
1178 * server.
cc754834 1179 */
2ece34a9 1180
cc754834
MS
1181 if (scRet == SEC_E_OK ||
1182 scRet == SEC_I_CONTINUE_NEEDED ||
1183 FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
1184 {
1185 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
1186 {
2ece34a9 1187 cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
321d8d57 1188
2ece34a9 1189 if (cbData <= 0)
cc754834 1190 {
2ece34a9 1191 DEBUG_printf(("http_sspi_client: send failed: %d", WSAGetLastError()));
cc754834
MS
1192 FreeContextBuffer(outBuffers[0].pvBuffer);
1193 DeleteSecurityContext(&conn->context);
2ece34a9 1194 return (-1);
cc754834
MS
1195 }
1196
2ece34a9 1197 DEBUG_printf(("http_sspi_client: %d bytes of handshake data sent.", cbData));
cc754834
MS
1198
1199 /*
1200 * Free output buffer.
1201 */
2ece34a9 1202
cc754834
MS
1203 FreeContextBuffer(outBuffers[0].pvBuffer);
1204 outBuffers[0].pvBuffer = NULL;
1205 }
1206 }
1207
1208 /*
2ece34a9
MS
1209 * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we
1210 * need to read more data from the server and try again.
cc754834 1211 */
2ece34a9 1212
cc754834
MS
1213 if (scRet == SEC_E_INCOMPLETE_MESSAGE)
1214 continue;
1215
1216 /*
2ece34a9
MS
1217 * If InitializeSecurityContext returned SEC_E_OK, then the handshake
1218 * completed successfully.
cc754834 1219 */
2ece34a9 1220
cc754834
MS
1221 if (scRet == SEC_E_OK)
1222 {
1223 /*
1224 * If the "extra" buffer contains data, this is encrypted application
2ece34a9
MS
1225 * protocol layer stuff. It needs to be saved. The application layer will
1226 * later decrypt it with DecryptMessage.
cc754834 1227 */
2ece34a9
MS
1228
1229 DEBUG_puts("http_sspi_client: Handshake was successful.");
cc754834
MS
1230
1231 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1232 {
2ece34a9 1233 memmove(conn->decryptBuffer, conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
cc754834
MS
1234
1235 conn->decryptBufferUsed = inBuffers[1].cbBuffer;
1236
2ece34a9 1237 DEBUG_printf(("http_sspi_client: %d bytes of app data was bundled with handshake data", conn->decryptBufferUsed));
cc754834
MS
1238 }
1239 else
1240 conn->decryptBufferUsed = 0;
1241
1242 /*
1243 * Bail out to quit
1244 */
2ece34a9 1245
cc754834
MS
1246 break;
1247 }
1248
1249 /*
1250 * Check for fatal error.
1251 */
2ece34a9 1252
cc754834
MS
1253 if (FAILED(scRet))
1254 {
2ece34a9
MS
1255 DEBUG_printf(("http_sspi_client: InitializeSecurityContext(2) failed: %x", scRet));
1256 ret = -1;
cc754834
MS
1257 break;
1258 }
1259
1260 /*
1261 * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
321d8d57 1262 * then the server just requested client authentication.
cc754834 1263 */
2ece34a9 1264
cc754834
MS
1265 if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
1266 {
1267 /*
1268 * Unimplemented
1269 */
2ece34a9
MS
1270
1271 DEBUG_printf(("http_sspi_client: server requested client credentials."));
1272 ret = -1;
cc754834
MS
1273 break;
1274 }
1275
1276 /*
2ece34a9 1277 * Copy any leftover data from the "extra" buffer, and go around again.
cc754834 1278 */
2ece34a9 1279
cc754834
MS
1280 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1281 {
2ece34a9 1282 memmove(conn->decryptBuffer, conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
cc754834
MS
1283
1284 conn->decryptBufferUsed = inBuffers[1].cbBuffer;
1285 }
1286 else
1287 {
1288 conn->decryptBufferUsed = 0;
1289 }
1290 }
1291
2ece34a9 1292 if (!ret)
cc754834 1293 {
cc754834 1294 /*
2ece34a9 1295 * Success! Get the server cert
cc754834 1296 */
2ece34a9
MS
1297
1298 conn->contextInitialized = TRUE;
1299
1300 scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(conn->remoteCert));
cc754834
MS
1301
1302 if (scRet != SEC_E_OK)
1303 {
2ece34a9
MS
1304 DEBUG_printf(("http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %x", scRet));
1305 return (-1);
cc754834
MS
1306 }
1307
2ece34a9
MS
1308#if 0
1309 /* TODO: Move this out for opt-in server cert validation, like other platforms. */
1310 scRet = http_sspi_verify(conn->remoteCert, hostname, conn->certFlags);
cc754834
MS
1311
1312 if (scRet != SEC_E_OK)
1313 {
2ece34a9
MS
1314 DEBUG_printf(("http_sspi_client: sspi_verify_certificate failed: %x", scRet));
1315 ret = -1;
cc754834
MS
1316 goto cleanup;
1317 }
2ece34a9 1318#endif // 0
321d8d57 1319
cc754834
MS
1320 /*
1321 * Find out how big the header/trailer will be:
1322 */
2ece34a9 1323
cc754834
MS
1324 scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
1325
1326 if (scRet != SEC_E_OK)
1327 {
2ece34a9
MS
1328 DEBUG_printf(("http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %x", scRet));
1329 ret = -1;
cc754834
MS
1330 }
1331 }
1332
2ece34a9
MS
1333 return (ret);
1334}
cc754834 1335
cc754834 1336
2ece34a9
MS
1337/*
1338 * 'http_sspi_free()' - Close a connection and free resources.
1339 */
1340
1341static void
1342http_sspi_free(_http_sspi_t *conn) /* I - Client connection */
1343{
1344 if (!conn)
1345 return;
1346
1347 if (conn->contextInitialized)
1348 DeleteSecurityContext(&conn->context);
1349
1350 if (conn->decryptBuffer)
1351 free(conn->decryptBuffer);
1352
1353 if (conn->readBuffer)
1354 free(conn->readBuffer);
1355
1356 if (conn->writeBuffer)
1357 free(conn->writeBuffer);
1358
1359 if (conn->localCert.pbCertEncoded)
1360 CertFreeCertificateContext(conn->localCert);
1361
1362 if (conn->remoteCert.pbCertEncoded)
1363 CertFreeCertificateContext(conn->remoteCert);
1364
1365 free(conn);
cc754834
MS
1366}
1367
1368
2ece34a9 1369#if 0
cc754834 1370/*
2ece34a9
MS
1371 * '_sspiGetCredentials()' - Retrieve an SSL/TLS certificate from the system store
1372 * If one cannot be found, one is created.
cc754834
MS
1373 */
1374BOOL /* O - 1 on success, 0 on failure */
2ece34a9
MS
1375_sspiGetCredentials(_http_sspi_t *conn,
1376 /* I - Client connection */
1377 const LPWSTR container,
1378 /* I - Cert container name */
1379 const TCHAR *cn, /* I - Common name of certificate */
1380 BOOL isServer)
1381 /* I - Is caller a server? */
cc754834 1382{
2ece34a9
MS
1383 HCERTSTORE store = NULL; /* Certificate store */
1384 PCCERT_CONTEXT storedContext = NULL;
1385 /* Context created from the store */
1386 PCCERT_CONTEXT createdContext = NULL;
1387 /* Context created by us */
1388 DWORD dwSize = 0; /* 32 bit size */
1389 PBYTE p = NULL; /* Temporary storage */
1390 HCRYPTPROV hProv = (HCRYPTPROV) NULL;
1391 /* Handle to a CSP */
1392 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
1393 SCHANNEL_CRED SchannelCred; /* Schannel credential data */
cc754834 1394 TimeStamp tsExpiry; /* Time stamp */
2ece34a9
MS
1395 SECURITY_STATUS Status; /* Status */
1396 HCRYPTKEY hKey = (HCRYPTKEY) NULL;
1397 /* Handle to crypto key */
1398 CRYPT_KEY_PROV_INFO kpi; /* Key container info */
1399 SYSTEMTIME et; /* System time */
1400 CERT_EXTENSIONS exts; /* Array of cert extensions */
1401 CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
cc754834
MS
1402 BOOL ok = TRUE; /* Return value */
1403
1404 if (!conn)
1405 return (FALSE);
2ece34a9
MS
1406 if (!cn)
1407 return (FALSE);
cc754834 1408
2ece34a9
MS
1409 if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
1410 PROV_RSA_FULL,
1411 CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
cc754834 1412 {
2ece34a9 1413 if (GetLastError() == NTE_EXISTS)
cc754834 1414 {
2ece34a9
MS
1415 if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
1416 PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
cc754834 1417 {
2ece34a9
MS
1418 DEBUG_printf(("_sspiGetCredentials: CryptAcquireContext failed: %x\n",
1419 GetLastError()));
cc754834
MS
1420 ok = FALSE;
1421 goto cleanup;
1422 }
cc754834 1423 }
2ece34a9 1424 }
cc754834 1425
2ece34a9
MS
1426 store = CertOpenStore(CERT_STORE_PROV_SYSTEM,
1427 X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
1428 hProv,
1429 CERT_SYSTEM_STORE_LOCAL_MACHINE |
1430 CERT_STORE_NO_CRYPT_RELEASE_FLAG |
1431 CERT_STORE_OPEN_EXISTING_FLAG,
1432 L"MY");
cc754834 1433
2ece34a9
MS
1434 if (!store)
1435 {
1436 DEBUG_printf(("_sspiGetCredentials: CertOpenSystemStore failed: %x\n",
1437 GetLastError()));
1438 ok = FALSE;
1439 goto cleanup;
1440 }
cc754834 1441
2ece34a9 1442 dwSize = 0;
cc754834 1443
2ece34a9
MS
1444 if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR,
1445 NULL, NULL, &dwSize, NULL))
1446 {
1447 DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x\n",
1448 GetLastError()));
1449 ok = FALSE;
1450 goto cleanup;
1451 }
cc754834 1452
2ece34a9 1453 p = (PBYTE) malloc(dwSize);
cc754834 1454
2ece34a9
MS
1455 if (!p)
1456 {
1457 DEBUG_printf(("_sspiGetCredentials: malloc failed for %d bytes", dwSize));
1458 ok = FALSE;
1459 goto cleanup;
1460 }
cc754834 1461
2ece34a9
MS
1462 if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR, NULL,
1463 p, &dwSize, NULL))
1464 {
1465 DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x",
1466 GetLastError()));
1467 ok = FALSE;
1468 goto cleanup;
1469 }
cc754834 1470
2ece34a9
MS
1471 sib.cbData = dwSize;
1472 sib.pbData = p;
cc754834 1473
2ece34a9
MS
1474 storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
1475 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
cc754834 1476
2ece34a9
MS
1477 if (!storedContext)
1478 {
1479 /*
1480 * If we couldn't find the context, then we'll
1481 * create a new one
1482 */
1483 if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
1484 {
1485 DEBUG_printf(("_sspiGetCredentials: CryptGenKey failed: %x",
1486 GetLastError()));
1487 ok = FALSE;
1488 goto cleanup;
cc754834
MS
1489 }
1490
2ece34a9
MS
1491 ZeroMemory(&kpi, sizeof(kpi));
1492 kpi.pwszContainerName = (LPWSTR) container;
1493 kpi.pwszProvName = MS_DEF_PROV_W;
1494 kpi.dwProvType = PROV_RSA_FULL;
1495 kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
1496 kpi.dwKeySpec = AT_KEYEXCHANGE;
cc754834 1497
2ece34a9
MS
1498 GetSystemTime(&et);
1499 et.wYear += 10;
1500
1501 ZeroMemory(&exts, sizeof(exts));
1502
1503 createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL,
1504 &et, &exts);
1505
1506 if (!createdContext)
cc754834 1507 {
2ece34a9
MS
1508 DEBUG_printf(("_sspiGetCredentials: CertCreateSelfSignCertificate failed: %x",
1509 GetLastError()));
cc754834 1510 ok = FALSE;
2ece34a9 1511 goto cleanup;
cc754834
MS
1512 }
1513
2ece34a9
MS
1514 if (!CertAddCertificateContextToStore(store, createdContext,
1515 CERT_STORE_ADD_REPLACE_EXISTING,
1516 &storedContext))
cc754834 1517 {
2ece34a9
MS
1518 DEBUG_printf(("_sspiGetCredentials: CertAddCertificateContextToStore failed: %x",
1519 GetLastError()));
1520 ok = FALSE;
1521 goto cleanup;
cc754834 1522 }
cc754834 1523
2ece34a9
MS
1524 ZeroMemory(&ckp, sizeof(ckp));
1525 ckp.pwszContainerName = (LPWSTR) container;
1526 ckp.pwszProvName = MS_DEF_PROV_W;
1527 ckp.dwProvType = PROV_RSA_FULL;
1528 ckp.dwFlags = CRYPT_MACHINE_KEYSET;
1529 ckp.dwKeySpec = AT_KEYEXCHANGE;
cc754834 1530
2ece34a9
MS
1531 if (!CertSetCertificateContextProperty(storedContext,
1532 CERT_KEY_PROV_INFO_PROP_ID,
1533 0, &ckp))
cc754834 1534 {
2ece34a9
MS
1535 DEBUG_printf(("_sspiGetCredentials: CertSetCertificateContextProperty failed: %x",
1536 GetLastError()));
cc754834 1537 ok = FALSE;
2ece34a9 1538 goto cleanup;
cc754834
MS
1539 }
1540 }
1541
2ece34a9 1542 ZeroMemory(&SchannelCred, sizeof(SchannelCred));
cc754834 1543
2ece34a9
MS
1544 SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
1545 SchannelCred.cCreds = 1;
1546 SchannelCred.paCred = &storedContext;
cc754834 1547
2ece34a9
MS
1548 /*
1549 * SSPI doesn't seem to like it if grbitEnabledProtocols
1550 * is set for a client
1551 */
1552 if (isServer)
1553 SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
cc754834 1554
2ece34a9
MS
1555 /*
1556 * Create an SSPI credential.
1557 */
1558 Status = AcquireCredentialsHandle(NULL, UNISP_NAME,
1559 isServer ? SECPKG_CRED_INBOUND:SECPKG_CRED_OUTBOUND,
1560 NULL, &SchannelCred, NULL, NULL, &conn->creds,
1561 &tsExpiry);
1562 if (Status != SEC_E_OK)
cc754834 1563 {
2ece34a9
MS
1564 DEBUG_printf(("_sspiGetCredentials: AcquireCredentialsHandle failed: %x", Status));
1565 ok = FALSE;
cc754834
MS
1566 goto cleanup;
1567 }
1568
2ece34a9 1569cleanup:
cc754834 1570
2ece34a9
MS
1571 /*
1572 * Cleanup
1573 */
1574 if (hKey)
1575 CryptDestroyKey(hKey);
cc754834 1576
2ece34a9
MS
1577 if (createdContext)
1578 CertFreeCertificateContext(createdContext);
321d8d57 1579
2ece34a9
MS
1580 if (storedContext)
1581 CertFreeCertificateContext(storedContext);
cc754834 1582
2ece34a9
MS
1583 if (p)
1584 free(p);
cc754834 1585
2ece34a9
MS
1586 if (store)
1587 CertCloseStore(store, 0);
cc754834 1588
2ece34a9
MS
1589 if (hProv)
1590 CryptReleaseContext(hProv, 0);
cc754834 1591
2ece34a9 1592 return (ok);
cc754834 1593}
2ece34a9 1594#endif // 0
cc754834
MS
1595
1596
1597/*
2ece34a9 1598 * 'http_sspi_server()' - Negotiate a TLS connection as a server.
cc754834 1599 */
2ece34a9
MS
1600
1601static int /* O - 0 on success, -1 on failure */
1602http_sspi_server(http_t *http, /* I - HTTP connection */
1603 const char *hostname) /* I - Hostname of server */
cc754834 1604{
2ece34a9
MS
1605 _http_sspi_t *conn = http->tls; /* I - SSPI data */
1606 DWORD dwSSPIFlags; /* SSL connection attributes we want */
1607 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
1608 TimeStamp tsExpiry; /* Time stamp */
1609 SECURITY_STATUS scRet; /* SSPI Status */
1610 SecBufferDesc inBuffer; /* Array of SecBuffer structs */
1611 SecBuffer inBuffers[2]; /* Security package buffer */
1612 SecBufferDesc outBuffer; /* Array of SecBuffer structs */
1613 SecBuffer outBuffers[1]; /* Security package buffer */
1614 int num = 0; /* 32 bit status value */
1615 BOOL fInitContext = TRUE; /* Has the context been init'd? */
1616 int ret = 0; /* Return value */
1617
1618
1619 DEBUG_printf(("http_sspi_server(http=%p, hostname=\"%s\")", http, hostname));
cc754834 1620
2ece34a9
MS
1621 dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
1622 ASC_REQ_REPLAY_DETECT |
1623 ASC_REQ_CONFIDENTIALITY |
1624 ASC_REQ_EXTENDED_ERROR |
1625 ASC_REQ_ALLOCATE_MEMORY |
1626 ASC_REQ_STREAM;
1627
1628 conn->decryptBufferUsed = 0;
cc754834
MS
1629
1630 /*
2ece34a9 1631 * Set OutBuffer for AcceptSecurityContext call
cc754834 1632 */
cc754834 1633
2ece34a9
MS
1634 outBuffer.cBuffers = 1;
1635 outBuffer.pBuffers = outBuffers;
1636 outBuffer.ulVersion = SECBUFFER_VERSION;
cc754834 1637
2ece34a9 1638 scRet = SEC_I_CONTINUE_NEEDED;
cc754834 1639
2ece34a9
MS
1640 while (scRet == SEC_I_CONTINUE_NEEDED ||
1641 scRet == SEC_E_INCOMPLETE_MESSAGE ||
1642 scRet == SEC_I_INCOMPLETE_CREDENTIALS)
cc754834 1643 {
2ece34a9 1644 if (conn->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
cc754834 1645 {
321d8d57 1646 if (conn->decryptBufferLength <= conn->decryptBufferUsed)
cc754834 1647 {
2ece34a9 1648 BYTE *temp; /* New buffer */
cc754834 1649
2ece34a9
MS
1650 if (conn->decryptBufferLength >= 262144)
1651 {
1652 WSASetLastError(E_OUTOFMEMORY);
1653 DEBUG_puts("http_sspi_server: Decryption buffer too large (>256k)");
1654 return (-1);
1655 }
cc754834 1656
2ece34a9
MS
1657 if ((temp = realloc(conn->decryptBuffer, conn->decryptBufferLength + 4096)) == NULL)
1658 {
1659 DEBUG_printf(("http_sspi_server: Unable to allocate %d byte buffer.", conn->decryptBufferLength + 4096));
1660 WSASetLastError(E_OUTOFMEMORY);
1661 return (-1);
1662 }
cc754834 1663
2ece34a9
MS
1664 conn->decryptBufferLength += 4096;
1665 conn->decryptBuffer = temp;
1666 }
cc754834 1667
2ece34a9 1668 for (;;)
cc754834 1669 {
2ece34a9 1670 num = recv(http->fd, conn->decryptBuffer + conn->decryptBufferUsed, (int)(conn->decryptBufferLength - conn->decryptBufferUsed), 0);
cc754834 1671
2ece34a9
MS
1672 if (num == -1 WSAGetLastError() == WSAEWOULDBLOCK)
1673 Sleep(1);
cc754834 1674 else
2ece34a9 1675 break;
cc754834 1676 }
cc754834 1677
2ece34a9
MS
1678 if (num < 0)
1679 {
1680 DEBUG_printf(("http_sspi_server: recv failed: %d", WSAGetLastError()));
1681 return (-1);
1682 }
1683 else if (num == 0)
1684 {
1685 DEBUG_puts("http_sspi_server: client disconnected");
1686 return (-1);
1687 }
1688
1689 DEBUG_printf(("http_sspi_server: received %d (handshake) bytes from client.", num));
1690 conn->decryptBufferUsed += num;
cc754834
MS
1691 }
1692
1693 /*
2ece34a9
MS
1694 * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process
1695 * on this run around the loop.
cc754834 1696 */
2ece34a9
MS
1697
1698 inBuffers[0].pvBuffer = conn->decryptBuffer;
1699 inBuffers[0].cbBuffer = (unsigned long)conn->decryptBufferUsed;
1700 inBuffers[0].BufferType = SECBUFFER_TOKEN;
1701
1702 inBuffers[1].pvBuffer = NULL;
1703 inBuffers[1].cbBuffer = 0;
1704 inBuffers[1].BufferType = SECBUFFER_EMPTY;
1705
1706 inBuffer.cBuffers = 2;
1707 inBuffer.pBuffers = inBuffers;
1708 inBuffer.ulVersion = SECBUFFER_VERSION;
cc754834
MS
1709
1710 /*
2ece34a9
MS
1711 * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to
1712 * free random garbage at the quit.
cc754834 1713 */
cc754834 1714
2ece34a9
MS
1715 outBuffers[0].pvBuffer = NULL;
1716 outBuffers[0].BufferType = SECBUFFER_TOKEN;
1717 outBuffers[0].cbBuffer = 0;
1718
1719 scRet = AcceptSecurityContext(&conn->creds, (fInitContext?NULL:&conn->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&conn->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry);
cc754834 1720
2ece34a9
MS
1721 fInitContext = FALSE;
1722
1723 if (scRet == SEC_E_OK ||
1724 scRet == SEC_I_CONTINUE_NEEDED ||
1725 (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0)))
1726 {
1727 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
cc754834 1728 {
2ece34a9
MS
1729 /*
1730 * Send response to server if there is one.
1731 */
cc754834 1732
2ece34a9
MS
1733 num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
1734
1735 if (num <= 0)
1736 {
1737 DEBUG_printf(("http_sspi_server: handshake send failed: %d", WSAGetLastError()));
1738 return (-1);
cc754834
MS
1739 }
1740
2ece34a9 1741 DEBUG_printf(("http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer));
cc754834 1742
2ece34a9
MS
1743 FreeContextBuffer(outBuffers[0].pvBuffer);
1744 outBuffers[0].pvBuffer = NULL;
cc754834 1745 }
2ece34a9
MS
1746 }
1747
1748 if (scRet == SEC_E_OK)
1749 {
1750 /*
1751 * If there's extra data then save it for next time we go to decrypt.
1752 */
cc754834 1753
2ece34a9
MS
1754 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1755 {
1756 memcpy(conn->decryptBuffer, (LPBYTE)(conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
1757 conn->decryptBufferUsed = inBuffers[1].cbBuffer;
1758 }
1759 else
1760 {
1761 conn->decryptBufferUsed = 0;
1762 }
1763 break;
cc754834 1764 }
2ece34a9 1765 else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE)
cc754834 1766 {
2ece34a9
MS
1767 DEBUG_printf(("http_sspi_server: AcceptSecurityContext failed: %x", scRet));
1768 ret = -1;
1769 break;
cc754834
MS
1770 }
1771
2ece34a9
MS
1772 if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
1773 scRet != SEC_I_INCOMPLETE_CREDENTIALS)
cc754834 1774 {
2ece34a9
MS
1775 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
1776 {
1777 memcpy(conn->decryptBuffer, (LPBYTE)(conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
1778 conn->decryptBufferUsed = inBuffers[1].cbBuffer;
1779 }
1780 else
1781 {
1782 conn->decryptBufferUsed = 0;
1783 }
cc754834 1784 }
2ece34a9
MS
1785 }
1786
1787 if (!ret)
1788 {
1789 conn->contextInitialized = TRUE;
1790
1791 /*
1792 * Find out how big the header will be:
1793 */
1794
1795 scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
1796
1797 if (scRet != SEC_E_OK)
cc754834 1798 {
2ece34a9
MS
1799 DEBUG_printf(("http_sspi_server: QueryContextAttributes failed: %x", scRet));
1800 ret = -1;
cc754834
MS
1801 }
1802 }
1803
2ece34a9 1804 return (ret);
cc754834
MS
1805}
1806
1807
2ece34a9 1808#if 0
cc754834 1809/*
2ece34a9 1810 * '_sspiSetAllowsAnyRoot()' - Set the client cert policy for untrusted root certs
cc754834 1811 */
2ece34a9
MS
1812void
1813_sspiSetAllowsAnyRoot(_http_sspi_t *conn,
1814 /* I - Client connection */
1815 BOOL allow)
1816 /* I - Allow any root */
cc754834 1817{
2ece34a9
MS
1818 conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_UNKNOWN_CA :
1819 conn->certFlags & ~SECURITY_FLAG_IGNORE_UNKNOWN_CA;
cc754834
MS
1820}
1821
1822
1823/*
2ece34a9 1824 * '_sspiSetAllowsExpiredCerts()' - Set the client cert policy for expired root certs
cc754834
MS
1825 */
1826void
2ece34a9
MS
1827_sspiSetAllowsExpiredCerts(_http_sspi_t *conn,
1828 /* I - Client connection */
1829 BOOL allow)
1830 /* I - Allow expired certs */
cc754834 1831{
2ece34a9
MS
1832 conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID :
1833 conn->certFlags & ~SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
cc754834
MS
1834}
1835
1836
1837/*
2ece34a9 1838 * 'http_sspi_verify()' - Verify a certificate.
cc754834 1839 */
2ece34a9
MS
1840
1841static DWORD /* O - Error code (0 == No error) */
1842http_sspi_verify(
1843 PCCERT_CONTEXT cert, /* I - Server certificate */
1844 const char *common_name, /* I - Common name */
1845 DWORD dwCertFlags) /* I - Verification flags */
cc754834 1846{
2ece34a9
MS
1847 HTTPSPolicyCallbackData httpsPolicy; /* HTTPS Policy Struct */
1848 CERT_CHAIN_POLICY_PARA policyPara; /* Cert chain policy parameters */
1849 CERT_CHAIN_POLICY_STATUS policyStatus;/* Cert chain policy status */
1850 CERT_CHAIN_PARA chainPara; /* Used for searching and matching criteria */
1851 PCCERT_CHAIN_CONTEXT chainContext = NULL;
cc754834 1852 /* Certificate chain */
2ece34a9
MS
1853 PWSTR commonNameUnicode = NULL;
1854 /* Unicode common name */
1855 LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
1856 szOID_SERVER_GATED_CRYPTO,
1857 szOID_SGC_NETSCAPE };
cc754834 1858 /* How are we using this certificate? */
2ece34a9 1859 DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
cc754834 1860 /* Number of ites in rgszUsages */
2ece34a9
MS
1861 DWORD count; /* 32 bit count variable */
1862 DWORD status; /* Return value */
cc754834 1863
2ece34a9
MS
1864
1865 if (!cert)
1866 return (SEC_E_WRONG_PRINCIPAL);
cc754834
MS
1867
1868 /*
2ece34a9 1869 * Convert common name to Unicode.
cc754834 1870 */
cc754834 1871
2ece34a9
MS
1872 if (!common_name || !*common_name)
1873 return (SEC_E_WRONG_PRINCIPAL);
1874
1875 count = MultiByteToWideChar(CP_ACP, 0, common_name, -1, NULL, 0);
1876 commonNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR));
1877 if (!commonNameUnicode)
1878 return (SEC_E_INSUFFICIENT_MEMORY);
1879
1880 if (!MultiByteToWideChar(CP_ACP, 0, common_name, -1, commonNameUnicode, count))
cc754834 1881 {
2ece34a9
MS
1882 LocalFree(commonNameUnicode);
1883 return (SEC_E_WRONG_PRINCIPAL);
cc754834
MS
1884 }
1885
1886 /*
1887 * Build certificate chain.
1888 */
2ece34a9 1889
cc754834 1890 ZeroMemory(&chainPara, sizeof(chainPara));
2ece34a9 1891
cc754834
MS
1892 chainPara.cbSize = sizeof(chainPara);
1893 chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
1894 chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
1895 chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
1896
2ece34a9 1897 if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext))
cc754834
MS
1898 {
1899 status = GetLastError();
1900 DEBUG_printf(("CertGetCertificateChain returned 0x%x\n", status));
2ece34a9
MS
1901
1902 LocalFree(commonNameUnicode);
1903 return (status);
cc754834
MS
1904 }
1905
1906 /*
1907 * Validate certificate chain.
321d8d57 1908 */
2ece34a9 1909
cc754834
MS
1910 ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
1911 httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData);
1912 httpsPolicy.dwAuthType = AUTHTYPE_SERVER;
1913 httpsPolicy.fdwChecks = dwCertFlags;
2ece34a9 1914 httpsPolicy.pwszServerName = commonNameUnicode;
cc754834
MS
1915
1916 memset(&policyPara, 0, sizeof(policyPara));
1917 policyPara.cbSize = sizeof(policyPara);
1918 policyPara.pvExtraPolicyPara = &httpsPolicy;
1919
1920 memset(&policyStatus, 0, sizeof(policyStatus));
1921 policyStatus.cbSize = sizeof(policyStatus);
1922
2ece34a9 1923 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus))
cc754834
MS
1924 {
1925 status = GetLastError();
1926 DEBUG_printf(("CertVerifyCertificateChainPolicy returned %d", status));
cc754834 1927 }
2ece34a9 1928 else if (policyStatus.dwError)
cc754834 1929 status = policyStatus.dwError;
2ece34a9
MS
1930 else
1931 status = SEC_E_OK;
cc754834
MS
1932
1933 if (chainContext)
1934 CertFreeCertificateChain(chainContext);
1935
2ece34a9
MS
1936 if (commonNameUnicode)
1937 LocalFree(commonNameUnicode);
cc754834
MS
1938
1939 return (status);
1940}
2ece34a9 1941#endif // 0
321d8d57
MS
1942
1943
1944/*
1945 * End of "$Id$".
1946 */