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