1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
22 ***************************************************************************/
25 * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
26 * but sslgen.c should ever call or use these functions.
28 * Note: don't use the GnuTLS' *_t variable type names in this source code,
29 * since they were not present in 1.0.X.
34 #include <gnutls/gnutls.h>
35 #include <gnutls/x509.h>
41 #ifdef HAVE_SYS_SOCKET_H
42 #include <sys/socket.h>
47 #include "inet_pton.h"
50 #include "parsedate.h"
51 #include "connect.h" /* for the connect timeout */
55 #define _MPRINTF_REPLACE /* use our functions only */
56 #include <curl/mprintf.h>
57 #include "curl_memory.h"
58 /* The last #include file should be: */
62 Some hackish cast macros based on:
63 http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html
65 #ifndef GNUTLS_POINTER_TO_INT_CAST
66 #define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
68 #ifndef GNUTLS_INT_TO_POINTER_CAST
69 #define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
72 /* Enable GnuTLS debugging by defining GTLSDEBUG */
73 /*#define GTLSDEBUG */
76 static void tls_log_func(int level, const char *str)
78 fprintf(stderr, "|<%d>| %s", level, str);
81 static bool gtls_inited = FALSE;
83 * Custom push and pull callback functions used by GNU TLS to read and write
84 * to the socket. These functions are simple wrappers to send() and recv()
85 * (although here using the sread/swrite macros as defined by setup_once.h).
86 * We use custom functions rather than the GNU TLS defaults because it allows
87 * us to get specific about the fourth "flags" argument, and to use arbitrary
88 * private data with gnutls_transport_set_ptr if we wish.
90 static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
92 return swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
95 static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
97 return sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
102 * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
103 * are not thread-safe and thus this function itself is not thread-safe and
104 * must only be called from within curl_global_init() to keep the thread
105 * situation under control!
107 int Curl_gtls_init(void)
111 ret = gnutls_global_init()?0:1;
113 gnutls_global_set_log_function(tls_log_func);
114 gnutls_global_set_log_level(2);
121 int Curl_gtls_cleanup(void)
124 gnutls_global_deinit();
130 static void showtime(struct SessionHandle *data,
137 tm = (struct tm *)gmtime_r(&stamp, &buffer);
141 snprintf(data->state.buffer,
143 "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n",
145 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
147 Curl_month[tm->tm_mon],
152 infof(data, "%s", data->state.buffer);
155 static gnutls_datum load_file (const char *file)
158 gnutls_datum loaded_file = { NULL, 0 };
162 if (!(f = fopen(file, "r")))
164 if (fseek(f, 0, SEEK_END) != 0
165 || (filelen = ftell(f)) < 0
166 || fseek(f, 0, SEEK_SET) != 0
167 || !(ptr = malloc((size_t)filelen)))
169 if (fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
174 loaded_file.data = ptr;
175 loaded_file.size = (unsigned int)filelen;
181 static void unload_file(gnutls_datum data) {
186 /* this function does a BLOCKING SSL/TLS (re-)handshake */
187 static CURLcode handshake(struct connectdata *conn,
188 gnutls_session session,
192 struct SessionHandle *data = conn->data;
197 rc = gnutls_handshake(session);
199 if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
200 long timeout_ms = Curl_timeleft(conn, NULL, duringconnect);
203 /* a precaution, no need to continue if time already is up */
204 failf(data, "SSL connection timeout");
205 return CURLE_OPERATION_TIMEDOUT;
208 rc = Curl_socket_ready(conn->sock[sockindex],
209 conn->sock[sockindex], (int)timeout_ms);
211 /* reabable or writable, go loop*/
215 failf(data, "SSL connection timeout");
216 return CURLE_OPERATION_TIMEDOUT;
219 /* anything that gets here is fatally bad */
220 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
221 return CURLE_SSL_CONNECT_ERROR;
229 failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc));
230 return CURLE_SSL_CONNECT_ERROR;
236 static gnutls_x509_crt_fmt do_file_type(const char *type)
238 if(!type || !type[0])
239 return GNUTLS_X509_FMT_PEM;
240 if(Curl_raw_equal(type, "PEM"))
241 return GNUTLS_X509_FMT_PEM;
242 if(Curl_raw_equal(type, "DER"))
243 return GNUTLS_X509_FMT_DER;
249 * This function is called after the TCP connect has completed. Setup the TLS
250 * layer and do all necessary magic.
253 Curl_gtls_connect(struct connectdata *conn,
257 static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
258 struct SessionHandle *data = conn->data;
259 gnutls_session session;
261 unsigned int cert_list_size;
262 const gnutls_datum *chainp;
263 unsigned int verify_status;
264 gnutls_x509_crt x509_cert,x509_issuer;
265 gnutls_datum issuerp;
266 char certbuf[256]; /* big enough? */
274 bool sni = TRUE; /* default is SNI enabled */
276 struct in6_addr addr;
281 if(conn->ssl[sockindex].state == ssl_connection_complete)
282 /* to make us tolerant against being called more than once for the
289 /* GnuTLS only supports SSLv3 and TLSv1 */
290 if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
291 failf(data, "GnuTLS does not support SSLv2");
292 return CURLE_SSL_CONNECT_ERROR;
294 else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
295 sni = FALSE; /* SSLv3 has no SNI */
297 /* allocate a cred struct */
298 rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
299 if(rc != GNUTLS_E_SUCCESS) {
300 failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
301 return CURLE_SSL_CONNECT_ERROR;
304 if(data->set.ssl.CAfile) {
305 /* set the trusted CA cert bundle file */
306 gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
307 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
309 rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
310 data->set.ssl.CAfile,
311 GNUTLS_X509_FMT_PEM);
313 infof(data, "error reading ca cert file %s (%s)\n",
314 data->set.ssl.CAfile, gnutls_strerror(rc));
315 if(data->set.ssl.verifypeer)
316 return CURLE_SSL_CACERT_BADFILE;
319 infof(data, "found %d certificates in %s\n",
320 rc, data->set.ssl.CAfile);
323 if(data->set.ssl.CRLfile) {
324 /* set the CRL list file */
325 rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
326 data->set.ssl.CRLfile,
327 GNUTLS_X509_FMT_PEM);
329 failf(data, "error reading crl file %s (%s)\n",
330 data->set.ssl.CRLfile, gnutls_strerror(rc));
331 return CURLE_SSL_CRL_BADFILE;
334 infof(data, "found %d CRL in %s\n",
335 rc, data->set.ssl.CRLfile);
338 /* Initialize TLS session as a client */
339 rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
340 if(rc != GNUTLS_E_SUCCESS) {
341 failf(data, "gnutls_init() failed: %d", rc);
342 return CURLE_SSL_CONNECT_ERROR;
345 /* convenient assign */
346 session = conn->ssl[sockindex].session;
348 if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
350 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
353 (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
354 strlen(conn->host.name)) < 0))
355 infof(data, "WARNING: failed to configure server name indication (SNI) "
358 /* Use default priorities */
359 rc = gnutls_set_default_priority(session);
360 if(rc != GNUTLS_E_SUCCESS)
361 return CURLE_SSL_CONNECT_ERROR;
363 if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) {
364 static const int protocol_priority[] = { GNUTLS_SSL3, 0 };
365 gnutls_protocol_set_priority(session, protocol_priority);
366 if(rc != GNUTLS_E_SUCCESS)
367 return CURLE_SSL_CONNECT_ERROR;
370 /* Sets the priority on the certificate types supported by gnutls. Priority
371 is higher for types specified before others. After specifying the types
372 you want, you must append a 0. */
373 rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
374 if(rc != GNUTLS_E_SUCCESS)
375 return CURLE_SSL_CONNECT_ERROR;
377 if(data->set.str[STRING_CERT]) {
378 if( gnutls_certificate_set_x509_key_file(
379 conn->ssl[sockindex].cred,
380 data->set.str[STRING_CERT],
381 data->set.str[STRING_KEY] ?
382 data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
383 do_file_type(data->set.str[STRING_CERT_TYPE]) ) != GNUTLS_E_SUCCESS) {
384 failf(data, "error reading X.509 key or certificate file");
385 return CURLE_SSL_CONNECT_ERROR;
389 /* put the credentials to the current session */
390 rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
391 conn->ssl[sockindex].cred);
393 /* set the connection handle (file descriptor for the socket) */
394 gnutls_transport_set_ptr(session,
395 GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]));
397 /* register callback functions to send and receive data. */
398 gnutls_transport_set_push_function(session, Curl_gtls_push);
399 gnutls_transport_set_pull_function(session, Curl_gtls_pull);
401 /* lowat must be set to zero when using custom push and pull functions. */
402 gnutls_transport_set_lowat(session, 0);
404 /* This might be a reconnect, so we check for a session ID in the cache
405 to speed up things */
407 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
408 /* we got a session id, use it! */
409 gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
411 /* Informational message */
412 infof (data, "SSL re-using session ID\n");
415 rc = handshake(conn, session, sockindex, TRUE);
417 /* handshake() sets its own error message with failf() */
420 /* This function will return the peer's raw certificate (chain) as sent by
421 the peer. These certificates are in raw format (DER encoded for
422 X.509). In case of a X.509 then a certificate list may be present. The
423 first certificate in the list is the peer's certificate, following the
424 issuer's certificate, then the issuer's issuer etc. */
426 chainp = gnutls_certificate_get_peers(session, &cert_list_size);
428 if(data->set.ssl.verifypeer ||
429 data->set.ssl.verifyhost ||
430 data->set.ssl.issuercert) {
431 failf(data, "failed to get server cert");
432 return CURLE_PEER_FAILED_VERIFICATION;
434 infof(data, "\t common name: WARNING couldn't obtain\n");
437 if(data->set.ssl.verifypeer) {
438 /* This function will try to verify the peer's certificate and return its
439 status (trusted, invalid etc.). The value of status should be one or
440 more of the gnutls_certificate_status_t enumerated elements bitwise
441 or'd. To avoid denial of service attacks some default upper limits
442 regarding the certificate key size and chain size are set. To override
443 them use gnutls_certificate_set_verify_limits(). */
445 rc = gnutls_certificate_verify_peers2(session, &verify_status);
447 failf(data, "server cert verify failed: %d", rc);
448 return CURLE_SSL_CONNECT_ERROR;
451 /* verify_status is a bitmask of gnutls_certificate_status bits */
452 if(verify_status & GNUTLS_CERT_INVALID) {
453 if(data->set.ssl.verifypeer) {
454 failf(data, "server certificate verification failed. CAfile: %s "
455 "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
456 data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
457 return CURLE_SSL_CACERT;
460 infof(data, "\t server certificate verification FAILED\n");
463 infof(data, "\t server certificate verification OK\n");
466 infof(data, "\t server certificate verification SKIPPED\n");
468 /* initialize an X.509 certificate structure. */
469 gnutls_x509_crt_init(&x509_cert);
471 /* convert the given DER or PEM encoded Certificate to the native
472 gnutls_x509_crt_t format */
473 gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
475 if (data->set.ssl.issuercert) {
476 gnutls_x509_crt_init(&x509_issuer);
477 issuerp = load_file(data->set.ssl.issuercert);
478 gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
479 rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer);
480 unload_file(issuerp);
482 failf(data, "server certificate issuer check failed (IssuerCert: %s)",
483 data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
484 return CURLE_SSL_ISSUER_ERROR;
486 infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n",
487 data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
490 size=sizeof(certbuf);
491 rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
492 0, /* the first and only one */
497 infof(data, "error fetching CN from cert:%s\n",
498 gnutls_strerror(rc));
501 /* This function will check if the given certificate's subject matches the
502 given hostname. This is a basic implementation of the matching described
503 in RFC2818 (HTTPS), which takes into account wildcards, and the subject
504 alternative name PKIX extension. Returns non zero on success, and zero on
506 rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
509 if(data->set.ssl.verifyhost > 1) {
510 failf(data, "SSL: certificate subject name (%s) does not match "
511 "target host name '%s'", certbuf, conn->host.dispname);
512 gnutls_x509_crt_deinit(x509_cert);
513 return CURLE_PEER_FAILED_VERIFICATION;
516 infof(data, "\t common name: %s (does not match '%s')\n",
517 certbuf, conn->host.dispname);
520 infof(data, "\t common name: %s (matched)\n", certbuf);
522 /* Check for time-based validity */
523 certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
525 if(certclock == (time_t)-1) {
526 failf(data, "server cert expiration date verify failed");
527 return CURLE_SSL_CONNECT_ERROR;
530 if(certclock < time(NULL)) {
531 if(data->set.ssl.verifypeer) {
532 failf(data, "server certificate expiration date has passed.");
533 return CURLE_PEER_FAILED_VERIFICATION;
536 infof(data, "\t server certificate expiration date FAILED\n");
539 infof(data, "\t server certificate expiration date OK\n");
541 certclock = gnutls_x509_crt_get_activation_time(x509_cert);
543 if(certclock == (time_t)-1) {
544 failf(data, "server cert activation date verify failed");
545 return CURLE_SSL_CONNECT_ERROR;
548 if(certclock > time(NULL)) {
549 if(data->set.ssl.verifypeer) {
550 failf(data, "server certificate not activated yet.");
551 return CURLE_PEER_FAILED_VERIFICATION;
554 infof(data, "\t server certificate activation date FAILED\n");
557 infof(data, "\t server certificate activation date OK\n");
570 /* public key algorithm's parameters */
571 algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
572 infof(data, "\t certificate public key: %s\n",
573 gnutls_pk_algorithm_get_name(algo));
575 /* version of the X.509 certificate. */
576 infof(data, "\t certificate version: #%d\n",
577 gnutls_x509_crt_get_version(x509_cert));
580 size = sizeof(certbuf);
581 gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
582 infof(data, "\t subject: %s\n", certbuf);
584 certclock = gnutls_x509_crt_get_activation_time(x509_cert);
585 showtime(data, "start date", certclock);
587 certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
588 showtime(data, "expire date", certclock);
590 size = sizeof(certbuf);
591 gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
592 infof(data, "\t issuer: %s\n", certbuf);
594 gnutls_x509_crt_deinit(x509_cert);
596 /* compression algorithm (if any) */
597 ptr = gnutls_compression_get_name(gnutls_compression_get(session));
598 /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
599 infof(data, "\t compression: %s\n", ptr);
601 /* the name of the cipher used. ie 3DES. */
602 ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
603 infof(data, "\t cipher: %s\n", ptr);
605 /* the MAC algorithms name. ie SHA1 */
606 ptr = gnutls_mac_get_name(gnutls_mac_get(session));
607 infof(data, "\t MAC: %s\n", ptr);
609 conn->ssl[sockindex].state = ssl_connection_complete;
612 /* we always unconditionally get the session id here, as even if we
613 already got it from the cache and asked to use it in the connection, it
614 might've been rejected and then a new one is in use now and we need to
616 void *connect_sessionid;
617 size_t connect_idsize;
619 /* get the session ID data size */
620 gnutls_session_get_data(session, NULL, &connect_idsize);
621 connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
623 if(connect_sessionid) {
624 /* extract session ID to the allocated buffer */
625 gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
628 /* there was one before in the cache, so instead of risking that the
629 previous one was rejected, we just kill that and store the new */
630 Curl_ssl_delsessionid(conn, ssl_sessionid);
632 /* store this session id */
633 return Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
642 /* return number of sent (non-SSL) bytes */
643 ssize_t Curl_gtls_send(struct connectdata *conn,
648 ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
651 if(rc == GNUTLS_E_AGAIN)
652 return 0; /* EWOULDBLOCK equivalent */
653 rc = -1; /* generic error code for send failure */
659 void Curl_gtls_close_all(struct SessionHandle *data)
661 /* FIX: make the OpenSSL code more generic and use parts of it here */
665 static void close_one(struct connectdata *conn,
668 if(conn->ssl[idx].session) {
669 gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
670 gnutls_deinit(conn->ssl[idx].session);
671 conn->ssl[idx].session = NULL;
673 if(conn->ssl[idx].cred) {
674 gnutls_certificate_free_credentials(conn->ssl[idx].cred);
675 conn->ssl[idx].cred = NULL;
679 void Curl_gtls_close(struct connectdata *conn, int sockindex)
681 close_one(conn, sockindex);
685 * This function is called to shut down the SSL layer but keep the
686 * socket open (CCC - Clear Command Channel)
688 int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
692 struct SessionHandle *data = conn->data;
696 /* This has only been tested on the proftpd server, and the mod_tls code
697 sends a close notify alert without waiting for a close notify alert in
698 response. Thus we wait for a close notify alert from the server, but
699 we do not send one. Let's hope other servers do the same... */
701 if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
702 gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
704 if(conn->ssl[sockindex].session) {
706 int what = Curl_socket_ready(conn->sock[sockindex],
707 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
709 /* Something to read, let's do it and hope that it is the close
710 notify alert from the server */
711 result = gnutls_record_recv(conn->ssl[sockindex].session,
715 /* This is the expected response. There was no data but only
716 the close notify alert */
720 case GNUTLS_E_INTERRUPTED:
721 infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
731 failf(data, "SSL shutdown timeout");
736 /* anything that gets here is fatally bad */
737 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
742 gnutls_deinit(conn->ssl[sockindex].session);
744 gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
746 conn->ssl[sockindex].cred = NULL;
747 conn->ssl[sockindex].session = NULL;
753 * If the read would block we return -1 and set 'wouldblock' to TRUE.
754 * Otherwise we return the amount of data read. Other errors should return -1
755 * and set 'wouldblock' to FALSE.
757 ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
758 int num, /* socketindex */
759 char *buf, /* store read data here */
760 size_t buffersize, /* max amount to read */
765 ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
766 if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
771 if(ret == GNUTLS_E_REHANDSHAKE) {
772 /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
773 proper way" takes a whole lot of work. */
774 CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE);
776 /* handshake() writes error message on its own */
778 *wouldblock = TRUE; /* then return as if this was a wouldblock */
784 failf(conn->data, "Peer closed the TLS connection");
789 failf(conn->data, "GnuTLS recv error (%d): %s",
790 (int)ret, gnutls_strerror((int)ret));
797 void Curl_gtls_session_free(void *ptr)
802 size_t Curl_gtls_version(char *buffer, size_t size)
804 return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
807 int Curl_gtls_seed(struct SessionHandle *data)
809 /* we have the "SSL is seeded" boolean static to prevent multiple
810 time-consuming seedings in vain */
811 static bool ssl_seeded = FALSE;
813 /* Quickly add a bit of entropy */
814 gcry_fast_random_poll();
816 if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
817 data->set.str[STRING_SSL_EGDSOCKET]) {
819 /* TODO: to a good job seeding the RNG
820 This may involve the gcry_control function and these options:
821 GCRYCTL_SET_RANDOM_SEED_FILE
822 GCRYCTL_SET_RNDEGD_SOCKET
829 #endif /* USE_GNUTLS */