797d18b16c9d50614d071f909015f31e16ce33b2
[platform/upstream/curl.git] / lib / gtls.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id$
22  ***************************************************************************/
23
24 /*
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.
27  *
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.
30  */
31
32 #include "setup.h"
33 #ifdef USE_GNUTLS
34 #include <gnutls/gnutls.h>
35 #include <gnutls/x509.h>
36 #include <gcrypt.h>
37
38 #include <string.h>
39 #include <stdlib.h>
40 #include <ctype.h>
41 #ifdef HAVE_SYS_SOCKET_H
42 #include <sys/socket.h>
43 #endif
44
45 #include "urldata.h"
46 #include "sendf.h"
47 #include "inet_pton.h"
48 #include "gtls.h"
49 #include "sslgen.h"
50 #include "parsedate.h"
51 #include "connect.h" /* for the connect timeout */
52 #include "select.h"
53 #include "rawstr.h"
54
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: */
59 #include "memdebug.h"
60
61 /*
62  Some hackish cast macros based on:
63  http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html
64 */
65 #ifndef GNUTLS_POINTER_TO_INT_CAST
66 #define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
67 #endif
68 #ifndef GNUTLS_INT_TO_POINTER_CAST
69 #define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
70 #endif
71
72 /* Enable GnuTLS debugging by defining GTLSDEBUG */
73 /*#define GTLSDEBUG */
74
75 #ifdef GTLSDEBUG
76 static void tls_log_func(int level, const char *str)
77 {
78     fprintf(stderr, "|<%d>| %s", level, str);
79 }
80 #endif
81 static bool gtls_inited = FALSE;
82 /*
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.
89  */
90 static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
91 {
92   return swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
93 }
94
95 static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
96 {
97   return sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
98 }
99
100 /* Curl_gtls_init()
101  *
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!
106  */
107 int Curl_gtls_init(void)
108 {
109   int ret = 1;
110   if(!gtls_inited) {
111     ret = gnutls_global_init()?0:1;
112 #ifdef GTLSDEBUG
113     gnutls_global_set_log_function(tls_log_func);
114     gnutls_global_set_log_level(2);
115 #endif
116     gtls_inited = TRUE;
117   }
118   return ret;
119 }
120
121 int Curl_gtls_cleanup(void)
122 {
123   if(gtls_inited) {
124     gnutls_global_deinit();
125     gtls_inited = FALSE;
126   }
127   return 1;
128 }
129
130 static void showtime(struct SessionHandle *data,
131                      const char *text,
132                      time_t stamp)
133 {
134   struct tm *tm;
135 #ifdef HAVE_GMTIME_R
136   struct tm buffer;
137   tm = (struct tm *)gmtime_r(&stamp, &buffer);
138 #else
139   tm = gmtime(&stamp);
140 #endif
141   snprintf(data->state.buffer,
142            BUFSIZE,
143            "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n",
144            text,
145            Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
146            tm->tm_mday,
147            Curl_month[tm->tm_mon],
148            tm->tm_year + 1900,
149            tm->tm_hour,
150            tm->tm_min,
151            tm->tm_sec);
152   infof(data, "%s", data->state.buffer);
153 }
154
155 static gnutls_datum load_file (const char *file)
156 {
157   FILE *f;
158   gnutls_datum loaded_file = { NULL, 0 };
159   long filelen;
160   void *ptr;
161
162   if (!(f = fopen(file, "r")))
163     return loaded_file;
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)))
168     goto out;
169   if (fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
170     free(ptr);
171     goto out;
172   }
173
174   loaded_file.data = ptr;
175   loaded_file.size = (unsigned int)filelen;
176 out:
177   fclose(f);
178   return loaded_file;
179 }
180
181 static void unload_file(gnutls_datum data) {
182   free(data.data);
183 }
184
185
186 /* this function does a BLOCKING SSL/TLS (re-)handshake */
187 static CURLcode handshake(struct connectdata *conn,
188                           gnutls_session session,
189                           int sockindex,
190                           bool duringconnect)
191 {
192   struct SessionHandle *data = conn->data;
193   int rc;
194   if(!gtls_inited)
195     Curl_gtls_init();
196   do {
197     rc = gnutls_handshake(session);
198
199     if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
200       long timeout_ms = Curl_timeleft(conn, NULL, duringconnect);
201
202       if(timeout_ms < 0) {
203         /* a precaution, no need to continue if time already is up */
204         failf(data, "SSL connection timeout");
205         return CURLE_OPERATION_TIMEDOUT;
206       }
207
208       rc = Curl_socket_ready(conn->sock[sockindex],
209                        conn->sock[sockindex], (int)timeout_ms);
210       if(rc > 0)
211         /* reabable or writable, go loop*/
212         continue;
213       else if(0 == rc) {
214         /* timeout */
215         failf(data, "SSL connection timeout");
216         return CURLE_OPERATION_TIMEDOUT;
217       }
218       else {
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;
222       }
223     }
224     else
225       break;
226   } while(1);
227
228   if(rc < 0) {
229     failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc));
230     return CURLE_SSL_CONNECT_ERROR;
231   }
232
233   return CURLE_OK;
234 }
235
236 static gnutls_x509_crt_fmt do_file_type(const char *type)
237 {
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;
244   return -1;
245 }
246
247
248 /*
249  * This function is called after the TCP connect has completed. Setup the TLS
250  * layer and do all necessary magic.
251  */
252 CURLcode
253 Curl_gtls_connect(struct connectdata *conn,
254                   int sockindex)
255
256 {
257   static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
258   struct SessionHandle *data = conn->data;
259   gnutls_session session;
260   int rc;
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? */
267   size_t size;
268   unsigned int algo;
269   unsigned int bits;
270   time_t certclock;
271   const char *ptr;
272   void *ssl_sessionid;
273   size_t ssl_idsize;
274   bool sni = TRUE; /* default is SNI enabled */
275 #ifdef ENABLE_IPV6
276   struct in6_addr addr;
277 #else
278   struct in_addr addr;
279 #endif
280
281   if(conn->ssl[sockindex].state == ssl_connection_complete)
282     /* to make us tolerant against being called more than once for the
283        same connection */
284     return CURLE_OK;
285
286   if(!gtls_inited)
287     Curl_gtls_init();
288
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;
293   }
294   else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
295     sni = FALSE; /* SSLv3 has no SNI */
296
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;
302   }
303
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);
308
309     rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
310                                                 data->set.ssl.CAfile,
311                                                 GNUTLS_X509_FMT_PEM);
312     if(rc < 0) {
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;
317     }
318     else
319       infof(data, "found %d certificates in %s\n",
320             rc, data->set.ssl.CAfile);
321   }
322
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);
328     if(rc < 0) {
329       failf(data, "error reading crl file %s (%s)\n",
330             data->set.ssl.CRLfile, gnutls_strerror(rc));
331       return CURLE_SSL_CRL_BADFILE;
332     }
333     else
334       infof(data, "found %d CRL in %s\n",
335             rc, data->set.ssl.CRLfile);
336   }
337
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;
343   }
344
345   /* convenient assign */
346   session = conn->ssl[sockindex].session;
347
348   if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
349 #ifdef ENABLE_IPV6
350       (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
351 #endif
352       sni &&
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) "
356           "TLS extension\n");
357
358   /* Use default priorities */
359   rc = gnutls_set_default_priority(session);
360   if(rc != GNUTLS_E_SUCCESS)
361     return CURLE_SSL_CONNECT_ERROR;
362
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;
368   }
369
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;
376
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;
386     }
387   }
388
389   /* put the credentials to the current session */
390   rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
391                               conn->ssl[sockindex].cred);
392
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]));
396
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);
400
401   /* lowat must be set to zero when using custom push and pull functions. */
402   gnutls_transport_set_lowat(session, 0);
403
404   /* This might be a reconnect, so we check for a session ID in the cache
405      to speed up things */
406
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);
410
411     /* Informational message */
412     infof (data, "SSL re-using session ID\n");
413   }
414
415   rc = handshake(conn, session, sockindex, TRUE);
416   if(rc)
417     /* handshake() sets its own error message with failf() */
418     return rc;
419
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. */
425
426   chainp = gnutls_certificate_get_peers(session, &cert_list_size);
427   if(!chainp) {
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;
433     }
434     infof(data, "\t common name: WARNING couldn't obtain\n");
435   }
436
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(). */
444
445     rc = gnutls_certificate_verify_peers2(session, &verify_status);
446     if(rc < 0) {
447       failf(data, "server cert verify failed: %d", rc);
448       return CURLE_SSL_CONNECT_ERROR;
449     }
450
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;
458       }
459       else
460         infof(data, "\t server certificate verification FAILED\n");
461     }
462     else
463       infof(data, "\t server certificate verification OK\n");
464   }
465   else
466     infof(data, "\t server certificate verification SKIPPED\n");
467
468   /* initialize an X.509 certificate structure. */
469   gnutls_x509_crt_init(&x509_cert);
470
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);
474
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);
481     if (rc <= 0) {
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;
485     }
486     infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n",
487           data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
488   }
489
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 */
493                                      FALSE,
494                                      certbuf,
495                                      &size);
496   if(rc) {
497     infof(data, "error fetching CN from cert:%s\n",
498           gnutls_strerror(rc));
499   }
500
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
505      failure. */
506   rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
507
508   if(!rc) {
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;
514     }
515     else
516       infof(data, "\t common name: %s (does not match '%s')\n",
517             certbuf, conn->host.dispname);
518   }
519   else
520     infof(data, "\t common name: %s (matched)\n", certbuf);
521
522   /* Check for time-based validity */
523   certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
524
525   if(certclock == (time_t)-1) {
526     failf(data, "server cert expiration date verify failed");
527     return CURLE_SSL_CONNECT_ERROR;
528   }
529
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;
534     }
535     else
536       infof(data, "\t server certificate expiration date FAILED\n");
537   }
538   else
539     infof(data, "\t server certificate expiration date OK\n");
540
541   certclock = gnutls_x509_crt_get_activation_time(x509_cert);
542
543   if(certclock == (time_t)-1) {
544     failf(data, "server cert activation date verify failed");
545     return CURLE_SSL_CONNECT_ERROR;
546   }
547
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;
552     }
553     else
554       infof(data, "\t server certificate activation date FAILED\n");
555   }
556   else
557     infof(data, "\t server certificate activation date OK\n");
558
559   /* Show:
560
561   - ciphers used
562   - subject
563   - start date
564   - expire date
565   - common name
566   - issuer
567
568   */
569
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));
574
575   /* version of the X.509 certificate. */
576   infof(data, "\t certificate version: #%d\n",
577         gnutls_x509_crt_get_version(x509_cert));
578
579
580   size = sizeof(certbuf);
581   gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
582   infof(data, "\t subject: %s\n", certbuf);
583
584   certclock = gnutls_x509_crt_get_activation_time(x509_cert);
585   showtime(data, "start date", certclock);
586
587   certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
588   showtime(data, "expire date", certclock);
589
590   size = sizeof(certbuf);
591   gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
592   infof(data, "\t issuer: %s\n", certbuf);
593
594   gnutls_x509_crt_deinit(x509_cert);
595
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);
600
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);
604
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);
608
609   conn->ssl[sockindex].state = ssl_connection_complete;
610
611   {
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
615        detect that. */
616     void *connect_sessionid;
617     size_t connect_idsize;
618
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 */
622
623     if(connect_sessionid) {
624       /* extract session ID to the allocated buffer */
625       gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
626
627       if(ssl_sessionid)
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);
631
632       /* store this session id */
633       return Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
634     }
635
636   }
637
638   return CURLE_OK;
639 }
640
641
642 /* return number of sent (non-SSL) bytes */
643 ssize_t Curl_gtls_send(struct connectdata *conn,
644                        int sockindex,
645                        const void *mem,
646                        size_t len)
647 {
648   ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
649
650   if(rc < 0 ) {
651     if(rc == GNUTLS_E_AGAIN)
652       return 0; /* EWOULDBLOCK equivalent */
653     rc = -1; /* generic error code for send failure */
654   }
655
656   return rc;
657 }
658
659 void Curl_gtls_close_all(struct SessionHandle *data)
660 {
661   /* FIX: make the OpenSSL code more generic and use parts of it here */
662   (void)data;
663 }
664
665 static void close_one(struct connectdata *conn,
666                       int idx)
667 {
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;
672   }
673   if(conn->ssl[idx].cred) {
674     gnutls_certificate_free_credentials(conn->ssl[idx].cred);
675     conn->ssl[idx].cred = NULL;
676   }
677 }
678
679 void Curl_gtls_close(struct connectdata *conn, int sockindex)
680 {
681   close_one(conn, sockindex);
682 }
683
684 /*
685  * This function is called to shut down the SSL layer but keep the
686  * socket open (CCC - Clear Command Channel)
687  */
688 int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
689 {
690   ssize_t result;
691   int retval = 0;
692   struct SessionHandle *data = conn->data;
693   int done = 0;
694   char buf[120];
695
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... */
700
701   if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
702       gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
703
704   if(conn->ssl[sockindex].session) {
705     while(!done) {
706       int what = Curl_socket_ready(conn->sock[sockindex],
707                              CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
708       if(what > 0) {
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,
712                                     buf, sizeof(buf));
713         switch(result) {
714         case 0:
715           /* This is the expected response. There was no data but only
716              the close notify alert */
717           done = 1;
718           break;
719         case GNUTLS_E_AGAIN:
720         case GNUTLS_E_INTERRUPTED:
721           infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
722           break;
723         default:
724           retval = -1;
725           done = 1;
726           break;
727         }
728       }
729       else if(0 == what) {
730         /* timeout */
731         failf(data, "SSL shutdown timeout");
732         done = 1;
733         break;
734       }
735       else {
736         /* anything that gets here is fatally bad */
737         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
738         retval = -1;
739         done = 1;
740       }
741     }
742     gnutls_deinit(conn->ssl[sockindex].session);
743   }
744   gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
745
746   conn->ssl[sockindex].cred = NULL;
747   conn->ssl[sockindex].session = NULL;
748
749   return retval;
750 }
751
752 /*
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.
756  */
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 */
761                        bool *wouldblock)
762 {
763   ssize_t ret;
764
765   ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
766   if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
767     *wouldblock = TRUE;
768     return -1;
769   }
770
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);
775     if(rc)
776       /* handshake() writes error message on its own */
777       return rc;
778     *wouldblock = TRUE; /* then return as if this was a wouldblock */
779     return -1;
780   }
781
782   *wouldblock = FALSE;
783   if(!ret) {
784     failf(conn->data, "Peer closed the TLS connection");
785     return -1;
786   }
787
788   if(ret < 0) {
789     failf(conn->data, "GnuTLS recv error (%d): %s",
790           (int)ret, gnutls_strerror((int)ret));
791     return -1;
792   }
793
794   return ret;
795 }
796
797 void Curl_gtls_session_free(void *ptr)
798 {
799   free(ptr);
800 }
801
802 size_t Curl_gtls_version(char *buffer, size_t size)
803 {
804   return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
805 }
806
807 int Curl_gtls_seed(struct SessionHandle *data)
808 {
809   /* we have the "SSL is seeded" boolean static to prevent multiple
810      time-consuming seedings in vain */
811   static bool ssl_seeded = FALSE;
812
813   /* Quickly add a bit of entropy */
814   gcry_fast_random_poll();
815
816   if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
817      data->set.str[STRING_SSL_EGDSOCKET]) {
818
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
823     */
824     ssl_seeded = TRUE;
825   }
826   return 0;
827 }
828
829 #endif /* USE_GNUTLS */