ReactOS 0.4.15-dev-8222-g9164419
schannel_wine.c
Go to the documentation of this file.
1/* Copyright (C) 2005 Juan Lang
2 * Copyright 2008 Henri Verbeet
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 *
18 * This file implements the schannel provider, or, the SSL/TLS implementations.
19 */
20
21#include "precomp.h"
22
23#include <wine/config.h>
24
26
27#if defined(SONAME_LIBGNUTLS) || defined (HAVE_SECURITY_SECURITY_H) || defined (SONAME_LIBMBEDTLS)
28
29#define SCHAN_INVALID_HANDLE ~0UL
30
31enum schan_handle_type
32{
33 SCHAN_HANDLE_CRED,
34 SCHAN_HANDLE_CTX,
35 SCHAN_HANDLE_FREE
36};
37
38struct schan_handle
39{
40 void *object;
41 enum schan_handle_type type;
42};
43
44struct schan_context
45{
47 ULONG req_ctx_attr;
48 const CERT_CONTEXT *cert;
49};
50
51static struct schan_handle *schan_handle_table;
52static struct schan_handle *schan_free_handles;
53static SIZE_T schan_handle_table_size;
54static SIZE_T schan_handle_count;
55
56/* Protocols enabled, only those may be used for the connection. */
57static DWORD config_enabled_protocols;
58
59/* Protocols disabled by default. They are enabled for using, but disabled when caller asks for default settings. */
60static DWORD config_default_disabled_protocols;
61
62static ULONG_PTR schan_alloc_handle(void *object, enum schan_handle_type type)
63{
64 struct schan_handle *handle;
65
66 if (schan_free_handles)
67 {
68 DWORD index = schan_free_handles - schan_handle_table;
69 /* Use a free handle */
70 handle = schan_free_handles;
71 if (handle->type != SCHAN_HANDLE_FREE)
72 {
73 ERR("Handle %d(%p) is in the free list, but has type %#x.\n", index, handle, handle->type);
74 return SCHAN_INVALID_HANDLE;
75 }
76 schan_free_handles = handle->object;
77 handle->object = object;
78 handle->type = type;
79
80 return index;
81 }
82 if (!(schan_handle_count < schan_handle_table_size))
83 {
84 /* Grow the table */
85 SIZE_T new_size = schan_handle_table_size + (schan_handle_table_size >> 1);
86 struct schan_handle *new_table = HeapReAlloc(GetProcessHeap(), 0, schan_handle_table, new_size * sizeof(*schan_handle_table));
87 if (!new_table)
88 {
89 ERR("Failed to grow the handle table\n");
90 return SCHAN_INVALID_HANDLE;
91 }
92 schan_handle_table = new_table;
93 schan_handle_table_size = new_size;
94 }
95
96 handle = &schan_handle_table[schan_handle_count++];
97 handle->object = object;
98 handle->type = type;
99
100 return handle - schan_handle_table;
101}
102
103static void *schan_free_handle(ULONG_PTR handle_idx, enum schan_handle_type type)
104{
105 struct schan_handle *handle;
106 void *object;
107
108 if (handle_idx == SCHAN_INVALID_HANDLE) return NULL;
109 if (handle_idx >= schan_handle_count) return NULL;
110 handle = &schan_handle_table[handle_idx];
111 if (handle->type != type)
112 {
113 ERR("Handle %ld(%p) is not of type %#x\n", handle_idx, handle, type);
114 return NULL;
115 }
116
117 object = handle->object;
118 handle->object = schan_free_handles;
119 handle->type = SCHAN_HANDLE_FREE;
120 schan_free_handles = handle;
121
122 return object;
123}
124
125static void *schan_get_object(ULONG_PTR handle_idx, enum schan_handle_type type)
126{
127 struct schan_handle *handle;
128
129 if (handle_idx == SCHAN_INVALID_HANDLE) return NULL;
130 if (handle_idx >= schan_handle_count) return NULL;
131 handle = &schan_handle_table[handle_idx];
132 if (handle->type != type)
133 {
134 ERR("Handle %ld(%p) is not of type %#x\n", handle_idx, handle, type);
135 return NULL;
136 }
137
138 return handle->object;
139}
140
141static void read_config(void)
142{
143 DWORD enabled = 0, default_disabled = 0;
144 HKEY protocols_key, key;
145 WCHAR subkey_name[64];
146 unsigned i;
147 DWORD res;
148
149 static BOOL config_read = FALSE;
150
151 static const WCHAR protocol_config_key_name[] = {
152 'S','Y','S','T','E','M','\\',
153 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
154 'C','o','n','t','r','o','l','\\',
155 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s','\\',
156 'S','C','H','A','N','N','E','L','\\',
157 'P','r','o','t','o','c','o','l','s',0 };
158
159 static const WCHAR clientW[] = {'\\','C','l','i','e','n','t',0};
160 static const WCHAR enabledW[] = {'e','n','a','b','l','e','d',0};
161 static const WCHAR disabledbydefaultW[] = {'D','i','s','a','b','l','e','d','B','y','D','e','f','a','u','l','t',0};
162
163 static const struct {
164 WCHAR key_name[20];
165 DWORD prot_client_flag;
166 BOOL enabled; /* If no config is present, enable the protocol */
167 BOOL disabled_by_default; /* Disable if caller asks for default protocol set */
168 } protocol_config_keys[] = {
169 {{'S','S','L',' ','2','.','0',0}, SP_PROT_SSL2_CLIENT, FALSE, TRUE}, /* NOTE: TRUE, TRUE on Windows */
170 {{'S','S','L',' ','3','.','0',0}, SP_PROT_SSL3_CLIENT, TRUE, FALSE},
171 {{'T','L','S',' ','1','.','0',0}, SP_PROT_TLS1_0_CLIENT, TRUE, FALSE},
172 {{'T','L','S',' ','1','.','1',0}, SP_PROT_TLS1_1_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ },
173 {{'T','L','S',' ','1','.','2',0}, SP_PROT_TLS1_2_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ }
174 };
175
176 /* No need for thread safety */
177 if(config_read)
178 return;
179
180 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, protocol_config_key_name, 0, KEY_READ, &protocols_key);
181 if(res == ERROR_SUCCESS) {
183
184 for(i=0; i < sizeof(protocol_config_keys)/sizeof(*protocol_config_keys); i++) {
185 strcpyW(subkey_name, protocol_config_keys[i].key_name);
186 strcatW(subkey_name, clientW);
187 res = RegOpenKeyExW(protocols_key, subkey_name, 0, KEY_READ, &key);
188 if(res != ERROR_SUCCESS) {
189 if(protocol_config_keys[i].enabled)
190 enabled |= protocol_config_keys[i].prot_client_flag;
191 if(protocol_config_keys[i].disabled_by_default)
192 default_disabled |= protocol_config_keys[i].prot_client_flag;
193 continue;
194 }
195
196 size = sizeof(value);
197 res = RegQueryValueExW(key, enabledW, NULL, &type, (BYTE*)&value, &size);
198 if(res == ERROR_SUCCESS) {
199 if(type == REG_DWORD && value)
200 enabled |= protocol_config_keys[i].prot_client_flag;
201 }else if(protocol_config_keys[i].enabled) {
202 enabled |= protocol_config_keys[i].prot_client_flag;
203 }
204
205 size = sizeof(value);
206 res = RegQueryValueExW(key, disabledbydefaultW, NULL, &type, (BYTE*)&value, &size);
207 if(res == ERROR_SUCCESS) {
208 if(type != REG_DWORD || value)
209 default_disabled |= protocol_config_keys[i].prot_client_flag;
210 }else if(protocol_config_keys[i].disabled_by_default) {
211 default_disabled |= protocol_config_keys[i].prot_client_flag;
212 }
213
215 }
216 }else {
217 /* No config, enable all known protocols. */
218 for(i=0; i < sizeof(protocol_config_keys)/sizeof(*protocol_config_keys); i++) {
219 if(protocol_config_keys[i].enabled)
220 enabled |= protocol_config_keys[i].prot_client_flag;
221 if(protocol_config_keys[i].disabled_by_default)
222 default_disabled |= protocol_config_keys[i].prot_client_flag;
223 }
224 }
225
226 RegCloseKey(protocols_key);
227
228 config_enabled_protocols = enabled & schan_imp_enabled_protocols();
229 config_default_disabled_protocols = default_disabled;
230 config_read = TRUE;
231
232 TRACE("enabled %x, disabled by default %x\n", config_enabled_protocols, config_default_disabled_protocols);
233}
234
235static SECURITY_STATUS schan_QueryCredentialsAttributes(
236 PCredHandle phCredential, ULONG ulAttribute, VOID *pBuffer)
237{
238 struct schan_credentials *cred;
240
241 cred = schan_get_object(phCredential->dwLower, SCHAN_HANDLE_CRED);
242 if(!cred)
244
245 switch (ulAttribute)
246 {
248 if (pBuffer)
249 {
250 /* FIXME: get from CryptoAPI */
251 FIXME("SECPKG_ATTR_SUPPORTED_ALGS: stub\n");
253 }
254 else
256 break;
258 if (pBuffer)
259 {
261
262 /* FIXME: get from CryptoAPI */
263 FIXME("SECPKG_ATTR_CIPHER_STRENGTHS: semi-stub\n");
264 r->dwMinimumCipherStrength = 40;
265 r->dwMaximumCipherStrength = 168;
266 ret = SEC_E_OK;
267 }
268 else
270 break;
272 if(pBuffer) {
273 /* Regardless of MSDN documentation, tests show that this attribute takes into account
274 * what protocols are enabled for given credential. */
276 ret = SEC_E_OK;
277 }else {
279 }
280 break;
281 default:
283 }
284 return ret;
285}
286
287static SECURITY_STATUS SEC_ENTRY schan_QueryCredentialsAttributesA(
288 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
289{
291
292 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
293
294 switch (ulAttribute)
295 {
297 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
299 break;
300 default:
301 ret = schan_QueryCredentialsAttributes(phCredential, ulAttribute,
302 pBuffer);
303 }
304 return ret;
305}
306
307SECURITY_STATUS SEC_ENTRY schan_QueryCredentialsAttributesW(
308 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
309{
311
312 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
313
314 switch (ulAttribute)
315 {
317 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
319 break;
320 default:
321 ret = schan_QueryCredentialsAttributes(phCredential, ulAttribute,
322 pBuffer);
323 }
324 return ret;
325}
326
327static SECURITY_STATUS schan_CheckCreds(const SCHANNEL_CRED *schanCred)
328{
330 DWORD i;
331
332 TRACE("dwVersion = %d\n", schanCred->dwVersion);
333 TRACE("cCreds = %d\n", schanCred->cCreds);
334 TRACE("hRootStore = %p\n", schanCred->hRootStore);
335 TRACE("cMappers = %d\n", schanCred->cMappers);
336 TRACE("cSupportedAlgs = %d:\n", schanCred->cSupportedAlgs);
337 for (i = 0; i < schanCred->cSupportedAlgs; i++)
338 TRACE("%08x\n", schanCred->palgSupportedAlgs[i]);
339 TRACE("grbitEnabledProtocols = %08x\n", schanCred->grbitEnabledProtocols);
340 TRACE("dwMinimumCipherStrength = %d\n", schanCred->dwMinimumCipherStrength);
341 TRACE("dwMaximumCipherStrength = %d\n", schanCred->dwMaximumCipherStrength);
342 TRACE("dwSessionLifespan = %d\n", schanCred->dwSessionLifespan);
343 TRACE("dwFlags = %08x\n", schanCred->dwFlags);
344 TRACE("dwCredFormat = %d\n", schanCred->dwCredFormat);
345
346 switch (schanCred->dwVersion)
347 {
348 case SCH_CRED_V3:
350 break;
351 default:
353 }
354
355 if (schanCred->cCreds == 0)
357 else if (schanCred->cCreds > 1)
359 else
360 {
361 DWORD keySpec;
362 HCRYPTPROV csp;
363 BOOL ret, freeCSP;
364
366 0, /* FIXME: what flags to use? */ NULL,
367 &csp, &keySpec, &freeCSP);
368 if (ret)
369 {
370 st = SEC_E_OK;
371 if (freeCSP)
372 CryptReleaseContext(csp, 0);
373 }
374 else
376 }
377 return st;
378}
379
380static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schanCred,
381 PCredHandle phCredential, PTimeStamp ptsExpiry)
382{
383 struct schan_credentials *creds;
384 unsigned enabled_protocols;
387
388 TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
389
390 if (schanCred)
391 {
392 st = schan_CheckCreds(schanCred);
393 if (st != SEC_E_OK && st != SEC_E_NO_CREDENTIALS)
394 return st;
395
396 st = SEC_E_OK;
397 }
398
399 read_config();
400 if(schanCred && schanCred->grbitEnabledProtocols)
401 enabled_protocols = schanCred->grbitEnabledProtocols & config_enabled_protocols;
402 else
403 enabled_protocols = config_enabled_protocols & ~config_default_disabled_protocols;
404 if(!enabled_protocols) {
405 ERR("Could not find matching protocol\n");
407 }
408
409 /* For now, the only thing I'm interested in is the direction of the
410 * connection, so just store it.
411 */
412 creds = HeapAlloc(GetProcessHeap(), 0, sizeof(*creds));
413 if (!creds) return SEC_E_INSUFFICIENT_MEMORY;
414
415 handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED);
416 if (handle == SCHAN_INVALID_HANDLE) goto fail;
417
420 {
421 schan_free_handle(handle, SCHAN_HANDLE_CRED);
422 goto fail;
423 }
424
426 phCredential->dwLower = handle;
427 phCredential->dwUpper = 0;
428
429 /* Outbound credentials have no expiry */
430 if (ptsExpiry)
431 {
432 ptsExpiry->LowPart = 0;
433 ptsExpiry->HighPart = 0;
434 }
435
436 return st;
437
438fail:
439 HeapFree(GetProcessHeap(), 0, creds);
441}
442
443static SECURITY_STATUS schan_AcquireServerCredentials(const SCHANNEL_CRED *schanCred,
444 PCredHandle phCredential, PTimeStamp ptsExpiry)
445{
447
448 TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
449
450 if (!schanCred) return SEC_E_NO_CREDENTIALS;
451
452 st = schan_CheckCreds(schanCred);
453 if (st == SEC_E_OK)
454 {
456 struct schan_credentials *creds;
457
458 creds = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*creds));
459 if (!creds) return SEC_E_INSUFFICIENT_MEMORY;
461
462 handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED);
463 if (handle == SCHAN_INVALID_HANDLE)
464 {
465 HeapFree(GetProcessHeap(), 0, creds);
467 }
468
469 phCredential->dwLower = handle;
470 phCredential->dwUpper = 0;
471
472 /* FIXME: get expiry from cert */
473 }
474 return st;
475}
476
477static SECURITY_STATUS schan_AcquireCredentialsHandle(ULONG fCredentialUse,
478 const SCHANNEL_CRED *schanCred, PCredHandle phCredential, PTimeStamp ptsExpiry)
479{
481
482 if (fCredentialUse == SECPKG_CRED_OUTBOUND)
483 ret = schan_AcquireClientCredentials(schanCred, phCredential,
484 ptsExpiry);
485 else
486 ret = schan_AcquireServerCredentials(schanCred, phCredential,
487 ptsExpiry);
488 return ret;
489}
490
491SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleA(
492 SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
493 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
494 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
495{
496 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
497 debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
498 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
499 return schan_AcquireCredentialsHandle(fCredentialUse,
500 pAuthData, phCredential, ptsExpiry);
501}
502
503SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleW(
504 SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
505 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
506 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
507{
508 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
509 debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
510 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
511 return schan_AcquireCredentialsHandle(fCredentialUse,
512 pAuthData, phCredential, ptsExpiry);
513}
514
515SECURITY_STATUS SEC_ENTRY schan_FreeCredentialsHandle(
516 PCredHandle phCredential)
517{
518 struct schan_credentials *creds;
519
520 TRACE("phCredential %p\n", phCredential);
521
522 if (!phCredential) return SEC_E_INVALID_HANDLE;
523
524 creds = schan_free_handle(phCredential->dwLower, SCHAN_HANDLE_CRED);
525 if (!creds) return SEC_E_INVALID_HANDLE;
526
529 HeapFree(GetProcessHeap(), 0, creds);
530
531 return SEC_E_OK;
532}
533
534static void init_schan_buffers(struct schan_buffers *s, const PSecBufferDesc desc,
535 int (*get_next_buffer)(const struct schan_transport *, struct schan_buffers *))
536{
537 s->offset = 0;
538 s->limit = ~0UL;
539 s->desc = desc;
540 s->current_buffer_idx = -1;
541 s->allow_buffer_resize = FALSE;
542 s->get_next_buffer = get_next_buffer;
543}
544
545static int schan_find_sec_buffer_idx(const SecBufferDesc *desc, unsigned int start_idx, ULONG buffer_type)
546{
547 unsigned int i;
549
550 for (i = start_idx; i < desc->cBuffers; ++i)
551 {
552 buffer = &desc->pBuffers[i];
553 if (buffer->BufferType == buffer_type) return i;
554 }
555
556 return -1;
557}
558
559static void schan_resize_current_buffer(const struct schan_buffers *s, SIZE_T min_size)
560{
561 SecBuffer *b = &s->desc->pBuffers[s->current_buffer_idx];
562 SIZE_T new_size = b->cbBuffer ? b->cbBuffer * 2 : 128;
563 void *new_data;
564
565 if (b->cbBuffer >= min_size || !s->allow_buffer_resize || min_size > UINT_MAX / 2) return;
566
567 while (new_size < min_size) new_size *= 2;
568
569 if (b->pvBuffer)
570 new_data = HeapReAlloc(GetProcessHeap(), 0, b->pvBuffer, new_size);
571 else
572 new_data = HeapAlloc(GetProcessHeap(), 0, new_size);
573
574 if (!new_data)
575 {
576 TRACE("Failed to resize %p from %d to %ld\n", b->pvBuffer, b->cbBuffer, new_size);
577 return;
578 }
579
580 b->cbBuffer = new_size;
581 b->pvBuffer = new_data;
582}
583
584char *schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count)
585{
586 SIZE_T max_count;
588
589 if (!s->desc)
590 {
591 TRACE("No desc\n");
592 return NULL;
593 }
594
595 if (s->current_buffer_idx == -1)
596 {
597 /* Initial buffer */
598 int buffer_idx = s->get_next_buffer(t, s);
599 if (buffer_idx == -1)
600 {
601 TRACE("No next buffer\n");
602 return NULL;
603 }
604 s->current_buffer_idx = buffer_idx;
605 }
606
607 buffer = &s->desc->pBuffers[s->current_buffer_idx];
608 TRACE("Using buffer %d: cbBuffer %d, BufferType %#x, pvBuffer %p\n", s->current_buffer_idx, buffer->cbBuffer, buffer->BufferType, buffer->pvBuffer);
609
610 schan_resize_current_buffer(s, s->offset + *count);
611 max_count = buffer->cbBuffer - s->offset;
612 if (s->limit != ~0UL && s->limit < max_count)
613 max_count = s->limit;
614 if (!max_count)
615 {
616 int buffer_idx;
617
618 s->allow_buffer_resize = FALSE;
619 buffer_idx = s->get_next_buffer(t, s);
620 if (buffer_idx == -1)
621 {
622 TRACE("No next buffer\n");
623 return NULL;
624 }
625 s->current_buffer_idx = buffer_idx;
626 s->offset = 0;
627 return schan_get_buffer(t, s, count);
628 }
629
630 if (*count > max_count)
631 *count = max_count;
632 if (s->limit != ~0UL)
633 s->limit -= *count;
634
635 return (char *)buffer->pvBuffer + s->offset;
636}
637
638/* schan_pull
639 * Read data from the transport input buffer.
640 *
641 * t - The session transport object.
642 * buff - The buffer into which to store the read data. Must be at least
643 * *buff_len bytes in length.
644 * buff_len - On input, *buff_len is the desired length to read. On successful
645 * return, *buff_len is the number of bytes actually read.
646 *
647 * Returns:
648 * 0 on success, in which case:
649 * *buff_len == 0 indicates end of file.
650 * *buff_len > 0 indicates that some data was read. May be less than
651 * what was requested, in which case the caller should call again if/
652 * when they want more.
653 * EAGAIN when no data could be read without blocking
654 * another errno-style error value on failure
655 *
656 */
657int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len)
658{
659 char *b;
660 SIZE_T local_len = *buff_len;
661
662 TRACE("Pull %lu bytes\n", local_len);
663
664 *buff_len = 0;
665
666 b = schan_get_buffer(t, &t->in, &local_len);
667 if (!b)
668 return EAGAIN;
669
670 memcpy(buff, b, local_len);
671 t->in.offset += local_len;
672
673 TRACE("Read %lu bytes\n", local_len);
674
675 *buff_len = local_len;
676 return 0;
677}
678
679/* schan_push
680 * Write data to the transport output buffer.
681 *
682 * t - The session transport object.
683 * buff - The buffer of data to write. Must be at least *buff_len bytes in length.
684 * buff_len - On input, *buff_len is the desired length to write. On successful
685 * return, *buff_len is the number of bytes actually written.
686 *
687 * Returns:
688 * 0 on success
689 * *buff_len will be > 0 indicating how much data was written. May be less
690 * than what was requested, in which case the caller should call again
691 if/when they want to write more.
692 * EAGAIN when no data could be written without blocking
693 * another errno-style error value on failure
694 *
695 */
696int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len)
697{
698 char *b;
699 SIZE_T local_len = *buff_len;
700
701 TRACE("Push %lu bytes\n", local_len);
702
703 *buff_len = 0;
704
705 b = schan_get_buffer(t, &t->out, &local_len);
706 if (!b)
707 return EAGAIN;
708
709 memcpy(b, buff, local_len);
710 t->out.offset += local_len;
711
712 TRACE("Wrote %lu bytes\n", local_len);
713
714 *buff_len = local_len;
715 return 0;
716}
717
719{
720 return t->ctx->session;
721}
722
723static int schan_init_sec_ctx_get_next_input_buffer(const struct schan_transport *t, struct schan_buffers *s)
724{
725 if (s->current_buffer_idx != -1)
726 return -1;
727 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
728}
729
730static int schan_init_sec_ctx_get_next_output_buffer(const struct schan_transport *t, struct schan_buffers *s)
731{
732 if (s->current_buffer_idx == -1)
733 {
734 int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
735 if (t->ctx->req_ctx_attr & ISC_REQ_ALLOCATE_MEMORY)
736 {
737 if (idx == -1)
738 {
739 idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_EMPTY);
740 if (idx != -1) s->desc->pBuffers[idx].BufferType = SECBUFFER_TOKEN;
741 }
742 if (idx != -1 && !s->desc->pBuffers[idx].pvBuffer)
743 {
744 s->desc->pBuffers[idx].cbBuffer = 0;
745 s->allow_buffer_resize = TRUE;
746 }
747 }
748 return idx;
749 }
750
751 return -1;
752}
753
754static void dump_buffer_desc(SecBufferDesc *desc)
755{
756 unsigned int i;
757
758 if (!desc) return;
759 TRACE("Buffer desc %p:\n", desc);
760 for (i = 0; i < desc->cBuffers; ++i)
761 {
762 SecBuffer *b = &desc->pBuffers[i];
763 TRACE("\tbuffer %u: cbBuffer %d, BufferType %#x pvBuffer %p\n", i, b->cbBuffer, b->BufferType, b->pvBuffer);
764 }
765}
766
767/***********************************************************************
768 * InitializeSecurityContextW
769 */
770SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
771 PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName,
772 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
773 PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
774 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
775{
776 struct schan_context *ctx;
777 struct schan_buffers *out_buffers;
778 struct schan_credentials *cred;
779 struct schan_transport transport;
780 SIZE_T expected_size = ~0UL;
782
783 TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext,
784 debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
785 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
786
787 dump_buffer_desc(pInput);
788 dump_buffer_desc(pOutput);
789
790 if (!phContext)
791 {
793
794 if (!phCredential) return SEC_E_INVALID_HANDLE;
795
796 cred = schan_get_object(phCredential->dwLower, SCHAN_HANDLE_CRED);
797 if (!cred) return SEC_E_INVALID_HANDLE;
798
800 {
801 WARN("Invalid credential use %#x\n", cred->credential_use);
803 }
804
805 ctx = HeapAlloc(GetProcessHeap(), 0, sizeof(*ctx));
806 if (!ctx) return SEC_E_INSUFFICIENT_MEMORY;
807
808 ctx->cert = NULL;
809 handle = schan_alloc_handle(ctx, SCHAN_HANDLE_CTX);
810 if (handle == SCHAN_INVALID_HANDLE)
811 {
814 }
815
816 if (!schan_imp_create_session(&ctx->session, cred))
817 {
818 schan_free_handle(handle, SCHAN_HANDLE_CTX);
821 }
822
823 if (pszTargetName)
824 {
825 UINT len = WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, NULL, 0, NULL, NULL );
826 char *target = HeapAlloc( GetProcessHeap(), 0, len );
827
828 if (target)
829 {
830 WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, target, len, NULL, NULL );
833 }
834 }
835 phNewContext->dwLower = handle;
836 phNewContext->dwUpper = 0;
837 }
838 else
839 {
840 SIZE_T record_size = 0;
841 unsigned char *ptr;
843 int idx;
844
845 if (!pInput)
847
848 idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_TOKEN);
849 if (idx == -1)
851
852 buffer = &pInput->pBuffers[idx];
853 ptr = buffer->pvBuffer;
854 expected_size = 0;
855
856 while (buffer->cbBuffer > expected_size + 5)
857 {
858 record_size = 5 + ((ptr[3] << 8) | ptr[4]);
859
860 if (buffer->cbBuffer < expected_size + record_size)
861 break;
862
863 expected_size += record_size;
864 ptr += record_size;
865 }
866
867 if (!expected_size)
868 {
869 TRACE("Expected at least %lu bytes, but buffer only contains %u bytes.\n",
870 max(6, record_size), buffer->cbBuffer);
872 }
873
874 TRACE("Using expected_size %lu.\n", expected_size);
875
876 ctx = schan_get_object(phContext->dwLower, SCHAN_HANDLE_CTX);
877 }
878
879 ctx->req_ctx_attr = fContextReq;
880
881 transport.ctx = ctx;
882 init_schan_buffers(&transport.in, pInput, schan_init_sec_ctx_get_next_input_buffer);
883 transport.in.limit = expected_size;
884 init_schan_buffers(&transport.out, pOutput, schan_init_sec_ctx_get_next_output_buffer);
885 schan_imp_set_session_transport(ctx->session, &transport);
886
887 /* Perform the TLS handshake */
888 ret = schan_imp_handshake(ctx->session);
889
890 if(transport.in.offset && transport.in.offset != pInput->pBuffers[0].cbBuffer) {
891 if(pInput->cBuffers<2 || pInput->pBuffers[1].BufferType!=SECBUFFER_EMPTY)
892 return SEC_E_INVALID_TOKEN;
893
894 pInput->pBuffers[1].BufferType = SECBUFFER_EXTRA;
895 pInput->pBuffers[1].cbBuffer = pInput->pBuffers[0].cbBuffer-transport.in.offset;
896 }
897
898 out_buffers = &transport.out;
899 if (out_buffers->current_buffer_idx != -1)
900 {
901 SecBuffer *buffer = &out_buffers->desc->pBuffers[out_buffers->current_buffer_idx];
902 buffer->cbBuffer = out_buffers->offset;
903 }
904
905 *pfContextAttr = 0;
906 if (ctx->req_ctx_attr & ISC_REQ_ALLOCATE_MEMORY)
907 *pfContextAttr |= ISC_RET_ALLOCATED_MEMORY;
908
909 return ret;
910}
911
912/***********************************************************************
913 * InitializeSecurityContextA
914 */
915SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextA(
916 PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName,
917 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
918 PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
919 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
920{
922 SEC_WCHAR *target_name = NULL;
923
924 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
925 debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
926 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
927
928 if (pszTargetName)
929 {
930 INT len = MultiByteToWideChar(CP_ACP, 0, pszTargetName, -1, NULL, 0);
931 target_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*target_name));
932 MultiByteToWideChar(CP_ACP, 0, pszTargetName, -1, target_name, len);
933 }
934
935 ret = schan_InitializeSecurityContextW(phCredential, phContext, target_name,
936 fContextReq, Reserved1, TargetDataRep, pInput, Reserved2,
937 phNewContext, pOutput, pfContextAttr, ptsExpiry);
938
939 HeapFree(GetProcessHeap(), 0, target_name);
940
941 return ret;
942}
943
944static
945SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
946 PCtxtHandle context_handle, ULONG attribute, PVOID buffer)
947{
948 struct schan_context *ctx;
949
950 TRACE("context_handle %p, attribute %#x, buffer %p\n",
951 context_handle, attribute, buffer);
952
953 if (!context_handle) return SEC_E_INVALID_HANDLE;
954 ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX);
955
956 switch(attribute)
957 {
959 {
962 if (status == SEC_E_OK)
963 {
964 SecPkgContext_StreamSizes *stream_sizes = buffer;
965 SIZE_T mac_size = info.dwHashStrength;
967 unsigned int message_size = schan_imp_get_max_message_size(ctx->session);
968
969 TRACE("Using %lu mac bytes, message size %u, block size %u\n",
970 mac_size, message_size, block_size);
971
972 /* These are defined by the TLS RFC */
973 stream_sizes->cbHeader = 5;
974 stream_sizes->cbTrailer = mac_size + 256; /* Max 255 bytes padding + 1 for padding size */
975 stream_sizes->cbMaximumMessage = message_size;
976 stream_sizes->cbBuffers = 4;
977 stream_sizes->cbBlockSize = block_size;
978 }
979
980 return status;
981 }
983 {
985
986 if (!ctx->cert) {
989
991 if(!cert_store)
992 return GetLastError();
993
996 if(status != SEC_E_OK)
997 return status;
998 }
999
1001 return SEC_E_OK;
1002 }
1004 {
1006 return schan_imp_get_connection_info(ctx->session, info);
1007 }
1008
1009 default:
1010 FIXME("Unhandled attribute %#x\n", attribute);
1012 }
1013}
1014
1015static
1016SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesA(
1017 PCtxtHandle context_handle, ULONG attribute, PVOID buffer)
1018{
1019 TRACE("context_handle %p, attribute %#x, buffer %p\n",
1020 context_handle, attribute, buffer);
1021
1022 switch(attribute)
1023 {
1025 return schan_QueryContextAttributesW(context_handle, attribute, buffer);
1027 return schan_QueryContextAttributesW(context_handle, attribute, buffer);
1029 return schan_QueryContextAttributesW(context_handle, attribute, buffer);
1030
1031 default:
1032 FIXME("Unhandled attribute %#x\n", attribute);
1034 }
1035}
1036
1037static int schan_encrypt_message_get_next_buffer(const struct schan_transport *t, struct schan_buffers *s)
1038{
1039 SecBuffer *b;
1040
1041 if (s->current_buffer_idx == -1)
1042 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_STREAM_HEADER);
1043
1044 b = &s->desc->pBuffers[s->current_buffer_idx];
1045
1046 if (b->BufferType == SECBUFFER_STREAM_HEADER)
1047 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
1048
1049 if (b->BufferType == SECBUFFER_DATA)
1050 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_STREAM_TRAILER);
1051
1052 return -1;
1053}
1054
1055static int schan_encrypt_message_get_next_buffer_token(const struct schan_transport *t, struct schan_buffers *s)
1056{
1057 SecBuffer *b;
1058
1059 if (s->current_buffer_idx == -1)
1060 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
1061
1062 b = &s->desc->pBuffers[s->current_buffer_idx];
1063
1064 if (b->BufferType == SECBUFFER_TOKEN)
1065 {
1066 int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
1067 if (idx != s->current_buffer_idx) return -1;
1068 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
1069 }
1070
1071 if (b->BufferType == SECBUFFER_DATA)
1072 {
1073 int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
1074 if (idx != -1)
1075 idx = schan_find_sec_buffer_idx(s->desc, idx + 1, SECBUFFER_TOKEN);
1076 return idx;
1077 }
1078
1079 return -1;
1080}
1081
1082static SECURITY_STATUS SEC_ENTRY schan_EncryptMessage(PCtxtHandle context_handle,
1083 ULONG quality, PSecBufferDesc message, ULONG message_seq_no)
1084{
1085 struct schan_transport transport;
1086 struct schan_context *ctx;
1087 struct schan_buffers *b;
1090 SIZE_T data_size;
1091 SIZE_T length;
1092 char *data;
1093 int idx;
1094
1095 TRACE("context_handle %p, quality %d, message %p, message_seq_no %d\n",
1096 context_handle, quality, message, message_seq_no);
1097
1098 if (!context_handle) return SEC_E_INVALID_HANDLE;
1099 ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX);
1100
1101 dump_buffer_desc(message);
1102
1103 idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_DATA);
1104 if (idx == -1)
1105 {
1106 WARN("No data buffer passed\n");
1107 return SEC_E_INTERNAL_ERROR;
1108 }
1109 buffer = &message->pBuffers[idx];
1110
1111 data_size = buffer->cbBuffer;
1112 data = HeapAlloc(GetProcessHeap(), 0, data_size);
1113 memcpy(data, buffer->pvBuffer, data_size);
1114
1115 transport.ctx = ctx;
1116 init_schan_buffers(&transport.in, NULL, NULL);
1117 if (schan_find_sec_buffer_idx(message, 0, SECBUFFER_STREAM_HEADER) != -1)
1118 init_schan_buffers(&transport.out, message, schan_encrypt_message_get_next_buffer);
1119 else
1120 init_schan_buffers(&transport.out, message, schan_encrypt_message_get_next_buffer_token);
1121 schan_imp_set_session_transport(ctx->session, &transport);
1122
1123 length = data_size;
1124 status = schan_imp_send(ctx->session, data, &length);
1125
1126 TRACE("Sent %ld bytes.\n", length);
1127
1128 if (length != data_size)
1130
1131 b = &transport.out;
1132 b->desc->pBuffers[b->current_buffer_idx].cbBuffer = b->offset;
1134
1135 TRACE("Returning %#x.\n", status);
1136
1137 return status;
1138}
1139
1140static int schan_decrypt_message_get_next_buffer(const struct schan_transport *t, struct schan_buffers *s)
1141{
1142 if (s->current_buffer_idx == -1)
1143 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
1144
1145 return -1;
1146}
1147
1148static int schan_validate_decrypt_buffer_desc(PSecBufferDesc message)
1149{
1150 int data_idx = -1;
1151 unsigned int empty_count = 0;
1152 unsigned int i;
1153
1154 if (message->cBuffers < 4)
1155 {
1156 WARN("Less than four buffers passed\n");
1157 return -1;
1158 }
1159
1160 for (i = 0; i < message->cBuffers; ++i)
1161 {
1162 SecBuffer *b = &message->pBuffers[i];
1163 if (b->BufferType == SECBUFFER_DATA)
1164 {
1165 if (data_idx != -1)
1166 {
1167 WARN("More than one data buffer passed\n");
1168 return -1;
1169 }
1170 data_idx = i;
1171 }
1172 else if (b->BufferType == SECBUFFER_EMPTY)
1173 ++empty_count;
1174 }
1175
1176 if (data_idx == -1)
1177 {
1178 WARN("No data buffer passed\n");
1179 return -1;
1180 }
1181
1182 if (empty_count < 3)
1183 {
1184 WARN("Less than three empty buffers passed\n");
1185 return -1;
1186 }
1187
1188 return data_idx;
1189}
1190
1191static void schan_decrypt_fill_buffer(PSecBufferDesc message, ULONG buffer_type, void *data, ULONG size)
1192{
1193 int idx;
1195
1196 idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_EMPTY);
1197 buffer = &message->pBuffers[idx];
1198
1199 buffer->BufferType = buffer_type;
1200 buffer->pvBuffer = data;
1201 buffer->cbBuffer = size;
1202}
1203
1204static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle,
1205 PSecBufferDesc message, ULONG message_seq_no, PULONG quality)
1206{
1207 struct schan_transport transport;
1208 struct schan_context *ctx;
1210 SIZE_T data_size;
1211 char *data;
1212 unsigned expected_size;
1213 SSIZE_T received = 0;
1214 int idx;
1215 unsigned char *buf_ptr;
1216
1217 TRACE("context_handle %p, message %p, message_seq_no %d, quality %p\n",
1218 context_handle, message, message_seq_no, quality);
1219
1220 if (!context_handle) return SEC_E_INVALID_HANDLE;
1221 ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX);
1222
1223 dump_buffer_desc(message);
1224
1225 idx = schan_validate_decrypt_buffer_desc(message);
1226 if (idx == -1)
1227 return SEC_E_INVALID_TOKEN;
1228 buffer = &message->pBuffers[idx];
1229 buf_ptr = buffer->pvBuffer;
1230
1231 expected_size = 5 + ((buf_ptr[3] << 8) | buf_ptr[4]);
1232 if(buffer->cbBuffer < expected_size)
1233 {
1234 TRACE("Expected %u bytes, but buffer only contains %u bytes\n", expected_size, buffer->cbBuffer);
1235 buffer->BufferType = SECBUFFER_MISSING;
1236 buffer->cbBuffer = expected_size - buffer->cbBuffer;
1237
1238 /* This is a bit weird, but windows does it too */
1239 idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_EMPTY);
1240 buffer = &message->pBuffers[idx];
1241 buffer->BufferType = SECBUFFER_MISSING;
1242 buffer->cbBuffer = expected_size - buffer->cbBuffer;
1243
1244 TRACE("Returning SEC_E_INCOMPLETE_MESSAGE\n");
1246 }
1247
1248 data_size = expected_size - 5;
1249 data = HeapAlloc(GetProcessHeap(), 0, data_size);
1250
1251 transport.ctx = ctx;
1252 init_schan_buffers(&transport.in, message, schan_decrypt_message_get_next_buffer);
1253 transport.in.limit = expected_size;
1254 init_schan_buffers(&transport.out, NULL, NULL);
1255 schan_imp_set_session_transport(ctx->session, &transport);
1256
1257 while (received < data_size)
1258 {
1259 SIZE_T length = data_size - received;
1261
1263 break;
1264
1265 if (status != SEC_E_OK)
1266 {
1268 ERR("Returning %x\n", status);
1269 return status;
1270 }
1271
1272 if (!length)
1273 break;
1274
1275 received += length;
1276 }
1277
1278 TRACE("Received %ld bytes\n", received);
1279
1280 memcpy(buf_ptr + 5, data, received);
1282
1283 schan_decrypt_fill_buffer(message, SECBUFFER_DATA,
1284 buf_ptr + 5, received);
1285
1286 schan_decrypt_fill_buffer(message, SECBUFFER_STREAM_TRAILER,
1287 buf_ptr + 5 + received, buffer->cbBuffer - 5 - received);
1288
1289 if(buffer->cbBuffer > expected_size)
1290 schan_decrypt_fill_buffer(message, SECBUFFER_EXTRA,
1291 buf_ptr + expected_size, buffer->cbBuffer - expected_size);
1292
1293 buffer->BufferType = SECBUFFER_STREAM_HEADER;
1294 buffer->cbBuffer = 5;
1295
1296 return SEC_E_OK;
1297}
1298
1299SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context_handle)
1300{
1301 struct schan_context *ctx;
1302
1303 TRACE("context_handle %p\n", context_handle);
1304
1305 if (!context_handle) return SEC_E_INVALID_HANDLE;
1306
1307 ctx = schan_free_handle(context_handle->dwLower, SCHAN_HANDLE_CTX);
1308 if (!ctx) return SEC_E_INVALID_HANDLE;
1309
1310 if (ctx->cert)
1314
1315 return SEC_E_OK;
1316}
1317
1319 1,
1321 schan_QueryCredentialsAttributesA,
1322 schan_AcquireCredentialsHandleA,
1323 schan_FreeCredentialsHandle,
1324 NULL, /* Reserved2 */
1325 schan_InitializeSecurityContextA,
1326 NULL, /* AcceptSecurityContext */
1327 NULL, /* CompleteAuthToken */
1328 schan_DeleteSecurityContext,
1329 NULL, /* ApplyControlToken */
1330 schan_QueryContextAttributesA,
1331 NULL, /* ImpersonateSecurityContext */
1332 NULL, /* RevertSecurityContext */
1333 NULL, /* MakeSignature */
1334 NULL, /* VerifySignature */
1336 NULL, /* QuerySecurityPackageInfoA */
1337 NULL, /* Reserved3 */
1338 NULL, /* Reserved4 */
1339 NULL, /* ExportSecurityContext */
1340 NULL, /* ImportSecurityContextA */
1341 NULL, /* AddCredentialsA */
1342 NULL, /* Reserved8 */
1343 NULL, /* QuerySecurityContextToken */
1344 schan_EncryptMessage,
1345 schan_DecryptMessage,
1346 NULL, /* SetContextAttributesA */
1347};
1348
1350 1,
1352 schan_QueryCredentialsAttributesW,
1353 schan_AcquireCredentialsHandleW,
1354 schan_FreeCredentialsHandle,
1355 NULL, /* Reserved2 */
1356 schan_InitializeSecurityContextW,
1357 NULL, /* AcceptSecurityContext */
1358 NULL, /* CompleteAuthToken */
1359 schan_DeleteSecurityContext,
1360 NULL, /* ApplyControlToken */
1361 schan_QueryContextAttributesW,
1362 NULL, /* ImpersonateSecurityContext */
1363 NULL, /* RevertSecurityContext */
1364 NULL, /* MakeSignature */
1365 NULL, /* VerifySignature */
1367 NULL, /* QuerySecurityPackageInfoW */
1368 NULL, /* Reserved3 */
1369 NULL, /* Reserved4 */
1370 NULL, /* ExportSecurityContext */
1371 NULL, /* ImportSecurityContextW */
1372 NULL, /* AddCredentialsW */
1373 NULL, /* Reserved8 */
1374 NULL, /* QuerySecurityContextToken */
1375 schan_EncryptMessage,
1376 schan_DecryptMessage,
1377 NULL, /* SetContextAttributesW */
1378};
1379
1380static const WCHAR schannelComment[] = { 'S','c','h','a','n','n','e','l',' ',
1381 'S','e','c','u','r','i','t','y',' ','P','a','c','k','a','g','e',0 };
1382static const WCHAR schannelDllName[] = { 's','c','h','a','n','n','e','l','.','d','l','l',0 };
1383
1384void SECUR32_initSchannelSP(void)
1385{
1386 /* This is what Windows reports. This shouldn't break any applications
1387 * even though the functions are missing, because the wrapper will
1388 * return SEC_E_UNSUPPORTED_FUNCTION if our function is NULL.
1389 */
1390 static const LONG caps =
1399 static const short version = 1;
1400 static const LONG maxToken = 16384;
1401 SEC_WCHAR *uniSPName = (SEC_WCHAR *)UNISP_NAME_W,
1402 *schannel = (SEC_WCHAR *)SCHANNEL_NAME_W;
1403 const SecPkgInfoW info[] = {
1404 { caps, version, UNISP_RPC_ID, maxToken, uniSPName, uniSPName },
1405 { caps, version, UNISP_RPC_ID, maxToken, schannel,
1406 (SEC_WCHAR *)schannelComment },
1407 };
1408 SecureProvider *provider;
1409
1410 if (!schan_imp_init())
1411 return;
1412
1413 schan_handle_table = HeapAlloc(GetProcessHeap(), 0, 64 * sizeof(*schan_handle_table));
1414 if (!schan_handle_table)
1415 {
1416 ERR("Failed to allocate schannel handle table.\n");
1417 goto fail;
1418 }
1419 schan_handle_table_size = 64;
1420
1421 provider = SECUR32_addProvider(&schanTableA, &schanTableW, schannelDllName);
1422 if (!provider)
1423 {
1424 ERR("Failed to add schannel provider.\n");
1425 goto fail;
1426 }
1427
1428 SECUR32_addPackages(provider, sizeof(info) / sizeof(info[0]), NULL, info);
1429
1430 return;
1431
1432fail:
1433 HeapFree(GetProcessHeap(), 0, schan_handle_table);
1434 schan_handle_table = NULL;
1436 return;
1437}
1438
1439void SECUR32_deinitSchannelSP(void)
1440{
1441 SIZE_T i = schan_handle_count;
1442
1443 if (!schan_handle_table) return;
1444
1445 /* deinitialized sessions first because a pointer to the credentials
1446 * may be stored for the session. */
1447 while (i--)
1448 {
1449 if (schan_handle_table[i].type == SCHAN_HANDLE_CTX)
1450 {
1451 struct schan_context *ctx = schan_free_handle(i, SCHAN_HANDLE_CTX);
1454 }
1455 }
1456 i = schan_handle_count;
1457 while (i--)
1458 {
1459 if (schan_handle_table[i].type != SCHAN_HANDLE_FREE)
1460 {
1461 struct schan_credentials *cred;
1462 cred = schan_free_handle(i, SCHAN_HANDLE_CRED);
1464 HeapFree(GetProcessHeap(), 0, cred);
1465 }
1466 }
1467 HeapFree(GetProcessHeap(), 0, schan_handle_table);
1469}
1470
1471#else /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H || SONAME_LIBMBEDTLS */
1472
1474{
1475 ERR("TLS library not found, SSL connections will fail\n");
1476}
1477
1479
1480#endif /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H || SONAME_LIBMBEDTLS */
#define EAGAIN
Definition: acclib.h:83
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define index(s, c)
Definition: various.h:29
LONG_PTR SSIZE_T
Definition: basetsd.h:181
@ Reserved2
Definition: bcd.h:202
@ Reserved1
Definition: bcd.h:201
#define FIXME(fmt,...)
Definition: debug.h:114
#define WARN(fmt,...)
Definition: debug.h:115
#define ERR(fmt,...)
Definition: debug.h:113
#define RegCloseKey(hKey)
Definition: registry.h:49
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned int idx
Definition: utils.c:41
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3333
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4103
BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags)
Definition: crypt.c:648
BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
Definition: cert.c:371
BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert, DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv, DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
Definition: cert.c:881
PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(PCCERT_CONTEXT pCertContext)
Definition: cert.c:360
HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType, HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void *pvPara)
Definition: store.c:815
BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
Definition: store.c:1127
#define CP_UNIXCP
Definition: compat.h:79
#define GetProcessHeap()
Definition: compat.h:736
#define CP_ACP
Definition: compat.h:109
#define HeapAlloc
Definition: compat.h:733
#define HeapReAlloc
Definition: compat.h:734
#define HeapFree(x, y, z)
Definition: compat.h:735
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
static const WCHAR version[]
Definition: asmname.c:66
#define SEC_ENTRY
Definition: stubs.c:6
r received
Definition: btrfs.c:3005
static unsigned char buff[32768]
Definition: fatten.c:17
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble GLdouble t
Definition: gl.h:2047
GLsizeiptr size
Definition: glext.h:5919
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition: glext.h:7750
GLuint res
Definition: glext.h:9613
GLuint buffer
Definition: glext.h:5915
GLuint index
Definition: glext.h:6031
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLenum GLsizei len
Definition: glext.h:6722
GLenum target
Definition: glext.h:7315
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define UINT_MAX
Definition: limits.h:41
int quality
Definition: jpeglib.h:992
static DWORD block_size(DWORD block)
Definition: jsutils.c:66
#define b
Definition: ke_i.h:79
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_w
Definition: kernel32.h:32
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static PVOID ptr
Definition: dispmode.c:27
static BYTE cert[]
Definition: msg.c:1437
static const WCHAR desc[]
Definition: protectdata.c:36
DWORD cert_store
Definition: store.c:344
unsigned int UINT
Definition: ndis.h:50
#define KEY_READ
Definition: nt_native.h:1023
PVOID *typedef PSecBuffer
Definition: ntsecpkg.h:440
long LONG
Definition: pedump.c:60
#define SECBUFFER_MISSING
Definition: sspi.h:163
LONG SECURITY_STATUS
Definition: sspi.h:34
#define ISC_REQ_ALLOCATE_MEMORY
Definition: sspi.h:370
#define SECPKG_FLAG_IMPERSONATION
Definition: sspi.h:134
#define SECPKG_CRED_OUTBOUND
Definition: sspi.h:291
#define SECPKG_FLAG_STREAM
Definition: sspi.h:136
#define SECBUFFER_STREAM_TRAILER
Definition: sspi.h:165
#define SECPKG_FLAG_EXTENDED_ERROR
Definition: sspi.h:133
#define SECBUFFER_STREAM_HEADER
Definition: sspi.h:166
#define SECBUFFER_TOKEN
Definition: sspi.h:161
#define SECPKG_CRED_ATTR_NAMES
Definition: sspi.h:246
#define ISC_RET_ALLOCATED_MEMORY
Definition: sspi.h:393
#define SECPKG_FLAG_PRIVACY
Definition: sspi.h:127
CHAR SEC_CHAR
Definition: sspi.h:30
#define SECPKG_FLAG_MULTI_REQUIRED
Definition: sspi.h:131
#define SECPKG_FLAG_CONNECTION
Definition: sspi.h:130
#define SECPKG_FLAG_INTEGRITY
Definition: sspi.h:126
void(SEC_ENTRY * SEC_GET_KEY_FN)(void *Arg, void *Principal, ULONG KeyVer, void **Key, SECURITY_STATUS *Status)
Definition: sspi.h:189
#define SECBUFFER_DATA
Definition: sspi.h:160
#define UNISP_NAME_W
Definition: sspi.h:38
#define SECPKG_CRED_INBOUND
Definition: sspi.h:290
#define SECBUFFER_EXTRA
Definition: sspi.h:164
#define SECPKG_FLAG_ACCEPT_WIN32_NAME
Definition: sspi.h:135
#define SECPKG_ATTR_STREAM_SIZES
Definition: sspi.h:525
WCHAR SEC_WCHAR
Definition: sspi.h:29
#define SECBUFFER_EMPTY
Definition: sspi.h:159
PVOID pBuffer
#define strcatW(d, s)
Definition: unicode.h:36
#define strcpyW(d, s)
Definition: unicode.h:35
#define UNISP_RPC_ID
Definition: schannel.h:82
#define SP_PROT_TLS1_1_CLIENT
Definition: schannel.h:33
#define SECPKG_ATTR_CONNECTION_INFO
Definition: schannel.h:76
#define SECPKG_ATTR_SUPPORTED_PROTOCOLS
Definition: schannel.h:74
#define SCHANNEL_CRED_VERSION
Definition: schannel.h:22
#define SCHANNEL_NAME_W
Definition: schannel.h:11
#define SECPKG_ATTR_CIPHER_STRENGTHS
Definition: schannel.h:73
#define SCH_CRED_V3
Definition: schannel.h:21
#define SP_PROT_TLS1_0_CLIENT
Definition: schannel.h:32
#define SECPKG_ATTR_SUPPORTED_ALGS
Definition: schannel.h:72
#define SP_PROT_TLS1_2_CLIENT
Definition: schannel.h:34
#define SP_PROT_SSL2_CLIENT
Definition: schannel.h:29
#define SP_PROT_SSL3_CLIENT
Definition: schannel.h:30
#define SECPKG_ATTR_REMOTE_CERT_CONTEXT
Definition: schannel.h:69
#define schan_imp_init
#define schan_imp_deinit
SECURITY_STATUS schan_imp_handshake(schan_imp_session session) DECLSPEC_HIDDEN
int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len) DECLSPEC_HIDDEN
struct schan_imp_session_opaque * schan_imp_session
Definition: schannel_priv.h:59
SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer, SIZE_T *length) DECLSPEC_HIDDEN
void schan_imp_set_session_transport(schan_imp_session session, struct schan_transport *t) DECLSPEC_HIDDEN
SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE, PCCERT_CONTEXT *cert) DECLSPEC_HIDDEN
SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, SIZE_T *length) DECLSPEC_HIDDEN
schan_imp_session schan_session_for_transport(struct schan_transport *t) DECLSPEC_HIDDEN
DWORD schan_imp_enabled_protocols(void) DECLSPEC_HIDDEN
SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesA(PULONG pcPackages, PSecPkgInfoA *ppPackageInfo)
Definition: secur32_wine.c:199
BOOL schan_imp_allocate_certificate_credentials(schan_credentials *) DECLSPEC_HIDDEN
unsigned int schan_imp_get_max_message_size(schan_imp_session session) DECLSPEC_HIDDEN
void schan_imp_free_certificate_credentials(schan_credentials *) DECLSPEC_HIDDEN
SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesW(PULONG pcPackages, PSecPkgInfoW *ppPackageInfo)
Definition: secur32_wine.c:58
SECURITY_STATUS WINAPI schan_FreeContextBuffer(PVOID pvoid)
Definition: secur32_wine.c:221
SecurityFunctionTableA schanTableA
int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len) DECLSPEC_HIDDEN
void schan_imp_set_session_target(schan_imp_session session, const char *target) DECLSPEC_HIDDEN
SecurityFunctionTableW schanTableW
void schan_imp_dispose_session(schan_imp_session session) DECLSPEC_HIDDEN
SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, SecPkgContext_ConnectionInfo *info) DECLSPEC_HIDDEN
SecureProvider * SECUR32_addProvider(const SecurityFunctionTableA *fnTableA, const SecurityFunctionTableW *fnTableW, PCWSTR moduleName) DECLSPEC_HIDDEN
Definition: secur32_wine.c:314
unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) DECLSPEC_HIDDEN
BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred) DECLSPEC_HIDDEN
void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd, const SecPkgInfoA *infoA, const SecPkgInfoW *infoW) DECLSPEC_HIDDEN
Definition: secur32_wine.c:362
char * schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count) DECLSPEC_HIDDEN
void SECUR32_initSchannelSP(void)
void SECUR32_deinitSchannelSP(void)
#define REG_DWORD
Definition: sdbapi.c:596
#define TRACE(s)
Definition: solgame.cpp:4
DWORD dwMaximumCipherStrength
Definition: schannel.h:98
DWORD dwFlags
Definition: schannel.h:100
DWORD dwSessionLifespan
Definition: schannel.h:99
ALG_ID * palgSupportedAlgs
Definition: schannel.h:95
DWORD cSupportedAlgs
Definition: schannel.h:94
HCERTSTORE hRootStore
Definition: schannel.h:91
DWORD dwMinimumCipherStrength
Definition: schannel.h:97
PCCERT_CONTEXT * paCred
Definition: schannel.h:90
DWORD dwCredFormat
Definition: schannel.h:101
DWORD dwVersion
Definition: schannel.h:88
DWORD cCreds
Definition: schannel.h:89
DWORD cMappers
Definition: schannel.h:92
DWORD grbitEnabledProtocols
Definition: schannel.h:96
ULONG LowPart
Definition: sspi.h:75
LONG HighPart
Definition: sspi.h:76
ULONG cBuffers
Definition: sspi.h:182
ULONG cbBuffer
Definition: sspi.h:153
ULONG_PTR dwLower
Definition: sspi.h:53
ULONG_PTR dwUpper
Definition: sspi.h:54
Definition: copy.c:22
Definition: tftpd.h:60
int current_buffer_idx
Definition: schannel_priv.h:75
const SecBufferDesc * desc
Definition: schannel_priv.h:74
struct schan_context * ctx
Definition: schannel_priv.h:82
Definition: ps.c:97
#define max(a, b)
Definition: svc.c:63
#define UL
Definition: tui.h:165
uint32_t * PULONG
Definition: typedefs.h:59
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
CONTEXT ctx
Definition: pdh_main.c:94
int ret
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
ULONG_PTR HCRYPTPROV
Definition: wincrypt.h:46
#define CERT_STORE_CREATE_NEW_FLAG
Definition: wincrypt.h:2464
#define CERT_STORE_PROV_MEMORY
Definition: wincrypt.h:2251
#define SEC_E_OK
Definition: winerror.h:2356
#define SEC_E_INVALID_HANDLE
Definition: winerror.h:2910
#define SEC_E_INTERNAL_ERROR
Definition: winerror.h:2913
#define SEC_E_UNKNOWN_CREDENTIALS
Definition: winerror.h:2922
#define SEC_E_NO_AUTHENTICATING_AUTHORITY
Definition: winerror.h:2926
#define SEC_E_UNSUPPORTED_FUNCTION
Definition: winerror.h:2911
#define SEC_E_INVALID_TOKEN
Definition: winerror.h:2917
#define SEC_E_NO_CREDENTIALS
Definition: winerror.h:2923
#define SEC_E_INSUFFICIENT_MEMORY
Definition: winerror.h:2909
#define SEC_I_CONTINUE_NEEDED
Definition: winerror.h:2927
#define SEC_E_INCOMPLETE_MESSAGE
Definition: winerror.h:2934
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193