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
32 #include <sys/types.h>
34 #ifdef SONAME_LIBGNUTLS
35 #include <gnutls/gnutls.h>
36 #include <gnutls/crypto.h>
37 #include <gnutls/abstract.h>
41 #define WIN32_NO_STATUS
46 #include "secur32_priv.h"
48 #include "wine/unixlib.h"
49 #include "wine/debug.h"
51 #if defined(SONAME_LIBGNUTLS)
53 WINE_DEFAULT_DEBUG_CHANNEL(secur32
);
54 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
56 /* Not present in gnutls version < 2.9.10. */
57 static int (*pgnutls_cipher_get_block_size
)(gnutls_cipher_algorithm_t
);
59 /* Not present in gnutls version < 3.0. */
60 static void (*pgnutls_transport_set_pull_timeout_function
)(gnutls_session_t
,
61 int (*)(gnutls_transport_ptr_t
, unsigned int));
62 static void (*pgnutls_dtls_set_mtu
)(gnutls_session_t
, unsigned int);
64 /* Not present in gnutls version < 3.2.0. */
65 static int (*pgnutls_alpn_get_selected_protocol
)(gnutls_session_t
, gnutls_datum_t
*);
66 static int (*pgnutls_alpn_set_protocols
)(gnutls_session_t
, const gnutls_datum_t
*,
67 unsigned, unsigned int);
69 /* Not present in gnutls version < 3.3.0. */
70 static int (*pgnutls_privkey_import_rsa_raw
)(gnutls_privkey_t
, const gnutls_datum_t
*,
71 const gnutls_datum_t
*, const gnutls_datum_t
*,
72 const gnutls_datum_t
*, const gnutls_datum_t
*,
73 const gnutls_datum_t
*, const gnutls_datum_t
*,
74 const gnutls_datum_t
*);
76 /* Not present in gnutls version < 3.4.0. */
77 static int (*pgnutls_privkey_export_x509
)(gnutls_privkey_t
, gnutls_x509_privkey_t
*);
79 static void *libgnutls_handle
;
80 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
81 MAKE_FUNCPTR(gnutls_alert_get
);
82 MAKE_FUNCPTR(gnutls_alert_get_name
);
83 MAKE_FUNCPTR(gnutls_certificate_allocate_credentials
);
84 MAKE_FUNCPTR(gnutls_certificate_free_credentials
);
85 MAKE_FUNCPTR(gnutls_certificate_get_peers
);
86 MAKE_FUNCPTR(gnutls_certificate_set_x509_key
);
87 MAKE_FUNCPTR(gnutls_cipher_get
);
88 MAKE_FUNCPTR(gnutls_cipher_get_key_size
);
89 MAKE_FUNCPTR(gnutls_credentials_set
);
90 MAKE_FUNCPTR(gnutls_deinit
);
91 MAKE_FUNCPTR(gnutls_global_deinit
);
92 MAKE_FUNCPTR(gnutls_global_init
);
93 MAKE_FUNCPTR(gnutls_global_set_log_function
);
94 MAKE_FUNCPTR(gnutls_global_set_log_level
);
95 MAKE_FUNCPTR(gnutls_handshake
);
96 MAKE_FUNCPTR(gnutls_init
);
97 MAKE_FUNCPTR(gnutls_kx_get
);
98 MAKE_FUNCPTR(gnutls_mac_get
);
99 MAKE_FUNCPTR(gnutls_mac_get_key_size
);
100 MAKE_FUNCPTR(gnutls_perror
);
101 MAKE_FUNCPTR(gnutls_protocol_get_version
);
102 MAKE_FUNCPTR(gnutls_priority_set_direct
);
103 MAKE_FUNCPTR(gnutls_privkey_deinit
);
104 MAKE_FUNCPTR(gnutls_privkey_init
);
105 MAKE_FUNCPTR(gnutls_record_get_max_size
);
106 MAKE_FUNCPTR(gnutls_record_recv
);
107 MAKE_FUNCPTR(gnutls_record_send
);
108 MAKE_FUNCPTR(gnutls_server_name_set
);
109 MAKE_FUNCPTR(gnutls_session_channel_binding
);
110 MAKE_FUNCPTR(gnutls_transport_get_ptr
);
111 MAKE_FUNCPTR(gnutls_transport_set_errno
);
112 MAKE_FUNCPTR(gnutls_transport_set_ptr
);
113 MAKE_FUNCPTR(gnutls_transport_set_pull_function
);
114 MAKE_FUNCPTR(gnutls_transport_set_push_function
);
115 MAKE_FUNCPTR(gnutls_x509_crt_deinit
);
116 MAKE_FUNCPTR(gnutls_x509_crt_import
);
117 MAKE_FUNCPTR(gnutls_x509_crt_init
);
118 MAKE_FUNCPTR(gnutls_x509_privkey_deinit
);
121 #if GNUTLS_VERSION_MAJOR < 3
122 #define GNUTLS_CIPHER_AES_192_CBC 92
123 #define GNUTLS_CIPHER_AES_128_GCM 93
124 #define GNUTLS_CIPHER_AES_256_GCM 94
126 #define GNUTLS_MAC_AEAD 200
128 #define GNUTLS_KX_ANON_ECDH 11
129 #define GNUTLS_KX_ECDHE_RSA 12
130 #define GNUTLS_KX_ECDHE_ECDSA 13
131 #define GNUTLS_KX_ECDHE_PSK 14
134 #if GNUTLS_VERSION_MAJOR < 3 || (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR < 5)
135 #define GNUTLS_ALPN_SERVER_PRECEDENCE (1<<1)
138 static int compat_cipher_get_block_size(gnutls_cipher_algorithm_t cipher
)
141 case GNUTLS_CIPHER_3DES_CBC
:
143 case GNUTLS_CIPHER_AES_128_CBC
:
144 case GNUTLS_CIPHER_AES_256_CBC
:
146 case GNUTLS_CIPHER_ARCFOUR_128
:
147 case GNUTLS_CIPHER_ARCFOUR_40
:
149 case GNUTLS_CIPHER_DES_CBC
:
151 case GNUTLS_CIPHER_NULL
:
153 case GNUTLS_CIPHER_RC2_40_CBC
:
156 FIXME("Unknown cipher %#x, returning 1\n", cipher
);
161 static void compat_gnutls_transport_set_pull_timeout_function(gnutls_session_t session
,
162 int (*func
)(gnutls_transport_ptr_t
, unsigned int))
167 static int compat_gnutls_privkey_export_x509(gnutls_privkey_t privkey
, gnutls_x509_privkey_t
*key
)
170 return GNUTLS_E_UNKNOWN_PK_ALGORITHM
;
173 static int compat_gnutls_privkey_import_rsa_raw(gnutls_privkey_t key
, const gnutls_datum_t
*p1
,
174 const gnutls_datum_t
*p2
, const gnutls_datum_t
*p3
,
175 const gnutls_datum_t
*p4
, const gnutls_datum_t
*p5
,
176 const gnutls_datum_t
*p6
, const gnutls_datum_t
*p7
,
177 const gnutls_datum_t
*p8
)
180 return GNUTLS_E_UNKNOWN_PK_ALGORITHM
;
183 static int compat_gnutls_alpn_get_selected_protocol(gnutls_session_t session
, gnutls_datum_t
*protocol
)
186 return GNUTLS_E_INVALID_REQUEST
;
189 static int compat_gnutls_alpn_set_protocols(gnutls_session_t session
, const gnutls_datum_t
*protocols
,
190 unsigned size
, unsigned int flags
)
193 return GNUTLS_E_INVALID_REQUEST
;
196 static void compat_gnutls_dtls_set_mtu(gnutls_session_t session
, unsigned int mtu
)
201 static void init_schan_buffers(struct schan_buffers
*s
, const PSecBufferDesc desc
,
202 int (*get_next_buffer
)(const struct schan_transport
*, struct schan_buffers
*))
207 s
->current_buffer_idx
= -1;
208 s
->alloc_buffer
= NULL
;
209 s
->get_next_buffer
= get_next_buffer
;
212 static int schan_find_sec_buffer_idx(const SecBufferDesc
*desc
, unsigned int start_idx
, ULONG buffer_type
)
217 for (i
= start_idx
; i
< desc
->cBuffers
; ++i
)
219 buffer
= &desc
->pBuffers
[i
];
220 if ((buffer
->BufferType
| SECBUFFER_ATTRMASK
) == (buffer_type
| SECBUFFER_ATTRMASK
))
227 static int handshake_get_next_buffer(const struct schan_transport
*t
, struct schan_buffers
*s
)
229 if (s
->current_buffer_idx
!= -1)
231 return schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_TOKEN
);
234 static int handshake_get_next_buffer_alloc(const struct schan_transport
*t
, struct schan_buffers
*s
)
236 if (s
->current_buffer_idx
== -1)
238 int idx
= schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_TOKEN
);
241 idx
= schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_EMPTY
);
242 if (idx
!= -1) s
->desc
->pBuffers
[idx
].BufferType
= SECBUFFER_TOKEN
;
244 if (idx
!= -1 && !s
->desc
->pBuffers
[idx
].pvBuffer
&& s
->alloc_buffer
)
246 s
->desc
->pBuffers
[idx
] = *s
->alloc_buffer
;
253 static int send_message_get_next_buffer(const struct schan_transport
*t
, struct schan_buffers
*s
)
257 if (s
->current_buffer_idx
== -1)
258 return schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_STREAM_HEADER
);
260 b
= &s
->desc
->pBuffers
[s
->current_buffer_idx
];
262 if (b
->BufferType
== SECBUFFER_STREAM_HEADER
)
263 return schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_DATA
);
265 if (b
->BufferType
== SECBUFFER_DATA
)
266 return schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_STREAM_TRAILER
);
271 static int send_message_get_next_buffer_token(const struct schan_transport
*t
, struct schan_buffers
*s
)
275 if (s
->current_buffer_idx
== -1)
276 return schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_TOKEN
);
278 b
= &s
->desc
->pBuffers
[s
->current_buffer_idx
];
280 if (b
->BufferType
== SECBUFFER_TOKEN
)
282 int idx
= schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_TOKEN
);
283 if (idx
!= s
->current_buffer_idx
) return -1;
284 return schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_DATA
);
287 if (b
->BufferType
== SECBUFFER_DATA
)
289 int idx
= schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_TOKEN
);
291 idx
= schan_find_sec_buffer_idx(s
->desc
, idx
+ 1, SECBUFFER_TOKEN
);
298 static int recv_message_get_next_buffer(const struct schan_transport
*t
, struct schan_buffers
*s
)
300 if (s
->current_buffer_idx
!= -1)
302 return schan_find_sec_buffer_idx(s
->desc
, 0, SECBUFFER_DATA
);
305 static char *get_buffer(const struct schan_transport
*t
, struct schan_buffers
*s
, SIZE_T
*count
)
316 if (s
->current_buffer_idx
== -1)
319 int buffer_idx
= s
->get_next_buffer(t
, s
);
320 if (buffer_idx
== -1)
322 TRACE("No next buffer\n");
325 s
->current_buffer_idx
= buffer_idx
;
328 buffer
= &s
->desc
->pBuffers
[s
->current_buffer_idx
];
329 TRACE("Using buffer %d: cbBuffer %d, BufferType %#x, pvBuffer %p\n", s
->current_buffer_idx
, buffer
->cbBuffer
, buffer
->BufferType
, buffer
->pvBuffer
);
331 max_count
= buffer
->cbBuffer
- s
->offset
;
332 if (s
->limit
!= ~0UL && s
->limit
< max_count
)
333 max_count
= s
->limit
;
339 buffer_idx
= s
->get_next_buffer(t
, s
);
340 if (buffer_idx
== -1)
342 TRACE("No next buffer\n");
345 s
->current_buffer_idx
= buffer_idx
;
347 buffer
= &s
->desc
->pBuffers
[buffer_idx
];
348 max_count
= buffer
->cbBuffer
;
349 if (s
->limit
!= ~0UL && s
->limit
< max_count
)
350 max_count
= s
->limit
;
353 if (*count
> max_count
)
355 if (s
->limit
!= ~0UL)
358 return (char *)buffer
->pvBuffer
+ s
->offset
;
361 static ssize_t
pull_adapter(gnutls_transport_ptr_t transport
, void *buff
, size_t buff_len
)
363 struct schan_transport
*t
= (struct schan_transport
*)transport
;
364 gnutls_session_t s
= (gnutls_session_t
)t
->session
;
365 SIZE_T len
= buff_len
;
368 TRACE("Push %lu bytes\n", len
);
370 b
= get_buffer(t
, &t
->in
, &len
);
373 pgnutls_transport_set_errno(s
, EAGAIN
);
376 memcpy(buff
, b
, len
);
378 TRACE("Wrote %lu bytes\n", len
);
382 static ssize_t
push_adapter(gnutls_transport_ptr_t transport
, const void *buff
, size_t buff_len
)
384 struct schan_transport
*t
= (struct schan_transport
*)transport
;
385 gnutls_session_t s
= (gnutls_session_t
)t
->session
;
386 SIZE_T len
= buff_len
;
389 TRACE("Push %lu bytes\n", len
);
391 b
= get_buffer(t
, &t
->out
, &len
);
394 pgnutls_transport_set_errno(s
, EAGAIN
);
397 memcpy(b
, buff
, len
);
398 t
->out
.offset
+= len
;
399 TRACE("Wrote %lu bytes\n", len
);
403 static const struct {
405 const char *gnutls_flag
;
406 } protocol_priority_flags
[] = {
407 {SP_PROT_DTLS1_2_CLIENT
, "VERS-DTLS1.2"},
408 {SP_PROT_DTLS1_0_CLIENT
, "VERS-DTLS1.0"},
409 {SP_PROT_TLS1_3_CLIENT
, "VERS-TLS1.3"},
410 {SP_PROT_TLS1_2_CLIENT
, "VERS-TLS1.2"},
411 {SP_PROT_TLS1_1_CLIENT
, "VERS-TLS1.1"},
412 {SP_PROT_TLS1_0_CLIENT
, "VERS-TLS1.0"},
413 {SP_PROT_SSL3_CLIENT
, "VERS-SSL3.0"}
414 /* {SP_PROT_SSL2_CLIENT} is not supported by GnuTLS */
417 static DWORD supported_protocols
;
419 static void check_supported_protocols(void)
421 gnutls_session_t session
;
426 err
= pgnutls_init(&session
, GNUTLS_CLIENT
);
427 if (err
!= GNUTLS_E_SUCCESS
)
433 for(i
= 0; i
< ARRAY_SIZE(protocol_priority_flags
); i
++)
435 sprintf(priority
, "NORMAL:-%s", protocol_priority_flags
[i
].gnutls_flag
);
436 err
= pgnutls_priority_set_direct(session
, priority
, NULL
);
437 if (err
== GNUTLS_E_SUCCESS
)
439 TRACE("%s is supported\n", protocol_priority_flags
[i
].gnutls_flag
);
440 supported_protocols
|= protocol_priority_flags
[i
].enable_flag
;
443 TRACE("%s is not supported\n", protocol_priority_flags
[i
].gnutls_flag
);
446 pgnutls_deinit(session
);
449 static NTSTATUS
schan_get_enabled_protocols( void *args
)
451 return supported_protocols
;
454 static int pull_timeout(gnutls_transport_ptr_t transport
, unsigned int timeout
)
456 struct schan_transport
*t
= (struct schan_transport
*)transport
;
457 gnutls_session_t s
= (gnutls_session_t
)t
->session
;
462 if (get_buffer(t
, &t
->in
, &count
)) return 1;
463 pgnutls_transport_set_errno(s
, EAGAIN
);
467 static NTSTATUS
schan_create_session( void *args
)
469 const struct create_session_params
*params
= args
;
470 schan_credentials
*cred
= params
->cred
;
471 gnutls_session_t
*s
= (gnutls_session_t
*)¶ms
->transport
->session
;
472 char priority
[128] = "NORMAL:%LATEST_RECORD_VERSION", *p
;
473 BOOL using_vers_all
= FALSE
, disabled
;
474 unsigned int i
, flags
= (cred
->credential_use
== SECPKG_CRED_INBOUND
) ? GNUTLS_SERVER
: GNUTLS_CLIENT
;
477 if (cred
->enabled_protocols
& (SP_PROT_DTLS1_0_CLIENT
| SP_PROT_DTLS1_2_CLIENT
))
479 flags
|= GNUTLS_DATAGRAM
;
482 err
= pgnutls_init(s
, flags
);
483 if (err
!= GNUTLS_E_SUCCESS
)
486 return STATUS_INTERNAL_ERROR
;
489 p
= priority
+ strlen(priority
);
491 /* VERS-ALL is nice to use for forward compatibility. It was introduced before support for TLS1.3,
492 * so if TLS1.3 is supported, we may safely use it. Otherwise explicitly disable all known
493 * disabled protocols. */
494 if (supported_protocols
& SP_PROT_TLS1_3_CLIENT
)
496 strcpy(p
, ":-VERS-ALL");
498 using_vers_all
= TRUE
;
501 for (i
= 0; i
< ARRAY_SIZE(protocol_priority_flags
); i
++)
503 if (!(supported_protocols
& protocol_priority_flags
[i
].enable_flag
)) continue;
505 disabled
= !(cred
->enabled_protocols
& protocol_priority_flags
[i
].enable_flag
);
506 if (using_vers_all
&& disabled
) continue;
509 *p
++ = disabled
? '-' : '+';
510 strcpy(p
, protocol_priority_flags
[i
].gnutls_flag
);
514 TRACE("Using %s priority\n", debugstr_a(priority
));
515 err
= pgnutls_priority_set_direct(*s
, priority
, NULL
);
516 if (err
!= GNUTLS_E_SUCCESS
)
520 return STATUS_INTERNAL_ERROR
;
523 err
= pgnutls_credentials_set(*s
, GNUTLS_CRD_CERTIFICATE
,
524 (gnutls_certificate_credentials_t
)cred
->credentials
);
525 if (err
!= GNUTLS_E_SUCCESS
)
529 return STATUS_INTERNAL_ERROR
;
532 pgnutls_transport_set_pull_function(*s
, pull_adapter
);
533 if (flags
& GNUTLS_DATAGRAM
) pgnutls_transport_set_pull_timeout_function(*s
, pull_timeout
);
534 pgnutls_transport_set_push_function(*s
, push_adapter
);
535 pgnutls_transport_set_ptr(*s
, (gnutls_transport_ptr_t
)params
->transport
);
537 return STATUS_SUCCESS
;
540 static NTSTATUS
schan_dispose_session( void *args
)
542 const struct session_params
*params
= args
;
543 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
545 return STATUS_SUCCESS
;
548 static NTSTATUS
schan_set_session_target( void *args
)
550 const struct set_session_target_params
*params
= args
;
551 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
552 pgnutls_server_name_set( s
, GNUTLS_NAME_DNS
, params
->target
, strlen(params
->target
) );
553 return STATUS_SUCCESS
;
556 static NTSTATUS
schan_handshake( void *args
)
558 const struct handshake_params
*params
= args
;
559 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
560 struct schan_transport
*t
= (struct schan_transport
*)pgnutls_transport_get_ptr(s
);
563 init_schan_buffers(&t
->in
, params
->input
, handshake_get_next_buffer
);
564 t
->in
.limit
= params
->input_size
;
565 init_schan_buffers(&t
->out
, params
->output
, handshake_get_next_buffer_alloc
);
566 t
->out
.alloc_buffer
= params
->alloc_buffer
;
569 err
= pgnutls_handshake(s
);
571 case GNUTLS_E_SUCCESS
:
572 TRACE("Handshake completed\n");
576 TRACE("Continue...\n");
577 return SEC_I_CONTINUE_NEEDED
;
579 case GNUTLS_E_WARNING_ALERT_RECEIVED
:
581 gnutls_alert_description_t alert
= pgnutls_alert_get(s
);
583 WARN("WARNING ALERT: %d %s\n", alert
, pgnutls_alert_get_name(alert
));
586 case GNUTLS_A_UNRECOGNIZED_NAME
:
590 return SEC_E_INTERNAL_ERROR
;
594 case GNUTLS_E_FATAL_ALERT_RECEIVED
:
596 gnutls_alert_description_t alert
= pgnutls_alert_get(s
);
597 WARN("FATAL ALERT: %d %s\n", alert
, pgnutls_alert_get_name(alert
));
598 return SEC_E_INTERNAL_ERROR
;
603 return SEC_E_INTERNAL_ERROR
;
611 static DWORD
get_protocol(gnutls_protocol_t proto
)
613 /* FIXME: currently schannel only implements client connections, but
614 * there's no reason it couldn't be used for servers as well. The
615 * context doesn't tell us which it is, so assume client for now.
619 case GNUTLS_SSL3
: return SP_PROT_SSL3_CLIENT
;
620 case GNUTLS_TLS1_0
: return SP_PROT_TLS1_0_CLIENT
;
621 case GNUTLS_TLS1_1
: return SP_PROT_TLS1_1_CLIENT
;
622 case GNUTLS_TLS1_2
: return SP_PROT_TLS1_2_CLIENT
;
623 case GNUTLS_DTLS1_0
: return SP_PROT_DTLS1_0_CLIENT
;
624 case GNUTLS_DTLS1_2
: return SP_PROT_DTLS1_2_CLIENT
;
626 FIXME("unknown protocol %d\n", proto
);
631 static ALG_ID
get_cipher_algid(gnutls_cipher_algorithm_t cipher
)
635 case GNUTLS_CIPHER_UNKNOWN
:
636 case GNUTLS_CIPHER_NULL
: return 0;
637 case GNUTLS_CIPHER_ARCFOUR_40
:
638 case GNUTLS_CIPHER_ARCFOUR_128
: return CALG_RC4
;
639 case GNUTLS_CIPHER_DES_CBC
: return CALG_DES
;
640 case GNUTLS_CIPHER_3DES_CBC
: return CALG_3DES
;
641 case GNUTLS_CIPHER_AES_128_CBC
:
642 case GNUTLS_CIPHER_AES_128_GCM
: return CALG_AES_128
;
643 case GNUTLS_CIPHER_AES_192_CBC
: return CALG_AES_192
;
644 case GNUTLS_CIPHER_AES_256_GCM
:
645 case GNUTLS_CIPHER_AES_256_CBC
: return CALG_AES_256
;
646 case GNUTLS_CIPHER_RC2_40_CBC
: return CALG_RC2
;
648 FIXME("unknown algorithm %d\n", cipher
);
653 static ALG_ID
get_mac_algid(gnutls_mac_algorithm_t mac
, gnutls_cipher_algorithm_t cipher
)
657 case GNUTLS_MAC_UNKNOWN
:
658 case GNUTLS_MAC_NULL
: return 0;
659 case GNUTLS_MAC_MD2
: return CALG_MD2
;
660 case GNUTLS_MAC_MD5
: return CALG_MD5
;
661 case GNUTLS_MAC_SHA1
: return CALG_SHA1
;
662 case GNUTLS_MAC_SHA256
: return CALG_SHA_256
;
663 case GNUTLS_MAC_SHA384
: return CALG_SHA_384
;
664 case GNUTLS_MAC_SHA512
: return CALG_SHA_512
;
665 case GNUTLS_MAC_AEAD
:
666 /* When using AEAD (such as GCM), we return PRF algorithm instead
667 which is defined in RFC 5289. */
670 case GNUTLS_CIPHER_AES_128_GCM
: return CALG_SHA_256
;
671 case GNUTLS_CIPHER_AES_256_GCM
: return CALG_SHA_384
;
677 FIXME("unknown algorithm %d, cipher %d\n", mac
, cipher
);
682 static ALG_ID
get_kx_algid(int kx
)
686 case GNUTLS_KX_UNKNOWN
: return 0;
688 case GNUTLS_KX_RSA_EXPORT
: return CALG_RSA_KEYX
;
689 case GNUTLS_KX_DHE_PSK
:
690 case GNUTLS_KX_DHE_DSS
:
691 case GNUTLS_KX_DHE_RSA
: return CALG_DH_EPHEM
;
692 case GNUTLS_KX_ANON_ECDH
: return CALG_ECDH
;
693 case GNUTLS_KX_ECDHE_RSA
:
694 case GNUTLS_KX_ECDHE_PSK
:
695 case GNUTLS_KX_ECDHE_ECDSA
: return CALG_ECDH_EPHEM
;
697 FIXME("unknown algorithm %d\n", kx
);
702 static NTSTATUS
schan_get_session_cipher_block_size( void *args
)
704 const struct session_params
*params
= args
;
705 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
706 return pgnutls_cipher_get_block_size(pgnutls_cipher_get(s
));
709 static NTSTATUS
schan_get_max_message_size( void *args
)
711 const struct session_params
*params
= args
;
712 return pgnutls_record_get_max_size((gnutls_session_t
)params
->session
);
715 static NTSTATUS
schan_get_connection_info( void *args
)
717 const struct get_connection_info_params
*params
= args
;
718 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
719 SecPkgContext_ConnectionInfo
*info
= params
->info
;
720 gnutls_protocol_t proto
= pgnutls_protocol_get_version(s
);
721 gnutls_cipher_algorithm_t alg
= pgnutls_cipher_get(s
);
722 gnutls_mac_algorithm_t mac
= pgnutls_mac_get(s
);
723 gnutls_kx_algorithm_t kx
= pgnutls_kx_get(s
);
725 info
->dwProtocol
= get_protocol(proto
);
726 info
->aiCipher
= get_cipher_algid(alg
);
727 info
->dwCipherStrength
= pgnutls_cipher_get_key_size(alg
) * 8;
728 info
->aiHash
= get_mac_algid(mac
, alg
);
729 info
->dwHashStrength
= pgnutls_mac_get_key_size(mac
) * 8;
730 info
->aiExch
= get_kx_algid(kx
);
731 /* FIXME: info->dwExchStrength? */
732 info
->dwExchStrength
= 0;
736 static NTSTATUS
schan_get_unique_channel_binding( void *args
)
738 const struct get_unique_channel_binding_params
*params
= args
;
739 gnutls_datum_t datum
;
742 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
744 rc
= pgnutls_session_channel_binding(s
, GNUTLS_CB_TLS_UNIQUE
, &datum
);
748 return SEC_E_INTERNAL_ERROR
;
750 if (params
->buffer
&& *params
->bufsize
>= datum
.size
)
752 memcpy( params
->buffer
, datum
.data
, datum
.size
);
755 else ret
= SEC_E_BUFFER_TOO_SMALL
;
757 *params
->bufsize
= datum
.size
;
762 static NTSTATUS
schan_get_key_signature_algorithm( void *args
)
764 const struct session_params
*params
= args
;
765 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
766 gnutls_kx_algorithm_t kx
= pgnutls_kx_get(s
);
768 TRACE("(%p)\n", params
->session
);
772 case GNUTLS_KX_UNKNOWN
: return 0;
774 case GNUTLS_KX_RSA_EXPORT
:
775 case GNUTLS_KX_DHE_RSA
:
776 case GNUTLS_KX_ECDHE_RSA
: return CALG_RSA_SIGN
;
777 case GNUTLS_KX_ECDHE_ECDSA
: return CALG_ECDSA
;
779 FIXME("unknown algorithm %d\n", kx
);
784 static NTSTATUS
schan_get_session_peer_certificate( void *args
)
786 const struct get_session_peer_certificate_params
*params
= args
;
787 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
788 CERT_BLOB
*certs
= params
->certs
;
789 const gnutls_datum_t
*datum
;
790 unsigned int i
, size
;
794 if (!(datum
= pgnutls_certificate_get_peers(s
, &count
))) return SEC_E_INTERNAL_ERROR
;
796 size
= count
* sizeof(certs
[0]);
797 for (i
= 0; i
< count
; i
++) size
+= datum
[i
].size
;
799 if (!certs
|| *params
->bufsize
< size
)
801 *params
->bufsize
= size
;
802 return SEC_E_BUFFER_TOO_SMALL
;
804 ptr
= (BYTE
*)&certs
[count
];
805 for (i
= 0; i
< count
; i
++)
807 certs
[i
].cbData
= datum
[i
].size
;
808 certs
[i
].pbData
= ptr
;
809 memcpy(certs
[i
].pbData
, datum
[i
].data
, datum
[i
].size
);
810 ptr
+= datum
[i
].size
;
813 *params
->bufsize
= size
;
814 *params
->retcount
= count
;
818 static NTSTATUS
schan_send( void *args
)
820 const struct send_params
*params
= args
;
821 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
822 struct schan_transport
*t
= (struct schan_transport
*)pgnutls_transport_get_ptr(s
);
823 SSIZE_T ret
, total
= 0;
825 if (schan_find_sec_buffer_idx(params
->output
, 0, SECBUFFER_STREAM_HEADER
) != -1)
826 init_schan_buffers(&t
->out
, params
->output
, send_message_get_next_buffer
);
828 init_schan_buffers(&t
->out
, params
->output
, send_message_get_next_buffer_token
);
832 ret
= pgnutls_record_send(s
, (const char *)params
->buffer
+ total
, *params
->length
- total
);
836 TRACE( "sent %ld now %ld/%ld\n", ret
, total
, *params
->length
);
837 if (total
== *params
->length
) break;
839 else if (ret
== GNUTLS_E_AGAIN
)
843 if (get_buffer(t
, &t
->out
, &count
)) continue;
844 return SEC_I_CONTINUE_NEEDED
;
849 return SEC_E_INTERNAL_ERROR
;
853 t
->out
.desc
->pBuffers
[t
->out
.current_buffer_idx
].cbBuffer
= t
->out
.offset
;
857 static NTSTATUS
schan_recv( void *args
)
859 const struct recv_params
*params
= args
;
860 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
861 struct schan_transport
*t
= (struct schan_transport
*)pgnutls_transport_get_ptr(s
);
862 size_t data_size
= *params
->length
;
865 SECURITY_STATUS status
= SEC_E_OK
;
867 init_schan_buffers(&t
->in
, params
->input
, recv_message_get_next_buffer
);
868 t
->in
.limit
= params
->input_size
;
870 while (received
< data_size
)
872 ret
= pgnutls_record_recv(s
, (char *)params
->buffer
+ received
, data_size
- received
);
874 if (ret
> 0) received
+= ret
;
875 else if (!ret
) break;
876 else if (ret
== GNUTLS_E_AGAIN
)
880 if (!get_buffer(t
, &t
->in
, &count
)) break;
882 else if (ret
== GNUTLS_E_REHANDSHAKE
)
884 TRACE("Rehandshake requested\n");
885 status
= SEC_I_RENEGOTIATE
;
891 return SEC_E_INTERNAL_ERROR
;
895 *params
->length
= received
;
899 static unsigned int parse_alpn_protocol_list(unsigned char *buffer
, unsigned int buflen
, gnutls_datum_t
*list
)
901 unsigned int len
, offset
= 0, count
= 0;
905 len
= buffer
[offset
++];
907 if (!len
|| len
> buflen
) return 0;
910 list
[count
].data
= &buffer
[offset
];
911 list
[count
].size
= len
;
921 static NTSTATUS
schan_set_application_protocols( void *args
)
923 const struct set_application_protocols_params
*params
= args
;
924 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
925 unsigned int extension_len
, extension
, count
= 0, offset
= 0;
926 unsigned short list_len
;
927 gnutls_datum_t
*protocols
;
930 if (sizeof(extension_len
) > params
->buflen
) return STATUS_INVALID_PARAMETER
;
931 extension_len
= *(unsigned int *)¶ms
->buffer
[offset
];
932 offset
+= sizeof(extension_len
);
934 if (offset
+ sizeof(extension
) > params
->buflen
) return STATUS_INVALID_PARAMETER
;
935 extension
= *(unsigned int *)¶ms
->buffer
[offset
];
936 if (extension
!= SecApplicationProtocolNegotiationExt_ALPN
)
938 FIXME("extension %u not supported\n", extension
);
939 return STATUS_NOT_SUPPORTED
;
941 offset
+= sizeof(extension
);
943 if (offset
+ sizeof(list_len
) > params
->buflen
) return STATUS_INVALID_PARAMETER
;
944 list_len
= *(unsigned short *)¶ms
->buffer
[offset
];
945 offset
+= sizeof(list_len
);
947 if (offset
+ list_len
> params
->buflen
) return STATUS_INVALID_PARAMETER
;
948 count
= parse_alpn_protocol_list(¶ms
->buffer
[offset
], list_len
, NULL
);
949 if (!count
|| !(protocols
= malloc(count
* sizeof(*protocols
)))) return STATUS_NO_MEMORY
;
951 parse_alpn_protocol_list(¶ms
->buffer
[offset
], list_len
, protocols
);
952 if ((ret
= pgnutls_alpn_set_protocols(s
, protocols
, count
, GNUTLS_ALPN_SERVER_PRECEDENCE
) < 0))
958 return STATUS_SUCCESS
;
961 static NTSTATUS
schan_get_application_protocol( void *args
)
963 const struct get_application_protocol_params
*params
= args
;
964 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
965 SecPkgContext_ApplicationProtocol
*protocol
= params
->protocol
;
966 gnutls_datum_t selected
;
968 memset(protocol
, 0, sizeof(*protocol
));
969 if (pgnutls_alpn_get_selected_protocol(s
, &selected
) < 0) return SEC_E_OK
;
971 if (selected
.size
<= sizeof(protocol
->ProtocolId
))
973 protocol
->ProtoNegoStatus
= SecApplicationProtocolNegotiationStatus_Success
;
974 protocol
->ProtoNegoExt
= SecApplicationProtocolNegotiationExt_ALPN
;
975 protocol
->ProtocolIdSize
= selected
.size
;
976 memcpy(protocol
->ProtocolId
, selected
.data
, selected
.size
);
977 TRACE("returning %s\n", wine_dbgstr_an((const char *)selected
.data
, selected
.size
));
982 static NTSTATUS
schan_set_dtls_mtu( void *args
)
984 const struct set_dtls_mtu_params
*params
= args
;
985 gnutls_session_t s
= (gnutls_session_t
)params
->session
;
987 pgnutls_dtls_set_mtu(s
, params
->mtu
);
988 TRACE("MTU set to %u\n", params
->mtu
);
992 static inline void reverse_bytes(BYTE
*buf
, ULONG len
)
996 for (i
= 0; i
< len
/ 2; i
++)
999 buf
[i
] = buf
[len
- i
- 1];
1000 buf
[len
- i
- 1] = tmp
;
1004 static ULONG
set_component(gnutls_datum_t
*comp
, BYTE
*data
, ULONG len
, ULONG
*buflen
)
1008 reverse_bytes(comp
->data
, comp
->size
);
1009 if (comp
->data
[0] & 0x80) /* add leading 0 byte if most significant bit is set */
1011 memmove(comp
->data
+ 1, comp
->data
, *buflen
);
1015 *buflen
-= comp
->size
;
1019 static gnutls_x509_privkey_t
get_x509_key(const DATA_BLOB
*key_blob
)
1021 gnutls_privkey_t key
= NULL
;
1022 gnutls_x509_privkey_t x509key
= NULL
;
1023 gnutls_datum_t m
, e
, d
, p
, q
, u
, e1
, e2
;
1026 DWORD size
= key_blob
->cbData
;
1029 if (size
< sizeof(BLOBHEADER
)) return NULL
;
1031 rsakey
= (RSAPUBKEY
*)(key_blob
->pbData
+ sizeof(BLOBHEADER
));
1032 TRACE("RSA key bitlen %u pubexp %u\n", rsakey
->bitlen
, rsakey
->pubexp
);
1034 size
-= sizeof(BLOBHEADER
) + FIELD_OFFSET(RSAPUBKEY
, pubexp
);
1035 set_component(&e
, (BYTE
*)&rsakey
->pubexp
, sizeof(rsakey
->pubexp
), &size
);
1037 ptr
= (BYTE
*)(rsakey
+ 1);
1038 ptr
+= set_component(&m
, ptr
, rsakey
->bitlen
/ 8, &size
);
1039 ptr
+= set_component(&p
, ptr
, rsakey
->bitlen
/ 16, &size
);
1040 ptr
+= set_component(&q
, ptr
, rsakey
->bitlen
/ 16, &size
);
1041 ptr
+= set_component(&e1
, ptr
, rsakey
->bitlen
/ 16, &size
);
1042 ptr
+= set_component(&e2
, ptr
, rsakey
->bitlen
/ 16, &size
);
1043 ptr
+= set_component(&u
, ptr
, rsakey
->bitlen
/ 16, &size
);
1044 ptr
+= set_component(&d
, ptr
, rsakey
->bitlen
/ 8, &size
);
1046 if ((ret
= pgnutls_privkey_init(&key
)) < 0)
1048 pgnutls_perror(ret
);
1052 if (((ret
= pgnutls_privkey_import_rsa_raw(key
, &m
, &e
, &d
, &p
, &q
, &u
, &e1
, &e2
)) < 0) ||
1053 (ret
= pgnutls_privkey_export_x509(key
, &x509key
)) < 0)
1055 pgnutls_perror(ret
);
1056 pgnutls_privkey_deinit(key
);
1063 static gnutls_x509_crt_t
get_x509_crt(const CERT_CONTEXT
*ctx
)
1065 gnutls_datum_t data
;
1066 gnutls_x509_crt_t crt
;
1069 if (!ctx
) return FALSE
;
1070 if (ctx
->dwCertEncodingType
!= X509_ASN_ENCODING
)
1072 FIXME("encoding type %u not supported\n", ctx
->dwCertEncodingType
);
1076 if ((ret
= pgnutls_x509_crt_init(&crt
)) < 0)
1078 pgnutls_perror(ret
);
1082 data
.data
= ctx
->pbCertEncoded
;
1083 data
.size
= ctx
->cbCertEncoded
;
1084 if ((ret
= pgnutls_x509_crt_import(crt
, &data
, GNUTLS_X509_FMT_DER
)) < 0)
1086 pgnutls_perror(ret
);
1087 pgnutls_x509_crt_deinit(crt
);
1094 static NTSTATUS
schan_allocate_certificate_credentials( void *args
)
1096 const struct allocate_certificate_credentials_params
*params
= args
;
1097 gnutls_certificate_credentials_t creds
;
1098 gnutls_x509_crt_t crt
;
1099 gnutls_x509_privkey_t key
;
1102 ret
= pgnutls_certificate_allocate_credentials(&creds
);
1103 if (ret
!= GNUTLS_E_SUCCESS
)
1105 pgnutls_perror(ret
);
1106 return STATUS_INTERNAL_ERROR
;
1111 params
->c
->credentials
= creds
;
1112 return STATUS_SUCCESS
;
1115 if (!(crt
= get_x509_crt(params
->ctx
)))
1117 pgnutls_certificate_free_credentials(creds
);
1118 return STATUS_INTERNAL_ERROR
;
1121 if (!(key
= get_x509_key(params
->key_blob
)))
1123 pgnutls_x509_crt_deinit(crt
);
1124 pgnutls_certificate_free_credentials(creds
);
1125 return STATUS_INTERNAL_ERROR
;
1128 ret
= pgnutls_certificate_set_x509_key(creds
, &crt
, 1, key
);
1129 pgnutls_x509_privkey_deinit(key
);
1130 pgnutls_x509_crt_deinit(crt
);
1131 if (ret
!= GNUTLS_E_SUCCESS
)
1133 pgnutls_perror(ret
);
1134 pgnutls_certificate_free_credentials(creds
);
1135 return STATUS_INTERNAL_ERROR
;
1138 params
->c
->credentials
= creds
;
1139 return STATUS_SUCCESS
;
1142 static NTSTATUS
schan_free_certificate_credentials( void *args
)
1144 const struct free_certificate_credentials_params
*params
= args
;
1145 pgnutls_certificate_free_credentials(params
->c
->credentials
);
1146 return STATUS_SUCCESS
;
1149 static void gnutls_log(int level
, const char *msg
)
1151 TRACE("<%d> %s", level
, msg
);
1154 static NTSTATUS
process_attach( void *args
)
1156 const char *env_str
;
1159 if ((env_str
= getenv("GNUTLS_SYSTEM_PRIORITY_FILE")))
1161 WARN("GNUTLS_SYSTEM_PRIORITY_FILE is %s.\n", debugstr_a(env_str
));
1165 WARN("Setting GNUTLS_SYSTEM_PRIORITY_FILE to \"/dev/null\".\n");
1166 setenv("GNUTLS_SYSTEM_PRIORITY_FILE", "/dev/null", 0);
1169 libgnutls_handle
= dlopen(SONAME_LIBGNUTLS
, RTLD_NOW
);
1170 if (!libgnutls_handle
)
1172 ERR_(winediag
)("Failed to load libgnutls, secure connections will not be available.\n");
1173 return STATUS_DLL_NOT_FOUND
;
1176 #define LOAD_FUNCPTR(f) \
1177 if (!(p##f = dlsym(libgnutls_handle, #f))) \
1179 ERR("Failed to load %s\n", #f); \
1183 LOAD_FUNCPTR(gnutls_alert_get
)
1184 LOAD_FUNCPTR(gnutls_alert_get_name
)
1185 LOAD_FUNCPTR(gnutls_certificate_allocate_credentials
)
1186 LOAD_FUNCPTR(gnutls_certificate_free_credentials
)
1187 LOAD_FUNCPTR(gnutls_certificate_get_peers
)
1188 LOAD_FUNCPTR(gnutls_certificate_set_x509_key
)
1189 LOAD_FUNCPTR(gnutls_cipher_get
)
1190 LOAD_FUNCPTR(gnutls_cipher_get_key_size
)
1191 LOAD_FUNCPTR(gnutls_credentials_set
)
1192 LOAD_FUNCPTR(gnutls_deinit
)
1193 LOAD_FUNCPTR(gnutls_global_deinit
)
1194 LOAD_FUNCPTR(gnutls_global_init
)
1195 LOAD_FUNCPTR(gnutls_global_set_log_function
)
1196 LOAD_FUNCPTR(gnutls_global_set_log_level
)
1197 LOAD_FUNCPTR(gnutls_handshake
)
1198 LOAD_FUNCPTR(gnutls_init
)
1199 LOAD_FUNCPTR(gnutls_kx_get
)
1200 LOAD_FUNCPTR(gnutls_mac_get
)
1201 LOAD_FUNCPTR(gnutls_mac_get_key_size
)
1202 LOAD_FUNCPTR(gnutls_perror
)
1203 LOAD_FUNCPTR(gnutls_protocol_get_version
)
1204 LOAD_FUNCPTR(gnutls_priority_set_direct
)
1205 LOAD_FUNCPTR(gnutls_privkey_deinit
)
1206 LOAD_FUNCPTR(gnutls_privkey_init
)
1207 LOAD_FUNCPTR(gnutls_record_get_max_size
);
1208 LOAD_FUNCPTR(gnutls_record_recv
);
1209 LOAD_FUNCPTR(gnutls_record_send
);
1210 LOAD_FUNCPTR(gnutls_server_name_set
)
1211 LOAD_FUNCPTR(gnutls_session_channel_binding
)
1212 LOAD_FUNCPTR(gnutls_transport_get_ptr
)
1213 LOAD_FUNCPTR(gnutls_transport_set_errno
)
1214 LOAD_FUNCPTR(gnutls_transport_set_ptr
)
1215 LOAD_FUNCPTR(gnutls_transport_set_pull_function
)
1216 LOAD_FUNCPTR(gnutls_transport_set_push_function
)
1217 LOAD_FUNCPTR(gnutls_x509_crt_deinit
)
1218 LOAD_FUNCPTR(gnutls_x509_crt_import
)
1219 LOAD_FUNCPTR(gnutls_x509_crt_init
)
1220 LOAD_FUNCPTR(gnutls_x509_privkey_deinit
)
1223 if (!(pgnutls_cipher_get_block_size
= dlsym(libgnutls_handle
, "gnutls_cipher_get_block_size")))
1225 WARN("gnutls_cipher_get_block_size not found\n");
1226 pgnutls_cipher_get_block_size
= compat_cipher_get_block_size
;
1228 if (!(pgnutls_transport_set_pull_timeout_function
= dlsym(libgnutls_handle
, "gnutls_transport_set_pull_timeout_function")))
1230 WARN("gnutls_transport_set_pull_timeout_function not found\n");
1231 pgnutls_transport_set_pull_timeout_function
= compat_gnutls_transport_set_pull_timeout_function
;
1233 if (!(pgnutls_alpn_set_protocols
= dlsym(libgnutls_handle
, "gnutls_alpn_set_protocols")))
1235 WARN("gnutls_alpn_set_protocols not found\n");
1236 pgnutls_alpn_set_protocols
= compat_gnutls_alpn_set_protocols
;
1238 if (!(pgnutls_alpn_get_selected_protocol
= dlsym(libgnutls_handle
, "gnutls_alpn_get_selected_protocol")))
1240 WARN("gnutls_alpn_get_selected_protocol not found\n");
1241 pgnutls_alpn_get_selected_protocol
= compat_gnutls_alpn_get_selected_protocol
;
1243 if (!(pgnutls_dtls_set_mtu
= dlsym(libgnutls_handle
, "gnutls_dtls_set_mtu")))
1245 WARN("gnutls_dtls_set_mtu not found\n");
1246 pgnutls_dtls_set_mtu
= compat_gnutls_dtls_set_mtu
;
1248 if (!(pgnutls_privkey_export_x509
= dlsym(libgnutls_handle
, "gnutls_privkey_export_x509")))
1250 WARN("gnutls_privkey_export_x509 not found\n");
1251 pgnutls_privkey_export_x509
= compat_gnutls_privkey_export_x509
;
1253 if (!(pgnutls_privkey_import_rsa_raw
= dlsym(libgnutls_handle
, "gnutls_privkey_import_rsa_raw")))
1255 WARN("gnutls_privkey_import_rsa_raw not found\n");
1256 pgnutls_privkey_import_rsa_raw
= compat_gnutls_privkey_import_rsa_raw
;
1259 ret
= pgnutls_global_init();
1260 if (ret
!= GNUTLS_E_SUCCESS
)
1262 pgnutls_perror(ret
);
1266 if (TRACE_ON(secur32
))
1268 pgnutls_global_set_log_level(4);
1269 pgnutls_global_set_log_function(gnutls_log
);
1272 check_supported_protocols();
1273 return STATUS_SUCCESS
;
1276 dlclose(libgnutls_handle
);
1277 libgnutls_handle
= NULL
;
1278 return STATUS_DLL_NOT_FOUND
;
1281 static NTSTATUS
process_detach( void *args
)
1283 pgnutls_global_deinit();
1284 dlclose(libgnutls_handle
);
1285 libgnutls_handle
= NULL
;
1286 return STATUS_SUCCESS
;
1289 const unixlib_entry_t __wine_unix_call_funcs
[] =
1293 schan_allocate_certificate_credentials
,
1294 schan_create_session
,
1295 schan_dispose_session
,
1296 schan_free_certificate_credentials
,
1297 schan_get_application_protocol
,
1298 schan_get_connection_info
,
1299 schan_get_enabled_protocols
,
1300 schan_get_key_signature_algorithm
,
1301 schan_get_max_message_size
,
1302 schan_get_session_cipher_block_size
,
1303 schan_get_session_peer_certificate
,
1304 schan_get_unique_channel_binding
,
1308 schan_set_application_protocols
,
1310 schan_set_session_target
,
1313 #endif /* SONAME_LIBGNUTLS */