dinput: Clear DIA_APPNOMAP BuildActionMap flag with specific device semantic.
[wine.git] / dlls / secur32 / schannel_gnutls.c
blob06d56fccee19ba87e82f2c67397700d9c7a33e03
1 /*
2 * GnuTLS-based implementation of the schannel (SSL/TLS) provider.
4 * Copyright 2005 Juan Lang
5 * Copyright 2008 Henri Verbeet
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #if 0
23 #pragma makedep unix
24 #endif
26 #include "config.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <dlfcn.h>
35 #ifdef SONAME_LIBGNUTLS
36 #include <gnutls/gnutls.h>
37 #include <gnutls/crypto.h>
38 #include <gnutls/abstract.h>
39 #endif
41 #include "ntstatus.h"
42 #define WIN32_NO_STATUS
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winternl.h"
46 #include "sspi.h"
47 #include "secur32_priv.h"
49 #include "wine/unixlib.h"
50 #include "wine/debug.h"
52 #if defined(SONAME_LIBGNUTLS)
54 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
55 WINE_DECLARE_DEBUG_CHANNEL(winediag);
57 static const char *system_priority_file;
59 /* Not present in gnutls version < 2.9.10. */
60 static int (*pgnutls_cipher_get_block_size)(gnutls_cipher_algorithm_t);
62 /* Not present in gnutls version < 3.0. */
63 static void (*pgnutls_transport_set_pull_timeout_function)(gnutls_session_t,
64 int (*)(gnutls_transport_ptr_t, unsigned int));
65 static void (*pgnutls_dtls_set_mtu)(gnutls_session_t, unsigned int);
66 static void (*pgnutls_dtls_set_timeouts)(gnutls_session_t, unsigned int, unsigned int);
68 /* Not present in gnutls version < 3.2.0. */
69 static int (*pgnutls_alpn_get_selected_protocol)(gnutls_session_t, gnutls_datum_t *);
70 static int (*pgnutls_alpn_set_protocols)(gnutls_session_t, const gnutls_datum_t *,
71 unsigned, unsigned int);
73 /* Not present in gnutls version < 3.3.0. */
74 static int (*pgnutls_privkey_import_rsa_raw)(gnutls_privkey_t, const gnutls_datum_t *,
75 const gnutls_datum_t *, const gnutls_datum_t *,
76 const gnutls_datum_t *, const gnutls_datum_t *,
77 const gnutls_datum_t *, const gnutls_datum_t *,
78 const gnutls_datum_t *);
80 /* Not present in gnutls version < 3.4.0. */
81 static int (*pgnutls_privkey_export_x509)(gnutls_privkey_t, gnutls_x509_privkey_t *);
83 static void *libgnutls_handle;
84 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
85 MAKE_FUNCPTR(gnutls_alert_get);
86 MAKE_FUNCPTR(gnutls_alert_get_name);
87 MAKE_FUNCPTR(gnutls_certificate_allocate_credentials);
88 MAKE_FUNCPTR(gnutls_certificate_free_credentials);
89 MAKE_FUNCPTR(gnutls_certificate_get_peers);
90 MAKE_FUNCPTR(gnutls_certificate_set_x509_key);
91 MAKE_FUNCPTR(gnutls_cipher_get);
92 MAKE_FUNCPTR(gnutls_cipher_get_key_size);
93 MAKE_FUNCPTR(gnutls_credentials_set);
94 MAKE_FUNCPTR(gnutls_deinit);
95 MAKE_FUNCPTR(gnutls_global_deinit);
96 MAKE_FUNCPTR(gnutls_global_init);
97 MAKE_FUNCPTR(gnutls_global_set_log_function);
98 MAKE_FUNCPTR(gnutls_global_set_log_level);
99 MAKE_FUNCPTR(gnutls_handshake);
100 MAKE_FUNCPTR(gnutls_init);
101 MAKE_FUNCPTR(gnutls_kx_get);
102 MAKE_FUNCPTR(gnutls_mac_get);
103 MAKE_FUNCPTR(gnutls_mac_get_key_size);
104 MAKE_FUNCPTR(gnutls_perror);
105 MAKE_FUNCPTR(gnutls_protocol_get_version);
106 MAKE_FUNCPTR(gnutls_priority_set_direct);
107 MAKE_FUNCPTR(gnutls_privkey_deinit);
108 MAKE_FUNCPTR(gnutls_privkey_init);
109 MAKE_FUNCPTR(gnutls_record_get_max_size);
110 MAKE_FUNCPTR(gnutls_record_recv);
111 MAKE_FUNCPTR(gnutls_record_send);
112 MAKE_FUNCPTR(gnutls_server_name_set);
113 MAKE_FUNCPTR(gnutls_session_channel_binding);
114 MAKE_FUNCPTR(gnutls_set_default_priority);
115 MAKE_FUNCPTR(gnutls_transport_get_ptr);
116 MAKE_FUNCPTR(gnutls_transport_set_errno);
117 MAKE_FUNCPTR(gnutls_transport_set_ptr);
118 MAKE_FUNCPTR(gnutls_transport_set_pull_function);
119 MAKE_FUNCPTR(gnutls_transport_set_push_function);
120 MAKE_FUNCPTR(gnutls_x509_crt_deinit);
121 MAKE_FUNCPTR(gnutls_x509_crt_import);
122 MAKE_FUNCPTR(gnutls_x509_crt_init);
123 MAKE_FUNCPTR(gnutls_x509_privkey_deinit);
124 MAKE_FUNCPTR(gnutls_alert_send);
125 #undef MAKE_FUNCPTR
127 #if GNUTLS_VERSION_MAJOR < 3
128 #define GNUTLS_CIPHER_AES_192_CBC 92
129 #define GNUTLS_CIPHER_AES_128_GCM 93
130 #define GNUTLS_CIPHER_AES_256_GCM 94
132 #define GNUTLS_MAC_AEAD 200
134 #define GNUTLS_KX_ANON_ECDH 11
135 #define GNUTLS_KX_ECDHE_RSA 12
136 #define GNUTLS_KX_ECDHE_ECDSA 13
137 #define GNUTLS_KX_ECDHE_PSK 14
138 #endif
140 #if GNUTLS_VERSION_MAJOR < 3 || (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR < 4)
141 #define GNUTLS_CIPHER_AES_128_CCM 19
142 #define GNUTLS_CIPHER_AES_256_CCM 20
143 #endif
145 #if GNUTLS_VERSION_MAJOR < 3 || (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR < 5)
146 #define GNUTLS_ALPN_SERVER_PRECEDENCE (1<<1)
147 #endif
149 static inline gnutls_session_t session_from_handle(UINT64 handle)
151 return (gnutls_session_t)(ULONG_PTR)handle;
154 static inline gnutls_certificate_credentials_t certificate_creds_from_handle(UINT64 handle)
156 return (gnutls_certificate_credentials_t)(ULONG_PTR)handle;
159 struct schan_buffers
161 SIZE_T offset;
162 SIZE_T limit;
163 const SecBufferDesc *desc;
164 int current_buffer_idx;
167 struct schan_transport
169 gnutls_session_t session;
170 struct schan_buffers in;
171 struct schan_buffers out;
174 static int compat_cipher_get_block_size(gnutls_cipher_algorithm_t cipher)
176 switch(cipher) {
177 case GNUTLS_CIPHER_3DES_CBC:
178 return 8;
179 case GNUTLS_CIPHER_AES_128_CBC:
180 case GNUTLS_CIPHER_AES_256_CBC:
181 return 16;
182 case GNUTLS_CIPHER_ARCFOUR_128:
183 case GNUTLS_CIPHER_ARCFOUR_40:
184 return 1;
185 case GNUTLS_CIPHER_DES_CBC:
186 return 8;
187 case GNUTLS_CIPHER_NULL:
188 return 1;
189 case GNUTLS_CIPHER_RC2_40_CBC:
190 return 8;
191 default:
192 FIXME("Unknown cipher %#x, returning 1\n", cipher);
193 return 1;
197 static void compat_gnutls_transport_set_pull_timeout_function(gnutls_session_t session,
198 int (*func)(gnutls_transport_ptr_t, unsigned int))
200 FIXME("\n");
203 static int compat_gnutls_privkey_export_x509(gnutls_privkey_t privkey, gnutls_x509_privkey_t *key)
205 FIXME("\n");
206 return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
209 static int compat_gnutls_privkey_import_rsa_raw(gnutls_privkey_t key, const gnutls_datum_t *p1,
210 const gnutls_datum_t *p2, const gnutls_datum_t *p3,
211 const gnutls_datum_t *p4, const gnutls_datum_t *p5,
212 const gnutls_datum_t *p6, const gnutls_datum_t *p7,
213 const gnutls_datum_t *p8)
215 FIXME("\n");
216 return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
219 static int compat_gnutls_alpn_get_selected_protocol(gnutls_session_t session, gnutls_datum_t *protocol)
221 FIXME("\n");
222 return GNUTLS_E_INVALID_REQUEST;
225 static int compat_gnutls_alpn_set_protocols(gnutls_session_t session, const gnutls_datum_t *protocols,
226 unsigned size, unsigned int flags)
228 FIXME("\n");
229 return GNUTLS_E_INVALID_REQUEST;
232 static void compat_gnutls_dtls_set_mtu(gnutls_session_t session, unsigned int mtu)
234 FIXME("\n");
237 static void compat_gnutls_dtls_set_timeouts(gnutls_session_t session, unsigned int retrans_timeout,
238 unsigned int total_timeout)
240 FIXME("\n");
243 static void init_schan_buffers(struct schan_buffers *s, const PSecBufferDesc desc)
245 s->offset = 0;
246 s->limit = ~0UL;
247 s->desc = desc;
248 s->current_buffer_idx = -1;
251 static int get_next_buffer(struct schan_buffers *s)
253 if (s->current_buffer_idx == -1)
254 return s->desc->cBuffers ? 0 : -1;
255 if (s->current_buffer_idx == s->desc->cBuffers - 1)
256 return -1;
257 return s->current_buffer_idx + 1;
260 static char *get_buffer(struct schan_buffers *s, SIZE_T *count)
262 SIZE_T max_count;
263 PSecBuffer buffer;
265 if (!s->desc)
267 TRACE("No desc\n");
268 return NULL;
271 if (s->current_buffer_idx == -1)
273 /* Initial buffer */
274 int buffer_idx = get_next_buffer(s);
275 if (buffer_idx == -1)
277 TRACE("No next buffer\n");
278 return NULL;
280 s->current_buffer_idx = buffer_idx;
283 buffer = &s->desc->pBuffers[s->current_buffer_idx];
284 TRACE("Using buffer %d: cbBuffer %d, BufferType %#x, pvBuffer %p\n",
285 s->current_buffer_idx, (unsigned)buffer->cbBuffer, (unsigned)buffer->BufferType, buffer->pvBuffer);
287 max_count = buffer->cbBuffer - s->offset;
288 if (s->limit != ~0UL && s->limit < max_count)
289 max_count = s->limit;
291 while (!max_count)
293 int buffer_idx;
295 buffer_idx = get_next_buffer(s);
296 if (buffer_idx == -1)
298 TRACE("No next buffer\n");
299 return NULL;
301 s->current_buffer_idx = buffer_idx;
302 s->offset = 0;
303 buffer = &s->desc->pBuffers[buffer_idx];
304 max_count = buffer->cbBuffer;
305 if (s->limit != ~0UL && s->limit < max_count)
306 max_count = s->limit;
309 if (*count > max_count)
310 *count = max_count;
311 if (s->limit != ~0UL)
312 s->limit -= *count;
314 return (char *)buffer->pvBuffer + s->offset;
317 static ssize_t pull_adapter(gnutls_transport_ptr_t transport, void *buff, size_t buff_len)
319 struct schan_transport *t = (struct schan_transport*)transport;
320 SIZE_T len = buff_len;
321 char *b;
323 TRACE("Pull %lu bytes\n", len);
325 b = get_buffer(&t->in, &len);
326 if (!b)
328 pgnutls_transport_set_errno(t->session, EAGAIN);
329 return -1;
331 memcpy(buff, b, len);
332 t->in.offset += len;
333 TRACE("Read %lu bytes\n", len);
334 return len;
337 static ssize_t push_adapter(gnutls_transport_ptr_t transport, const void *buff, size_t buff_len)
339 struct schan_transport *t = (struct schan_transport*)transport;
340 SIZE_T len = buff_len;
341 char *b;
343 TRACE("Push %lu bytes\n", len);
345 b = get_buffer(&t->out, &len);
346 if (!b)
348 pgnutls_transport_set_errno(t->session, EAGAIN);
349 return -1;
351 memcpy(b, buff, len);
352 t->out.offset += len;
353 TRACE("Wrote %lu bytes\n", len);
354 return len;
357 struct protocol_priority_flag {
358 DWORD enable_flag;
359 const char *gnutls_flag;
362 static const struct protocol_priority_flag client_protocol_priority_flags[] = {
363 {SP_PROT_DTLS1_2_CLIENT, "VERS-DTLS1.2"},
364 {SP_PROT_DTLS1_0_CLIENT, "VERS-DTLS1.0"},
365 {SP_PROT_TLS1_3_CLIENT, "VERS-TLS1.3"},
366 {SP_PROT_TLS1_2_CLIENT, "VERS-TLS1.2"},
367 {SP_PROT_TLS1_1_CLIENT, "VERS-TLS1.1"},
368 {SP_PROT_TLS1_0_CLIENT, "VERS-TLS1.0"},
369 {SP_PROT_SSL3_CLIENT, "VERS-SSL3.0"}
370 /* {SP_PROT_SSL2_CLIENT} is not supported by GnuTLS */
373 static const struct protocol_priority_flag server_protocol_priority_flags[] = {
374 {SP_PROT_DTLS1_2_SERVER, "VERS-DTLS1.2"},
375 {SP_PROT_DTLS1_0_SERVER, "VERS-DTLS1.0"},
376 {SP_PROT_TLS1_3_SERVER, "VERS-TLS1.3"},
377 {SP_PROT_TLS1_2_SERVER, "VERS-TLS1.2"},
378 {SP_PROT_TLS1_1_SERVER, "VERS-TLS1.1"},
379 {SP_PROT_TLS1_0_SERVER, "VERS-TLS1.0"},
380 {SP_PROT_SSL3_SERVER, "VERS-SSL3.0"}
381 /* {SP_PROT_SSL2_SERVER} is not supported by GnuTLS */
384 static DWORD supported_protocols;
386 static void check_supported_protocols(
387 const struct protocol_priority_flag *flags, int num_flags, BOOLEAN server)
389 const char *type_desc = server ? "server" : "client";
390 gnutls_session_t session;
391 char priority[64];
392 unsigned i;
393 int err;
395 err = pgnutls_init(&session, server ? GNUTLS_SERVER : GNUTLS_CLIENT);
396 if (err != GNUTLS_E_SUCCESS)
398 pgnutls_perror(err);
399 return;
402 for(i = 0; i < num_flags; i++)
404 sprintf(priority, "NORMAL:-%s", flags[i].gnutls_flag);
405 err = pgnutls_priority_set_direct(session, priority, NULL);
406 if (err == GNUTLS_E_SUCCESS)
408 TRACE("%s %s is supported\n", type_desc, flags[i].gnutls_flag);
409 supported_protocols |= flags[i].enable_flag;
411 else
412 TRACE("%s %s is not supported\n", type_desc, flags[i].gnutls_flag);
415 pgnutls_deinit(session);
418 static NTSTATUS schan_get_enabled_protocols( void *args )
420 return supported_protocols;
423 static int pull_timeout(gnutls_transport_ptr_t transport, unsigned int timeout)
425 struct schan_transport *t = (struct schan_transport*)transport;
426 SIZE_T count = 0;
428 TRACE("\n");
430 if (get_buffer(&t->in, &count)) return 1;
432 return 0;
435 static NTSTATUS set_priority(schan_credentials *cred, gnutls_session_t session)
437 char priority[128] = "NORMAL:%LATEST_RECORD_VERSION", *p;
438 BOOL server = !!(cred->credential_use & SECPKG_CRED_INBOUND);
439 const struct protocol_priority_flag *protocols =
440 server ? server_protocol_priority_flags : client_protocol_priority_flags;
441 int num_protocols = server ? ARRAYSIZE(server_protocol_priority_flags)
442 : ARRAYSIZE(client_protocol_priority_flags);
443 BOOL using_vers_all = FALSE, disabled;
444 int i, err;
446 if (system_priority_file && strcmp(system_priority_file, "/dev/null"))
448 TRACE("Using defaults with system priority file override\n");
449 err = pgnutls_set_default_priority(session);
450 if (err != GNUTLS_E_SUCCESS)
452 pgnutls_perror(err);
453 return STATUS_INTERNAL_ERROR;
455 return STATUS_SUCCESS;
458 p = priority + strlen(priority);
460 /* VERS-ALL is nice to use for forward compatibility. It was introduced before support for TLS1.3,
461 * so if TLS1.3 is supported, we may safely use it. Otherwise explicitly disable all known
462 * disabled protocols. */
463 if (supported_protocols & SP_PROT_TLS1_3_CLIENT)
465 strcpy(p, ":-VERS-ALL");
466 p += strlen(p);
467 using_vers_all = TRUE;
470 for (i = 0; i < num_protocols; i++)
472 if (!(supported_protocols & protocols[i].enable_flag)) continue;
474 disabled = !(cred->enabled_protocols & protocols[i].enable_flag);
475 if (using_vers_all && disabled) continue;
477 *p++ = ':';
478 *p++ = disabled ? '-' : '+';
479 strcpy(p, protocols[i].gnutls_flag);
480 p += strlen(p);
483 TRACE("Using %s priority\n", debugstr_a(priority));
484 err = pgnutls_priority_set_direct(session, priority, NULL);
485 if (err != GNUTLS_E_SUCCESS)
487 pgnutls_perror(err);
488 return STATUS_INTERNAL_ERROR;
491 return STATUS_SUCCESS;
494 static NTSTATUS schan_create_session( void *args )
496 const struct create_session_params *params = args;
497 schan_credentials *cred = params->cred;
498 unsigned int flags = (cred->credential_use == SECPKG_CRED_INBOUND) ? GNUTLS_SERVER : GNUTLS_CLIENT;
499 struct schan_transport *transport;
500 gnutls_session_t s;
501 NTSTATUS status;
502 int err;
504 *params->session = 0;
506 if (cred->enabled_protocols & SP_PROT_DTLS1_X)
508 flags |= GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
511 err = pgnutls_init(&s, flags);
512 if (err != GNUTLS_E_SUCCESS)
514 pgnutls_perror(err);
515 return STATUS_INTERNAL_ERROR;
518 if (!(transport = calloc(1, sizeof(*transport))))
520 pgnutls_deinit(s);
521 return STATUS_INTERNAL_ERROR;
523 transport->session = s;
525 if ((status = set_priority(cred, s)))
527 pgnutls_deinit(s);
528 free(transport);
529 return status;
532 err = pgnutls_credentials_set(s, GNUTLS_CRD_CERTIFICATE, certificate_creds_from_handle(cred->credentials));
533 if (err != GNUTLS_E_SUCCESS)
535 pgnutls_perror(err);
536 pgnutls_deinit(s);
537 free(transport);
538 return STATUS_INTERNAL_ERROR;
541 pgnutls_transport_set_pull_function(s, pull_adapter);
542 if (flags & GNUTLS_DATAGRAM) pgnutls_transport_set_pull_timeout_function(s, pull_timeout);
543 pgnutls_transport_set_push_function(s, push_adapter);
544 pgnutls_transport_set_ptr(s, (gnutls_transport_ptr_t)transport);
545 *params->session = (ULONG_PTR)s;
547 return STATUS_SUCCESS;
550 static NTSTATUS schan_dispose_session( void *args )
552 const struct session_params *params = args;
553 gnutls_session_t s = session_from_handle(params->session);
554 struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
555 pgnutls_transport_set_ptr(s, NULL);
556 pgnutls_deinit(s);
557 free(t);
558 return STATUS_SUCCESS;
561 static NTSTATUS schan_set_session_target( void *args )
563 const struct set_session_target_params *params = args;
564 gnutls_session_t s = session_from_handle(params->session);
565 pgnutls_server_name_set( s, GNUTLS_NAME_DNS, params->target, strlen(params->target) );
566 return STATUS_SUCCESS;
569 static NTSTATUS schan_handshake( void *args )
571 const struct handshake_params *params = args;
572 gnutls_session_t s = session_from_handle(params->session);
573 struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
574 NTSTATUS status;
575 int err;
577 init_schan_buffers(&t->in, params->input);
578 t->in.limit = params->input_size;
579 init_schan_buffers(&t->out, params->output);
581 if (params->control_token == control_token_shutdown)
583 err = pgnutls_alert_send(s, GNUTLS_AL_WARNING, GNUTLS_A_CLOSE_NOTIFY);
584 if (err == GNUTLS_E_SUCCESS)
586 status = SEC_E_OK;
588 else if (err == GNUTLS_E_AGAIN)
590 status = SEC_E_INVALID_TOKEN;
592 else
594 pgnutls_perror(err);
595 status = SEC_E_INTERNAL_ERROR;
597 goto done;
600 while (1)
602 err = pgnutls_handshake(s);
603 if (err == GNUTLS_E_SUCCESS)
605 TRACE("Handshake completed\n");
606 status = SEC_E_OK;
608 else if (err == GNUTLS_E_AGAIN)
610 TRACE("Continue...\n");
611 status = SEC_I_CONTINUE_NEEDED;
613 else if (err == GNUTLS_E_WARNING_ALERT_RECEIVED)
615 gnutls_alert_description_t alert = pgnutls_alert_get(s);
617 WARN("WARNING ALERT: %d %s\n", alert, pgnutls_alert_get_name(alert));
619 if (alert == GNUTLS_A_UNRECOGNIZED_NAME)
621 TRACE("Ignoring\n");
622 continue;
624 else
625 status = SEC_E_INTERNAL_ERROR;
627 else if (err == GNUTLS_E_FATAL_ALERT_RECEIVED)
629 gnutls_alert_description_t alert = pgnutls_alert_get(s);
630 WARN("FATAL ALERT: %d %s\n", alert, pgnutls_alert_get_name(alert));
631 status = SEC_E_INTERNAL_ERROR;
633 else
635 pgnutls_perror(err);
636 status = SEC_E_INTERNAL_ERROR;
638 break;
641 done:
642 *params->input_offset = t->in.offset;
643 *params->output_buffer_idx = t->out.current_buffer_idx;
644 *params->output_offset = t->out.offset;
646 return status;
649 static DWORD get_protocol(gnutls_protocol_t proto)
651 /* FIXME: currently schannel only implements client connections, but
652 * there's no reason it couldn't be used for servers as well. The
653 * context doesn't tell us which it is, so assume client for now.
655 switch (proto)
657 case GNUTLS_SSL3: return SP_PROT_SSL3_CLIENT;
658 case GNUTLS_TLS1_0: return SP_PROT_TLS1_0_CLIENT;
659 case GNUTLS_TLS1_1: return SP_PROT_TLS1_1_CLIENT;
660 case GNUTLS_TLS1_2: return SP_PROT_TLS1_2_CLIENT;
661 case GNUTLS_DTLS1_0: return SP_PROT_DTLS1_0_CLIENT;
662 case GNUTLS_DTLS1_2: return SP_PROT_DTLS1_2_CLIENT;
663 default:
664 FIXME("unknown protocol %d\n", proto);
665 return 0;
669 static ALG_ID get_cipher_algid(gnutls_cipher_algorithm_t cipher)
671 switch (cipher)
673 case GNUTLS_CIPHER_UNKNOWN:
674 case GNUTLS_CIPHER_NULL: return 0;
675 case GNUTLS_CIPHER_ARCFOUR_40:
676 case GNUTLS_CIPHER_ARCFOUR_128: return CALG_RC4;
677 case GNUTLS_CIPHER_DES_CBC: return CALG_DES;
678 case GNUTLS_CIPHER_3DES_CBC: return CALG_3DES;
679 case GNUTLS_CIPHER_AES_128_CBC:
680 case GNUTLS_CIPHER_AES_128_GCM: return CALG_AES_128;
681 case GNUTLS_CIPHER_AES_192_CBC: return CALG_AES_192;
682 case GNUTLS_CIPHER_AES_256_GCM:
683 case GNUTLS_CIPHER_AES_256_CBC: return CALG_AES_256;
684 case GNUTLS_CIPHER_RC2_40_CBC: return CALG_RC2;
685 default:
686 FIXME("unknown algorithm %d\n", cipher);
687 return 0;
691 static ALG_ID get_mac_algid(gnutls_mac_algorithm_t mac, gnutls_cipher_algorithm_t cipher)
693 switch (mac)
695 case GNUTLS_MAC_UNKNOWN:
696 case GNUTLS_MAC_NULL: return 0;
697 case GNUTLS_MAC_MD2: return CALG_MD2;
698 case GNUTLS_MAC_MD5: return CALG_MD5;
699 case GNUTLS_MAC_SHA1: return CALG_SHA1;
700 case GNUTLS_MAC_SHA256: return CALG_SHA_256;
701 case GNUTLS_MAC_SHA384: return CALG_SHA_384;
702 case GNUTLS_MAC_SHA512: return CALG_SHA_512;
703 case GNUTLS_MAC_AEAD:
704 /* When using AEAD (such as GCM), we return PRF algorithm instead
705 which is defined in RFC 5289. */
706 switch (cipher)
708 case GNUTLS_CIPHER_AES_128_GCM: return CALG_SHA_256;
709 case GNUTLS_CIPHER_AES_256_GCM: return CALG_SHA_384;
710 default:
711 break;
713 /* fall through */
714 default:
715 FIXME("unknown algorithm %d, cipher %d\n", mac, cipher);
716 return 0;
720 static ALG_ID get_kx_algid(int kx)
722 switch (kx)
724 case GNUTLS_KX_UNKNOWN: return 0;
725 case GNUTLS_KX_RSA:
726 case GNUTLS_KX_RSA_EXPORT: return CALG_RSA_KEYX;
727 case GNUTLS_KX_DHE_PSK:
728 case GNUTLS_KX_DHE_DSS:
729 case GNUTLS_KX_DHE_RSA: return CALG_DH_EPHEM;
730 case GNUTLS_KX_ANON_ECDH: return CALG_ECDH;
731 case GNUTLS_KX_ECDHE_RSA:
732 case GNUTLS_KX_ECDHE_PSK:
733 case GNUTLS_KX_ECDHE_ECDSA: return CALG_ECDH_EPHEM;
734 default:
735 FIXME("unknown algorithm %d\n", kx);
736 return 0;
740 static NTSTATUS schan_get_session_cipher_block_size( void *args )
742 const struct session_params *params = args;
743 gnutls_session_t s = session_from_handle(params->session);
744 return pgnutls_cipher_get_block_size(pgnutls_cipher_get(s));
747 static NTSTATUS schan_get_max_message_size( void *args )
749 const struct session_params *params = args;
750 gnutls_session_t s = session_from_handle(params->session);
751 return pgnutls_record_get_max_size(s);
754 static NTSTATUS schan_get_connection_info( void *args )
756 const struct get_connection_info_params *params = args;
757 gnutls_session_t s = session_from_handle(params->session);
758 SecPkgContext_ConnectionInfo *info = params->info;
759 gnutls_protocol_t proto = pgnutls_protocol_get_version(s);
760 gnutls_cipher_algorithm_t alg = pgnutls_cipher_get(s);
761 gnutls_mac_algorithm_t mac = pgnutls_mac_get(s);
762 gnutls_kx_algorithm_t kx = pgnutls_kx_get(s);
764 info->dwProtocol = get_protocol(proto);
765 info->aiCipher = get_cipher_algid(alg);
766 info->dwCipherStrength = pgnutls_cipher_get_key_size(alg) * 8;
767 info->aiHash = get_mac_algid(mac, alg);
768 info->dwHashStrength = pgnutls_mac_get_key_size(mac) * 8;
769 info->aiExch = get_kx_algid(kx);
770 /* FIXME: info->dwExchStrength? */
771 info->dwExchStrength = 0;
772 return SEC_E_OK;
775 static DWORD get_protocol_version( gnutls_session_t session )
777 gnutls_protocol_t proto = pgnutls_protocol_get_version( session );
779 switch (proto)
781 case GNUTLS_SSL3: return 0x300;
782 case GNUTLS_TLS1_0: return 0x301;
783 case GNUTLS_TLS1_1: return 0x302;
784 case GNUTLS_TLS1_2: return 0x303;
785 case GNUTLS_DTLS1_0: return 0x201;
786 case GNUTLS_DTLS1_2: return 0x202;
787 default:
788 FIXME( "unknown protocol %u\n", proto );
789 return 0;
793 static const WCHAR *get_cipher_str( gnutls_session_t session )
795 static const WCHAR aesW[] = {'A','E','S',0};
796 static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
797 gnutls_cipher_algorithm_t cipher = pgnutls_cipher_get( session );
799 switch (cipher)
801 case GNUTLS_CIPHER_AES_128_CBC:
802 case GNUTLS_CIPHER_AES_192_CBC:
803 case GNUTLS_CIPHER_AES_256_CBC:
804 case GNUTLS_CIPHER_AES_128_GCM:
805 case GNUTLS_CIPHER_AES_256_GCM:
806 case GNUTLS_CIPHER_AES_128_CCM:
807 case GNUTLS_CIPHER_AES_256_CCM:
808 return aesW;
809 default:
810 FIXME( "unknown cipher %u\n", cipher );
811 return unknownW;
815 static DWORD get_cipher_len( gnutls_session_t session )
817 gnutls_cipher_algorithm_t cipher = pgnutls_cipher_get( session );
819 switch (cipher)
821 case GNUTLS_CIPHER_AES_128_CBC:
822 case GNUTLS_CIPHER_AES_128_GCM:
823 case GNUTLS_CIPHER_AES_128_CCM:
824 return 128;
825 case GNUTLS_CIPHER_AES_192_CBC:
826 return 192;
827 case GNUTLS_CIPHER_AES_256_CBC:
828 case GNUTLS_CIPHER_AES_256_GCM:
829 case GNUTLS_CIPHER_AES_256_CCM:
830 return 256;
831 default:
832 FIXME( "unknown cipher %u\n", cipher );
833 return 0;
837 static DWORD get_cipher_block_len( gnutls_session_t session )
839 gnutls_cipher_algorithm_t cipher = pgnutls_cipher_get( session );
840 return pgnutls_cipher_get_block_size( cipher );
843 static const WCHAR *get_hash_str( gnutls_session_t session, BOOL full )
845 static const WCHAR shaW[] = {'S','H','A',0};
846 static const WCHAR sha1W[] = {'S','H','A','1',0};
847 static const WCHAR sha224W[] = {'S','H','A','2','2','4',0};
848 static const WCHAR sha256W[] = {'S','H','A','2','5','6',0};
849 static const WCHAR sha384W[] = {'S','H','A','3','8','4',0};
850 static const WCHAR sha512W[] = {'S','H','A','5','1','2',0};
851 static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
852 gnutls_mac_algorithm_t mac = pgnutls_mac_get( session );
854 switch (mac)
856 case GNUTLS_MAC_SHA1: return full ? sha1W : shaW;
857 case GNUTLS_MAC_SHA224: return sha224W;
858 case GNUTLS_MAC_SHA256: return sha256W;
859 case GNUTLS_MAC_SHA384: return sha384W;
860 case GNUTLS_MAC_SHA512: return sha512W;
861 default:
862 FIXME( "unknown mac %u\n", mac );
863 return unknownW;
867 static DWORD get_hash_len( gnutls_session_t session )
869 gnutls_mac_algorithm_t mac = pgnutls_mac_get( session );
870 return pgnutls_mac_get_key_size( mac ) * 8;
873 static const WCHAR *get_exchange_str( gnutls_session_t session, BOOL full )
875 static const WCHAR ecdhW[] = {'E','C','D','H',0};
876 static const WCHAR ecdheW[] = {'E','C','D','H','E',0};
877 static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
878 gnutls_kx_algorithm_t kx = pgnutls_kx_get( session );
880 switch (kx)
882 case GNUTLS_KX_ECDHE_RSA:
883 case GNUTLS_KX_ECDHE_ECDSA:
884 return full ? ecdheW : ecdhW;
885 default:
886 FIXME( "unknown kx %u\n", kx );
887 return unknownW;
891 static const WCHAR *get_certificate_str( gnutls_session_t session )
893 static const WCHAR rsaW[] = {'R','S','A',0};
894 static const WCHAR ecdsaW[] = {'E','C','D','S','A',0};
895 static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
896 gnutls_kx_algorithm_t kx = pgnutls_kx_get( session );
898 switch (kx)
900 case GNUTLS_KX_RSA:
901 case GNUTLS_KX_RSA_EXPORT:
902 case GNUTLS_KX_DHE_RSA:
903 case GNUTLS_KX_ECDHE_RSA: return rsaW;
904 case GNUTLS_KX_ECDHE_ECDSA: return ecdsaW;
905 default:
906 FIXME( "unknown kx %u\n", kx );
907 return unknownW;
911 static const WCHAR *get_chaining_mode_str( gnutls_session_t session )
913 static const WCHAR cbcW[] = {'C','B','C',0};
914 static const WCHAR ccmW[] = {'C','C','M',0};
915 static const WCHAR gcmW[] = {'G','C','M',0};
916 static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
917 gnutls_cipher_algorithm_t cipher = pgnutls_cipher_get( session );
919 switch (cipher)
921 case GNUTLS_CIPHER_AES_128_CBC:
922 case GNUTLS_CIPHER_AES_192_CBC:
923 case GNUTLS_CIPHER_AES_256_CBC:
924 return cbcW;
925 case GNUTLS_CIPHER_AES_128_GCM:
926 case GNUTLS_CIPHER_AES_256_GCM:
927 return gcmW;
928 case GNUTLS_CIPHER_AES_128_CCM:
929 case GNUTLS_CIPHER_AES_256_CCM:
930 return ccmW;
931 default:
932 FIXME( "unknown cipher %u\n", cipher );
933 return unknownW;
937 static NTSTATUS schan_get_cipher_info( void *args )
939 const WCHAR tlsW[] = {'T','L','S','_',0};
940 const WCHAR underscoreW[] = {'_',0};
941 const WCHAR widthW[] = {'_','W','I','T','H','_',0};
942 const struct get_cipher_info_params *params = args;
943 gnutls_session_t session = session_from_handle( params->session );
944 SecPkgContext_CipherInfo *info = params->info;
945 char buf[11];
946 WCHAR *ptr;
947 int len;
949 info->dwProtocol = get_protocol_version( session );
950 info->dwCipherSuite = 0; /* FIXME */
951 info->dwBaseCipherSuite = 0; /* FIXME */
952 wcscpy( info->szCipher, get_cipher_str( session ) );
953 info->dwCipherLen = get_cipher_len( session );
954 info->dwCipherBlockLen = get_cipher_block_len( session );
955 wcscpy( info->szHash, get_hash_str( session, TRUE ) );
956 info->dwHashLen = get_hash_len( session );
957 wcscpy( info->szExchange, get_exchange_str( session, FALSE ) );
958 info->dwMinExchangeLen = 0;
959 info->dwMaxExchangeLen = 65536;
960 wcscpy( info->szCertificate, get_certificate_str( session ) );
961 info->dwKeyType = 0; /* FIXME */
963 wcscpy( info->szCipherSuite, tlsW );
964 wcscat( info->szCipherSuite, get_exchange_str( session, TRUE ) );
965 wcscat( info->szCipherSuite, underscoreW );
966 wcscat( info->szCipherSuite, info->szCertificate );
967 wcscat( info->szCipherSuite, widthW );
968 wcscat( info->szCipherSuite, info->szCipher );
969 wcscat( info->szCipherSuite, underscoreW );
970 len = sprintf( buf, "%u", (unsigned int)info->dwCipherLen ) + 1;
971 ptr = info->szCipherSuite + wcslen( info->szCipherSuite );
972 ntdll_umbstowcs( buf, len, ptr, len );
973 wcscat( info->szCipherSuite, underscoreW );
974 wcscat( info->szCipherSuite, get_chaining_mode_str( session ) );
975 wcscat( info->szCipherSuite, underscoreW );
976 wcscat( info->szCipherSuite, get_hash_str( session, FALSE ) );
977 return SEC_E_OK;
980 static NTSTATUS schan_get_unique_channel_binding( void *args )
982 const struct get_unique_channel_binding_params *params = args;
983 gnutls_session_t s = session_from_handle(params->session);
984 gnutls_datum_t datum;
985 int rc;
986 SECURITY_STATUS ret;
988 rc = pgnutls_session_channel_binding(s, GNUTLS_CB_TLS_UNIQUE, &datum);
989 if (rc)
991 pgnutls_perror(rc);
992 return SEC_E_INTERNAL_ERROR;
994 if (params->buffer && *params->bufsize >= datum.size)
996 memcpy( params->buffer, datum.data, datum.size );
997 ret = SEC_E_OK;
999 else ret = SEC_E_BUFFER_TOO_SMALL;
1001 *params->bufsize = datum.size;
1002 free(datum.data);
1003 return ret;
1006 static NTSTATUS schan_get_key_signature_algorithm( void *args )
1008 const struct session_params *params = args;
1009 gnutls_session_t s = session_from_handle(params->session);
1010 gnutls_kx_algorithm_t kx = pgnutls_kx_get(s);
1012 TRACE("(%p)\n", s);
1014 switch (kx)
1016 case GNUTLS_KX_UNKNOWN: return 0;
1017 case GNUTLS_KX_RSA:
1018 case GNUTLS_KX_RSA_EXPORT:
1019 case GNUTLS_KX_DHE_RSA:
1020 case GNUTLS_KX_ECDHE_RSA: return CALG_RSA_SIGN;
1021 case GNUTLS_KX_ECDHE_ECDSA: return CALG_ECDSA;
1022 default:
1023 FIXME("unknown algorithm %d\n", kx);
1024 return 0;
1028 static NTSTATUS schan_get_session_peer_certificate( void *args )
1030 const struct get_session_peer_certificate_params *params = args;
1031 gnutls_session_t s = session_from_handle(params->session);
1032 const gnutls_datum_t *datum;
1033 unsigned int i, size;
1034 BYTE *ptr;
1035 unsigned int count;
1036 ULONG *sizes;
1038 if (!(datum = pgnutls_certificate_get_peers(s, &count))) return SEC_E_INTERNAL_ERROR;
1040 size = count * sizeof(*sizes);
1041 for (i = 0; i < count; i++) size += datum[i].size;
1043 if (!params->buffer || *params->bufsize < size)
1045 *params->bufsize = size;
1046 return SEC_E_BUFFER_TOO_SMALL;
1048 sizes = (ULONG *)params->buffer;
1049 ptr = params->buffer + count * sizeof(*sizes);
1050 for (i = 0; i < count; i++)
1052 sizes[i] = datum[i].size;
1053 memcpy(ptr, datum[i].data, datum[i].size);
1054 ptr += datum[i].size;
1057 *params->bufsize = size;
1058 *params->retcount = count;
1059 return SEC_E_OK;
1062 static NTSTATUS schan_send( void *args )
1064 const struct send_params *params = args;
1065 gnutls_session_t s = session_from_handle(params->session);
1066 struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
1067 SSIZE_T ret, total = 0;
1069 init_schan_buffers(&t->out, params->output);
1071 for (;;)
1073 ret = pgnutls_record_send(s, (const char *)params->buffer + total, params->length - total);
1074 if (ret >= 0)
1076 total += ret;
1077 TRACE( "sent %ld now %ld/%u\n", ret, total, (unsigned)params->length );
1078 if (total == params->length) break;
1080 else if (ret == GNUTLS_E_AGAIN)
1082 SIZE_T count = 0;
1084 if (get_buffer(&t->out, &count)) continue;
1085 return SEC_I_CONTINUE_NEEDED;
1087 else
1089 pgnutls_perror(ret);
1090 return SEC_E_INTERNAL_ERROR;
1094 *params->output_buffer_idx = t->out.current_buffer_idx;
1095 *params->output_offset = t->out.offset;
1096 return SEC_E_OK;
1099 static NTSTATUS schan_recv( void *args )
1101 const struct recv_params *params = args;
1102 gnutls_session_t s = session_from_handle(params->session);
1103 struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
1104 size_t data_size = *params->length;
1105 size_t received = 0;
1106 ssize_t ret;
1107 SECURITY_STATUS status = SEC_E_OK;
1109 init_schan_buffers(&t->in, params->input);
1110 t->in.limit = params->input_size;
1112 while (received < data_size)
1114 ret = pgnutls_record_recv(s, (char *)params->buffer + received, data_size - received);
1116 if (ret > 0) received += ret;
1117 else if (!ret) break;
1118 else if (ret == GNUTLS_E_AGAIN)
1120 SIZE_T count = 0;
1122 if (!get_buffer(&t->in, &count)) break;
1124 else if (ret == GNUTLS_E_REHANDSHAKE)
1126 TRACE("Rehandshake requested\n");
1127 status = SEC_I_RENEGOTIATE;
1128 break;
1130 else
1132 pgnutls_perror(ret);
1133 return SEC_E_INTERNAL_ERROR;
1137 *params->length = received;
1138 return status;
1141 static unsigned int parse_alpn_protocol_list(unsigned char *buffer, unsigned int buflen, gnutls_datum_t *list)
1143 unsigned int len, offset = 0, count = 0;
1145 while (buflen)
1147 len = buffer[offset++];
1148 buflen--;
1149 if (!len || len > buflen) return 0;
1150 if (list)
1152 list[count].data = &buffer[offset];
1153 list[count].size = len;
1155 buflen -= len;
1156 offset += len;
1157 count++;
1160 return count;
1163 static NTSTATUS schan_set_application_protocols( void *args )
1165 const struct set_application_protocols_params *params = args;
1166 gnutls_session_t s = session_from_handle(params->session);
1167 unsigned int extension_len, extension, count = 0, offset = 0;
1168 unsigned short list_len;
1169 gnutls_datum_t *protocols;
1170 int ret;
1172 if (sizeof(extension_len) > params->buflen) return STATUS_INVALID_PARAMETER;
1173 extension_len = *(unsigned int *)&params->buffer[offset];
1174 offset += sizeof(extension_len);
1176 if (offset + sizeof(extension) > params->buflen) return STATUS_INVALID_PARAMETER;
1177 extension = *(unsigned int *)&params->buffer[offset];
1178 if (extension != SecApplicationProtocolNegotiationExt_ALPN)
1180 FIXME("extension %u not supported\n", extension);
1181 return STATUS_NOT_SUPPORTED;
1183 offset += sizeof(extension);
1185 if (offset + sizeof(list_len) > params->buflen) return STATUS_INVALID_PARAMETER;
1186 list_len = *(unsigned short *)&params->buffer[offset];
1187 offset += sizeof(list_len);
1189 if (offset + list_len > params->buflen) return STATUS_INVALID_PARAMETER;
1190 count = parse_alpn_protocol_list(&params->buffer[offset], list_len, NULL);
1191 if (!count || !(protocols = malloc(count * sizeof(*protocols)))) return STATUS_NO_MEMORY;
1193 parse_alpn_protocol_list(&params->buffer[offset], list_len, protocols);
1194 if ((ret = pgnutls_alpn_set_protocols(s, protocols, count, GNUTLS_ALPN_SERVER_PRECEDENCE) < 0))
1196 pgnutls_perror(ret);
1199 free(protocols);
1200 return STATUS_SUCCESS;
1203 static NTSTATUS schan_get_application_protocol( void *args )
1205 const struct get_application_protocol_params *params = args;
1206 gnutls_session_t s = session_from_handle(params->session);
1207 SecPkgContext_ApplicationProtocol *protocol = params->protocol;
1208 gnutls_datum_t selected;
1210 memset(protocol, 0, sizeof(*protocol));
1211 if (pgnutls_alpn_get_selected_protocol(s, &selected) < 0) return SEC_E_OK;
1213 if (selected.size <= sizeof(protocol->ProtocolId))
1215 protocol->ProtoNegoStatus = SecApplicationProtocolNegotiationStatus_Success;
1216 protocol->ProtoNegoExt = SecApplicationProtocolNegotiationExt_ALPN;
1217 protocol->ProtocolIdSize = selected.size;
1218 memcpy(protocol->ProtocolId, selected.data, selected.size);
1219 TRACE("returning %s\n", wine_dbgstr_an((const char *)selected.data, selected.size));
1221 return SEC_E_OK;
1224 static NTSTATUS schan_set_dtls_mtu( void *args )
1226 const struct set_dtls_mtu_params *params = args;
1227 gnutls_session_t s = session_from_handle(params->session);
1229 pgnutls_dtls_set_mtu(s, params->mtu);
1230 TRACE("MTU set to %u\n", params->mtu);
1231 return SEC_E_OK;
1234 static NTSTATUS schan_set_dtls_timeouts( void *args )
1236 const struct set_dtls_timeouts_params *params = args;
1237 gnutls_session_t s = session_from_handle(params->session);
1239 pgnutls_dtls_set_timeouts(s, params->retrans_timeout, params->total_timeout);
1240 return SEC_E_OK;
1243 static inline void reverse_bytes(BYTE *buf, ULONG len)
1245 BYTE tmp;
1246 ULONG i;
1247 for (i = 0; i < len / 2; i++)
1249 tmp = buf[i];
1250 buf[i] = buf[len - i - 1];
1251 buf[len - i - 1] = tmp;
1255 static ULONG set_component(gnutls_datum_t *comp, BYTE *data, ULONG len, ULONG *buflen)
1257 comp->data = data;
1258 comp->size = len;
1259 reverse_bytes(comp->data, comp->size);
1260 if (comp->data[0] & 0x80) /* add leading 0 byte if most significant bit is set */
1262 memmove(comp->data + 1, comp->data, *buflen);
1263 comp->data[0] = 0;
1264 comp->size++;
1266 *buflen -= comp->size;
1267 return comp->size;
1270 static gnutls_x509_privkey_t get_x509_key(ULONG key_size, const BYTE *key_blob)
1272 gnutls_privkey_t key = NULL;
1273 gnutls_x509_privkey_t x509key = NULL;
1274 gnutls_datum_t m, e, d, p, q, u, e1, e2;
1275 BYTE *ptr;
1276 RSAPUBKEY *rsakey;
1277 DWORD size = key_size;
1278 int ret;
1280 if (size < sizeof(BLOBHEADER)) return NULL;
1282 rsakey = (RSAPUBKEY *)(key_blob + sizeof(BLOBHEADER));
1283 TRACE("RSA key bitlen %u pubexp %u\n", (unsigned)rsakey->bitlen, (unsigned)rsakey->pubexp);
1285 size -= sizeof(BLOBHEADER) + FIELD_OFFSET(RSAPUBKEY, pubexp);
1286 set_component(&e, (BYTE *)&rsakey->pubexp, sizeof(rsakey->pubexp), &size);
1288 ptr = (BYTE *)(rsakey + 1);
1289 ptr += set_component(&m, ptr, rsakey->bitlen / 8, &size);
1290 ptr += set_component(&p, ptr, rsakey->bitlen / 16, &size);
1291 ptr += set_component(&q, ptr, rsakey->bitlen / 16, &size);
1292 ptr += set_component(&e1, ptr, rsakey->bitlen / 16, &size);
1293 ptr += set_component(&e2, ptr, rsakey->bitlen / 16, &size);
1294 ptr += set_component(&u, ptr, rsakey->bitlen / 16, &size);
1295 ptr += set_component(&d, ptr, rsakey->bitlen / 8, &size);
1297 if ((ret = pgnutls_privkey_init(&key)) < 0)
1299 pgnutls_perror(ret);
1300 return NULL;
1303 if (((ret = pgnutls_privkey_import_rsa_raw(key, &m, &e, &d, &p, &q, &u, &e1, &e2)) < 0) ||
1304 (ret = pgnutls_privkey_export_x509(key, &x509key)) < 0)
1306 pgnutls_perror(ret);
1307 pgnutls_privkey_deinit(key);
1308 return NULL;
1311 return x509key;
1314 static gnutls_x509_crt_t get_x509_crt(const struct allocate_certificate_credentials_params *params)
1316 gnutls_datum_t data;
1317 gnutls_x509_crt_t crt;
1318 int ret;
1320 if (params->cert_encoding != X509_ASN_ENCODING)
1322 FIXME("encoding type %u not supported\n", (unsigned)params->cert_encoding);
1323 return NULL;
1326 if ((ret = pgnutls_x509_crt_init(&crt)) < 0)
1328 pgnutls_perror(ret);
1329 return NULL;
1332 data.data = params->cert_blob;
1333 data.size = params->cert_size;
1334 if ((ret = pgnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_DER)) < 0)
1336 pgnutls_perror(ret);
1337 pgnutls_x509_crt_deinit(crt);
1338 return NULL;
1341 return crt;
1344 static NTSTATUS schan_allocate_certificate_credentials( void *args )
1346 const struct allocate_certificate_credentials_params *params = args;
1347 gnutls_certificate_credentials_t creds;
1348 gnutls_x509_crt_t crt;
1349 gnutls_x509_privkey_t key;
1350 int ret;
1352 ret = pgnutls_certificate_allocate_credentials(&creds);
1353 if (ret != GNUTLS_E_SUCCESS)
1355 pgnutls_perror(ret);
1356 return STATUS_INTERNAL_ERROR;
1359 if (!params->cert_blob)
1361 params->c->credentials = (ULONG_PTR)creds;
1362 return STATUS_SUCCESS;
1365 if (!(crt = get_x509_crt(params)))
1367 pgnutls_certificate_free_credentials(creds);
1368 return STATUS_INTERNAL_ERROR;
1371 if (!(key = get_x509_key(params->key_size, params->key_blob)))
1373 pgnutls_x509_crt_deinit(crt);
1374 pgnutls_certificate_free_credentials(creds);
1375 return STATUS_INTERNAL_ERROR;
1378 ret = pgnutls_certificate_set_x509_key(creds, &crt, 1, key);
1379 pgnutls_x509_privkey_deinit(key);
1380 pgnutls_x509_crt_deinit(crt);
1381 if (ret != GNUTLS_E_SUCCESS)
1383 pgnutls_perror(ret);
1384 pgnutls_certificate_free_credentials(creds);
1385 return STATUS_INTERNAL_ERROR;
1388 params->c->credentials = (ULONG_PTR)creds;
1389 return STATUS_SUCCESS;
1392 static NTSTATUS schan_free_certificate_credentials( void *args )
1394 const struct free_certificate_credentials_params *params = args;
1395 pgnutls_certificate_free_credentials(certificate_creds_from_handle(params->c->credentials));
1396 return STATUS_SUCCESS;
1399 static void gnutls_log(int level, const char *msg)
1401 TRACE("<%d> %s", level, msg);
1404 static NTSTATUS process_attach( void *args )
1406 int ret;
1408 if ((system_priority_file = getenv("GNUTLS_SYSTEM_PRIORITY_FILE")))
1410 TRACE("GNUTLS_SYSTEM_PRIORITY_FILE is %s.\n", debugstr_a(system_priority_file));
1412 else
1414 WARN("Setting GNUTLS_SYSTEM_PRIORITY_FILE to \"/dev/null\".\n");
1415 setenv("GNUTLS_SYSTEM_PRIORITY_FILE", "/dev/null", 0);
1418 libgnutls_handle = dlopen(SONAME_LIBGNUTLS, RTLD_NOW);
1419 if (!libgnutls_handle)
1421 ERR_(winediag)("Failed to load libgnutls, secure connections will not be available.\n");
1422 return STATUS_DLL_NOT_FOUND;
1425 #define LOAD_FUNCPTR(f) \
1426 if (!(p##f = dlsym(libgnutls_handle, #f))) \
1428 ERR("Failed to load %s\n", #f); \
1429 goto fail; \
1432 LOAD_FUNCPTR(gnutls_alert_get)
1433 LOAD_FUNCPTR(gnutls_alert_get_name)
1434 LOAD_FUNCPTR(gnutls_certificate_allocate_credentials)
1435 LOAD_FUNCPTR(gnutls_certificate_free_credentials)
1436 LOAD_FUNCPTR(gnutls_certificate_get_peers)
1437 LOAD_FUNCPTR(gnutls_certificate_set_x509_key)
1438 LOAD_FUNCPTR(gnutls_cipher_get)
1439 LOAD_FUNCPTR(gnutls_cipher_get_key_size)
1440 LOAD_FUNCPTR(gnutls_credentials_set)
1441 LOAD_FUNCPTR(gnutls_deinit)
1442 LOAD_FUNCPTR(gnutls_global_deinit)
1443 LOAD_FUNCPTR(gnutls_global_init)
1444 LOAD_FUNCPTR(gnutls_global_set_log_function)
1445 LOAD_FUNCPTR(gnutls_global_set_log_level)
1446 LOAD_FUNCPTR(gnutls_handshake)
1447 LOAD_FUNCPTR(gnutls_init)
1448 LOAD_FUNCPTR(gnutls_kx_get)
1449 LOAD_FUNCPTR(gnutls_mac_get)
1450 LOAD_FUNCPTR(gnutls_mac_get_key_size)
1451 LOAD_FUNCPTR(gnutls_perror)
1452 LOAD_FUNCPTR(gnutls_protocol_get_version)
1453 LOAD_FUNCPTR(gnutls_priority_set_direct)
1454 LOAD_FUNCPTR(gnutls_privkey_deinit)
1455 LOAD_FUNCPTR(gnutls_privkey_init)
1456 LOAD_FUNCPTR(gnutls_record_get_max_size);
1457 LOAD_FUNCPTR(gnutls_record_recv);
1458 LOAD_FUNCPTR(gnutls_record_send);
1459 LOAD_FUNCPTR(gnutls_server_name_set)
1460 LOAD_FUNCPTR(gnutls_session_channel_binding)
1461 LOAD_FUNCPTR(gnutls_set_default_priority)
1462 LOAD_FUNCPTR(gnutls_transport_get_ptr)
1463 LOAD_FUNCPTR(gnutls_transport_set_errno)
1464 LOAD_FUNCPTR(gnutls_transport_set_ptr)
1465 LOAD_FUNCPTR(gnutls_transport_set_pull_function)
1466 LOAD_FUNCPTR(gnutls_transport_set_push_function)
1467 LOAD_FUNCPTR(gnutls_x509_crt_deinit)
1468 LOAD_FUNCPTR(gnutls_x509_crt_import)
1469 LOAD_FUNCPTR(gnutls_x509_crt_init)
1470 LOAD_FUNCPTR(gnutls_x509_privkey_deinit)
1471 LOAD_FUNCPTR(gnutls_alert_send)
1472 #undef LOAD_FUNCPTR
1474 if (!(pgnutls_cipher_get_block_size = dlsym(libgnutls_handle, "gnutls_cipher_get_block_size")))
1476 WARN("gnutls_cipher_get_block_size not found\n");
1477 pgnutls_cipher_get_block_size = compat_cipher_get_block_size;
1479 if (!(pgnutls_transport_set_pull_timeout_function = dlsym(libgnutls_handle, "gnutls_transport_set_pull_timeout_function")))
1481 WARN("gnutls_transport_set_pull_timeout_function not found\n");
1482 pgnutls_transport_set_pull_timeout_function = compat_gnutls_transport_set_pull_timeout_function;
1484 if (!(pgnutls_alpn_set_protocols = dlsym(libgnutls_handle, "gnutls_alpn_set_protocols")))
1486 WARN("gnutls_alpn_set_protocols not found\n");
1487 pgnutls_alpn_set_protocols = compat_gnutls_alpn_set_protocols;
1489 if (!(pgnutls_alpn_get_selected_protocol = dlsym(libgnutls_handle, "gnutls_alpn_get_selected_protocol")))
1491 WARN("gnutls_alpn_get_selected_protocol not found\n");
1492 pgnutls_alpn_get_selected_protocol = compat_gnutls_alpn_get_selected_protocol;
1494 if (!(pgnutls_dtls_set_mtu = dlsym(libgnutls_handle, "gnutls_dtls_set_mtu")))
1496 WARN("gnutls_dtls_set_mtu not found\n");
1497 pgnutls_dtls_set_mtu = compat_gnutls_dtls_set_mtu;
1499 if (!(pgnutls_dtls_set_timeouts = dlsym(libgnutls_handle, "gnutls_dtls_set_timeouts")))
1501 WARN("gnutls_dtls_set_timeouts not found\n");
1502 pgnutls_dtls_set_timeouts = compat_gnutls_dtls_set_timeouts;
1504 if (!(pgnutls_privkey_export_x509 = dlsym(libgnutls_handle, "gnutls_privkey_export_x509")))
1506 WARN("gnutls_privkey_export_x509 not found\n");
1507 pgnutls_privkey_export_x509 = compat_gnutls_privkey_export_x509;
1509 if (!(pgnutls_privkey_import_rsa_raw = dlsym(libgnutls_handle, "gnutls_privkey_import_rsa_raw")))
1511 WARN("gnutls_privkey_import_rsa_raw not found\n");
1512 pgnutls_privkey_import_rsa_raw = compat_gnutls_privkey_import_rsa_raw;
1515 ret = pgnutls_global_init();
1516 if (ret != GNUTLS_E_SUCCESS)
1518 pgnutls_perror(ret);
1519 goto fail;
1522 if (TRACE_ON(secur32))
1524 pgnutls_global_set_log_level(4);
1525 pgnutls_global_set_log_function(gnutls_log);
1528 check_supported_protocols(client_protocol_priority_flags, ARRAYSIZE(client_protocol_priority_flags), FALSE);
1529 check_supported_protocols(server_protocol_priority_flags, ARRAYSIZE(server_protocol_priority_flags), TRUE);
1530 return STATUS_SUCCESS;
1532 fail:
1533 dlclose(libgnutls_handle);
1534 libgnutls_handle = NULL;
1535 return STATUS_DLL_NOT_FOUND;
1538 static NTSTATUS process_detach( void *args )
1540 pgnutls_global_deinit();
1541 dlclose(libgnutls_handle);
1542 libgnutls_handle = NULL;
1543 return STATUS_SUCCESS;
1546 const unixlib_entry_t __wine_unix_call_funcs[] =
1548 process_attach,
1549 process_detach,
1550 schan_allocate_certificate_credentials,
1551 schan_create_session,
1552 schan_dispose_session,
1553 schan_free_certificate_credentials,
1554 schan_get_application_protocol,
1555 schan_get_cipher_info,
1556 schan_get_connection_info,
1557 schan_get_enabled_protocols,
1558 schan_get_key_signature_algorithm,
1559 schan_get_max_message_size,
1560 schan_get_session_cipher_block_size,
1561 schan_get_session_peer_certificate,
1562 schan_get_unique_channel_binding,
1563 schan_handshake,
1564 schan_recv,
1565 schan_send,
1566 schan_set_application_protocols,
1567 schan_set_dtls_mtu,
1568 schan_set_session_target,
1569 schan_set_dtls_timeouts,
1572 #ifdef _WIN64
1574 typedef ULONG PTR32;
1576 typedef struct SecBufferDesc32
1578 ULONG ulVersion;
1579 ULONG cBuffers;
1580 PTR32 pBuffers;
1581 } SecBufferDesc32;
1583 typedef struct SecBuffer32
1585 ULONG cbBuffer;
1586 ULONG BufferType;
1587 PTR32 pvBuffer;
1588 } SecBuffer32;
1590 static NTSTATUS wow64_schan_allocate_certificate_credentials( void *args )
1592 struct
1594 PTR32 c;
1595 ULONG cert_encoding;
1596 ULONG cert_size;
1597 PTR32 cert_blob;
1598 ULONG key_size;
1599 PTR32 key_blob;
1600 } const *params32 = args;
1601 struct allocate_certificate_credentials_params params =
1603 ULongToPtr(params32->c),
1604 params32->cert_encoding,
1605 params32->cert_size,
1606 ULongToPtr(params32->cert_blob),
1607 params32->key_size,
1608 ULongToPtr(params32->key_blob),
1610 return schan_allocate_certificate_credentials(&params);
1613 static NTSTATUS wow64_schan_create_session( void *args )
1615 struct
1617 PTR32 cred;
1618 PTR32 session;
1619 } const *params32 = args;
1620 struct create_session_params params =
1622 ULongToPtr(params32->cred),
1623 ULongToPtr(params32->session),
1625 return schan_create_session(&params);
1628 static NTSTATUS wow64_schan_free_certificate_credentials( void *args )
1630 struct
1632 PTR32 c;
1633 } const *params32 = args;
1634 struct free_certificate_credentials_params params =
1636 ULongToPtr(params32->c),
1638 return schan_free_certificate_credentials(&params);
1641 static NTSTATUS wow64_schan_get_application_protocol( void *args )
1643 struct
1645 schan_session session;
1646 PTR32 protocol;
1647 } const *params32 = args;
1648 struct get_application_protocol_params params =
1650 params32->session,
1651 ULongToPtr(params32->protocol),
1653 return schan_get_application_protocol(&params);
1656 static NTSTATUS wow64_schan_get_connection_info( void *args )
1658 struct
1660 schan_session session;
1661 PTR32 info;
1662 } const *params32 = args;
1663 struct get_connection_info_params params =
1665 params32->session,
1666 ULongToPtr(params32->info),
1668 return schan_get_connection_info(&params);
1671 static NTSTATUS wow64_schan_get_cipher_info( void *args )
1673 struct
1675 schan_session session;
1676 PTR32 info;
1677 } const *params32 = args;
1678 struct get_cipher_info_params params =
1680 params32->session,
1681 ULongToPtr(params32->info),
1683 return schan_get_cipher_info(&params);
1686 static NTSTATUS wow64_schan_get_session_peer_certificate( void *args )
1688 struct
1690 schan_session session;
1691 PTR32 buffer;
1692 PTR32 bufsize;
1693 PTR32 retcount;
1694 } const *params32 = args;
1695 struct get_session_peer_certificate_params params =
1697 params32->session,
1698 ULongToPtr(params32->buffer),
1699 ULongToPtr(params32->bufsize),
1700 ULongToPtr(params32->retcount),
1702 return schan_get_session_peer_certificate(&params);
1705 static NTSTATUS wow64_schan_get_unique_channel_binding( void *args )
1707 struct
1709 schan_session session;
1710 PTR32 buffer;
1711 PTR32 bufsize;
1712 } const *params32 = args;
1713 struct get_unique_channel_binding_params params =
1715 params32->session,
1716 ULongToPtr(params32->buffer),
1717 ULongToPtr(params32->bufsize),
1719 return schan_get_unique_channel_binding(&params);
1722 static void secbufferdesc_32to64(const SecBufferDesc32 *desc32, SecBufferDesc *desc)
1724 unsigned int i;
1726 desc->ulVersion = desc32->ulVersion;
1727 desc->cBuffers = desc32->cBuffers;
1728 for (i = 0; i < desc->cBuffers; ++i)
1730 SecBuffer32 *buffer32 = ULongToPtr(desc32->pBuffers + i * sizeof(*buffer32));
1731 desc->pBuffers[i].cbBuffer = buffer32->cbBuffer;
1732 desc->pBuffers[i].BufferType = buffer32->BufferType;
1733 desc->pBuffers[i].pvBuffer = ULongToPtr(buffer32->pvBuffer);
1737 static NTSTATUS wow64_schan_handshake( void *args )
1739 SecBuffer input_buffers[3];
1740 SecBufferDesc input = { 0, 0, input_buffers };
1741 SecBuffer output_buffers[3];
1742 SecBufferDesc output = { 0, 0, output_buffers };
1744 struct
1746 schan_session session;
1747 PTR32 input;
1748 ULONG input_size;
1749 PTR32 output;
1750 PTR32 input_offset;
1751 PTR32 output_buffer_idx;
1752 PTR32 output_offset;
1753 enum control_token control_token;
1754 } const *params32 = args;
1755 struct handshake_params params =
1757 params32->session,
1758 params32->input ? &input : NULL,
1759 params32->input_size,
1760 params32->output ? &output : NULL,
1761 ULongToPtr(params32->input_offset),
1762 ULongToPtr(params32->output_buffer_idx),
1763 ULongToPtr(params32->output_offset),
1764 params32->control_token,
1766 if (params32->input)
1768 SecBufferDesc32 *desc32 = ULongToPtr(params32->input);
1769 assert(desc32->cBuffers <= ARRAY_SIZE(input_buffers));
1770 secbufferdesc_32to64(desc32, &input);
1772 if (params32->output)
1774 SecBufferDesc32 *desc32 = ULongToPtr(params32->output);
1775 assert(desc32->cBuffers <= ARRAY_SIZE(output_buffers));
1776 secbufferdesc_32to64(desc32, &output);
1778 return schan_handshake(&params);
1781 static NTSTATUS wow64_schan_recv( void *args )
1783 SecBuffer buffers[3];
1784 SecBufferDesc input = { 0, 0, buffers };
1786 struct
1788 schan_session session;
1789 PTR32 input;
1790 ULONG input_size;
1791 PTR32 buffer;
1792 PTR32 length;
1793 } const *params32 = args;
1794 struct recv_params params =
1796 params32->session,
1797 params32->input ? &input : NULL,
1798 params32->input_size,
1799 ULongToPtr(params32->buffer),
1800 ULongToPtr(params32->length),
1802 if (params32->input)
1804 SecBufferDesc32 *desc32 = ULongToPtr(params32->input);
1805 assert(desc32->cBuffers <= ARRAY_SIZE(buffers));
1806 secbufferdesc_32to64(desc32, &input);
1808 return schan_recv(&params);
1811 static NTSTATUS wow64_schan_send( void *args )
1813 SecBuffer buffers[3];
1814 SecBufferDesc output = { 0, 0, buffers };
1816 struct
1818 schan_session session;
1819 PTR32 output;
1820 PTR32 buffer;
1821 ULONG length;
1822 PTR32 output_buffer_idx;
1823 PTR32 output_offset;
1824 } const *params32 = args;
1825 struct send_params params =
1827 params32->session,
1828 params32->output ? &output : NULL,
1829 ULongToPtr(params32->buffer),
1830 params32->length,
1831 ULongToPtr(params32->output_buffer_idx),
1832 ULongToPtr(params32->output_offset),
1834 if (params32->output)
1836 SecBufferDesc32 *desc32 = ULongToPtr(params32->output);
1837 assert(desc32->cBuffers <= ARRAY_SIZE(buffers));
1838 secbufferdesc_32to64(desc32, &output);
1840 return schan_send(&params);
1843 static NTSTATUS wow64_schan_set_application_protocols( void *args )
1845 struct
1847 schan_session session;
1848 PTR32 buffer;
1849 unsigned int buflen;
1850 } const *params32 = args;
1851 struct set_application_protocols_params params =
1853 params32->session,
1854 ULongToPtr(params32->buffer),
1855 params32->buflen,
1857 return schan_set_application_protocols(&params);
1860 static NTSTATUS wow64_schan_set_session_target( void *args )
1862 struct
1864 schan_session session;
1865 PTR32 target;
1866 } const *params32 = args;
1867 struct set_session_target_params params =
1869 params32->session,
1870 ULongToPtr(params32->target),
1872 return schan_set_session_target(&params);
1875 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
1877 process_attach,
1878 process_detach,
1879 wow64_schan_allocate_certificate_credentials,
1880 wow64_schan_create_session,
1881 schan_dispose_session,
1882 wow64_schan_free_certificate_credentials,
1883 wow64_schan_get_application_protocol,
1884 wow64_schan_get_cipher_info,
1885 wow64_schan_get_connection_info,
1886 schan_get_enabled_protocols,
1887 schan_get_key_signature_algorithm,
1888 schan_get_max_message_size,
1889 schan_get_session_cipher_block_size,
1890 wow64_schan_get_session_peer_certificate,
1891 wow64_schan_get_unique_channel_binding,
1892 wow64_schan_handshake,
1893 wow64_schan_recv,
1894 wow64_schan_send,
1895 wow64_schan_set_application_protocols,
1896 schan_set_dtls_mtu,
1897 wow64_schan_set_session_target,
1898 schan_set_dtls_timeouts,
1901 #endif /* _WIN64 */
1903 #endif /* SONAME_LIBGNUTLS */