Update tag value for tizen 2.0 build
[external/curl.git] / lib / gtls.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2010, 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  ***************************************************************************/
22
23 /*
24  * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
25  * but sslgen.c should ever call or use these functions.
26  *
27  * Note: don't use the GnuTLS' *_t variable type names in this source code,
28  * since they were not present in 1.0.X.
29  */
30
31 #include "setup.h"
32 #ifdef USE_GNUTLS
33 #include <gnutls/gnutls.h>
34 #include <gnutls/x509.h>
35 #include <gcrypt.h>
36
37 #include <string.h>
38 #include <stdlib.h>
39 #include <ctype.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 #include <sys/socket.h>
42 #endif
43
44 #include "urldata.h"
45 #include "sendf.h"
46 #include "inet_pton.h"
47 #include "gtls.h"
48 #include "sslgen.h"
49 #include "parsedate.h"
50 #include "connect.h" /* for the connect timeout */
51 #include "select.h"
52 #include "rawstr.h"
53
54 #define _MPRINTF_REPLACE /* use our functions only */
55 #include <curl/mprintf.h>
56 #include "curl_memory.h"
57 /* The last #include file should be: */
58 #include "memdebug.h"
59
60 /*
61  Some hackish cast macros based on:
62  http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html
63 */
64 #ifndef GNUTLS_POINTER_TO_INT_CAST
65 #define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
66 #endif
67 #ifndef GNUTLS_INT_TO_POINTER_CAST
68 #define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
69 #endif
70
71 /* Enable GnuTLS debugging by defining GTLSDEBUG */
72 /*#define GTLSDEBUG */
73
74 #ifdef GTLSDEBUG
75 static void tls_log_func(int level, const char *str)
76 {
77     fprintf(stderr, "|<%d>| %s", level, str);
78 }
79 #endif
80 static bool gtls_inited = FALSE;
81
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  * When these custom push and pull callbacks fail, GNU TLS checks its own
91  * session-specific error variable, and when not set also its own global
92  * errno variable, in order to take appropriate action. GNU TLS does not
93  * require that the transport is actually a socket. This implies that for
94  * Windows builds these callbacks should ideally set the session-specific
95  * error variable using function gnutls_transport_set_errno or as a last
96  * resort global errno variable using gnutls_transport_set_global_errno,
97  * with a transport agnostic error value. This implies that some winsock
98  * error translation must take place in these callbacks.
99  */
100
101 #ifdef USE_WINSOCK
102 #  define gtls_EINTR  4
103 #  define gtls_EIO    5
104 #  define gtls_EAGAIN 11
105 static int gtls_mapped_sockerrno(void)
106 {
107   switch(SOCKERRNO) {
108   case WSAEWOULDBLOCK:
109     return gtls_EAGAIN;
110   case WSAEINTR:
111     return gtls_EINTR;
112   default:
113     break;
114   }
115   return gtls_EIO;
116 }
117 #endif
118
119 static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
120 {
121   ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
122 #ifdef USE_WINSOCK
123   if(ret < 0)
124     gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
125 #endif
126   return ret;
127 }
128
129 static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
130 {
131   ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
132 #ifdef USE_WINSOCK
133   if(ret < 0)
134     gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
135 #endif
136   return ret;
137 }
138
139 /* Curl_gtls_init()
140  *
141  * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
142  * are not thread-safe and thus this function itself is not thread-safe and
143  * must only be called from within curl_global_init() to keep the thread
144  * situation under control!
145  */
146 int Curl_gtls_init(void)
147 {
148   int ret = 1;
149   if(!gtls_inited) {
150     ret = gnutls_global_init()?0:1;
151 #ifdef GTLSDEBUG
152     gnutls_global_set_log_function(tls_log_func);
153     gnutls_global_set_log_level(2);
154 #endif
155     gtls_inited = TRUE;
156   }
157   return ret;
158 }
159
160 int Curl_gtls_cleanup(void)
161 {
162   if(gtls_inited) {
163     gnutls_global_deinit();
164     gtls_inited = FALSE;
165   }
166   return 1;
167 }
168
169 static void showtime(struct SessionHandle *data,
170                      const char *text,
171                      time_t stamp)
172 {
173   struct tm *tm;
174 #ifdef HAVE_GMTIME_R
175   struct tm buffer;
176   tm = (struct tm *)gmtime_r(&stamp, &buffer);
177 #else
178   tm = gmtime(&stamp);
179 #endif
180   snprintf(data->state.buffer,
181            BUFSIZE,
182            "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n",
183            text,
184            Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
185            tm->tm_mday,
186            Curl_month[tm->tm_mon],
187            tm->tm_year + 1900,
188            tm->tm_hour,
189            tm->tm_min,
190            tm->tm_sec);
191   infof(data, "%s", data->state.buffer);
192 }
193
194 static gnutls_datum load_file (const char *file)
195 {
196   FILE *f;
197   gnutls_datum loaded_file = { NULL, 0 };
198   long filelen;
199   void *ptr;
200
201   if (!(f = fopen(file, "r")))
202     return loaded_file;
203   if (fseek(f, 0, SEEK_END) != 0
204       || (filelen = ftell(f)) < 0
205       || fseek(f, 0, SEEK_SET) != 0
206       || !(ptr = malloc((size_t)filelen)))
207     goto out;
208   if (fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
209     free(ptr);
210     goto out;
211   }
212
213   loaded_file.data = ptr;
214   loaded_file.size = (unsigned int)filelen;
215 out:
216   fclose(f);
217   return loaded_file;
218 }
219
220 static void unload_file(gnutls_datum data) {
221   free(data.data);
222 }
223
224
225 /* this function does a SSL/TLS (re-)handshake */
226 static CURLcode handshake(struct connectdata *conn,
227                           int sockindex,
228                           bool duringconnect,
229                           bool nonblocking)
230 {
231   struct SessionHandle *data = conn->data;
232   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
233   gnutls_session session = conn->ssl[sockindex].session;
234   curl_socket_t sockfd = conn->sock[sockindex];
235   long timeout_ms;
236   int rc;
237   int what;
238
239   for(;;) {
240     /* check allowed time left */
241     timeout_ms = Curl_timeleft(conn, NULL, duringconnect);
242
243     if(timeout_ms < 0) {
244       /* no need to continue if time already is up */
245       failf(data, "SSL connection timeout");
246       return CURLE_OPERATION_TIMEDOUT;
247     }
248
249     /* if ssl is expecting something, check if it's available. */
250     if(connssl->connecting_state == ssl_connect_2_reading
251        || connssl->connecting_state == ssl_connect_2_writing) {
252
253       curl_socket_t writefd = ssl_connect_2_writing==
254         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
255       curl_socket_t readfd = ssl_connect_2_reading==
256         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
257
258       what = Curl_socket_ready(readfd, writefd,
259                                nonblocking?0:(int)timeout_ms?1000:timeout_ms);
260       if(what < 0) {
261         /* fatal error */
262         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
263         return CURLE_SSL_CONNECT_ERROR;
264       }
265       else if(0 == what) {
266         if(nonblocking)
267           return CURLE_OK;
268         else if(timeout_ms) {
269           /* timeout */
270           failf(data, "SSL connection timeout at %ld", timeout_ms);
271           return CURLE_OPERATION_TIMEDOUT;
272         }
273       }
274       /* socket is readable or writable */
275     }
276
277     rc = gnutls_handshake(session);
278
279     if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
280       connssl->connecting_state =
281         gnutls_record_get_direction(session)?
282         ssl_connect_2_writing:ssl_connect_2_reading;
283       if(nonblocking)
284         return CURLE_OK;
285     }
286     else if (rc < 0) {
287       failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc));
288       return CURLE_SSL_CONNECT_ERROR;
289     }
290     else {
291       /* Reset our connect state machine */
292       connssl->connecting_state = ssl_connect_1;
293       return CURLE_OK;
294     }
295   }
296 }
297
298 static gnutls_x509_crt_fmt do_file_type(const char *type)
299 {
300   if(!type || !type[0])
301     return GNUTLS_X509_FMT_PEM;
302   if(Curl_raw_equal(type, "PEM"))
303     return GNUTLS_X509_FMT_PEM;
304   if(Curl_raw_equal(type, "DER"))
305     return GNUTLS_X509_FMT_DER;
306   return -1;
307 }
308
309 static CURLcode
310 gtls_connect_step1(struct connectdata *conn,
311                    int sockindex)
312 {
313   static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
314   struct SessionHandle *data = conn->data;
315   gnutls_session session;
316   int rc;
317   void *ssl_sessionid;
318   size_t ssl_idsize;
319   bool sni = TRUE; /* default is SNI enabled */
320 #ifdef ENABLE_IPV6
321   struct in6_addr addr;
322 #else
323   struct in_addr addr;
324 #endif
325
326   if(conn->ssl[sockindex].state == ssl_connection_complete)
327     /* to make us tolerant against being called more than once for the
328        same connection */
329     return CURLE_OK;
330
331   if(!gtls_inited)
332     Curl_gtls_init();
333
334   /* GnuTLS only supports SSLv3 and TLSv1 */
335   if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
336     failf(data, "GnuTLS does not support SSLv2");
337     return CURLE_SSL_CONNECT_ERROR;
338   }
339   else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
340     sni = FALSE; /* SSLv3 has no SNI */
341
342   /* allocate a cred struct */
343   rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
344   if(rc != GNUTLS_E_SUCCESS) {
345     failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
346     return CURLE_SSL_CONNECT_ERROR;
347   }
348
349   if(data->set.ssl.CAfile) {
350     /* set the trusted CA cert bundle file */
351     gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
352                                         GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
353
354     rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
355                                                 data->set.ssl.CAfile,
356                                                 GNUTLS_X509_FMT_PEM);
357     if(rc < 0) {
358       infof(data, "error reading ca cert file %s (%s)\n",
359             data->set.ssl.CAfile, gnutls_strerror(rc));
360       if(data->set.ssl.verifypeer)
361         return CURLE_SSL_CACERT_BADFILE;
362     }
363     else
364       infof(data, "found %d certificates in %s\n",
365             rc, data->set.ssl.CAfile);
366   }
367
368   if(data->set.ssl.CRLfile) {
369     /* set the CRL list file */
370     rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
371                                               data->set.ssl.CRLfile,
372                                               GNUTLS_X509_FMT_PEM);
373     if(rc < 0) {
374       failf(data, "error reading crl file %s (%s)\n",
375             data->set.ssl.CRLfile, gnutls_strerror(rc));
376       return CURLE_SSL_CRL_BADFILE;
377     }
378     else
379       infof(data, "found %d CRL in %s\n",
380             rc, data->set.ssl.CRLfile);
381   }
382
383   /* Initialize TLS session as a client */
384   rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
385   if(rc != GNUTLS_E_SUCCESS) {
386     failf(data, "gnutls_init() failed: %d", rc);
387     return CURLE_SSL_CONNECT_ERROR;
388   }
389
390   /* convenient assign */
391   session = conn->ssl[sockindex].session;
392
393   if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
394 #ifdef ENABLE_IPV6
395       (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
396 #endif
397       sni &&
398       (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
399                               strlen(conn->host.name)) < 0))
400     infof(data, "WARNING: failed to configure server name indication (SNI) "
401           "TLS extension\n");
402
403   /* Use default priorities */
404   rc = gnutls_set_default_priority(session);
405   if(rc != GNUTLS_E_SUCCESS)
406     return CURLE_SSL_CONNECT_ERROR;
407
408   if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) {
409     static const int protocol_priority[] = { GNUTLS_SSL3, 0 };
410     gnutls_protocol_set_priority(session, protocol_priority);
411     if(rc != GNUTLS_E_SUCCESS)
412       return CURLE_SSL_CONNECT_ERROR;
413   }
414
415   /* Sets the priority on the certificate types supported by gnutls. Priority
416      is higher for types specified before others. After specifying the types
417      you want, you must append a 0. */
418   rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
419   if(rc != GNUTLS_E_SUCCESS)
420     return CURLE_SSL_CONNECT_ERROR;
421
422   if(data->set.str[STRING_CERT]) {
423     if( gnutls_certificate_set_x509_key_file(
424           conn->ssl[sockindex].cred,
425           data->set.str[STRING_CERT],
426           data->set.str[STRING_KEY] ?
427           data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
428           do_file_type(data->set.str[STRING_CERT_TYPE]) ) != GNUTLS_E_SUCCESS) {
429       failf(data, "error reading X.509 key or certificate file");
430       return CURLE_SSL_CONNECT_ERROR;
431     }
432   }
433
434   /* put the credentials to the current session */
435   rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
436                               conn->ssl[sockindex].cred);
437
438   /* set the connection handle (file descriptor for the socket) */
439   gnutls_transport_set_ptr(session,
440                            GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]));
441
442   /* register callback functions to send and receive data. */
443   gnutls_transport_set_push_function(session, Curl_gtls_push);
444   gnutls_transport_set_pull_function(session, Curl_gtls_pull);
445
446   /* lowat must be set to zero when using custom push and pull functions. */
447   gnutls_transport_set_lowat(session, 0);
448
449   /* This might be a reconnect, so we check for a session ID in the cache
450      to speed up things */
451
452   if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
453     /* we got a session id, use it! */
454     gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
455
456     /* Informational message */
457     infof (data, "SSL re-using session ID\n");
458   }
459
460   return CURLE_OK;
461 }
462
463 static Curl_recv gtls_recv;
464 static Curl_send gtls_send;
465
466 static CURLcode
467 gtls_connect_step3(struct connectdata *conn,
468                    int sockindex)
469 {
470   unsigned int cert_list_size;
471   const gnutls_datum *chainp;
472   unsigned int verify_status;
473   gnutls_x509_crt x509_cert,x509_issuer;
474   gnutls_datum issuerp;
475   char certbuf[256]; /* big enough? */
476   size_t size;
477   unsigned int algo;
478   unsigned int bits;
479   time_t certclock;
480   const char *ptr;
481   struct SessionHandle *data = conn->data;
482   gnutls_session session = conn->ssl[sockindex].session;
483   int rc;
484   int incache;
485   void *ssl_sessionid;
486
487   /* This function will return the peer's raw certificate (chain) as sent by
488      the peer. These certificates are in raw format (DER encoded for
489      X.509). In case of a X.509 then a certificate list may be present. The
490      first certificate in the list is the peer's certificate, following the
491      issuer's certificate, then the issuer's issuer etc. */
492
493   chainp = gnutls_certificate_get_peers(session, &cert_list_size);
494   if(!chainp) {
495     if(data->set.ssl.verifypeer ||
496        data->set.ssl.verifyhost ||
497        data->set.ssl.issuercert) {
498       failf(data, "failed to get server cert");
499       return CURLE_PEER_FAILED_VERIFICATION;
500     }
501     infof(data, "\t common name: WARNING couldn't obtain\n");
502   }
503
504   if(data->set.ssl.verifypeer) {
505     /* This function will try to verify the peer's certificate and return its
506        status (trusted, invalid etc.). The value of status should be one or
507        more of the gnutls_certificate_status_t enumerated elements bitwise
508        or'd. To avoid denial of service attacks some default upper limits
509        regarding the certificate key size and chain size are set. To override
510        them use gnutls_certificate_set_verify_limits(). */
511
512     rc = gnutls_certificate_verify_peers2(session, &verify_status);
513     if(rc < 0) {
514       failf(data, "server cert verify failed: %d", rc);
515       return CURLE_SSL_CONNECT_ERROR;
516     }
517
518     /* verify_status is a bitmask of gnutls_certificate_status bits */
519     if(verify_status & GNUTLS_CERT_INVALID) {
520       if(data->set.ssl.verifypeer) {
521         failf(data, "server certificate verification failed. CAfile: %s "
522               "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
523               data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
524         return CURLE_SSL_CACERT;
525       }
526       else
527         infof(data, "\t server certificate verification FAILED\n");
528     }
529     else
530       infof(data, "\t server certificate verification OK\n");
531   }
532   else
533     infof(data, "\t server certificate verification SKIPPED\n");
534
535   /* initialize an X.509 certificate structure. */
536   gnutls_x509_crt_init(&x509_cert);
537
538   /* convert the given DER or PEM encoded Certificate to the native
539      gnutls_x509_crt_t format */
540   gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
541
542   if (data->set.ssl.issuercert) {
543     gnutls_x509_crt_init(&x509_issuer);
544     issuerp = load_file(data->set.ssl.issuercert);
545     gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
546     rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer);
547     unload_file(issuerp);
548     if (rc <= 0) {
549       failf(data, "server certificate issuer check failed (IssuerCert: %s)",
550             data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
551       return CURLE_SSL_ISSUER_ERROR;
552     }
553     infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n",
554           data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
555   }
556
557   size=sizeof(certbuf);
558   rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
559                                      0, /* the first and only one */
560                                      FALSE,
561                                      certbuf,
562                                      &size);
563   if(rc) {
564     infof(data, "error fetching CN from cert:%s\n",
565           gnutls_strerror(rc));
566   }
567
568   /* This function will check if the given certificate's subject matches the
569      given hostname. This is a basic implementation of the matching described
570      in RFC2818 (HTTPS), which takes into account wildcards, and the subject
571      alternative name PKIX extension. Returns non zero on success, and zero on
572      failure. */
573   rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
574
575   if(!rc) {
576     if(data->set.ssl.verifyhost > 1) {
577       failf(data, "SSL: certificate subject name (%s) does not match "
578             "target host name '%s'", certbuf, conn->host.dispname);
579       gnutls_x509_crt_deinit(x509_cert);
580       return CURLE_PEER_FAILED_VERIFICATION;
581     }
582     else
583       infof(data, "\t common name: %s (does not match '%s')\n",
584             certbuf, conn->host.dispname);
585   }
586   else
587     infof(data, "\t common name: %s (matched)\n", certbuf);
588
589   /* Check for time-based validity */
590   certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
591
592   if(certclock == (time_t)-1) {
593     failf(data, "server cert expiration date verify failed");
594     return CURLE_SSL_CONNECT_ERROR;
595   }
596
597   if(certclock < time(NULL)) {
598     if(data->set.ssl.verifypeer) {
599       failf(data, "server certificate expiration date has passed.");
600       return CURLE_PEER_FAILED_VERIFICATION;
601     }
602     else
603       infof(data, "\t server certificate expiration date FAILED\n");
604   }
605   else
606     infof(data, "\t server certificate expiration date OK\n");
607
608   certclock = gnutls_x509_crt_get_activation_time(x509_cert);
609
610   if(certclock == (time_t)-1) {
611     failf(data, "server cert activation date verify failed");
612     return CURLE_SSL_CONNECT_ERROR;
613   }
614
615   if(certclock > time(NULL)) {
616     if(data->set.ssl.verifypeer) {
617       failf(data, "server certificate not activated yet.");
618       return CURLE_PEER_FAILED_VERIFICATION;
619     }
620     else
621       infof(data, "\t server certificate activation date FAILED\n");
622   }
623   else
624     infof(data, "\t server certificate activation date OK\n");
625
626   /* Show:
627
628   - ciphers used
629   - subject
630   - start date
631   - expire date
632   - common name
633   - issuer
634
635   */
636
637   /* public key algorithm's parameters */
638   algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
639   infof(data, "\t certificate public key: %s\n",
640         gnutls_pk_algorithm_get_name(algo));
641
642   /* version of the X.509 certificate. */
643   infof(data, "\t certificate version: #%d\n",
644         gnutls_x509_crt_get_version(x509_cert));
645
646
647   size = sizeof(certbuf);
648   gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
649   infof(data, "\t subject: %s\n", certbuf);
650
651   certclock = gnutls_x509_crt_get_activation_time(x509_cert);
652   showtime(data, "start date", certclock);
653
654   certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
655   showtime(data, "expire date", certclock);
656
657   size = sizeof(certbuf);
658   gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
659   infof(data, "\t issuer: %s\n", certbuf);
660
661   gnutls_x509_crt_deinit(x509_cert);
662
663   /* compression algorithm (if any) */
664   ptr = gnutls_compression_get_name(gnutls_compression_get(session));
665   /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
666   infof(data, "\t compression: %s\n", ptr);
667
668   /* the name of the cipher used. ie 3DES. */
669   ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
670   infof(data, "\t cipher: %s\n", ptr);
671
672   /* the MAC algorithms name. ie SHA1 */
673   ptr = gnutls_mac_get_name(gnutls_mac_get(session));
674   infof(data, "\t MAC: %s\n", ptr);
675
676   conn->ssl[sockindex].state = ssl_connection_complete;
677   conn->recv[sockindex] = gtls_recv;
678   conn->send[sockindex] = gtls_send;
679
680   {
681     /* we always unconditionally get the session id here, as even if we
682        already got it from the cache and asked to use it in the connection, it
683        might've been rejected and then a new one is in use now and we need to
684        detect that. */
685     void *connect_sessionid;
686     size_t connect_idsize;
687
688     /* get the session ID data size */
689     gnutls_session_get_data(session, NULL, &connect_idsize);
690     connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
691
692     if(connect_sessionid) {
693       /* extract session ID to the allocated buffer */
694       gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
695
696       incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
697       if (incache) {
698         /* there was one before in the cache, so instead of risking that the
699            previous one was rejected, we just kill that and store the new */
700         Curl_ssl_delsessionid(conn, ssl_sessionid);
701       }
702
703       /* store this session id */
704       return Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
705     }
706   }
707
708   return CURLE_OK;
709 }
710
711
712 /*
713  * This function is called after the TCP connect has completed. Setup the TLS
714  * layer and do all necessary magic.
715  */
716 /* We use connssl->connecting_state to keep track of the connection status;
717    there are three states: 'ssl_connect_1' (not started yet or complete),
718    'ssl_connect_2_reading' (waiting for data from server), and
719    'ssl_connect_2_writing' (waiting to be able to write).
720  */
721 static CURLcode
722 gtls_connect_common(struct connectdata *conn,
723                     int sockindex,
724                     bool nonblocking,
725                     bool *done)
726 {
727   int rc;
728   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
729
730   /* Initiate the connection, if not already done */
731   if(ssl_connect_1==connssl->connecting_state) {
732     rc = gtls_connect_step1 (conn, sockindex);
733     if(rc)
734       return rc;
735   }
736
737   rc = handshake(conn, sockindex, TRUE, nonblocking);
738   if(rc)
739     /* handshake() sets its own error message with failf() */
740     return rc;
741
742   /* Finish connecting once the handshake is done */
743   if(ssl_connect_1==connssl->connecting_state) {
744     rc = gtls_connect_step3(conn, sockindex);
745     if(rc)
746       return rc;
747   }
748
749   *done = ssl_connect_1==connssl->connecting_state;
750
751   return CURLE_OK;
752 }
753
754 CURLcode
755 Curl_gtls_connect_nonblocking(struct connectdata *conn,
756                               int sockindex,
757                               bool *done)
758 {
759   return gtls_connect_common(conn, sockindex, TRUE, done);
760 }
761
762 CURLcode
763 Curl_gtls_connect(struct connectdata *conn,
764                   int sockindex)
765
766 {
767   CURLcode retcode;
768   bool done = FALSE;
769
770   retcode = gtls_connect_common(conn, sockindex, FALSE, &done);
771   if(retcode)
772     return retcode;
773
774   DEBUGASSERT(done);
775
776   return CURLE_OK;
777 }
778
779 static ssize_t gtls_send(struct connectdata *conn,
780                          int sockindex,
781                          const void *mem,
782                          size_t len,
783                          CURLcode *curlcode)
784 {
785   ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
786
787   if(rc < 0 ) {
788     *curlcode = (rc == GNUTLS_E_AGAIN)
789       ? CURLE_AGAIN
790       : CURLE_SEND_ERROR;
791
792     rc = -1;
793   }
794
795   return rc;
796 }
797
798 void Curl_gtls_close_all(struct SessionHandle *data)
799 {
800   /* FIX: make the OpenSSL code more generic and use parts of it here */
801   (void)data;
802 }
803
804 static void close_one(struct connectdata *conn,
805                       int idx)
806 {
807   if(conn->ssl[idx].session) {
808     gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
809     gnutls_deinit(conn->ssl[idx].session);
810     conn->ssl[idx].session = NULL;
811   }
812   if(conn->ssl[idx].cred) {
813     gnutls_certificate_free_credentials(conn->ssl[idx].cred);
814     conn->ssl[idx].cred = NULL;
815   }
816 }
817
818 void Curl_gtls_close(struct connectdata *conn, int sockindex)
819 {
820   close_one(conn, sockindex);
821 }
822
823 /*
824  * This function is called to shut down the SSL layer but keep the
825  * socket open (CCC - Clear Command Channel)
826  */
827 int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
828 {
829   ssize_t result;
830   int retval = 0;
831   struct SessionHandle *data = conn->data;
832   int done = 0;
833   char buf[120];
834
835   /* This has only been tested on the proftpd server, and the mod_tls code
836      sends a close notify alert without waiting for a close notify alert in
837      response. Thus we wait for a close notify alert from the server, but
838      we do not send one. Let's hope other servers do the same... */
839
840   if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
841       gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
842
843   if(conn->ssl[sockindex].session) {
844     while(!done) {
845       int what = Curl_socket_ready(conn->sock[sockindex],
846                              CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
847       if(what > 0) {
848         /* Something to read, let's do it and hope that it is the close
849            notify alert from the server */
850         result = gnutls_record_recv(conn->ssl[sockindex].session,
851                                     buf, sizeof(buf));
852         switch(result) {
853         case 0:
854           /* This is the expected response. There was no data but only
855              the close notify alert */
856           done = 1;
857           break;
858         case GNUTLS_E_AGAIN:
859         case GNUTLS_E_INTERRUPTED:
860           infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
861           break;
862         default:
863           retval = -1;
864           done = 1;
865           break;
866         }
867       }
868       else if(0 == what) {
869         /* timeout */
870         failf(data, "SSL shutdown timeout");
871         done = 1;
872         break;
873       }
874       else {
875         /* anything that gets here is fatally bad */
876         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
877         retval = -1;
878         done = 1;
879       }
880     }
881     gnutls_deinit(conn->ssl[sockindex].session);
882   }
883   gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
884
885   conn->ssl[sockindex].cred = NULL;
886   conn->ssl[sockindex].session = NULL;
887
888   return retval;
889 }
890
891 static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
892                          int num,                  /* socketindex */
893                          char *buf,                /* store read data here */
894                          size_t buffersize,        /* max amount to read */
895                          CURLcode *curlcode)
896 {
897   ssize_t ret;
898
899   ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
900   if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
901     *curlcode = CURLE_AGAIN;
902     return -1;
903   }
904
905   if(ret == GNUTLS_E_REHANDSHAKE) {
906     /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
907        proper way" takes a whole lot of work. */
908     CURLcode rc = handshake(conn, num, FALSE, FALSE);
909     if(rc)
910       /* handshake() writes error message on its own */
911       *curlcode = rc;
912     else
913       *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
914     return -1;
915   }
916
917   if(ret < 0) {
918     failf(conn->data, "GnuTLS recv error (%d): %s",
919           (int)ret, gnutls_strerror((int)ret));
920     *curlcode = CURLE_RECV_ERROR;
921     return -1;
922   }
923
924   return ret;
925 }
926
927 void Curl_gtls_session_free(void *ptr)
928 {
929   free(ptr);
930 }
931
932 size_t Curl_gtls_version(char *buffer, size_t size)
933 {
934   return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
935 }
936
937 int Curl_gtls_seed(struct SessionHandle *data)
938 {
939   /* we have the "SSL is seeded" boolean static to prevent multiple
940      time-consuming seedings in vain */
941   static bool ssl_seeded = FALSE;
942
943   /* Quickly add a bit of entropy */
944   gcry_fast_random_poll();
945
946   if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
947      data->set.str[STRING_SSL_EGDSOCKET]) {
948
949     /* TODO: to a good job seeding the RNG
950        This may involve the gcry_control function and these options:
951        GCRYCTL_SET_RANDOM_SEED_FILE
952        GCRYCTL_SET_RNDEGD_SOCKET
953     */
954     ssl_seeded = TRUE;
955   }
956   return 0;
957 }
958
959 #endif /* USE_GNUTLS */