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