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