]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/sspi.c
Use httpAddrListen and new httpAddrClose in cupsd and other places that need it.
[thirdparty/cups.git] / cups / sspi.c
CommitLineData
cc754834 1/*
321d8d57 2 * "$Id$"
cc754834 3 *
321d8d57
MS
4 * Windows SSPI SSL implementation for CUPS.
5 *
6 * Copyright 2010-2011 by Apple Inc.
cc754834
MS
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 * Contents:
15 *
321d8d57
MS
16 * sspi_alloc() - Allocate SSPI ssl object
17 * _sspiGetCredentials() - Retrieve an SSL/TLS certificate from the
18 * system store If one cannot be found, one is
19 * created.
20 * _sspiConnect() - Make an SSL connection. This function
21 * assumes a TCP/IP connection has already been
22 * successfully made
23 * _sspiAccept() - Accept an SSL/TLS connection
24 * _sspiSetAllowsAnyRoot() - Set the client cert policy for untrusted
25 * root certs
26 * _sspiSetAllowsExpiredCerts() - Set the client cert policy for expired root
27 * certs
28 * _sspiWrite() - Write a buffer to an ssl socket
29 * _sspiRead() - Read a buffer from an ssl socket
30 * _sspiPending() - Returns the number of available bytes
31 * _sspiFree() - Close a connection and free resources
32 * sspi_verify_certificate() - Verify a server certificate
cc754834
MS
33 */
34
35/*
36 * Include necessary headers...
37 */
38
39#include "sspi-private.h"
40#include "debug-private.h"
321d8d57 41
cc754834
MS
42
43/* required to link this library for certificate functions */
44#pragma comment(lib, "Crypt32.lib")
45#pragma comment(lib, "Secur32.lib")
46#pragma comment(lib, "Ws2_32.lib")
47
48
49#if !defined(SECURITY_FLAG_IGNORE_UNKNOWN_CA)
50# define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */
51#endif
52
53#if !defined(SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)
54# define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */
55#endif
56
57static DWORD sspi_verify_certificate(PCCERT_CONTEXT serverCert,
58 const CHAR *serverName,
59 DWORD dwCertFlags);
60
61
62/*
63 * 'sspi_alloc()' - Allocate SSPI ssl object
64 */
65_sspi_struct_t* /* O - New SSPI/SSL object */
66_sspiAlloc(void)
67{
68 _sspi_struct_t *conn = calloc(sizeof(_sspi_struct_t), 1);
69
70 if (conn)
71 conn->sock = INVALID_SOCKET;
72
73 return (conn);
74}
75
76
77/*
78 * '_sspiGetCredentials()' - Retrieve an SSL/TLS certificate from the system store
79 * If one cannot be found, one is created.
80 */
81BOOL /* O - 1 on success, 0 on failure */
82_sspiGetCredentials(_sspi_struct_t *conn,
83 /* I - Client connection */
84 const LPWSTR container,
85 /* I - Cert container name */
86 const TCHAR *cn, /* I - Common name of certificate */
87 BOOL isServer)
321d8d57 88 /* I - Is caller a server? */
cc754834
MS
89{
90 HCERTSTORE store = NULL; /* Certificate store */
91 PCCERT_CONTEXT storedContext = NULL;
321d8d57 92 /* Context created from the store */
cc754834 93 PCCERT_CONTEXT createdContext = NULL;
321d8d57 94 /* Context created by us */
cc754834
MS
95 DWORD dwSize = 0; /* 32 bit size */
96 PBYTE p = NULL; /* Temporary storage */
97 HCRYPTPROV hProv = (HCRYPTPROV) NULL;
98 /* Handle to a CSP */
99 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
100 SCHANNEL_CRED SchannelCred; /* Schannel credential data */
101 TimeStamp tsExpiry; /* Time stamp */
102 SECURITY_STATUS Status; /* Status */
103 HCRYPTKEY hKey = (HCRYPTKEY) NULL;
104 /* Handle to crypto key */
105 CRYPT_KEY_PROV_INFO kpi; /* Key container info */
106 SYSTEMTIME et; /* System time */
107 CERT_EXTENSIONS exts; /* Array of cert extensions */
108 CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
109 BOOL ok = TRUE; /* Return value */
110
111 if (!conn)
112 return (FALSE);
113 if (!cn)
114 return (FALSE);
115
116 if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
117 PROV_RSA_FULL,
118 CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
119 {
120 if (GetLastError() == NTE_EXISTS)
121 {
122 if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
123 PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
124 {
125 DEBUG_printf(("_sspiGetCredentials: CryptAcquireContext failed: %x\n",
126 GetLastError()));
127 ok = FALSE;
128 goto cleanup;
129 }
130 }
131 }
132
133 store = CertOpenStore(CERT_STORE_PROV_SYSTEM,
134 X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
135 hProv,
136 CERT_SYSTEM_STORE_LOCAL_MACHINE |
137 CERT_STORE_NO_CRYPT_RELEASE_FLAG |
138 CERT_STORE_OPEN_EXISTING_FLAG,
139 L"MY");
140
141 if (!store)
142 {
143 DEBUG_printf(("_sspiGetCredentials: CertOpenSystemStore failed: %x\n",
144 GetLastError()));
145 ok = FALSE;
146 goto cleanup;
147 }
148
149 dwSize = 0;
321d8d57 150
cc754834
MS
151 if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR,
152 NULL, NULL, &dwSize, NULL))
153 {
154 DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x\n",
155 GetLastError()));
156 ok = FALSE;
157 goto cleanup;
158 }
159
160 p = (PBYTE) malloc(dwSize);
161
162 if (!p)
163 {
164 DEBUG_printf(("_sspiGetCredentials: malloc failed for %d bytes", dwSize));
165 ok = FALSE;
166 goto cleanup;
167 }
168
169 if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR, NULL,
170 p, &dwSize, NULL))
171 {
172 DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x",
173 GetLastError()));
174 ok = FALSE;
175 goto cleanup;
176 }
177
178 sib.cbData = dwSize;
179 sib.pbData = p;
180
181 storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
182 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
321d8d57 183
cc754834
MS
184 if (!storedContext)
185 {
321d8d57 186 /*
cc754834
MS
187 * If we couldn't find the context, then we'll
188 * create a new one
189 */
190 if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
191 {
192 DEBUG_printf(("_sspiGetCredentials: CryptGenKey failed: %x",
193 GetLastError()));
194 ok = FALSE;
195 goto cleanup;
196 }
197
198 ZeroMemory(&kpi, sizeof(kpi));
199 kpi.pwszContainerName = (LPWSTR) container;
200 kpi.pwszProvName = MS_DEF_PROV_W;
201 kpi.dwProvType = PROV_RSA_FULL;
202 kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
203 kpi.dwKeySpec = AT_KEYEXCHANGE;
204
205 GetSystemTime(&et);
206 et.wYear += 10;
207
208 ZeroMemory(&exts, sizeof(exts));
209
210 createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL,
211 &et, &exts);
321d8d57 212
cc754834
MS
213 if (!createdContext)
214 {
215 DEBUG_printf(("_sspiGetCredentials: CertCreateSelfSignCertificate failed: %x",
216 GetLastError()));
217 ok = FALSE;
218 goto cleanup;
219 }
220
221 if (!CertAddCertificateContextToStore(store, createdContext,
222 CERT_STORE_ADD_REPLACE_EXISTING,
223 &storedContext))
224 {
225 DEBUG_printf(("_sspiGetCredentials: CertAddCertificateContextToStore failed: %x",
226 GetLastError()));
227 ok = FALSE;
228 goto cleanup;
229 }
230
231 ZeroMemory(&ckp, sizeof(ckp));
232 ckp.pwszContainerName = (LPWSTR) container;
233 ckp.pwszProvName = MS_DEF_PROV_W;
234 ckp.dwProvType = PROV_RSA_FULL;
235 ckp.dwFlags = CRYPT_MACHINE_KEYSET;
236 ckp.dwKeySpec = AT_KEYEXCHANGE;
237
238 if (!CertSetCertificateContextProperty(storedContext,
239 CERT_KEY_PROV_INFO_PROP_ID,
240 0, &ckp))
241 {
242 DEBUG_printf(("_sspiGetCredentials: CertSetCertificateContextProperty failed: %x",
243 GetLastError()));
244 ok = FALSE;
245 goto cleanup;
246 }
247 }
248
249 ZeroMemory(&SchannelCred, sizeof(SchannelCred));
250
251 SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
252 SchannelCred.cCreds = 1;
253 SchannelCred.paCred = &storedContext;
254
255 /*
256 * SSPI doesn't seem to like it if grbitEnabledProtocols
257 * is set for a client
258 */
259 if (isServer)
260 SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
261
262 /*
263 * Create an SSPI credential.
264 */
321d8d57 265 Status = AcquireCredentialsHandle(NULL, UNISP_NAME,
cc754834
MS
266 isServer ? SECPKG_CRED_INBOUND:SECPKG_CRED_OUTBOUND,
267 NULL, &SchannelCred, NULL, NULL, &conn->creds,
268 &tsExpiry);
269 if (Status != SEC_E_OK)
270 {
271 DEBUG_printf(("_sspiGetCredentials: AcquireCredentialsHandle failed: %x", Status));
272 ok = FALSE;
273 goto cleanup;
274 }
275
276cleanup:
277
278 /*
279 * Cleanup
280 */
281 if (hKey)
282 CryptDestroyKey(hKey);
283
284 if (createdContext)
285 CertFreeCertificateContext(createdContext);
286
287 if (storedContext)
288 CertFreeCertificateContext(storedContext);
289
290 if (p)
291 free(p);
292
293 if (store)
294 CertCloseStore(store, 0);
295
296 if (hProv)
297 CryptReleaseContext(hProv, 0);
298
299 return (ok);
300}
301
302
303/*
304 * '_sspiConnect()' - Make an SSL connection. This function
305 * assumes a TCP/IP connection has already
306 * been successfully made
307 */
308BOOL /* O - 1 on success, 0 on failure */
309_sspiConnect(_sspi_struct_t *conn, /* I - Client connection */
321d8d57 310 const CHAR *hostname) /* I - Server hostname */
cc754834
MS
311{
312 PCCERT_CONTEXT serverCert; /* Server certificate */
313 DWORD dwSSPIFlags; /* SSL connection attributes we want */
314 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
315 TimeStamp tsExpiry; /* Time stamp */
316 SECURITY_STATUS scRet; /* Status */
317 DWORD cbData; /* Data count */
318 SecBufferDesc inBuffer; /* Array of SecBuffer structs */
319 SecBuffer inBuffers[2]; /* Security package buffer */
320 SecBufferDesc outBuffer; /* Array of SecBuffer structs */
321 SecBuffer outBuffers[1]; /* Security package buffer */
322 BOOL ok = TRUE; /* Return value */
323
324 serverCert = NULL;
325
326 dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
327 ISC_REQ_REPLAY_DETECT |
328 ISC_REQ_CONFIDENTIALITY |
329 ISC_RET_EXTENDED_ERROR |
330 ISC_REQ_ALLOCATE_MEMORY |
331 ISC_REQ_STREAM;
332
333 /*
334 * Initiate a ClientHello message and generate a token.
335 */
336 outBuffers[0].pvBuffer = NULL;
337 outBuffers[0].BufferType = SECBUFFER_TOKEN;
338 outBuffers[0].cbBuffer = 0;
339
340 outBuffer.cBuffers = 1;
341 outBuffer.pBuffers = outBuffers;
342 outBuffer.ulVersion = SECBUFFER_VERSION;
343
344 scRet = InitializeSecurityContext(&conn->creds, NULL, TEXT(""), dwSSPIFlags,
345 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
346 &outBuffer, &dwSSPIOutFlags, &tsExpiry);
347
348 if (scRet != SEC_I_CONTINUE_NEEDED)
349 {
350 DEBUG_printf(("_sspiConnect: InitializeSecurityContext(1) failed: %x", scRet));
351 ok = FALSE;
352 goto cleanup;
353 }
354
355 /*
356 * Send response to server if there is one.
357 */
358 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
359 {
360 cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
361
362 if ((cbData == SOCKET_ERROR) || !cbData)
363 {
364 DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError()));
365 FreeContextBuffer(outBuffers[0].pvBuffer);
366 DeleteSecurityContext(&conn->context);
367 ok = FALSE;
368 goto cleanup;
369 }
370
371 DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData));
372
373 /*
374 * Free output buffer.
375 */
376 FreeContextBuffer(outBuffers[0].pvBuffer);
377 outBuffers[0].pvBuffer = NULL;
378 }
379
380 dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
381 ISC_REQ_SEQUENCE_DETECT |
382 ISC_REQ_REPLAY_DETECT |
383 ISC_REQ_CONFIDENTIALITY |
384 ISC_RET_EXTENDED_ERROR |
385 ISC_REQ_ALLOCATE_MEMORY |
386 ISC_REQ_STREAM;
387
388 conn->decryptBufferUsed = 0;
389
321d8d57 390 /*
cc754834
MS
391 * Loop until the handshake is finished or an error occurs.
392 */
393 scRet = SEC_I_CONTINUE_NEEDED;
394
395 while(scRet == SEC_I_CONTINUE_NEEDED ||
396 scRet == SEC_E_INCOMPLETE_MESSAGE ||
321d8d57 397 scRet == SEC_I_INCOMPLETE_CREDENTIALS)
cc754834
MS
398 {
399 if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE))
400 {
321d8d57 401 if (conn->decryptBufferLength <= conn->decryptBufferUsed)
cc754834
MS
402 {
403 conn->decryptBufferLength += 4096;
404 conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer, conn->decryptBufferLength);
405
406 if (!conn->decryptBuffer)
407 {
408 DEBUG_printf(("_sspiConnect: unable to allocate %d byte decrypt buffer",
409 conn->decryptBufferLength));
410 SetLastError(E_OUTOFMEMORY);
411 ok = FALSE;
412 goto cleanup;
413 }
414 }
321d8d57
MS
415
416 cbData = recv(conn->sock, conn->decryptBuffer + conn->decryptBufferUsed,
cc754834 417 (int) (conn->decryptBufferLength - conn->decryptBufferUsed), 0);
321d8d57 418
cc754834
MS
419 if (cbData == SOCKET_ERROR)
420 {
421 DEBUG_printf(("_sspiConnect: recv failed: %d", WSAGetLastError()));
422 ok = FALSE;
423 goto cleanup;
424 }
425 else if (cbData == 0)
426 {
427 DEBUG_printf(("_sspiConnect: server unexpectedly disconnected"));
428 ok = FALSE;
429 goto cleanup;
430 }
431
432 DEBUG_printf(("_sspiConnect: %d bytes of handshake data received",
433 cbData));
434
435 conn->decryptBufferUsed += cbData;
436 }
437
438 /*
439 * Set up the input buffers. Buffer 0 is used to pass in data
440 * received from the server. Schannel will consume some or all
441 * of this. Leftover data (if any) will be placed in buffer 1 and
442 * given a buffer type of SECBUFFER_EXTRA.
443 */
444 inBuffers[0].pvBuffer = conn->decryptBuffer;
445 inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
446 inBuffers[0].BufferType = SECBUFFER_TOKEN;
447
448 inBuffers[1].pvBuffer = NULL;
449 inBuffers[1].cbBuffer = 0;
450 inBuffers[1].BufferType = SECBUFFER_EMPTY;
451
452 inBuffer.cBuffers = 2;
453 inBuffer.pBuffers = inBuffers;
454 inBuffer.ulVersion = SECBUFFER_VERSION;
455
456 /*
457 * Set up the output buffers. These are initialized to NULL
458 * so as to make it less likely we'll attempt to free random
459 * garbage later.
460 */
461 outBuffers[0].pvBuffer = NULL;
462 outBuffers[0].BufferType= SECBUFFER_TOKEN;
463 outBuffers[0].cbBuffer = 0;
464
465 outBuffer.cBuffers = 1;
466 outBuffer.pBuffers = outBuffers;
467 outBuffer.ulVersion = SECBUFFER_VERSION;
468
469 /*
470 * Call InitializeSecurityContext.
471 */
472 scRet = InitializeSecurityContext(&conn->creds, &conn->context, NULL, dwSSPIFlags,
473 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL,
474 &outBuffer, &dwSSPIOutFlags, &tsExpiry);
475
476 /*
321d8d57 477 * If InitializeSecurityContext was successful (or if the error was
cc754834
MS
478 * one of the special extended ones), send the contends of the output
479 * buffer to the server.
480 */
481 if (scRet == SEC_E_OK ||
482 scRet == SEC_I_CONTINUE_NEEDED ||
483 FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
484 {
485 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
486 {
487 cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
321d8d57 488
cc754834
MS
489 if ((cbData == SOCKET_ERROR) || !cbData)
490 {
491 DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError()));
492 FreeContextBuffer(outBuffers[0].pvBuffer);
493 DeleteSecurityContext(&conn->context);
494 ok = FALSE;
495 goto cleanup;
496 }
497
498 DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData));
499
500 /*
501 * Free output buffer.
502 */
503 FreeContextBuffer(outBuffers[0].pvBuffer);
504 outBuffers[0].pvBuffer = NULL;
505 }
506 }
507
508 /*
509 * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE,
510 * then we need to read more data from the server and try again.
511 */
512 if (scRet == SEC_E_INCOMPLETE_MESSAGE)
513 continue;
514
515 /*
321d8d57 516 * If InitializeSecurityContext returned SEC_E_OK, then the
cc754834
MS
517 * handshake completed successfully.
518 */
519 if (scRet == SEC_E_OK)
520 {
521 /*
522 * If the "extra" buffer contains data, this is encrypted application
523 * protocol layer stuff. It needs to be saved. The application layer
524 * will later decrypt it with DecryptMessage.
525 */
526 DEBUG_printf(("_sspiConnect: Handshake was successful"));
527
528 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
529 {
530 if (conn->decryptBufferLength < inBuffers[1].cbBuffer)
531 {
532 conn->decryptBuffer = realloc(conn->decryptBuffer, inBuffers[1].cbBuffer);
533
534 if (!conn->decryptBuffer)
535 {
536 DEBUG_printf(("_sspiConnect: unable to allocate %d bytes for decrypt buffer",
537 inBuffers[1].cbBuffer));
538 SetLastError(E_OUTOFMEMORY);
539 ok = FALSE;
540 goto cleanup;
541 }
542 }
543
544 memmove(conn->decryptBuffer,
545 conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer),
546 inBuffers[1].cbBuffer);
547
548 conn->decryptBufferUsed = inBuffers[1].cbBuffer;
549
550 DEBUG_printf(("_sspiConnect: %d bytes of app data was bundled with handshake data",
551 conn->decryptBufferUsed));
552 }
553 else
554 conn->decryptBufferUsed = 0;
555
556 /*
557 * Bail out to quit
558 */
559 break;
560 }
561
562 /*
563 * Check for fatal error.
564 */
565 if (FAILED(scRet))
566 {
567 DEBUG_printf(("_sspiConnect: InitializeSecurityContext(2) failed: %x", scRet));
568 ok = FALSE;
569 break;
570 }
571
572 /*
573 * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
321d8d57 574 * then the server just requested client authentication.
cc754834
MS
575 */
576 if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
577 {
578 /*
579 * Unimplemented
580 */
581 DEBUG_printf(("_sspiConnect: server requested client credentials"));
582 ok = FALSE;
583 break;
584 }
585
586 /*
587 * Copy any leftover data from the "extra" buffer, and go around
588 * again.
589 */
590 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
591 {
592 memmove(conn->decryptBuffer,
593 conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer),
594 inBuffers[1].cbBuffer);
595
596 conn->decryptBufferUsed = inBuffers[1].cbBuffer;
597 }
598 else
599 {
600 conn->decryptBufferUsed = 0;
601 }
602 }
603
604 if (ok)
605 {
606 conn->contextInitialized = TRUE;
607
608 /*
609 * Get the server cert
610 */
611 scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID*) &serverCert );
612
613 if (scRet != SEC_E_OK)
614 {
615 DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %x", scRet));
616 ok = FALSE;
617 goto cleanup;
618 }
619
620 scRet = sspi_verify_certificate(serverCert, hostname, conn->certFlags);
621
622 if (scRet != SEC_E_OK)
623 {
624 DEBUG_printf(("_sspiConnect: sspi_verify_certificate failed: %x", scRet));
625 ok = FALSE;
626 goto cleanup;
627 }
321d8d57 628
cc754834
MS
629 /*
630 * Find out how big the header/trailer will be:
631 */
632 scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
633
634 if (scRet != SEC_E_OK)
635 {
636 DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %x", scRet));
637 ok = FALSE;
638 }
639 }
640
641cleanup:
642
643 if (serverCert)
644 CertFreeCertificateContext(serverCert);
645
646 return (ok);
647}
648
649
650/*
651 * '_sspiAccept()' - Accept an SSL/TLS connection
652 */
653BOOL /* O - 1 on success, 0 on failure */
654_sspiAccept(_sspi_struct_t *conn) /* I - Client connection */
655{
656 DWORD dwSSPIFlags; /* SSL connection attributes we want */
657 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
658 TimeStamp tsExpiry; /* Time stamp */
659 SECURITY_STATUS scRet; /* SSPI Status */
660 SecBufferDesc inBuffer; /* Array of SecBuffer structs */
661 SecBuffer inBuffers[2]; /* Security package buffer */
662 SecBufferDesc outBuffer; /* Array of SecBuffer structs */
663 SecBuffer outBuffers[1]; /* Security package buffer */
664 DWORD num = 0; /* 32 bit status value */
665 BOOL fInitContext = TRUE;
666 /* Has the context been init'd? */
667 BOOL ok = TRUE; /* Return value */
668
669 if (!conn)
670 return (FALSE);
671
672 dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
673 ASC_REQ_REPLAY_DETECT |
674 ASC_REQ_CONFIDENTIALITY |
675 ASC_REQ_EXTENDED_ERROR |
676 ASC_REQ_ALLOCATE_MEMORY |
677 ASC_REQ_STREAM;
678
679 conn->decryptBufferUsed = 0;
321d8d57 680
cc754834
MS
681 /*
682 * Set OutBuffer for AcceptSecurityContext call
683 */
684 outBuffer.cBuffers = 1;
685 outBuffer.pBuffers = outBuffers;
686 outBuffer.ulVersion = SECBUFFER_VERSION;
687
688 scRet = SEC_I_CONTINUE_NEEDED;
689
690 while (scRet == SEC_I_CONTINUE_NEEDED ||
691 scRet == SEC_E_INCOMPLETE_MESSAGE ||
321d8d57 692 scRet == SEC_I_INCOMPLETE_CREDENTIALS)
cc754834
MS
693 {
694 if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE))
695 {
321d8d57 696 if (conn->decryptBufferLength <= conn->decryptBufferUsed)
cc754834
MS
697 {
698 conn->decryptBufferLength += 4096;
699 conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer,
700 conn->decryptBufferLength);
701
702 if (!conn->decryptBuffer)
703 {
704 DEBUG_printf(("_sspiAccept: unable to allocate %d byte decrypt buffer",
705 conn->decryptBufferLength));
706 ok = FALSE;
707 goto cleanup;
708 }
709 }
710
711 for (;;)
712 {
713 num = recv(conn->sock,
714 conn->decryptBuffer + conn->decryptBufferUsed,
715 (int)(conn->decryptBufferLength - conn->decryptBufferUsed),
716 0);
717
718 if ((num == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
719 Sleep(1);
720 else
721 break;
722 }
723
724 if (num == SOCKET_ERROR)
725 {
726 DEBUG_printf(("_sspiAccept: recv failed: %d", WSAGetLastError()));
727 ok = FALSE;
728 goto cleanup;
729 }
730 else if (num == 0)
731 {
732 DEBUG_printf(("_sspiAccept: client disconnected"));
733 ok = FALSE;
734 goto cleanup;
735 }
736
737 DEBUG_printf(("_sspiAccept: received %d (handshake) bytes from client",
738 num));
739 conn->decryptBufferUsed += num;
740 }
741
742 /*
743 * InBuffers[1] is for getting extra data that
744 * SSPI/SCHANNEL doesn't proccess on this
745 * run around the loop.
746 */
747 inBuffers[0].pvBuffer = conn->decryptBuffer;
748 inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
749 inBuffers[0].BufferType = SECBUFFER_TOKEN;
750
751 inBuffers[1].pvBuffer = NULL;
752 inBuffers[1].cbBuffer = 0;
753 inBuffers[1].BufferType = SECBUFFER_EMPTY;
754
755 inBuffer.cBuffers = 2;
756 inBuffer.pBuffers = inBuffers;
757 inBuffer.ulVersion = SECBUFFER_VERSION;
758
759 /*
760 * Initialize these so if we fail, pvBuffer contains NULL,
761 * so we don't try to free random garbage at the quit
762 */
763 outBuffers[0].pvBuffer = NULL;
764 outBuffers[0].BufferType = SECBUFFER_TOKEN;
765 outBuffers[0].cbBuffer = 0;
766
767 scRet = AcceptSecurityContext(&conn->creds, (fInitContext?NULL:&conn->context),
768 &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP,
769 (fInitContext?&conn->context:NULL), &outBuffer,
770 &dwSSPIOutFlags, &tsExpiry);
771
772 fInitContext = FALSE;
773
774 if (scRet == SEC_E_OK ||
775 scRet == SEC_I_CONTINUE_NEEDED ||
776 (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0)))
777 {
778 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
779 {
780 /*
781 * Send response to server if there is one
782 */
783 num = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
784
785 if ((num == SOCKET_ERROR) || (num == 0))
786 {
787 DEBUG_printf(("_sspiAccept: handshake send failed: %d", WSAGetLastError()));
788 ok = FALSE;
789 goto cleanup;
790 }
791
792 DEBUG_printf(("_sspiAccept: send %d handshake bytes to client",
793 outBuffers[0].cbBuffer));
794
795 FreeContextBuffer(outBuffers[0].pvBuffer);
796 outBuffers[0].pvBuffer = NULL;
797 }
798 }
799
800 if (scRet == SEC_E_OK)
801 {
802 /*
321d8d57 803 * If there's extra data then save it for
cc754834
MS
804 * next time we go to decrypt
805 */
806 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
807 {
808 memcpy(conn->decryptBuffer,
809 (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)),
810 inBuffers[1].cbBuffer);
811 conn->decryptBufferUsed = inBuffers[1].cbBuffer;
812 }
813 else
814 {
815 conn->decryptBufferUsed = 0;
816 }
817
818 ok = TRUE;
819 break;
820 }
821 else if (FAILED(scRet) && (scRet != SEC_E_INCOMPLETE_MESSAGE))
822 {
823 DEBUG_printf(("_sspiAccept: AcceptSecurityContext failed: %x", scRet));
824 ok = FALSE;
825 break;
826 }
827
828 if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
829 scRet != SEC_I_INCOMPLETE_CREDENTIALS)
830 {
831 if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
832 {
833 memcpy(conn->decryptBuffer,
834 (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)),
835 inBuffers[1].cbBuffer);
836 conn->decryptBufferUsed = inBuffers[1].cbBuffer;
837 }
838 else
839 {
840 conn->decryptBufferUsed = 0;
841 }
842 }
843 }
844
845 if (ok)
846 {
847 conn->contextInitialized = TRUE;
848
849 /*
850 * Find out how big the header will be:
851 */
852 scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
853
854 if (scRet != SEC_E_OK)
855 {
856 DEBUG_printf(("_sspiAccept: QueryContextAttributes failed: %x", scRet));
857 ok = FALSE;
858 }
859 }
860
861cleanup:
862
863 return (ok);
864}
865
866
867/*
868 * '_sspiSetAllowsAnyRoot()' - Set the client cert policy for untrusted root certs
869 */
870void
871_sspiSetAllowsAnyRoot(_sspi_struct_t *conn,
872 /* I - Client connection */
873 BOOL allow)
874 /* I - Allow any root */
875{
876 conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_UNKNOWN_CA :
877 conn->certFlags & ~SECURITY_FLAG_IGNORE_UNKNOWN_CA;
878}
879
880
881/*
882 * '_sspiSetAllowsExpiredCerts()' - Set the client cert policy for expired root certs
883 */
884void
885_sspiSetAllowsExpiredCerts(_sspi_struct_t *conn,
886 /* I - Client connection */
887 BOOL allow)
888 /* I - Allow expired certs */
889{
890 conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID :
891 conn->certFlags & ~SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
892}
893
894
895/*
896 * '_sspiWrite()' - Write a buffer to an ssl socket
897 */
898int /* O - Bytes written or SOCKET_ERROR */
899_sspiWrite(_sspi_struct_t *conn, /* I - Client connection */
900 void *buf, /* I - Buffer */
901 size_t len) /* I - Buffer length */
902{
903 SecBufferDesc message; /* Array of SecBuffer struct */
904 SecBuffer buffers[4] = { 0 }; /* Security package buffer */
905 BYTE *buffer = NULL; /* Scratch buffer */
906 int bufferLen; /* Buffer length */
907 size_t bytesLeft; /* Bytes left to write */
908 int index = 0; /* Index into buffer */
909 int num = 0; /* Return value */
910
911 if (!conn || !buf || !len)
912 {
913 WSASetLastError(WSAEINVAL);
914 num = SOCKET_ERROR;
915 goto cleanup;
916 }
917
918 bufferLen = conn->streamSizes.cbMaximumMessage +
919 conn->streamSizes.cbHeader +
920 conn->streamSizes.cbTrailer;
921
922 buffer = (BYTE*) malloc(bufferLen);
923
924 if (!buffer)
925 {
926 DEBUG_printf(("_sspiWrite: buffer alloc of %d bytes failed", bufferLen));
927 WSASetLastError(E_OUTOFMEMORY);
928 num = SOCKET_ERROR;
929 goto cleanup;
930 }
931
932 bytesLeft = len;
933
934 while (bytesLeft)
935 {
936 size_t chunk = min(conn->streamSizes.cbMaximumMessage, /* Size of data to write */
937 bytesLeft);
938 SECURITY_STATUS scRet; /* SSPI status */
321d8d57 939
cc754834
MS
940 /*
941 * Copy user data into the buffer, starting
942 * just past the header
943 */
944 memcpy(buffer + conn->streamSizes.cbHeader,
945 ((BYTE*) buf) + index,
946 chunk);
947
948 /*
949 * Setup the SSPI buffers
950 */
951 message.ulVersion = SECBUFFER_VERSION;
952 message.cBuffers = 4;
953 message.pBuffers = buffers;
954 buffers[0].pvBuffer = buffer;
955 buffers[0].cbBuffer = conn->streamSizes.cbHeader;
956 buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
957 buffers[1].pvBuffer = buffer + conn->streamSizes.cbHeader;
958 buffers[1].cbBuffer = (unsigned long) chunk;
959 buffers[1].BufferType = SECBUFFER_DATA;
960 buffers[2].pvBuffer = buffer + conn->streamSizes.cbHeader + chunk;
961 buffers[2].cbBuffer = conn->streamSizes.cbTrailer;
962 buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
963 buffers[3].BufferType = SECBUFFER_EMPTY;
964
965 /*
966 * Encrypt the data
967 */
968 scRet = EncryptMessage(&conn->context, 0, &message, 0);
969
970 if (FAILED(scRet))
971 {
972 DEBUG_printf(("_sspiWrite: EncryptMessage failed: %x", scRet));
973 WSASetLastError(WSASYSCALLFAILURE);
974 num = SOCKET_ERROR;
975 goto cleanup;
976 }
977
978 /*
321d8d57 979 * Send the data. Remember the size of
cc754834
MS
980 * the total data to send is the size
981 * of the header, the size of the data
982 * the caller passed in and the size
983 * of the trailer
984 */
985 num = send(conn->sock,
986 buffer,
987 buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer,
988 0);
989
990 if ((num == SOCKET_ERROR) || (num == 0))
991 {
992 DEBUG_printf(("_sspiWrite: send failed: %ld", WSAGetLastError()));
993 goto cleanup;
994 }
321d8d57 995
cc754834
MS
996 bytesLeft -= (int) chunk;
997 index += (int) chunk;
998 }
999
1000 num = (int) len;
1001
1002cleanup:
1003
1004 if (buffer)
1005 free(buffer);
1006
1007 return (num);
1008}
1009
1010
1011/*
1012 * '_sspiRead()' - Read a buffer from an ssl socket
1013 */
1014int /* O - Bytes read or SOCKET_ERROR */
1015_sspiRead(_sspi_struct_t *conn, /* I - Client connection */
1016 void *buf, /* I - Buffer */
1017 size_t len) /* I - Buffer length */
1018{
1019 SecBufferDesc message; /* Array of SecBuffer struct */
1020 SecBuffer buffers[4] = { 0 }; /* Security package buffer */
1021 int num = 0; /* Return value */
1022
1023 if (!conn)
1024 {
1025 WSASetLastError(WSAEINVAL);
1026 num = SOCKET_ERROR;
1027 goto cleanup;
1028 }
1029
1030 /*
1031 * If there are bytes that have already been
1032 * decrypted and have not yet been read, return
1033 * those
1034 */
1035 if (buf && (conn->readBufferUsed > 0))
1036 {
1037 int bytesToCopy = (int) min(conn->readBufferUsed, len); /* Amount of bytes to copy */
1038 /* from read buffer */
1039
1040 memcpy(buf, conn->readBuffer, bytesToCopy);
1041 conn->readBufferUsed -= bytesToCopy;
1042
1043 if (conn->readBufferUsed > 0)
1044 /*
1045 * If the caller didn't request all the bytes
1046 * we have in the buffer, then move the unread
1047 * bytes down
1048 */
1049 memmove(conn->readBuffer,
1050 conn->readBuffer + bytesToCopy,
1051 conn->readBufferUsed);
1052
1053 num = bytesToCopy;
1054 }
1055 else
1056 {
1057 PSecBuffer pDataBuffer; /* Data buffer */
1058 PSecBuffer pExtraBuffer; /* Excess data buffer */
1059 SECURITY_STATUS scRet; /* SSPI status */
1060 int i; /* Loop control variable */
1061
1062 /*
1063 * Initialize security buffer structs
1064 */
1065 message.ulVersion = SECBUFFER_VERSION;
1066 message.cBuffers = 4;
1067 message.pBuffers = buffers;
1068
1069 do
1070 {
1071 /*
321d8d57 1072 * If there is not enough space in the
cc754834
MS
1073 * buffer, then increase it's size
1074 */
321d8d57 1075 if (conn->decryptBufferLength <= conn->decryptBufferUsed)
cc754834
MS
1076 {
1077 conn->decryptBufferLength += 4096;
321d8d57 1078 conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer,
cc754834
MS
1079 conn->decryptBufferLength);
1080
1081 if (!conn->decryptBuffer)
1082 {
1083 DEBUG_printf(("_sspiRead: unable to allocate %d byte buffer",
1084 conn->decryptBufferLength));
1085 WSASetLastError(E_OUTOFMEMORY);
1086 num = SOCKET_ERROR;
1087 goto cleanup;
1088 }
1089 }
1090
1091 buffers[0].pvBuffer = conn->decryptBuffer;
1092 buffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
1093 buffers[0].BufferType = SECBUFFER_DATA;
1094 buffers[1].BufferType = SECBUFFER_EMPTY;
1095 buffers[2].BufferType = SECBUFFER_EMPTY;
1096 buffers[3].BufferType = SECBUFFER_EMPTY;
1097
1098 scRet = DecryptMessage(&conn->context, &message, 0, NULL);
1099
1100 if (scRet == SEC_E_INCOMPLETE_MESSAGE)
1101 {
1102 if (buf)
1103 {
1104 num = recv(conn->sock,
1105 conn->decryptBuffer + conn->decryptBufferUsed,
1106 (int)(conn->decryptBufferLength - conn->decryptBufferUsed),
1107 0);
1108 if (num == SOCKET_ERROR)
1109 {
1110 DEBUG_printf(("_sspiRead: recv failed: %d", WSAGetLastError()));
1111 goto cleanup;
1112 }
1113 else if (num == 0)
1114 {
1115 DEBUG_printf(("_sspiRead: server disconnected"));
1116 goto cleanup;
1117 }
1118
1119 conn->decryptBufferUsed += num;
1120 }
1121 else
1122 {
1123 num = (int) conn->readBufferUsed;
1124 goto cleanup;
1125 }
1126 }
1127 }
1128 while (scRet == SEC_E_INCOMPLETE_MESSAGE);
1129
1130 if (scRet == SEC_I_CONTEXT_EXPIRED)
1131 {
1132 DEBUG_printf(("_sspiRead: context expired"));
1133 WSASetLastError(WSAECONNRESET);
1134 num = SOCKET_ERROR;
1135 goto cleanup;
1136 }
1137 else if (scRet != SEC_E_OK)
1138 {
1139 DEBUG_printf(("_sspiRead: DecryptMessage failed: %lx", scRet));
1140 WSASetLastError(WSASYSCALLFAILURE);
1141 num = SOCKET_ERROR;
1142 goto cleanup;
1143 }
1144
1145 /*
1146 * The decryption worked. Now, locate data buffer.
1147 */
1148 pDataBuffer = NULL;
1149 pExtraBuffer = NULL;
1150 for (i = 1; i < 4; i++)
1151 {
1152 if (buffers[i].BufferType == SECBUFFER_DATA)
1153 pDataBuffer = &buffers[i];
1154 else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA))
1155 pExtraBuffer = &buffers[i];
1156 }
1157
1158 /*
1159 * If a data buffer is found, then copy
1160 * the decrypted bytes to the passed-in
1161 * buffer
1162 */
1163 if (pDataBuffer)
1164 {
1165 int bytesToCopy = min(pDataBuffer->cbBuffer, (int) len);
1166 /* Number of bytes to copy into buf */
1167 int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy;
1168 /* Number of bytes to save in our read buffer */
1169
1170 if (bytesToCopy)
1171 memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy);
1172
1173 /*
1174 * If there are more decrypted bytes than can be
1175 * copied to the passed in buffer, then save them
1176 */
1177 if (bytesToSave)
1178 {
1179 if ((int)(conn->readBufferLength - conn->readBufferUsed) < bytesToSave)
1180 {
1181 conn->readBufferLength = conn->readBufferUsed + bytesToSave;
1182 conn->readBuffer = realloc(conn->readBuffer,
1183 conn->readBufferLength);
1184
1185 if (!conn->readBuffer)
1186 {
1187 DEBUG_printf(("_sspiRead: unable to allocate %d bytes", conn->readBufferLength));
1188 WSASetLastError(E_OUTOFMEMORY);
1189 num = SOCKET_ERROR;
1190 goto cleanup;
1191 }
1192 }
1193
1194 memcpy(((BYTE*) conn->readBuffer) + conn->readBufferUsed,
1195 ((BYTE*) pDataBuffer->pvBuffer) + bytesToCopy,
1196 bytesToSave);
1197
1198 conn->readBufferUsed += bytesToSave;
1199 }
1200
1201 num = (buf) ? bytesToCopy : (int) conn->readBufferUsed;
1202 }
1203 else
1204 {
1205 DEBUG_printf(("_sspiRead: unable to find data buffer"));
1206 WSASetLastError(WSASYSCALLFAILURE);
1207 num = SOCKET_ERROR;
1208 goto cleanup;
1209 }
1210
1211 /*
1212 * If the decryption process left extra bytes,
1213 * then save those back in decryptBuffer. They will
1214 * be processed the next time through the loop.
1215 */
321d8d57 1216 if (pExtraBuffer)
cc754834
MS
1217 {
1218 memmove(conn->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
1219 conn->decryptBufferUsed = pExtraBuffer->cbBuffer;
1220 }
1221 else
1222 {
1223 conn->decryptBufferUsed = 0;
1224 }
1225 }
1226
1227cleanup:
1228
1229 return (num);
1230}
1231
1232
1233/*
1234 * '_sspiPending()' - Returns the number of available bytes
1235 */
1236int /* O - Number of available bytes */
1237_sspiPending(_sspi_struct_t *conn) /* I - Client connection */
1238{
1239 return (_sspiRead(conn, NULL, 0));
1240}
1241
1242
1243/*
1244 * '_sspiFree()' - Close a connection and free resources
1245 */
1246void
1247_sspiFree(_sspi_struct_t *conn) /* I - Client connection */
1248{
1249 if (!conn)
1250 return;
1251
1252 if (conn->contextInitialized)
1253 {
1254 SecBufferDesc message; /* Array of SecBuffer struct */
1255 SecBuffer buffers[1] = { 0 };
1256 /* Security package buffer */
1257 DWORD dwType; /* Type */
1258 DWORD status; /* Status */
1259
321d8d57 1260 /*
cc754834
MS
1261 * Notify schannel that we are about to close the connection.
1262 */
1263 dwType = SCHANNEL_SHUTDOWN;
1264
1265 buffers[0].pvBuffer = &dwType;
1266 buffers[0].BufferType = SECBUFFER_TOKEN;
1267 buffers[0].cbBuffer = sizeof(dwType);
1268
1269 message.cBuffers = 1;
1270 message.pBuffers = buffers;
1271 message.ulVersion = SECBUFFER_VERSION;
1272
1273 status = ApplyControlToken(&conn->context, &message);
1274
321d8d57 1275 if (SUCCEEDED(status))
cc754834
MS
1276 {
1277 PBYTE pbMessage; /* Message buffer */
1278 DWORD cbMessage; /* Message buffer count */
1279 DWORD cbData; /* Data count */
1280 DWORD dwSSPIFlags; /* SSL attributes we requested */
1281 DWORD dwSSPIOutFlags; /* SSL attributes we received */
1282 TimeStamp tsExpiry; /* Time stamp */
1283
1284 dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
1285 ASC_REQ_REPLAY_DETECT |
1286 ASC_REQ_CONFIDENTIALITY |
1287 ASC_REQ_EXTENDED_ERROR |
1288 ASC_REQ_ALLOCATE_MEMORY |
1289 ASC_REQ_STREAM;
1290
1291 buffers[0].pvBuffer = NULL;
1292 buffers[0].BufferType = SECBUFFER_TOKEN;
1293 buffers[0].cbBuffer = 0;
1294
1295 message.cBuffers = 1;
1296 message.pBuffers = buffers;
1297 message.ulVersion = SECBUFFER_VERSION;
1298
1299 status = AcceptSecurityContext(&conn->creds, &conn->context, NULL,
1300 dwSSPIFlags, SECURITY_NATIVE_DREP, NULL,
1301 &message, &dwSSPIOutFlags, &tsExpiry);
1302
321d8d57 1303 if (SUCCEEDED(status))
cc754834
MS
1304 {
1305 pbMessage = buffers[0].pvBuffer;
1306 cbMessage = buffers[0].cbBuffer;
1307
1308 /*
1309 * Send the close notify message to the client.
1310 */
1311 if (pbMessage && cbMessage)
1312 {
1313 cbData = send(conn->sock, pbMessage, cbMessage, 0);
1314 if ((cbData == SOCKET_ERROR) || (cbData == 0))
1315 {
1316 status = WSAGetLastError();
1317 DEBUG_printf(("_sspiFree: sending close notify failed: %d", status));
1318 }
1319 else
1320 {
1321 FreeContextBuffer(pbMessage);
1322 }
1323 }
1324 }
1325 else
1326 {
1327 DEBUG_printf(("_sspiFree: AcceptSecurityContext failed: %x", status));
1328 }
1329 }
1330 else
1331 {
1332 DEBUG_printf(("_sspiFree: ApplyControlToken failed: %x", status));
1333 }
1334
1335 DeleteSecurityContext(&conn->context);
1336 conn->contextInitialized = FALSE;
1337 }
1338
1339 if (conn->decryptBuffer)
1340 {
1341 free(conn->decryptBuffer);
1342 conn->decryptBuffer = NULL;
1343 }
1344
1345 if (conn->readBuffer)
1346 {
1347 free(conn->readBuffer);
1348 conn->readBuffer = NULL;
1349 }
1350
1351 if (conn->sock != INVALID_SOCKET)
1352 {
1353 closesocket(conn->sock);
1354 conn->sock = INVALID_SOCKET;
1355 }
1356
1357 free(conn);
1358}
1359
1360
1361/*
1362 * 'sspi_verify_certificate()' - Verify a server certificate
1363 */
1364static DWORD /* 0 - Error code (0 == No error) */
1365sspi_verify_certificate(PCCERT_CONTEXT serverCert,
1366 /* I - Server certificate */
1367 const CHAR *serverName,
1368 /* I - Server name */
1369 DWORD dwCertFlags)
1370 /* I - Verification flags */
1371{
1372 HTTPSPolicyCallbackData httpsPolicy;
1373 /* HTTPS Policy Struct */
1374 CERT_CHAIN_POLICY_PARA policyPara;
1375 /* Cert chain policy parameters */
1376 CERT_CHAIN_POLICY_STATUS policyStatus;
1377 /* Cert chain policy status */
1378 CERT_CHAIN_PARA chainPara;
1379 /* Used for searching and matching criteria */
1380 PCCERT_CHAIN_CONTEXT chainContext = NULL;
1381 /* Certificate chain */
1382 PWSTR serverNameUnicode = NULL;
1383 /* Unicode server name */
1384 LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
1385 szOID_SERVER_GATED_CRYPTO,
1386 szOID_SGC_NETSCAPE };
1387 /* How are we using this certificate? */
1388 DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
1389 /* Number of ites in rgszUsages */
1390 DWORD count; /* 32 bit count variable */
1391 DWORD status; /* Return value */
1392
1393 if (!serverCert)
1394 {
1395 status = SEC_E_WRONG_PRINCIPAL;
1396 goto cleanup;
1397 }
1398
1399 /*
1400 * Convert server name to unicode.
1401 */
1402 if (!serverName || (strlen(serverName) == 0))
1403 {
1404 status = SEC_E_WRONG_PRINCIPAL;
1405 goto cleanup;
1406 }
1407
1408 count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, NULL, 0);
1409 serverNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR));
1410 if (!serverNameUnicode)
1411 {
1412 status = SEC_E_INSUFFICIENT_MEMORY;
1413 goto cleanup;
1414 }
1415 count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, serverNameUnicode, count);
1416 if (count == 0)
1417 {
1418 status = SEC_E_WRONG_PRINCIPAL;
1419 goto cleanup;
1420 }
1421
1422 /*
1423 * Build certificate chain.
1424 */
1425 ZeroMemory(&chainPara, sizeof(chainPara));
1426 chainPara.cbSize = sizeof(chainPara);
1427 chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
1428 chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
1429 chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
1430
1431 if (!CertGetCertificateChain(NULL, serverCert, NULL, serverCert->hCertStore,
1432 &chainPara, 0, NULL, &chainContext))
1433 {
1434 status = GetLastError();
1435 DEBUG_printf(("CertGetCertificateChain returned 0x%x\n", status));
1436 goto cleanup;
1437 }
1438
1439 /*
1440 * Validate certificate chain.
321d8d57 1441 */
cc754834
MS
1442 ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
1443 httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData);
1444 httpsPolicy.dwAuthType = AUTHTYPE_SERVER;
1445 httpsPolicy.fdwChecks = dwCertFlags;
1446 httpsPolicy.pwszServerName = serverNameUnicode;
1447
1448 memset(&policyPara, 0, sizeof(policyPara));
1449 policyPara.cbSize = sizeof(policyPara);
1450 policyPara.pvExtraPolicyPara = &httpsPolicy;
1451
1452 memset(&policyStatus, 0, sizeof(policyStatus));
1453 policyStatus.cbSize = sizeof(policyStatus);
1454
1455 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext,
1456 &policyPara, &policyStatus))
1457 {
1458 status = GetLastError();
1459 DEBUG_printf(("CertVerifyCertificateChainPolicy returned %d", status));
1460 goto cleanup;
1461 }
1462
1463 if (policyStatus.dwError)
1464 {
1465 status = policyStatus.dwError;
1466 goto cleanup;
1467 }
1468
1469 status = SEC_E_OK;
1470
1471cleanup:
1472
1473 if (chainContext)
1474 CertFreeCertificateChain(chainContext);
1475
1476 if (serverNameUnicode)
1477 LocalFree(serverNameUnicode);
1478
1479 return (status);
1480}
321d8d57
MS
1481
1482
1483/*
1484 * End of "$Id$".
1485 */