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
33 #include <sys/types.h>
35 #ifdef SONAME_LIBGNUTLS
36 #include <gnutls/gnutls.h>
37 #include <gnutls/crypto.h>
38 #include <gnutls/abstract.h>
42 #define WIN32_NO_STATUS
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
);
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
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
145 #if GNUTLS_VERSION_MAJOR < 3 || (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR < 5)
146 #define GNUTLS_ALPN_SERVER_PRECEDENCE (1<<1)
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
;
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
)
177 case GNUTLS_CIPHER_3DES_CBC
:
179 case GNUTLS_CIPHER_AES_128_CBC
:
180 case GNUTLS_CIPHER_AES_256_CBC
:
182 case GNUTLS_CIPHER_ARCFOUR_128
:
183 case GNUTLS_CIPHER_ARCFOUR_40
:
185 case GNUTLS_CIPHER_DES_CBC
:
187 case GNUTLS_CIPHER_NULL
:
189 case GNUTLS_CIPHER_RC2_40_CBC
:
192 FIXME("Unknown cipher %#x, returning 1\n", cipher
);
197 static void compat_gnutls_transport_set_pull_timeout_function(gnutls_session_t session
,
198 int (*func
)(gnutls_transport_ptr_t
, unsigned int))
203 static int compat_gnutls_privkey_export_x509(gnutls_privkey_t privkey
, gnutls_x509_privkey_t
*key
)
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
)
216 return GNUTLS_E_UNKNOWN_PK_ALGORITHM
;
219 static int compat_gnutls_alpn_get_selected_protocol(gnutls_session_t session
, gnutls_datum_t
*protocol
)
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
)
229 return GNUTLS_E_INVALID_REQUEST
;
232 static void compat_gnutls_dtls_set_mtu(gnutls_session_t session
, unsigned int mtu
)
237 static void compat_gnutls_dtls_set_timeouts(gnutls_session_t session
, unsigned int retrans_timeout
,
238 unsigned int total_timeout
)
243 static void init_schan_buffers(struct schan_buffers
*s
, const PSecBufferDesc 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)
257 return s
->current_buffer_idx
+ 1;
260 static char *get_buffer(struct schan_buffers
*s
, SIZE_T
*count
)
271 if (s
->current_buffer_idx
== -1)
274 int buffer_idx
= get_next_buffer(s
);
275 if (buffer_idx
== -1)
277 TRACE("No next buffer\n");
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
;
295 buffer_idx
= get_next_buffer(s
);
296 if (buffer_idx
== -1)
298 TRACE("No next buffer\n");
301 s
->current_buffer_idx
= buffer_idx
;
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
)
311 if (s
->limit
!= ~0UL)
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
;
323 TRACE("Pull %lu bytes\n", len
);
325 b
= get_buffer(&t
->in
, &len
);
328 pgnutls_transport_set_errno(t
->session
, EAGAIN
);
331 memcpy(buff
, b
, len
);
333 TRACE("Read %lu bytes\n", 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
;
343 TRACE("Push %lu bytes\n", len
);
345 b
= get_buffer(&t
->out
, &len
);
348 pgnutls_transport_set_errno(t
->session
, EAGAIN
);
351 memcpy(b
, buff
, len
);
352 t
->out
.offset
+= len
;
353 TRACE("Wrote %lu bytes\n", len
);
357 struct protocol_priority_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
;
395 err
= pgnutls_init(&session
, server
? GNUTLS_SERVER
: GNUTLS_CLIENT
);
396 if (err
!= GNUTLS_E_SUCCESS
)
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
;
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
;
430 if (get_buffer(&t
->in
, &count
)) return 1;
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
;
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
)
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");
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;
478 *p
++ = disabled
? '-' : '+';
479 strcpy(p
, protocols
[i
].gnutls_flag
);
483 TRACE("Using %s priority\n", debugstr_a(priority
));
484 err
= pgnutls_priority_set_direct(session
, priority
, NULL
);
485 if (err
!= GNUTLS_E_SUCCESS
)
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
;
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
)
515 return STATUS_INTERNAL_ERROR
;
518 if (!(transport
= calloc(1, sizeof(*transport
))))
521 return STATUS_INTERNAL_ERROR
;
523 transport
->session
= s
;
525 if ((status
= set_priority(cred
, s
)))
532 err
= pgnutls_credentials_set(s
, GNUTLS_CRD_CERTIFICATE
, certificate_creds_from_handle(cred
->credentials
));
533 if (err
!= GNUTLS_E_SUCCESS
)
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
);
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
);
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
)
588 else if (err
== GNUTLS_E_AGAIN
)
590 status
= SEC_E_INVALID_TOKEN
;
595 status
= SEC_E_INTERNAL_ERROR
;
602 err
= pgnutls_handshake(s
);
603 if (err
== GNUTLS_E_SUCCESS
)
605 TRACE("Handshake completed\n");
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
)
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
;
636 status
= SEC_E_INTERNAL_ERROR
;
642 *params
->input_offset
= t
->in
.offset
;
643 *params
->output_buffer_idx
= t
->out
.current_buffer_idx
;
644 *params
->output_offset
= t
->out
.offset
;
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.
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
;
664 FIXME("unknown protocol %d\n", proto
);
669 static ALG_ID
get_cipher_algid(gnutls_cipher_algorithm_t 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
;
686 FIXME("unknown algorithm %d\n", cipher
);
691 static ALG_ID
get_mac_algid(gnutls_mac_algorithm_t mac
, gnutls_cipher_algorithm_t cipher
)
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. */
708 case GNUTLS_CIPHER_AES_128_GCM
: return CALG_SHA_256
;
709 case GNUTLS_CIPHER_AES_256_GCM
: return CALG_SHA_384
;
715 FIXME("unknown algorithm %d, cipher %d\n", mac
, cipher
);
720 static ALG_ID
get_kx_algid(int kx
)
724 case GNUTLS_KX_UNKNOWN
: return 0;
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
;
735 FIXME("unknown algorithm %d\n", kx
);
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;
775 static DWORD
get_protocol_version( gnutls_session_t session
)
777 gnutls_protocol_t proto
= pgnutls_protocol_get_version( session
);
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;
788 FIXME( "unknown protocol %u\n", proto
);
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
);
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
:
810 FIXME( "unknown cipher %u\n", cipher
);
815 static DWORD
get_cipher_len( gnutls_session_t session
)
817 gnutls_cipher_algorithm_t cipher
= pgnutls_cipher_get( session
);
821 case GNUTLS_CIPHER_AES_128_CBC
:
822 case GNUTLS_CIPHER_AES_128_GCM
:
823 case GNUTLS_CIPHER_AES_128_CCM
:
825 case GNUTLS_CIPHER_AES_192_CBC
:
827 case GNUTLS_CIPHER_AES_256_CBC
:
828 case GNUTLS_CIPHER_AES_256_GCM
:
829 case GNUTLS_CIPHER_AES_256_CCM
:
832 FIXME( "unknown cipher %u\n", cipher
);
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
);
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
;
862 FIXME( "unknown mac %u\n", mac
);
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
);
882 case GNUTLS_KX_ECDHE_RSA
:
883 case GNUTLS_KX_ECDHE_ECDSA
:
884 return full
? ecdheW
: ecdhW
;
886 FIXME( "unknown kx %u\n", kx
);
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
);
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
;
906 FIXME( "unknown kx %u\n", kx
);
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
);
921 case GNUTLS_CIPHER_AES_128_CBC
:
922 case GNUTLS_CIPHER_AES_192_CBC
:
923 case GNUTLS_CIPHER_AES_256_CBC
:
925 case GNUTLS_CIPHER_AES_128_GCM
:
926 case GNUTLS_CIPHER_AES_256_GCM
:
928 case GNUTLS_CIPHER_AES_128_CCM
:
929 case GNUTLS_CIPHER_AES_256_CCM
:
932 FIXME( "unknown cipher %u\n", cipher
);
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
;
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
) );
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
;
988 rc
= pgnutls_session_channel_binding(s
, GNUTLS_CB_TLS_UNIQUE
, &datum
);
992 return SEC_E_INTERNAL_ERROR
;
994 if (params
->buffer
&& *params
->bufsize
>= datum
.size
)
996 memcpy( params
->buffer
, datum
.data
, datum
.size
);
999 else ret
= SEC_E_BUFFER_TOO_SMALL
;
1001 *params
->bufsize
= datum
.size
;
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
);
1016 case GNUTLS_KX_UNKNOWN
: return 0;
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
;
1023 FIXME("unknown algorithm %d\n", kx
);
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
;
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
;
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
);
1073 ret
= pgnutls_record_send(s
, (const char *)params
->buffer
+ total
, params
->length
- total
);
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
)
1084 if (get_buffer(&t
->out
, &count
)) continue;
1085 return SEC_I_CONTINUE_NEEDED
;
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
;
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;
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
)
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
;
1132 pgnutls_perror(ret
);
1133 return SEC_E_INTERNAL_ERROR
;
1137 *params
->length
= received
;
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;
1147 len
= buffer
[offset
++];
1149 if (!len
|| len
> buflen
) return 0;
1152 list
[count
].data
= &buffer
[offset
];
1153 list
[count
].size
= len
;
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
;
1172 if (sizeof(extension_len
) > params
->buflen
) return STATUS_INVALID_PARAMETER
;
1173 extension_len
= *(unsigned int *)¶ms
->buffer
[offset
];
1174 offset
+= sizeof(extension_len
);
1176 if (offset
+ sizeof(extension
) > params
->buflen
) return STATUS_INVALID_PARAMETER
;
1177 extension
= *(unsigned int *)¶ms
->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 *)¶ms
->buffer
[offset
];
1187 offset
+= sizeof(list_len
);
1189 if (offset
+ list_len
> params
->buflen
) return STATUS_INVALID_PARAMETER
;
1190 count
= parse_alpn_protocol_list(¶ms
->buffer
[offset
], list_len
, NULL
);
1191 if (!count
|| !(protocols
= malloc(count
* sizeof(*protocols
)))) return STATUS_NO_MEMORY
;
1193 parse_alpn_protocol_list(¶ms
->buffer
[offset
], list_len
, protocols
);
1194 if ((ret
= pgnutls_alpn_set_protocols(s
, protocols
, count
, GNUTLS_ALPN_SERVER_PRECEDENCE
) < 0))
1196 pgnutls_perror(ret
);
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
));
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
);
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
);
1243 static inline void reverse_bytes(BYTE
*buf
, ULONG len
)
1247 for (i
= 0; i
< len
/ 2; 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
)
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
);
1266 *buflen
-= 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
;
1277 DWORD size
= key_size
;
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
);
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
);
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
;
1320 if (params
->cert_encoding
!= X509_ASN_ENCODING
)
1322 FIXME("encoding type %u not supported\n", (unsigned)params
->cert_encoding
);
1326 if ((ret
= pgnutls_x509_crt_init(&crt
)) < 0)
1328 pgnutls_perror(ret
);
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
);
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
;
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
)
1408 if ((system_priority_file
= getenv("GNUTLS_SYSTEM_PRIORITY_FILE")))
1410 TRACE("GNUTLS_SYSTEM_PRIORITY_FILE is %s.\n", debugstr_a(system_priority_file
));
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); \
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
)
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
);
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
;
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
[] =
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
,
1566 schan_set_application_protocols
,
1568 schan_set_session_target
,
1569 schan_set_dtls_timeouts
,
1574 typedef ULONG PTR32
;
1576 typedef struct SecBufferDesc32
1583 typedef struct SecBuffer32
1590 static NTSTATUS
wow64_schan_allocate_certificate_credentials( void *args
)
1595 ULONG cert_encoding
;
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
),
1608 ULongToPtr(params32
->key_blob
),
1610 return schan_allocate_certificate_credentials(¶ms
);
1613 static NTSTATUS
wow64_schan_create_session( void *args
)
1619 } const *params32
= args
;
1620 struct create_session_params params
=
1622 ULongToPtr(params32
->cred
),
1623 ULongToPtr(params32
->session
),
1625 return schan_create_session(¶ms
);
1628 static NTSTATUS
wow64_schan_free_certificate_credentials( void *args
)
1633 } const *params32
= args
;
1634 struct free_certificate_credentials_params params
=
1636 ULongToPtr(params32
->c
),
1638 return schan_free_certificate_credentials(¶ms
);
1641 static NTSTATUS
wow64_schan_get_application_protocol( void *args
)
1645 schan_session session
;
1647 } const *params32
= args
;
1648 struct get_application_protocol_params params
=
1651 ULongToPtr(params32
->protocol
),
1653 return schan_get_application_protocol(¶ms
);
1656 static NTSTATUS
wow64_schan_get_connection_info( void *args
)
1660 schan_session session
;
1662 } const *params32
= args
;
1663 struct get_connection_info_params params
=
1666 ULongToPtr(params32
->info
),
1668 return schan_get_connection_info(¶ms
);
1671 static NTSTATUS
wow64_schan_get_cipher_info( void *args
)
1675 schan_session session
;
1677 } const *params32
= args
;
1678 struct get_cipher_info_params params
=
1681 ULongToPtr(params32
->info
),
1683 return schan_get_cipher_info(¶ms
);
1686 static NTSTATUS
wow64_schan_get_session_peer_certificate( void *args
)
1690 schan_session session
;
1694 } const *params32
= args
;
1695 struct get_session_peer_certificate_params params
=
1698 ULongToPtr(params32
->buffer
),
1699 ULongToPtr(params32
->bufsize
),
1700 ULongToPtr(params32
->retcount
),
1702 return schan_get_session_peer_certificate(¶ms
);
1705 static NTSTATUS
wow64_schan_get_unique_channel_binding( void *args
)
1709 schan_session session
;
1712 } const *params32
= args
;
1713 struct get_unique_channel_binding_params params
=
1716 ULongToPtr(params32
->buffer
),
1717 ULongToPtr(params32
->bufsize
),
1719 return schan_get_unique_channel_binding(¶ms
);
1722 static void secbufferdesc_32to64(const SecBufferDesc32
*desc32
, SecBufferDesc
*desc
)
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
};
1746 schan_session session
;
1751 PTR32 output_buffer_idx
;
1752 PTR32 output_offset
;
1753 enum control_token control_token
;
1754 } const *params32
= args
;
1755 struct handshake_params params
=
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(¶ms
);
1781 static NTSTATUS
wow64_schan_recv( void *args
)
1783 SecBuffer buffers
[3];
1784 SecBufferDesc input
= { 0, 0, buffers
};
1788 schan_session session
;
1793 } const *params32
= args
;
1794 struct recv_params params
=
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(¶ms
);
1811 static NTSTATUS
wow64_schan_send( void *args
)
1813 SecBuffer buffers
[3];
1814 SecBufferDesc output
= { 0, 0, buffers
};
1818 schan_session session
;
1822 PTR32 output_buffer_idx
;
1823 PTR32 output_offset
;
1824 } const *params32
= args
;
1825 struct send_params params
=
1828 params32
->output
? &output
: NULL
,
1829 ULongToPtr(params32
->buffer
),
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(¶ms
);
1843 static NTSTATUS
wow64_schan_set_application_protocols( void *args
)
1847 schan_session session
;
1849 unsigned int buflen
;
1850 } const *params32
= args
;
1851 struct set_application_protocols_params params
=
1854 ULongToPtr(params32
->buffer
),
1857 return schan_set_application_protocols(¶ms
);
1860 static NTSTATUS
wow64_schan_set_session_target( void *args
)
1864 schan_session session
;
1866 } const *params32
= args
;
1867 struct set_session_target_params params
=
1870 ULongToPtr(params32
->target
),
1872 return schan_set_session_target(¶ms
);
1875 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
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
,
1895 wow64_schan_set_application_protocols
,
1897 wow64_schan_set_session_target
,
1898 schan_set_dtls_timeouts
,
1903 #endif /* SONAME_LIBGNUTLS */