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 /* Not present in gnutls version < 2.9.10. */
58 static int (*pgnutls_cipher_get_block_size
)(gnutls_cipher_algorithm_t
);
60 /* Not present in gnutls version < 3.0. */
61 static void (*pgnutls_transport_set_pull_timeout_function
)(gnutls_session_t
,
62 int (*)(gnutls_transport_ptr_t
, unsigned int));
63 static void (*pgnutls_dtls_set_mtu
)(gnutls_session_t
, unsigned int);
64 static void (*pgnutls_dtls_set_timeouts
)(gnutls_session_t
, unsigned int, unsigned int);
66 /* Not present in gnutls version < 3.2.0. */
67 static int (*pgnutls_alpn_get_selected_protocol
)(gnutls_session_t
, gnutls_datum_t
*);
68 static int (*pgnutls_alpn_set_protocols
)(gnutls_session_t
, const gnutls_datum_t
*,
69 unsigned, unsigned int);
71 /* Not present in gnutls version < 3.3.0. */
72 static int (*pgnutls_privkey_import_rsa_raw
)(gnutls_privkey_t
, const gnutls_datum_t
*,
73 const gnutls_datum_t
*, const gnutls_datum_t
*,
74 const gnutls_datum_t
*, const gnutls_datum_t
*,
75 const gnutls_datum_t
*, const gnutls_datum_t
*,
76 const gnutls_datum_t
*);
78 /* Not present in gnutls version < 3.4.0. */
79 static int (*pgnutls_privkey_export_x509
)(gnutls_privkey_t
, gnutls_x509_privkey_t
*);
81 static void *libgnutls_handle
;
82 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
83 MAKE_FUNCPTR(gnutls_alert_get
);
84 MAKE_FUNCPTR(gnutls_alert_get_name
);
85 MAKE_FUNCPTR(gnutls_certificate_allocate_credentials
);
86 MAKE_FUNCPTR(gnutls_certificate_free_credentials
);
87 MAKE_FUNCPTR(gnutls_certificate_get_peers
);
88 MAKE_FUNCPTR(gnutls_certificate_set_x509_key
);
89 MAKE_FUNCPTR(gnutls_cipher_get
);
90 MAKE_FUNCPTR(gnutls_cipher_get_key_size
);
91 MAKE_FUNCPTR(gnutls_credentials_set
);
92 MAKE_FUNCPTR(gnutls_deinit
);
93 MAKE_FUNCPTR(gnutls_global_deinit
);
94 MAKE_FUNCPTR(gnutls_global_init
);
95 MAKE_FUNCPTR(gnutls_global_set_log_function
);
96 MAKE_FUNCPTR(gnutls_global_set_log_level
);
97 MAKE_FUNCPTR(gnutls_handshake
);
98 MAKE_FUNCPTR(gnutls_init
);
99 MAKE_FUNCPTR(gnutls_kx_get
);
100 MAKE_FUNCPTR(gnutls_mac_get
);
101 MAKE_FUNCPTR(gnutls_mac_get_key_size
);
102 MAKE_FUNCPTR(gnutls_perror
);
103 MAKE_FUNCPTR(gnutls_protocol_get_version
);
104 MAKE_FUNCPTR(gnutls_priority_set_direct
);
105 MAKE_FUNCPTR(gnutls_privkey_deinit
);
106 MAKE_FUNCPTR(gnutls_privkey_init
);
107 MAKE_FUNCPTR(gnutls_record_get_max_size
);
108 MAKE_FUNCPTR(gnutls_record_recv
);
109 MAKE_FUNCPTR(gnutls_record_send
);
110 MAKE_FUNCPTR(gnutls_server_name_set
);
111 MAKE_FUNCPTR(gnutls_session_channel_binding
);
112 MAKE_FUNCPTR(gnutls_transport_get_ptr
);
113 MAKE_FUNCPTR(gnutls_transport_set_errno
);
114 MAKE_FUNCPTR(gnutls_transport_set_ptr
);
115 MAKE_FUNCPTR(gnutls_transport_set_pull_function
);
116 MAKE_FUNCPTR(gnutls_transport_set_push_function
);
117 MAKE_FUNCPTR(gnutls_x509_crt_deinit
);
118 MAKE_FUNCPTR(gnutls_x509_crt_import
);
119 MAKE_FUNCPTR(gnutls_x509_crt_init
);
120 MAKE_FUNCPTR(gnutls_x509_privkey_deinit
);
123 #if GNUTLS_VERSION_MAJOR < 3
124 #define GNUTLS_CIPHER_AES_192_CBC 92
125 #define GNUTLS_CIPHER_AES_128_GCM 93
126 #define GNUTLS_CIPHER_AES_256_GCM 94
128 #define GNUTLS_MAC_AEAD 200
130 #define GNUTLS_KX_ANON_ECDH 11
131 #define GNUTLS_KX_ECDHE_RSA 12
132 #define GNUTLS_KX_ECDHE_ECDSA 13
133 #define GNUTLS_KX_ECDHE_PSK 14
136 #if GNUTLS_VERSION_MAJOR < 3 || (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR < 5)
137 #define GNUTLS_ALPN_SERVER_PRECEDENCE (1<<1)
140 static inline gnutls_session_t
session_from_handle(UINT64 handle
)
142 return (gnutls_session_t
)(ULONG_PTR
)handle
;
145 static inline gnutls_certificate_credentials_t
certificate_creds_from_handle(UINT64 handle
)
147 return (gnutls_certificate_credentials_t
)(ULONG_PTR
)handle
;
154 const SecBufferDesc
*desc
;
155 int current_buffer_idx
;
158 struct schan_transport
160 gnutls_session_t session
;
161 struct schan_buffers in
;
162 struct schan_buffers out
;
165 static int compat_cipher_get_block_size(gnutls_cipher_algorithm_t cipher
)
168 case GNUTLS_CIPHER_3DES_CBC
:
170 case GNUTLS_CIPHER_AES_128_CBC
:
171 case GNUTLS_CIPHER_AES_256_CBC
:
173 case GNUTLS_CIPHER_ARCFOUR_128
:
174 case GNUTLS_CIPHER_ARCFOUR_40
:
176 case GNUTLS_CIPHER_DES_CBC
:
178 case GNUTLS_CIPHER_NULL
:
180 case GNUTLS_CIPHER_RC2_40_CBC
:
183 FIXME("Unknown cipher %#x, returning 1\n", cipher
);
188 static void compat_gnutls_transport_set_pull_timeout_function(gnutls_session_t session
,
189 int (*func
)(gnutls_transport_ptr_t
, unsigned int))
194 static int compat_gnutls_privkey_export_x509(gnutls_privkey_t privkey
, gnutls_x509_privkey_t
*key
)
197 return GNUTLS_E_UNKNOWN_PK_ALGORITHM
;
200 static int compat_gnutls_privkey_import_rsa_raw(gnutls_privkey_t key
, const gnutls_datum_t
*p1
,
201 const gnutls_datum_t
*p2
, const gnutls_datum_t
*p3
,
202 const gnutls_datum_t
*p4
, const gnutls_datum_t
*p5
,
203 const gnutls_datum_t
*p6
, const gnutls_datum_t
*p7
,
204 const gnutls_datum_t
*p8
)
207 return GNUTLS_E_UNKNOWN_PK_ALGORITHM
;
210 static int compat_gnutls_alpn_get_selected_protocol(gnutls_session_t session
, gnutls_datum_t
*protocol
)
213 return GNUTLS_E_INVALID_REQUEST
;
216 static int compat_gnutls_alpn_set_protocols(gnutls_session_t session
, const gnutls_datum_t
*protocols
,
217 unsigned size
, unsigned int flags
)
220 return GNUTLS_E_INVALID_REQUEST
;
223 static void compat_gnutls_dtls_set_mtu(gnutls_session_t session
, unsigned int mtu
)
228 static void compat_gnutls_dtls_set_timeouts(gnutls_session_t session
, unsigned int retrans_timeout
,
229 unsigned int total_timeout
)
234 static void init_schan_buffers(struct schan_buffers
*s
, const PSecBufferDesc desc
)
239 s
->current_buffer_idx
= -1;
242 static int get_next_buffer(struct schan_buffers
*s
)
244 if (s
->current_buffer_idx
== -1)
245 return s
->desc
->cBuffers
? 0 : -1;
246 if (s
->current_buffer_idx
== s
->desc
->cBuffers
- 1)
248 return s
->current_buffer_idx
+ 1;
251 static char *get_buffer(struct schan_buffers
*s
, SIZE_T
*count
)
262 if (s
->current_buffer_idx
== -1)
265 int buffer_idx
= get_next_buffer(s
);
266 if (buffer_idx
== -1)
268 TRACE("No next buffer\n");
271 s
->current_buffer_idx
= buffer_idx
;
274 buffer
= &s
->desc
->pBuffers
[s
->current_buffer_idx
];
275 TRACE("Using buffer %d: cbBuffer %d, BufferType %#x, pvBuffer %p\n",
276 s
->current_buffer_idx
, (unsigned)buffer
->cbBuffer
, (unsigned)buffer
->BufferType
, buffer
->pvBuffer
);
278 max_count
= buffer
->cbBuffer
- s
->offset
;
279 if (s
->limit
!= ~0UL && s
->limit
< max_count
)
280 max_count
= s
->limit
;
286 buffer_idx
= get_next_buffer(s
);
287 if (buffer_idx
== -1)
289 TRACE("No next buffer\n");
292 s
->current_buffer_idx
= buffer_idx
;
294 buffer
= &s
->desc
->pBuffers
[buffer_idx
];
295 max_count
= buffer
->cbBuffer
;
296 if (s
->limit
!= ~0UL && s
->limit
< max_count
)
297 max_count
= s
->limit
;
300 if (*count
> max_count
)
302 if (s
->limit
!= ~0UL)
305 return (char *)buffer
->pvBuffer
+ s
->offset
;
308 static ssize_t
pull_adapter(gnutls_transport_ptr_t transport
, void *buff
, size_t buff_len
)
310 struct schan_transport
*t
= (struct schan_transport
*)transport
;
311 SIZE_T len
= buff_len
;
314 TRACE("Pull %lu bytes\n", len
);
316 b
= get_buffer(&t
->in
, &len
);
319 pgnutls_transport_set_errno(t
->session
, EAGAIN
);
322 memcpy(buff
, b
, len
);
324 TRACE("Read %lu bytes\n", len
);
328 static ssize_t
push_adapter(gnutls_transport_ptr_t transport
, const void *buff
, size_t buff_len
)
330 struct schan_transport
*t
= (struct schan_transport
*)transport
;
331 SIZE_T len
= buff_len
;
334 TRACE("Push %lu bytes\n", len
);
336 b
= get_buffer(&t
->out
, &len
);
339 pgnutls_transport_set_errno(t
->session
, EAGAIN
);
342 memcpy(b
, buff
, len
);
343 t
->out
.offset
+= len
;
344 TRACE("Wrote %lu bytes\n", len
);
348 static const struct {
350 const char *gnutls_flag
;
351 } protocol_priority_flags
[] = {
352 {SP_PROT_DTLS1_2_CLIENT
, "VERS-DTLS1.2"},
353 {SP_PROT_DTLS1_0_CLIENT
, "VERS-DTLS1.0"},
354 {SP_PROT_TLS1_3_CLIENT
, "VERS-TLS1.3"},
355 {SP_PROT_TLS1_2_CLIENT
, "VERS-TLS1.2"},
356 {SP_PROT_TLS1_1_CLIENT
, "VERS-TLS1.1"},
357 {SP_PROT_TLS1_0_CLIENT
, "VERS-TLS1.0"},
358 {SP_PROT_SSL3_CLIENT
, "VERS-SSL3.0"}
359 /* {SP_PROT_SSL2_CLIENT} is not supported by GnuTLS */
362 static DWORD supported_protocols
;
364 static void check_supported_protocols(void)
366 gnutls_session_t session
;
371 err
= pgnutls_init(&session
, GNUTLS_CLIENT
);
372 if (err
!= GNUTLS_E_SUCCESS
)
378 for(i
= 0; i
< ARRAY_SIZE(protocol_priority_flags
); i
++)
380 sprintf(priority
, "NORMAL:-%s", protocol_priority_flags
[i
].gnutls_flag
);
381 err
= pgnutls_priority_set_direct(session
, priority
, NULL
);
382 if (err
== GNUTLS_E_SUCCESS
)
384 TRACE("%s is supported\n", protocol_priority_flags
[i
].gnutls_flag
);
385 supported_protocols
|= protocol_priority_flags
[i
].enable_flag
;
388 TRACE("%s is not supported\n", protocol_priority_flags
[i
].gnutls_flag
);
391 pgnutls_deinit(session
);
394 static NTSTATUS
schan_get_enabled_protocols( void *args
)
396 return supported_protocols
;
399 static int pull_timeout(gnutls_transport_ptr_t transport
, unsigned int timeout
)
401 struct schan_transport
*t
= (struct schan_transport
*)transport
;
406 if (get_buffer(&t
->in
, &count
)) return 1;
411 static NTSTATUS
schan_create_session( void *args
)
413 const struct create_session_params
*params
= args
;
414 schan_credentials
*cred
= params
->cred
;
415 char priority
[128] = "NORMAL:%LATEST_RECORD_VERSION", *p
;
416 BOOL using_vers_all
= FALSE
, disabled
;
417 unsigned int i
, flags
= (cred
->credential_use
== SECPKG_CRED_INBOUND
) ? GNUTLS_SERVER
: GNUTLS_CLIENT
;
418 struct schan_transport
*transport
;
422 *params
->session
= 0;
424 if (cred
->enabled_protocols
& (SP_PROT_DTLS1_0_CLIENT
| SP_PROT_DTLS1_2_CLIENT
))
426 flags
|= GNUTLS_DATAGRAM
| GNUTLS_NONBLOCK
;
429 err
= pgnutls_init(&s
, flags
);
430 if (err
!= GNUTLS_E_SUCCESS
)
433 return STATUS_INTERNAL_ERROR
;
436 if (!(transport
= calloc(1, sizeof(*transport
))))
439 return STATUS_INTERNAL_ERROR
;
441 transport
->session
= s
;
443 p
= priority
+ strlen(priority
);
445 /* VERS-ALL is nice to use for forward compatibility. It was introduced before support for TLS1.3,
446 * so if TLS1.3 is supported, we may safely use it. Otherwise explicitly disable all known
447 * disabled protocols. */
448 if (supported_protocols
& SP_PROT_TLS1_3_CLIENT
)
450 strcpy(p
, ":-VERS-ALL");
452 using_vers_all
= TRUE
;
455 for (i
= 0; i
< ARRAY_SIZE(protocol_priority_flags
); i
++)
457 if (!(supported_protocols
& protocol_priority_flags
[i
].enable_flag
)) continue;
459 disabled
= !(cred
->enabled_protocols
& protocol_priority_flags
[i
].enable_flag
);
460 if (using_vers_all
&& disabled
) continue;
463 *p
++ = disabled
? '-' : '+';
464 strcpy(p
, protocol_priority_flags
[i
].gnutls_flag
);
468 TRACE("Using %s priority\n", debugstr_a(priority
));
469 err
= pgnutls_priority_set_direct(s
, priority
, NULL
);
470 if (err
!= GNUTLS_E_SUCCESS
)
475 return STATUS_INTERNAL_ERROR
;
478 err
= pgnutls_credentials_set(s
, GNUTLS_CRD_CERTIFICATE
, certificate_creds_from_handle(cred
->credentials
));
479 if (err
!= GNUTLS_E_SUCCESS
)
484 return STATUS_INTERNAL_ERROR
;
487 pgnutls_transport_set_pull_function(s
, pull_adapter
);
488 if (flags
& GNUTLS_DATAGRAM
) pgnutls_transport_set_pull_timeout_function(s
, pull_timeout
);
489 pgnutls_transport_set_push_function(s
, push_adapter
);
490 pgnutls_transport_set_ptr(s
, (gnutls_transport_ptr_t
)transport
);
491 *params
->session
= (ULONG_PTR
)s
;
493 return STATUS_SUCCESS
;
496 static NTSTATUS
schan_dispose_session( void *args
)
498 const struct session_params
*params
= args
;
499 gnutls_session_t s
= session_from_handle(params
->session
);
500 struct schan_transport
*t
= (struct schan_transport
*)pgnutls_transport_get_ptr(s
);
501 pgnutls_transport_set_ptr(s
, NULL
);
504 return STATUS_SUCCESS
;
507 static NTSTATUS
schan_set_session_target( void *args
)
509 const struct set_session_target_params
*params
= args
;
510 gnutls_session_t s
= session_from_handle(params
->session
);
511 pgnutls_server_name_set( s
, GNUTLS_NAME_DNS
, params
->target
, strlen(params
->target
) );
512 return STATUS_SUCCESS
;
515 static NTSTATUS
schan_handshake( void *args
)
517 const struct handshake_params
*params
= args
;
518 gnutls_session_t s
= session_from_handle(params
->session
);
519 struct schan_transport
*t
= (struct schan_transport
*)pgnutls_transport_get_ptr(s
);
523 init_schan_buffers(&t
->in
, params
->input
);
524 t
->in
.limit
= params
->input_size
;
525 init_schan_buffers(&t
->out
, params
->output
);
529 err
= pgnutls_handshake(s
);
530 if (err
== GNUTLS_E_SUCCESS
)
532 TRACE("Handshake completed\n");
535 else if (err
== GNUTLS_E_AGAIN
)
537 TRACE("Continue...\n");
538 status
= SEC_I_CONTINUE_NEEDED
;
540 else if (err
== GNUTLS_E_WARNING_ALERT_RECEIVED
)
542 gnutls_alert_description_t alert
= pgnutls_alert_get(s
);
544 WARN("WARNING ALERT: %d %s\n", alert
, pgnutls_alert_get_name(alert
));
546 if (alert
== GNUTLS_A_UNRECOGNIZED_NAME
)
552 status
= SEC_E_INTERNAL_ERROR
;
554 else if (err
== GNUTLS_E_FATAL_ALERT_RECEIVED
)
556 gnutls_alert_description_t alert
= pgnutls_alert_get(s
);
557 WARN("FATAL ALERT: %d %s\n", alert
, pgnutls_alert_get_name(alert
));
558 status
= SEC_E_INTERNAL_ERROR
;
563 status
= SEC_E_INTERNAL_ERROR
;
568 *params
->input_offset
= t
->in
.offset
;
569 *params
->output_buffer_idx
= t
->out
.current_buffer_idx
;
570 *params
->output_offset
= t
->out
.offset
;
575 static DWORD
get_protocol(gnutls_protocol_t proto
)
577 /* FIXME: currently schannel only implements client connections, but
578 * there's no reason it couldn't be used for servers as well. The
579 * context doesn't tell us which it is, so assume client for now.
583 case GNUTLS_SSL3
: return SP_PROT_SSL3_CLIENT
;
584 case GNUTLS_TLS1_0
: return SP_PROT_TLS1_0_CLIENT
;
585 case GNUTLS_TLS1_1
: return SP_PROT_TLS1_1_CLIENT
;
586 case GNUTLS_TLS1_2
: return SP_PROT_TLS1_2_CLIENT
;
587 case GNUTLS_DTLS1_0
: return SP_PROT_DTLS1_0_CLIENT
;
588 case GNUTLS_DTLS1_2
: return SP_PROT_DTLS1_2_CLIENT
;
590 FIXME("unknown protocol %d\n", proto
);
595 static ALG_ID
get_cipher_algid(gnutls_cipher_algorithm_t cipher
)
599 case GNUTLS_CIPHER_UNKNOWN
:
600 case GNUTLS_CIPHER_NULL
: return 0;
601 case GNUTLS_CIPHER_ARCFOUR_40
:
602 case GNUTLS_CIPHER_ARCFOUR_128
: return CALG_RC4
;
603 case GNUTLS_CIPHER_DES_CBC
: return CALG_DES
;
604 case GNUTLS_CIPHER_3DES_CBC
: return CALG_3DES
;
605 case GNUTLS_CIPHER_AES_128_CBC
:
606 case GNUTLS_CIPHER_AES_128_GCM
: return CALG_AES_128
;
607 case GNUTLS_CIPHER_AES_192_CBC
: return CALG_AES_192
;
608 case GNUTLS_CIPHER_AES_256_GCM
:
609 case GNUTLS_CIPHER_AES_256_CBC
: return CALG_AES_256
;
610 case GNUTLS_CIPHER_RC2_40_CBC
: return CALG_RC2
;
612 FIXME("unknown algorithm %d\n", cipher
);
617 static ALG_ID
get_mac_algid(gnutls_mac_algorithm_t mac
, gnutls_cipher_algorithm_t cipher
)
621 case GNUTLS_MAC_UNKNOWN
:
622 case GNUTLS_MAC_NULL
: return 0;
623 case GNUTLS_MAC_MD2
: return CALG_MD2
;
624 case GNUTLS_MAC_MD5
: return CALG_MD5
;
625 case GNUTLS_MAC_SHA1
: return CALG_SHA1
;
626 case GNUTLS_MAC_SHA256
: return CALG_SHA_256
;
627 case GNUTLS_MAC_SHA384
: return CALG_SHA_384
;
628 case GNUTLS_MAC_SHA512
: return CALG_SHA_512
;
629 case GNUTLS_MAC_AEAD
:
630 /* When using AEAD (such as GCM), we return PRF algorithm instead
631 which is defined in RFC 5289. */
634 case GNUTLS_CIPHER_AES_128_GCM
: return CALG_SHA_256
;
635 case GNUTLS_CIPHER_AES_256_GCM
: return CALG_SHA_384
;
641 FIXME("unknown algorithm %d, cipher %d\n", mac
, cipher
);
646 static ALG_ID
get_kx_algid(int kx
)
650 case GNUTLS_KX_UNKNOWN
: return 0;
652 case GNUTLS_KX_RSA_EXPORT
: return CALG_RSA_KEYX
;
653 case GNUTLS_KX_DHE_PSK
:
654 case GNUTLS_KX_DHE_DSS
:
655 case GNUTLS_KX_DHE_RSA
: return CALG_DH_EPHEM
;
656 case GNUTLS_KX_ANON_ECDH
: return CALG_ECDH
;
657 case GNUTLS_KX_ECDHE_RSA
:
658 case GNUTLS_KX_ECDHE_PSK
:
659 case GNUTLS_KX_ECDHE_ECDSA
: return CALG_ECDH_EPHEM
;
661 FIXME("unknown algorithm %d\n", kx
);
666 static NTSTATUS
schan_get_session_cipher_block_size( void *args
)
668 const struct session_params
*params
= args
;
669 gnutls_session_t s
= session_from_handle(params
->session
);
670 return pgnutls_cipher_get_block_size(pgnutls_cipher_get(s
));
673 static NTSTATUS
schan_get_max_message_size( void *args
)
675 const struct session_params
*params
= args
;
676 gnutls_session_t s
= session_from_handle(params
->session
);
677 return pgnutls_record_get_max_size(s
);
680 static NTSTATUS
schan_get_connection_info( void *args
)
682 const struct get_connection_info_params
*params
= args
;
683 gnutls_session_t s
= session_from_handle(params
->session
);
684 SecPkgContext_ConnectionInfo
*info
= params
->info
;
685 gnutls_protocol_t proto
= pgnutls_protocol_get_version(s
);
686 gnutls_cipher_algorithm_t alg
= pgnutls_cipher_get(s
);
687 gnutls_mac_algorithm_t mac
= pgnutls_mac_get(s
);
688 gnutls_kx_algorithm_t kx
= pgnutls_kx_get(s
);
690 info
->dwProtocol
= get_protocol(proto
);
691 info
->aiCipher
= get_cipher_algid(alg
);
692 info
->dwCipherStrength
= pgnutls_cipher_get_key_size(alg
) * 8;
693 info
->aiHash
= get_mac_algid(mac
, alg
);
694 info
->dwHashStrength
= pgnutls_mac_get_key_size(mac
) * 8;
695 info
->aiExch
= get_kx_algid(kx
);
696 /* FIXME: info->dwExchStrength? */
697 info
->dwExchStrength
= 0;
701 static DWORD
get_protocol_version( gnutls_session_t session
)
703 gnutls_protocol_t proto
= pgnutls_protocol_get_version( session
);
707 case GNUTLS_SSL3
: return 0x300;
708 case GNUTLS_TLS1_0
: return 0x301;
709 case GNUTLS_TLS1_1
: return 0x302;
710 case GNUTLS_TLS1_2
: return 0x303;
711 case GNUTLS_DTLS1_0
: return 0x201;
712 case GNUTLS_DTLS1_2
: return 0x202;
714 FIXME( "unknown protocol %u\n", proto
);
719 static const WCHAR
*get_cipher_str( gnutls_session_t session
)
721 static const WCHAR aesW
[] = {'A','E','S',0};
722 static const WCHAR unknownW
[] = {'<','u','n','k','n','o','w','n','>',0};
723 gnutls_cipher_algorithm_t cipher
= pgnutls_cipher_get( session
);
727 case GNUTLS_CIPHER_AES_128_CBC
:
728 case GNUTLS_CIPHER_AES_192_CBC
:
729 case GNUTLS_CIPHER_AES_256_CBC
:
730 case GNUTLS_CIPHER_AES_128_GCM
:
731 case GNUTLS_CIPHER_AES_256_GCM
:
732 case GNUTLS_CIPHER_AES_128_CCM
:
733 case GNUTLS_CIPHER_AES_256_CCM
:
736 FIXME( "unknown cipher %u\n", cipher
);
741 static DWORD
get_cipher_len( gnutls_session_t session
)
743 gnutls_cipher_algorithm_t cipher
= pgnutls_cipher_get( session
);
747 case GNUTLS_CIPHER_AES_128_CBC
:
748 case GNUTLS_CIPHER_AES_128_GCM
:
749 case GNUTLS_CIPHER_AES_128_CCM
:
751 case GNUTLS_CIPHER_AES_192_CBC
:
753 case GNUTLS_CIPHER_AES_256_CBC
:
754 case GNUTLS_CIPHER_AES_256_GCM
:
755 case GNUTLS_CIPHER_AES_256_CCM
:
758 FIXME( "unknown cipher %u\n", cipher
);
763 static DWORD
get_cipher_block_len( gnutls_session_t session
)
765 gnutls_cipher_algorithm_t cipher
= pgnutls_cipher_get( session
);
766 return pgnutls_cipher_get_block_size( cipher
);
769 static const WCHAR
*get_hash_str( gnutls_session_t session
, BOOL full
)
771 static const WCHAR shaW
[] = {'S','H','A',0};
772 static const WCHAR sha1W
[] = {'S','H','A','1',0};
773 static const WCHAR sha224W
[] = {'S','H','A','2','2','4',0};
774 static const WCHAR sha256W
[] = {'S','H','A','2','5','6',0};
775 static const WCHAR sha384W
[] = {'S','H','A','3','8','4',0};
776 static const WCHAR sha512W
[] = {'S','H','A','5','1','2',0};
777 static const WCHAR unknownW
[] = {'<','u','n','k','n','o','w','n','>',0};
778 gnutls_mac_algorithm_t mac
= pgnutls_mac_get( session
);
782 case GNUTLS_MAC_SHA1
: return full
? sha1W
: shaW
;
783 case GNUTLS_MAC_SHA224
: return sha224W
;
784 case GNUTLS_MAC_SHA256
: return sha256W
;
785 case GNUTLS_MAC_SHA384
: return sha384W
;
786 case GNUTLS_MAC_SHA512
: return sha512W
;
788 FIXME( "unknown mac %u\n", mac
);
793 static DWORD
get_hash_len( gnutls_session_t session
)
795 gnutls_mac_algorithm_t mac
= pgnutls_mac_get( session
);
796 return pgnutls_mac_get_key_size( mac
) * 8;
799 static const WCHAR
*get_exchange_str( gnutls_session_t session
, BOOL full
)
801 static const WCHAR ecdhW
[] = {'E','C','D','H',0};
802 static const WCHAR ecdheW
[] = {'E','C','D','H','E',0};
803 static const WCHAR unknownW
[] = {'<','u','n','k','n','o','w','n','>',0};
804 gnutls_kx_algorithm_t kx
= pgnutls_kx_get( session
);
808 case GNUTLS_KX_ECDHE_RSA
:
809 case GNUTLS_KX_ECDHE_ECDSA
:
810 return full
? ecdheW
: ecdhW
;
812 FIXME( "unknown kx %u\n", kx
);
817 static const WCHAR
*get_certificate_str( gnutls_session_t session
)
819 static const WCHAR rsaW
[] = {'R','S','A',0};
820 static const WCHAR ecdsaW
[] = {'E','C','D','S','A',0};
821 static const WCHAR unknownW
[] = {'<','u','n','k','n','o','w','n','>',0};
822 gnutls_kx_algorithm_t kx
= pgnutls_kx_get( session
);
827 case GNUTLS_KX_RSA_EXPORT
:
828 case GNUTLS_KX_DHE_RSA
:
829 case GNUTLS_KX_ECDHE_RSA
: return rsaW
;
830 case GNUTLS_KX_ECDHE_ECDSA
: return ecdsaW
;
832 FIXME( "unknown kx %u\n", kx
);
837 static const WCHAR
*get_chaining_mode_str( gnutls_session_t session
)
839 static const WCHAR cbcW
[] = {'C','B','C',0};
840 static const WCHAR ccmW
[] = {'C','C','M',0};
841 static const WCHAR gcmW
[] = {'G','C','M',0};
842 static const WCHAR unknownW
[] = {'<','u','n','k','n','o','w','n','>',0};
843 gnutls_cipher_algorithm_t cipher
= pgnutls_cipher_get( session
);
847 case GNUTLS_CIPHER_AES_128_CBC
:
848 case GNUTLS_CIPHER_AES_192_CBC
:
849 case GNUTLS_CIPHER_AES_256_CBC
:
851 case GNUTLS_CIPHER_AES_128_GCM
:
852 case GNUTLS_CIPHER_AES_256_GCM
:
854 case GNUTLS_CIPHER_AES_128_CCM
:
855 case GNUTLS_CIPHER_AES_256_CCM
:
858 FIXME( "unknown cipher %u\n", cipher
);
863 static NTSTATUS
schan_get_cipher_info( void *args
)
865 const WCHAR tlsW
[] = {'T','L','S','_',0};
866 const WCHAR underscoreW
[] = {'_',0};
867 const WCHAR widthW
[] = {'_','W','I','T','H','_',0};
868 const struct get_cipher_info_params
*params
= args
;
869 gnutls_session_t session
= session_from_handle( params
->session
);
870 SecPkgContext_CipherInfo
*info
= params
->info
;
875 info
->dwProtocol
= get_protocol_version( session
);
876 info
->dwCipherSuite
= 0; /* FIXME */
877 info
->dwBaseCipherSuite
= 0; /* FIXME */
878 wcscpy( info
->szCipher
, get_cipher_str( session
) );
879 info
->dwCipherLen
= get_cipher_len( session
);
880 info
->dwCipherBlockLen
= get_cipher_block_len( session
);
881 wcscpy( info
->szHash
, get_hash_str( session
, TRUE
) );
882 info
->dwHashLen
= get_hash_len( session
);
883 wcscpy( info
->szExchange
, get_exchange_str( session
, FALSE
) );
884 info
->dwMinExchangeLen
= 0;
885 info
->dwMaxExchangeLen
= 65536;
886 wcscpy( info
->szCertificate
, get_certificate_str( session
) );
887 info
->dwKeyType
= 0; /* FIXME */
889 wcscpy( info
->szCipherSuite
, tlsW
);
890 wcscat( info
->szCipherSuite
, get_exchange_str( session
, TRUE
) );
891 wcscat( info
->szCipherSuite
, underscoreW
);
892 wcscat( info
->szCipherSuite
, info
->szCertificate
);
893 wcscat( info
->szCipherSuite
, widthW
);
894 wcscat( info
->szCipherSuite
, info
->szCipher
);
895 wcscat( info
->szCipherSuite
, underscoreW
);
896 len
= sprintf( buf
, "%u", (unsigned int)info
->dwCipherLen
) + 1;
897 ptr
= info
->szCipherSuite
+ wcslen( info
->szCipherSuite
);
898 ntdll_umbstowcs( buf
, len
, ptr
, len
);
899 wcscat( info
->szCipherSuite
, underscoreW
);
900 wcscat( info
->szCipherSuite
, get_chaining_mode_str( session
) );
901 wcscat( info
->szCipherSuite
, underscoreW
);
902 wcscat( info
->szCipherSuite
, get_hash_str( session
, FALSE
) );
906 static NTSTATUS
schan_get_unique_channel_binding( void *args
)
908 const struct get_unique_channel_binding_params
*params
= args
;
909 gnutls_session_t s
= session_from_handle(params
->session
);
910 gnutls_datum_t datum
;
914 rc
= pgnutls_session_channel_binding(s
, GNUTLS_CB_TLS_UNIQUE
, &datum
);
918 return SEC_E_INTERNAL_ERROR
;
920 if (params
->buffer
&& *params
->bufsize
>= datum
.size
)
922 memcpy( params
->buffer
, datum
.data
, datum
.size
);
925 else ret
= SEC_E_BUFFER_TOO_SMALL
;
927 *params
->bufsize
= datum
.size
;
932 static NTSTATUS
schan_get_key_signature_algorithm( void *args
)
934 const struct session_params
*params
= args
;
935 gnutls_session_t s
= session_from_handle(params
->session
);
936 gnutls_kx_algorithm_t kx
= pgnutls_kx_get(s
);
942 case GNUTLS_KX_UNKNOWN
: return 0;
944 case GNUTLS_KX_RSA_EXPORT
:
945 case GNUTLS_KX_DHE_RSA
:
946 case GNUTLS_KX_ECDHE_RSA
: return CALG_RSA_SIGN
;
947 case GNUTLS_KX_ECDHE_ECDSA
: return CALG_ECDSA
;
949 FIXME("unknown algorithm %d\n", kx
);
954 static NTSTATUS
schan_get_session_peer_certificate( void *args
)
956 const struct get_session_peer_certificate_params
*params
= args
;
957 gnutls_session_t s
= session_from_handle(params
->session
);
958 const gnutls_datum_t
*datum
;
959 unsigned int i
, size
;
964 if (!(datum
= pgnutls_certificate_get_peers(s
, &count
))) return SEC_E_INTERNAL_ERROR
;
966 size
= count
* sizeof(*sizes
);
967 for (i
= 0; i
< count
; i
++) size
+= datum
[i
].size
;
969 if (!params
->buffer
|| *params
->bufsize
< size
)
971 *params
->bufsize
= size
;
972 return SEC_E_BUFFER_TOO_SMALL
;
974 sizes
= (ULONG
*)params
->buffer
;
975 ptr
= params
->buffer
+ count
* sizeof(*sizes
);
976 for (i
= 0; i
< count
; i
++)
978 sizes
[i
] = datum
[i
].size
;
979 memcpy(ptr
, datum
[i
].data
, datum
[i
].size
);
980 ptr
+= datum
[i
].size
;
983 *params
->bufsize
= size
;
984 *params
->retcount
= count
;
988 static NTSTATUS
schan_send( void *args
)
990 const struct send_params
*params
= args
;
991 gnutls_session_t s
= session_from_handle(params
->session
);
992 struct schan_transport
*t
= (struct schan_transport
*)pgnutls_transport_get_ptr(s
);
993 SSIZE_T ret
, total
= 0;
995 init_schan_buffers(&t
->out
, params
->output
);
999 ret
= pgnutls_record_send(s
, (const char *)params
->buffer
+ total
, params
->length
- total
);
1003 TRACE( "sent %ld now %ld/%u\n", ret
, total
, (unsigned)params
->length
);
1004 if (total
== params
->length
) break;
1006 else if (ret
== GNUTLS_E_AGAIN
)
1010 if (get_buffer(&t
->out
, &count
)) continue;
1011 return SEC_I_CONTINUE_NEEDED
;
1015 pgnutls_perror(ret
);
1016 return SEC_E_INTERNAL_ERROR
;
1020 *params
->output_buffer_idx
= t
->out
.current_buffer_idx
;
1021 *params
->output_offset
= t
->out
.offset
;
1025 static NTSTATUS
schan_recv( void *args
)
1027 const struct recv_params
*params
= args
;
1028 gnutls_session_t s
= session_from_handle(params
->session
);
1029 struct schan_transport
*t
= (struct schan_transport
*)pgnutls_transport_get_ptr(s
);
1030 size_t data_size
= *params
->length
;
1031 size_t received
= 0;
1033 SECURITY_STATUS status
= SEC_E_OK
;
1035 init_schan_buffers(&t
->in
, params
->input
);
1036 t
->in
.limit
= params
->input_size
;
1038 while (received
< data_size
)
1040 ret
= pgnutls_record_recv(s
, (char *)params
->buffer
+ received
, data_size
- received
);
1042 if (ret
> 0) received
+= ret
;
1043 else if (!ret
) break;
1044 else if (ret
== GNUTLS_E_AGAIN
)
1048 if (!get_buffer(&t
->in
, &count
)) break;
1050 else if (ret
== GNUTLS_E_REHANDSHAKE
)
1052 TRACE("Rehandshake requested\n");
1053 status
= SEC_I_RENEGOTIATE
;
1058 pgnutls_perror(ret
);
1059 return SEC_E_INTERNAL_ERROR
;
1063 *params
->length
= received
;
1067 static unsigned int parse_alpn_protocol_list(unsigned char *buffer
, unsigned int buflen
, gnutls_datum_t
*list
)
1069 unsigned int len
, offset
= 0, count
= 0;
1073 len
= buffer
[offset
++];
1075 if (!len
|| len
> buflen
) return 0;
1078 list
[count
].data
= &buffer
[offset
];
1079 list
[count
].size
= len
;
1089 static NTSTATUS
schan_set_application_protocols( void *args
)
1091 const struct set_application_protocols_params
*params
= args
;
1092 gnutls_session_t s
= session_from_handle(params
->session
);
1093 unsigned int extension_len
, extension
, count
= 0, offset
= 0;
1094 unsigned short list_len
;
1095 gnutls_datum_t
*protocols
;
1098 if (sizeof(extension_len
) > params
->buflen
) return STATUS_INVALID_PARAMETER
;
1099 extension_len
= *(unsigned int *)¶ms
->buffer
[offset
];
1100 offset
+= sizeof(extension_len
);
1102 if (offset
+ sizeof(extension
) > params
->buflen
) return STATUS_INVALID_PARAMETER
;
1103 extension
= *(unsigned int *)¶ms
->buffer
[offset
];
1104 if (extension
!= SecApplicationProtocolNegotiationExt_ALPN
)
1106 FIXME("extension %u not supported\n", extension
);
1107 return STATUS_NOT_SUPPORTED
;
1109 offset
+= sizeof(extension
);
1111 if (offset
+ sizeof(list_len
) > params
->buflen
) return STATUS_INVALID_PARAMETER
;
1112 list_len
= *(unsigned short *)¶ms
->buffer
[offset
];
1113 offset
+= sizeof(list_len
);
1115 if (offset
+ list_len
> params
->buflen
) return STATUS_INVALID_PARAMETER
;
1116 count
= parse_alpn_protocol_list(¶ms
->buffer
[offset
], list_len
, NULL
);
1117 if (!count
|| !(protocols
= malloc(count
* sizeof(*protocols
)))) return STATUS_NO_MEMORY
;
1119 parse_alpn_protocol_list(¶ms
->buffer
[offset
], list_len
, protocols
);
1120 if ((ret
= pgnutls_alpn_set_protocols(s
, protocols
, count
, GNUTLS_ALPN_SERVER_PRECEDENCE
) < 0))
1122 pgnutls_perror(ret
);
1126 return STATUS_SUCCESS
;
1129 static NTSTATUS
schan_get_application_protocol( void *args
)
1131 const struct get_application_protocol_params
*params
= args
;
1132 gnutls_session_t s
= session_from_handle(params
->session
);
1133 SecPkgContext_ApplicationProtocol
*protocol
= params
->protocol
;
1134 gnutls_datum_t selected
;
1136 memset(protocol
, 0, sizeof(*protocol
));
1137 if (pgnutls_alpn_get_selected_protocol(s
, &selected
) < 0) return SEC_E_OK
;
1139 if (selected
.size
<= sizeof(protocol
->ProtocolId
))
1141 protocol
->ProtoNegoStatus
= SecApplicationProtocolNegotiationStatus_Success
;
1142 protocol
->ProtoNegoExt
= SecApplicationProtocolNegotiationExt_ALPN
;
1143 protocol
->ProtocolIdSize
= selected
.size
;
1144 memcpy(protocol
->ProtocolId
, selected
.data
, selected
.size
);
1145 TRACE("returning %s\n", wine_dbgstr_an((const char *)selected
.data
, selected
.size
));
1150 static NTSTATUS
schan_set_dtls_mtu( void *args
)
1152 const struct set_dtls_mtu_params
*params
= args
;
1153 gnutls_session_t s
= session_from_handle(params
->session
);
1155 pgnutls_dtls_set_mtu(s
, params
->mtu
);
1156 TRACE("MTU set to %u\n", params
->mtu
);
1160 static NTSTATUS
schan_set_dtls_timeouts( void *args
)
1162 const struct set_dtls_timeouts_params
*params
= args
;
1163 gnutls_session_t s
= session_from_handle(params
->session
);
1165 pgnutls_dtls_set_timeouts(s
, params
->retrans_timeout
, params
->total_timeout
);
1169 static inline void reverse_bytes(BYTE
*buf
, ULONG len
)
1173 for (i
= 0; i
< len
/ 2; i
++)
1176 buf
[i
] = buf
[len
- i
- 1];
1177 buf
[len
- i
- 1] = tmp
;
1181 static ULONG
set_component(gnutls_datum_t
*comp
, BYTE
*data
, ULONG len
, ULONG
*buflen
)
1185 reverse_bytes(comp
->data
, comp
->size
);
1186 if (comp
->data
[0] & 0x80) /* add leading 0 byte if most significant bit is set */
1188 memmove(comp
->data
+ 1, comp
->data
, *buflen
);
1192 *buflen
-= comp
->size
;
1196 static gnutls_x509_privkey_t
get_x509_key(ULONG key_size
, const BYTE
*key_blob
)
1198 gnutls_privkey_t key
= NULL
;
1199 gnutls_x509_privkey_t x509key
= NULL
;
1200 gnutls_datum_t m
, e
, d
, p
, q
, u
, e1
, e2
;
1203 DWORD size
= key_size
;
1206 if (size
< sizeof(BLOBHEADER
)) return NULL
;
1208 rsakey
= (RSAPUBKEY
*)(key_blob
+ sizeof(BLOBHEADER
));
1209 TRACE("RSA key bitlen %u pubexp %u\n", (unsigned)rsakey
->bitlen
, (unsigned)rsakey
->pubexp
);
1211 size
-= sizeof(BLOBHEADER
) + FIELD_OFFSET(RSAPUBKEY
, pubexp
);
1212 set_component(&e
, (BYTE
*)&rsakey
->pubexp
, sizeof(rsakey
->pubexp
), &size
);
1214 ptr
= (BYTE
*)(rsakey
+ 1);
1215 ptr
+= set_component(&m
, ptr
, rsakey
->bitlen
/ 8, &size
);
1216 ptr
+= set_component(&p
, ptr
, rsakey
->bitlen
/ 16, &size
);
1217 ptr
+= set_component(&q
, ptr
, rsakey
->bitlen
/ 16, &size
);
1218 ptr
+= set_component(&e1
, ptr
, rsakey
->bitlen
/ 16, &size
);
1219 ptr
+= set_component(&e2
, ptr
, rsakey
->bitlen
/ 16, &size
);
1220 ptr
+= set_component(&u
, ptr
, rsakey
->bitlen
/ 16, &size
);
1221 ptr
+= set_component(&d
, ptr
, rsakey
->bitlen
/ 8, &size
);
1223 if ((ret
= pgnutls_privkey_init(&key
)) < 0)
1225 pgnutls_perror(ret
);
1229 if (((ret
= pgnutls_privkey_import_rsa_raw(key
, &m
, &e
, &d
, &p
, &q
, &u
, &e1
, &e2
)) < 0) ||
1230 (ret
= pgnutls_privkey_export_x509(key
, &x509key
)) < 0)
1232 pgnutls_perror(ret
);
1233 pgnutls_privkey_deinit(key
);
1240 static gnutls_x509_crt_t
get_x509_crt(const struct allocate_certificate_credentials_params
*params
)
1242 gnutls_datum_t data
;
1243 gnutls_x509_crt_t crt
;
1246 if (params
->cert_encoding
!= X509_ASN_ENCODING
)
1248 FIXME("encoding type %u not supported\n", (unsigned)params
->cert_encoding
);
1252 if ((ret
= pgnutls_x509_crt_init(&crt
)) < 0)
1254 pgnutls_perror(ret
);
1258 data
.data
= params
->cert_blob
;
1259 data
.size
= params
->cert_size
;
1260 if ((ret
= pgnutls_x509_crt_import(crt
, &data
, GNUTLS_X509_FMT_DER
)) < 0)
1262 pgnutls_perror(ret
);
1263 pgnutls_x509_crt_deinit(crt
);
1270 static NTSTATUS
schan_allocate_certificate_credentials( void *args
)
1272 const struct allocate_certificate_credentials_params
*params
= args
;
1273 gnutls_certificate_credentials_t creds
;
1274 gnutls_x509_crt_t crt
;
1275 gnutls_x509_privkey_t key
;
1278 ret
= pgnutls_certificate_allocate_credentials(&creds
);
1279 if (ret
!= GNUTLS_E_SUCCESS
)
1281 pgnutls_perror(ret
);
1282 return STATUS_INTERNAL_ERROR
;
1285 if (!params
->cert_blob
)
1287 params
->c
->credentials
= (ULONG_PTR
)creds
;
1288 return STATUS_SUCCESS
;
1291 if (!(crt
= get_x509_crt(params
)))
1293 pgnutls_certificate_free_credentials(creds
);
1294 return STATUS_INTERNAL_ERROR
;
1297 if (!(key
= get_x509_key(params
->key_size
, params
->key_blob
)))
1299 pgnutls_x509_crt_deinit(crt
);
1300 pgnutls_certificate_free_credentials(creds
);
1301 return STATUS_INTERNAL_ERROR
;
1304 ret
= pgnutls_certificate_set_x509_key(creds
, &crt
, 1, key
);
1305 pgnutls_x509_privkey_deinit(key
);
1306 pgnutls_x509_crt_deinit(crt
);
1307 if (ret
!= GNUTLS_E_SUCCESS
)
1309 pgnutls_perror(ret
);
1310 pgnutls_certificate_free_credentials(creds
);
1311 return STATUS_INTERNAL_ERROR
;
1314 params
->c
->credentials
= (ULONG_PTR
)creds
;
1315 return STATUS_SUCCESS
;
1318 static NTSTATUS
schan_free_certificate_credentials( void *args
)
1320 const struct free_certificate_credentials_params
*params
= args
;
1321 pgnutls_certificate_free_credentials(certificate_creds_from_handle(params
->c
->credentials
));
1322 return STATUS_SUCCESS
;
1325 static void gnutls_log(int level
, const char *msg
)
1327 TRACE("<%d> %s", level
, msg
);
1330 static NTSTATUS
process_attach( void *args
)
1332 const char *env_str
;
1335 if ((env_str
= getenv("GNUTLS_SYSTEM_PRIORITY_FILE")))
1337 WARN("GNUTLS_SYSTEM_PRIORITY_FILE is %s.\n", debugstr_a(env_str
));
1341 WARN("Setting GNUTLS_SYSTEM_PRIORITY_FILE to \"/dev/null\".\n");
1342 setenv("GNUTLS_SYSTEM_PRIORITY_FILE", "/dev/null", 0);
1345 libgnutls_handle
= dlopen(SONAME_LIBGNUTLS
, RTLD_NOW
);
1346 if (!libgnutls_handle
)
1348 ERR_(winediag
)("Failed to load libgnutls, secure connections will not be available.\n");
1349 return STATUS_DLL_NOT_FOUND
;
1352 #define LOAD_FUNCPTR(f) \
1353 if (!(p##f = dlsym(libgnutls_handle, #f))) \
1355 ERR("Failed to load %s\n", #f); \
1359 LOAD_FUNCPTR(gnutls_alert_get
)
1360 LOAD_FUNCPTR(gnutls_alert_get_name
)
1361 LOAD_FUNCPTR(gnutls_certificate_allocate_credentials
)
1362 LOAD_FUNCPTR(gnutls_certificate_free_credentials
)
1363 LOAD_FUNCPTR(gnutls_certificate_get_peers
)
1364 LOAD_FUNCPTR(gnutls_certificate_set_x509_key
)
1365 LOAD_FUNCPTR(gnutls_cipher_get
)
1366 LOAD_FUNCPTR(gnutls_cipher_get_key_size
)
1367 LOAD_FUNCPTR(gnutls_credentials_set
)
1368 LOAD_FUNCPTR(gnutls_deinit
)
1369 LOAD_FUNCPTR(gnutls_global_deinit
)
1370 LOAD_FUNCPTR(gnutls_global_init
)
1371 LOAD_FUNCPTR(gnutls_global_set_log_function
)
1372 LOAD_FUNCPTR(gnutls_global_set_log_level
)
1373 LOAD_FUNCPTR(gnutls_handshake
)
1374 LOAD_FUNCPTR(gnutls_init
)
1375 LOAD_FUNCPTR(gnutls_kx_get
)
1376 LOAD_FUNCPTR(gnutls_mac_get
)
1377 LOAD_FUNCPTR(gnutls_mac_get_key_size
)
1378 LOAD_FUNCPTR(gnutls_perror
)
1379 LOAD_FUNCPTR(gnutls_protocol_get_version
)
1380 LOAD_FUNCPTR(gnutls_priority_set_direct
)
1381 LOAD_FUNCPTR(gnutls_privkey_deinit
)
1382 LOAD_FUNCPTR(gnutls_privkey_init
)
1383 LOAD_FUNCPTR(gnutls_record_get_max_size
);
1384 LOAD_FUNCPTR(gnutls_record_recv
);
1385 LOAD_FUNCPTR(gnutls_record_send
);
1386 LOAD_FUNCPTR(gnutls_server_name_set
)
1387 LOAD_FUNCPTR(gnutls_session_channel_binding
)
1388 LOAD_FUNCPTR(gnutls_transport_get_ptr
)
1389 LOAD_FUNCPTR(gnutls_transport_set_errno
)
1390 LOAD_FUNCPTR(gnutls_transport_set_ptr
)
1391 LOAD_FUNCPTR(gnutls_transport_set_pull_function
)
1392 LOAD_FUNCPTR(gnutls_transport_set_push_function
)
1393 LOAD_FUNCPTR(gnutls_x509_crt_deinit
)
1394 LOAD_FUNCPTR(gnutls_x509_crt_import
)
1395 LOAD_FUNCPTR(gnutls_x509_crt_init
)
1396 LOAD_FUNCPTR(gnutls_x509_privkey_deinit
)
1399 if (!(pgnutls_cipher_get_block_size
= dlsym(libgnutls_handle
, "gnutls_cipher_get_block_size")))
1401 WARN("gnutls_cipher_get_block_size not found\n");
1402 pgnutls_cipher_get_block_size
= compat_cipher_get_block_size
;
1404 if (!(pgnutls_transport_set_pull_timeout_function
= dlsym(libgnutls_handle
, "gnutls_transport_set_pull_timeout_function")))
1406 WARN("gnutls_transport_set_pull_timeout_function not found\n");
1407 pgnutls_transport_set_pull_timeout_function
= compat_gnutls_transport_set_pull_timeout_function
;
1409 if (!(pgnutls_alpn_set_protocols
= dlsym(libgnutls_handle
, "gnutls_alpn_set_protocols")))
1411 WARN("gnutls_alpn_set_protocols not found\n");
1412 pgnutls_alpn_set_protocols
= compat_gnutls_alpn_set_protocols
;
1414 if (!(pgnutls_alpn_get_selected_protocol
= dlsym(libgnutls_handle
, "gnutls_alpn_get_selected_protocol")))
1416 WARN("gnutls_alpn_get_selected_protocol not found\n");
1417 pgnutls_alpn_get_selected_protocol
= compat_gnutls_alpn_get_selected_protocol
;
1419 if (!(pgnutls_dtls_set_mtu
= dlsym(libgnutls_handle
, "gnutls_dtls_set_mtu")))
1421 WARN("gnutls_dtls_set_mtu not found\n");
1422 pgnutls_dtls_set_mtu
= compat_gnutls_dtls_set_mtu
;
1424 if (!(pgnutls_dtls_set_timeouts
= dlsym(libgnutls_handle
, "gnutls_dtls_set_timeouts")))
1426 WARN("gnutls_dtls_set_timeouts not found\n");
1427 pgnutls_dtls_set_timeouts
= compat_gnutls_dtls_set_timeouts
;
1429 if (!(pgnutls_privkey_export_x509
= dlsym(libgnutls_handle
, "gnutls_privkey_export_x509")))
1431 WARN("gnutls_privkey_export_x509 not found\n");
1432 pgnutls_privkey_export_x509
= compat_gnutls_privkey_export_x509
;
1434 if (!(pgnutls_privkey_import_rsa_raw
= dlsym(libgnutls_handle
, "gnutls_privkey_import_rsa_raw")))
1436 WARN("gnutls_privkey_import_rsa_raw not found\n");
1437 pgnutls_privkey_import_rsa_raw
= compat_gnutls_privkey_import_rsa_raw
;
1440 ret
= pgnutls_global_init();
1441 if (ret
!= GNUTLS_E_SUCCESS
)
1443 pgnutls_perror(ret
);
1447 if (TRACE_ON(secur32
))
1449 pgnutls_global_set_log_level(4);
1450 pgnutls_global_set_log_function(gnutls_log
);
1453 check_supported_protocols();
1454 return STATUS_SUCCESS
;
1457 dlclose(libgnutls_handle
);
1458 libgnutls_handle
= NULL
;
1459 return STATUS_DLL_NOT_FOUND
;
1462 static NTSTATUS
process_detach( void *args
)
1464 pgnutls_global_deinit();
1465 dlclose(libgnutls_handle
);
1466 libgnutls_handle
= NULL
;
1467 return STATUS_SUCCESS
;
1470 const unixlib_entry_t __wine_unix_call_funcs
[] =
1474 schan_allocate_certificate_credentials
,
1475 schan_create_session
,
1476 schan_dispose_session
,
1477 schan_free_certificate_credentials
,
1478 schan_get_application_protocol
,
1479 schan_get_cipher_info
,
1480 schan_get_connection_info
,
1481 schan_get_enabled_protocols
,
1482 schan_get_key_signature_algorithm
,
1483 schan_get_max_message_size
,
1484 schan_get_session_cipher_block_size
,
1485 schan_get_session_peer_certificate
,
1486 schan_get_unique_channel_binding
,
1490 schan_set_application_protocols
,
1492 schan_set_session_target
,
1493 schan_set_dtls_timeouts
,
1498 typedef ULONG PTR32
;
1500 typedef struct SecBufferDesc32
1507 typedef struct SecBuffer32
1514 static NTSTATUS
wow64_schan_allocate_certificate_credentials( void *args
)
1519 ULONG cert_encoding
;
1524 } const *params32
= args
;
1525 struct allocate_certificate_credentials_params params
=
1527 ULongToPtr(params32
->c
),
1528 params32
->cert_encoding
,
1529 params32
->cert_size
,
1530 ULongToPtr(params32
->cert_blob
),
1532 ULongToPtr(params32
->key_blob
),
1534 return schan_allocate_certificate_credentials(¶ms
);
1537 static NTSTATUS
wow64_schan_create_session( void *args
)
1543 } const *params32
= args
;
1544 struct create_session_params params
=
1546 ULongToPtr(params32
->cred
),
1547 ULongToPtr(params32
->session
),
1549 return schan_create_session(¶ms
);
1552 static NTSTATUS
wow64_schan_free_certificate_credentials( void *args
)
1557 } const *params32
= args
;
1558 struct free_certificate_credentials_params params
=
1560 ULongToPtr(params32
->c
),
1562 return schan_free_certificate_credentials(¶ms
);
1565 static NTSTATUS
wow64_schan_get_application_protocol( void *args
)
1569 schan_session session
;
1571 } const *params32
= args
;
1572 struct get_application_protocol_params params
=
1575 ULongToPtr(params32
->protocol
),
1577 return schan_get_application_protocol(¶ms
);
1580 static NTSTATUS
wow64_schan_get_connection_info( void *args
)
1584 schan_session session
;
1586 } const *params32
= args
;
1587 struct get_connection_info_params params
=
1590 ULongToPtr(params32
->info
),
1592 return schan_get_connection_info(¶ms
);
1595 static NTSTATUS
wow64_schan_get_cipher_info( void *args
)
1599 schan_session session
;
1601 } const *params32
= args
;
1602 struct get_cipher_info_params params
=
1605 ULongToPtr(params32
->info
),
1607 return schan_get_cipher_info(¶ms
);
1610 static NTSTATUS
wow64_schan_get_session_peer_certificate( void *args
)
1614 schan_session session
;
1618 } const *params32
= args
;
1619 struct get_session_peer_certificate_params params
=
1622 ULongToPtr(params32
->buffer
),
1623 ULongToPtr(params32
->bufsize
),
1624 ULongToPtr(params32
->retcount
),
1626 return schan_get_session_peer_certificate(¶ms
);
1629 static NTSTATUS
wow64_schan_get_unique_channel_binding( void *args
)
1633 schan_session session
;
1636 } const *params32
= args
;
1637 struct get_unique_channel_binding_params params
=
1640 ULongToPtr(params32
->buffer
),
1641 ULongToPtr(params32
->bufsize
),
1643 return schan_get_unique_channel_binding(¶ms
);
1646 static void secbufferdesc_32to64(const SecBufferDesc32
*desc32
, SecBufferDesc
*desc
)
1650 desc
->ulVersion
= desc32
->ulVersion
;
1651 desc
->cBuffers
= desc32
->cBuffers
;
1652 for (i
= 0; i
< desc
->cBuffers
; ++i
)
1654 SecBuffer32
*buffer32
= ULongToPtr(desc32
->pBuffers
+ i
* sizeof(*buffer32
));
1655 desc
->pBuffers
[i
].cbBuffer
= buffer32
->cbBuffer
;
1656 desc
->pBuffers
[i
].BufferType
= buffer32
->BufferType
;
1657 desc
->pBuffers
[i
].pvBuffer
= ULongToPtr(buffer32
->pvBuffer
);
1661 static NTSTATUS
wow64_schan_handshake( void *args
)
1663 SecBuffer input_buffers
[3];
1664 SecBufferDesc input
= { 0, 0, input_buffers
};
1665 SecBuffer output_buffers
[3];
1666 SecBufferDesc output
= { 0, 0, output_buffers
};
1670 schan_session session
;
1675 PTR32 output_buffer_idx
;
1676 PTR32 output_offset
;
1677 } const *params32
= args
;
1678 struct handshake_params params
=
1681 params32
->input
? &input
: NULL
,
1682 params32
->input_size
,
1683 params32
->output
? &output
: NULL
,
1684 ULongToPtr(params32
->input_offset
),
1685 ULongToPtr(params32
->output_buffer_idx
),
1686 ULongToPtr(params32
->output_offset
),
1688 if (params32
->input
)
1690 SecBufferDesc32
*desc32
= ULongToPtr(params32
->input
);
1691 assert(desc32
->cBuffers
<= ARRAY_SIZE(input_buffers
));
1692 secbufferdesc_32to64(desc32
, &input
);
1694 if (params32
->output
)
1696 SecBufferDesc32
*desc32
= ULongToPtr(params32
->output
);
1697 assert(desc32
->cBuffers
<= ARRAY_SIZE(output_buffers
));
1698 secbufferdesc_32to64(desc32
, &output
);
1700 return schan_handshake(¶ms
);
1703 static NTSTATUS
wow64_schan_recv( void *args
)
1705 SecBuffer buffers
[3];
1706 SecBufferDesc input
= { 0, 0, buffers
};
1710 schan_session session
;
1715 } const *params32
= args
;
1716 struct recv_params params
=
1719 params32
->input
? &input
: NULL
,
1720 params32
->input_size
,
1721 ULongToPtr(params32
->buffer
),
1722 ULongToPtr(params32
->length
),
1724 if (params32
->input
)
1726 SecBufferDesc32
*desc32
= ULongToPtr(params32
->input
);
1727 assert(desc32
->cBuffers
<= ARRAY_SIZE(buffers
));
1728 secbufferdesc_32to64(desc32
, &input
);
1730 return schan_recv(¶ms
);
1733 static NTSTATUS
wow64_schan_send( void *args
)
1735 SecBuffer buffers
[3];
1736 SecBufferDesc output
= { 0, 0, buffers
};
1740 schan_session session
;
1744 PTR32 output_buffer_idx
;
1745 PTR32 output_offset
;
1746 } const *params32
= args
;
1747 struct send_params params
=
1750 params32
->output
? &output
: NULL
,
1751 ULongToPtr(params32
->buffer
),
1753 ULongToPtr(params32
->output_buffer_idx
),
1754 ULongToPtr(params32
->output_offset
),
1756 if (params32
->output
)
1758 SecBufferDesc32
*desc32
= ULongToPtr(params32
->output
);
1759 assert(desc32
->cBuffers
<= ARRAY_SIZE(buffers
));
1760 secbufferdesc_32to64(desc32
, &output
);
1762 return schan_send(¶ms
);
1765 static NTSTATUS
wow64_schan_set_application_protocols( void *args
)
1769 schan_session session
;
1771 unsigned int buflen
;
1772 } const *params32
= args
;
1773 struct set_application_protocols_params params
=
1776 ULongToPtr(params32
->buffer
),
1779 return schan_set_application_protocols(¶ms
);
1782 static NTSTATUS
wow64_schan_set_session_target( void *args
)
1786 schan_session session
;
1788 } const *params32
= args
;
1789 struct set_session_target_params params
=
1792 ULongToPtr(params32
->target
),
1794 return schan_set_session_target(¶ms
);
1797 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
1801 wow64_schan_allocate_certificate_credentials
,
1802 wow64_schan_create_session
,
1803 schan_dispose_session
,
1804 wow64_schan_free_certificate_credentials
,
1805 wow64_schan_get_application_protocol
,
1806 wow64_schan_get_cipher_info
,
1807 wow64_schan_get_connection_info
,
1808 schan_get_enabled_protocols
,
1809 schan_get_key_signature_algorithm
,
1810 schan_get_max_message_size
,
1811 schan_get_session_cipher_block_size
,
1812 wow64_schan_get_session_peer_certificate
,
1813 wow64_schan_get_unique_channel_binding
,
1814 wow64_schan_handshake
,
1817 wow64_schan_set_application_protocols
,
1819 wow64_schan_set_session_target
,
1820 schan_set_dtls_timeouts
,
1825 #endif /* SONAME_LIBGNUTLS */