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