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