1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, 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
75static void tls_log_func(int level, const char *str)
76{
77    fprintf(stderr, "|<%d>| %s", level, str);
78}
79#endif
80static 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
105static 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
119static 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
129static 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 */
146int 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
160int Curl_gtls_cleanup(void)
161{
162  if(gtls_inited) {
163    gnutls_global_deinit();
164    gtls_inited = FALSE;
165  }
166  return 1;
167}
168
169static void showtime(struct SessionHandle *data,
170                     const char *text,
171                     time_t stamp)
172{
173  struct tm buffer;
174  const struct tm *tm = &buffer;
175  CURLcode result = Curl_gmtime(stamp, &buffer);
176  if(result)
177    return;
178
179  snprintf(data->state.buffer,
180           BUFSIZE,
181           "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n",
182           text,
183           Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
184           tm->tm_mday,
185           Curl_month[tm->tm_mon],
186           tm->tm_year + 1900,
187           tm->tm_hour,
188           tm->tm_min,
189           tm->tm_sec);
190  infof(data, "%s", data->state.buffer);
191}
192
193static gnutls_datum load_file (const char *file)
194{
195  FILE *f;
196  gnutls_datum loaded_file = { NULL, 0 };
197  long filelen;
198  void *ptr;
199
200  if(!(f = fopen(file, "r")))
201    return loaded_file;
202  if(fseek(f, 0, SEEK_END) != 0
203     || (filelen = ftell(f)) < 0
204     || fseek(f, 0, SEEK_SET) != 0
205     || !(ptr = malloc((size_t)filelen)))
206    goto out;
207  if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
208    free(ptr);
209    goto out;
210  }
211
212  loaded_file.data = ptr;
213  loaded_file.size = (unsigned int)filelen;
214out:
215  fclose(f);
216  return loaded_file;
217}
218
219static void unload_file(gnutls_datum data) {
220  free(data.data);
221}
222
223
224/* this function does a SSL/TLS (re-)handshake */
225static CURLcode handshake(struct connectdata *conn,
226                          int sockindex,
227                          bool duringconnect,
228                          bool nonblocking)
229{
230  struct SessionHandle *data = conn->data;
231  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
232  gnutls_session session = conn->ssl[sockindex].session;
233  curl_socket_t sockfd = conn->sock[sockindex];
234  long timeout_ms;
235  int rc;
236  int what;
237
238  for(;;) {
239    /* check allowed time left */
240    timeout_ms = Curl_timeleft(data, NULL, duringconnect);
241
242    if(timeout_ms < 0) {
243      /* no need to continue if time already is up */
244      failf(data, "SSL connection timeout");
245      return CURLE_OPERATION_TIMEDOUT;
246    }
247
248    /* if ssl is expecting something, check if it's available. */
249    if(connssl->connecting_state == ssl_connect_2_reading
250       || connssl->connecting_state == ssl_connect_2_writing) {
251
252      curl_socket_t writefd = ssl_connect_2_writing==
253        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
254      curl_socket_t readfd = ssl_connect_2_reading==
255        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
256
257      what = Curl_socket_ready(readfd, writefd,
258                               nonblocking?0:
259                               timeout_ms?timeout_ms:1000);
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
298static 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
309static CURLcode
310gtls_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#ifdef USE_TLS_SRP
350  if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
351    infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username);
352
353    rc = gnutls_srp_allocate_client_credentials(
354           &conn->ssl[sockindex].srp_client_cred);
355    if(rc != GNUTLS_E_SUCCESS) {
356      failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
357            gnutls_strerror(rc));
358      return CURLE_OUT_OF_MEMORY;
359    }
360
361    rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].
362                                           srp_client_cred,
363                                           data->set.ssl.username,
364                                           data->set.ssl.password);
365    if(rc != GNUTLS_E_SUCCESS) {
366      failf(data, "gnutls_srp_set_client_cred() failed: %s",
367            gnutls_strerror(rc));
368      return CURLE_BAD_FUNCTION_ARGUMENT;
369    }
370  }
371#endif
372
373  if(data->set.ssl.CAfile) {
374    /* set the trusted CA cert bundle file */
375    gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
376                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
377
378    rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
379                                                data->set.ssl.CAfile,
380                                                GNUTLS_X509_FMT_PEM);
381    if(rc < 0) {
382      infof(data, "error reading ca cert file %s (%s)\n",
383            data->set.ssl.CAfile, gnutls_strerror(rc));
384      if(data->set.ssl.verifypeer)
385        return CURLE_SSL_CACERT_BADFILE;
386    }
387    else
388      infof(data, "found %d certificates in %s\n",
389            rc, data->set.ssl.CAfile);
390  }
391
392  if(data->set.ssl.CRLfile) {
393    /* set the CRL list file */
394    rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
395                                              data->set.ssl.CRLfile,
396                                              GNUTLS_X509_FMT_PEM);
397    if(rc < 0) {
398      failf(data, "error reading crl file %s (%s)\n",
399            data->set.ssl.CRLfile, gnutls_strerror(rc));
400      return CURLE_SSL_CRL_BADFILE;
401    }
402    else
403      infof(data, "found %d CRL in %s\n",
404            rc, data->set.ssl.CRLfile);
405  }
406
407  /* Initialize TLS session as a client */
408  rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
409  if(rc != GNUTLS_E_SUCCESS) {
410    failf(data, "gnutls_init() failed: %d", rc);
411    return CURLE_SSL_CONNECT_ERROR;
412  }
413
414  /* convenient assign */
415  session = conn->ssl[sockindex].session;
416
417  if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
418#ifdef ENABLE_IPV6
419     (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
420#endif
421     sni &&
422     (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
423                             strlen(conn->host.name)) < 0))
424    infof(data, "WARNING: failed to configure server name indication (SNI) "
425          "TLS extension\n");
426
427  /* Use default priorities */
428  rc = gnutls_set_default_priority(session);
429  if(rc != GNUTLS_E_SUCCESS)
430    return CURLE_SSL_CONNECT_ERROR;
431
432  if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) {
433    static const int protocol_priority[] = { GNUTLS_SSL3, 0 };
434    gnutls_protocol_set_priority(session, protocol_priority);
435    if(rc != GNUTLS_E_SUCCESS)
436      return CURLE_SSL_CONNECT_ERROR;
437  }
438
439  /* Sets the priority on the certificate types supported by gnutls. Priority
440     is higher for types specified before others. After specifying the types
441     you want, you must append a 0. */
442  rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
443  if(rc != GNUTLS_E_SUCCESS)
444    return CURLE_SSL_CONNECT_ERROR;
445
446  if(data->set.str[STRING_CERT]) {
447    if(gnutls_certificate_set_x509_key_file(
448         conn->ssl[sockindex].cred,
449         data->set.str[STRING_CERT],
450         data->set.str[STRING_KEY] ?
451         data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
452         do_file_type(data->set.str[STRING_CERT_TYPE]) ) !=
453       GNUTLS_E_SUCCESS) {
454      failf(data, "error reading X.509 key or certificate file");
455      return CURLE_SSL_CONNECT_ERROR;
456    }
457  }
458
459#ifdef USE_TLS_SRP
460  /* put the credentials to the current session */
461  if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
462    rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
463                                conn->ssl[sockindex].srp_client_cred);
464    if(rc != GNUTLS_E_SUCCESS)
465      failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
466  }
467  else
468#endif
469    rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
470                                conn->ssl[sockindex].cred);
471
472  /* set the connection handle (file descriptor for the socket) */
473  gnutls_transport_set_ptr(session,
474                           GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]));
475
476  /* register callback functions to send and receive data. */
477  gnutls_transport_set_push_function(session, Curl_gtls_push);
478  gnutls_transport_set_pull_function(session, Curl_gtls_pull);
479
480  /* lowat must be set to zero when using custom push and pull functions. */
481  gnutls_transport_set_lowat(session, 0);
482
483  /* This might be a reconnect, so we check for a session ID in the cache
484     to speed up things */
485
486  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
487    /* we got a session id, use it! */
488    gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
489
490    /* Informational message */
491    infof (data, "SSL re-using session ID\n");
492  }
493
494  return CURLE_OK;
495}
496
497static Curl_recv gtls_recv;
498static Curl_send gtls_send;
499
500static CURLcode
501gtls_connect_step3(struct connectdata *conn,
502                   int sockindex)
503{
504  unsigned int cert_list_size;
505  const gnutls_datum *chainp;
506  unsigned int verify_status;
507  gnutls_x509_crt x509_cert,x509_issuer;
508  gnutls_datum issuerp;
509  char certbuf[256]; /* big enough? */
510  size_t size;
511  unsigned int algo;
512  unsigned int bits;
513  time_t certclock;
514  const char *ptr;
515  struct SessionHandle *data = conn->data;
516  gnutls_session session = conn->ssl[sockindex].session;
517  int rc;
518  int incache;
519  void *ssl_sessionid;
520  CURLcode result = CURLE_OK;
521
522  /* This function will return the peer's raw certificate (chain) as sent by
523     the peer. These certificates are in raw format (DER encoded for
524     X.509). In case of a X.509 then a certificate list may be present. The
525     first certificate in the list is the peer's certificate, following the
526     issuer's certificate, then the issuer's issuer etc. */
527
528  chainp = gnutls_certificate_get_peers(session, &cert_list_size);
529  if(!chainp) {
530    if(data->set.ssl.verifypeer ||
531       data->set.ssl.verifyhost ||
532       data->set.ssl.issuercert) {
533#ifdef USE_TLS_SRP
534      if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
535         && data->set.ssl.username != NULL
536         && !data->set.ssl.verifypeer
537         && gnutls_cipher_get(session)) {
538        /* no peer cert, but auth is ok if we have SRP user and cipher and no
539           peer verify */
540      }
541      else {
542#endif
543        failf(data, "failed to get server cert");
544        return CURLE_PEER_FAILED_VERIFICATION;
545#ifdef USE_TLS_SRP
546      }
547#endif
548    }
549    infof(data, "\t common name: WARNING couldn't obtain\n");
550  }
551
552  if(data->set.ssl.verifypeer) {
553    /* This function will try to verify the peer's certificate and return its
554       status (trusted, invalid etc.). The value of status should be one or
555       more of the gnutls_certificate_status_t enumerated elements bitwise
556       or'd. To avoid denial of service attacks some default upper limits
557       regarding the certificate key size and chain size are set. To override
558       them use gnutls_certificate_set_verify_limits(). */
559
560    rc = gnutls_certificate_verify_peers2(session, &verify_status);
561    if(rc < 0) {
562      failf(data, "server cert verify failed: %d", rc);
563      return CURLE_SSL_CONNECT_ERROR;
564    }
565
566    /* verify_status is a bitmask of gnutls_certificate_status bits */
567    if(verify_status & GNUTLS_CERT_INVALID) {
568      if(data->set.ssl.verifypeer) {
569        failf(data, "server certificate verification failed. CAfile: %s "
570              "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
571              data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
572        return CURLE_SSL_CACERT;
573      }
574      else
575        infof(data, "\t server certificate verification FAILED\n");
576    }
577    else
578      infof(data, "\t server certificate verification OK\n");
579  }
580  else {
581    infof(data, "\t server certificate verification SKIPPED\n");
582    goto after_server_cert_verification;
583  }
584
585  /* initialize an X.509 certificate structure. */
586  gnutls_x509_crt_init(&x509_cert);
587
588  /* convert the given DER or PEM encoded Certificate to the native
589     gnutls_x509_crt_t format */
590  gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
591
592  if(data->set.ssl.issuercert) {
593    gnutls_x509_crt_init(&x509_issuer);
594    issuerp = load_file(data->set.ssl.issuercert);
595    gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
596    rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer);
597    unload_file(issuerp);
598    if(rc <= 0) {
599      failf(data, "server certificate issuer check failed (IssuerCert: %s)",
600            data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
601      return CURLE_SSL_ISSUER_ERROR;
602    }
603    infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n",
604          data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
605  }
606
607  size=sizeof(certbuf);
608  rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
609                                     0, /* the first and only one */
610                                     FALSE,
611                                     certbuf,
612                                     &size);
613  if(rc) {
614    infof(data, "error fetching CN from cert:%s\n",
615          gnutls_strerror(rc));
616  }
617
618  /* This function will check if the given certificate's subject matches the
619     given hostname. This is a basic implementation of the matching described
620     in RFC2818 (HTTPS), which takes into account wildcards, and the subject
621     alternative name PKIX extension. Returns non zero on success, and zero on
622     failure. */
623  rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
624
625  if(!rc) {
626    if(data->set.ssl.verifyhost > 1) {
627      failf(data, "SSL: certificate subject name (%s) does not match "
628            "target host name '%s'", certbuf, conn->host.dispname);
629      gnutls_x509_crt_deinit(x509_cert);
630      return CURLE_PEER_FAILED_VERIFICATION;
631    }
632    else
633      infof(data, "\t common name: %s (does not match '%s')\n",
634            certbuf, conn->host.dispname);
635  }
636  else
637    infof(data, "\t common name: %s (matched)\n", certbuf);
638
639  /* Check for time-based validity */
640  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
641
642  if(certclock == (time_t)-1) {
643    failf(data, "server cert expiration date verify failed");
644    return CURLE_SSL_CONNECT_ERROR;
645  }
646
647  if(certclock < time(NULL)) {
648    if(data->set.ssl.verifypeer) {
649      failf(data, "server certificate expiration date has passed.");
650      return CURLE_PEER_FAILED_VERIFICATION;
651    }
652    else
653      infof(data, "\t server certificate expiration date FAILED\n");
654  }
655  else
656    infof(data, "\t server certificate expiration date OK\n");
657
658  certclock = gnutls_x509_crt_get_activation_time(x509_cert);
659
660  if(certclock == (time_t)-1) {
661    failf(data, "server cert activation date verify failed");
662    return CURLE_SSL_CONNECT_ERROR;
663  }
664
665  if(certclock > time(NULL)) {
666    if(data->set.ssl.verifypeer) {
667      failf(data, "server certificate not activated yet.");
668      return CURLE_PEER_FAILED_VERIFICATION;
669    }
670    else
671      infof(data, "\t server certificate activation date FAILED\n");
672  }
673  else
674    infof(data, "\t server certificate activation date OK\n");
675
676  /* Show:
677
678  - ciphers used
679  - subject
680  - start date
681  - expire date
682  - common name
683  - issuer
684
685  */
686
687  /* public key algorithm's parameters */
688  algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
689  infof(data, "\t certificate public key: %s\n",
690        gnutls_pk_algorithm_get_name(algo));
691
692  /* version of the X.509 certificate. */
693  infof(data, "\t certificate version: #%d\n",
694        gnutls_x509_crt_get_version(x509_cert));
695
696
697  size = sizeof(certbuf);
698  gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
699  infof(data, "\t subject: %s\n", certbuf);
700
701  certclock = gnutls_x509_crt_get_activation_time(x509_cert);
702  showtime(data, "start date", certclock);
703
704  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
705  showtime(data, "expire date", certclock);
706
707  size = sizeof(certbuf);
708  gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
709  infof(data, "\t issuer: %s\n", certbuf);
710
711  gnutls_x509_crt_deinit(x509_cert);
712
713after_server_cert_verification:
714
715  /* compression algorithm (if any) */
716  ptr = gnutls_compression_get_name(gnutls_compression_get(session));
717  /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
718  infof(data, "\t compression: %s\n", ptr);
719
720  /* the name of the cipher used. ie 3DES. */
721  ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
722  infof(data, "\t cipher: %s\n", ptr);
723
724  /* the MAC algorithms name. ie SHA1 */
725  ptr = gnutls_mac_get_name(gnutls_mac_get(session));
726  infof(data, "\t MAC: %s\n", ptr);
727
728  conn->ssl[sockindex].state = ssl_connection_complete;
729  conn->recv[sockindex] = gtls_recv;
730  conn->send[sockindex] = gtls_send;
731
732  {
733    /* we always unconditionally get the session id here, as even if we
734       already got it from the cache and asked to use it in the connection, it
735       might've been rejected and then a new one is in use now and we need to
736       detect that. */
737    void *connect_sessionid;
738    size_t connect_idsize;
739
740    /* get the session ID data size */
741    gnutls_session_get_data(session, NULL, &connect_idsize);
742    connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
743
744    if(connect_sessionid) {
745      /* extract session ID to the allocated buffer */
746      gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
747
748      incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
749      if(incache) {
750        /* there was one before in the cache, so instead of risking that the
751           previous one was rejected, we just kill that and store the new */
752        Curl_ssl_delsessionid(conn, ssl_sessionid);
753      }
754
755      /* store this session id */
756      result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
757      if(result) {
758        free(connect_sessionid);
759        result = CURLE_OUT_OF_MEMORY;
760      }
761    }
762    else
763      result = CURLE_OUT_OF_MEMORY;
764  }
765
766  return result;
767}
768
769
770/*
771 * This function is called after the TCP connect has completed. Setup the TLS
772 * layer and do all necessary magic.
773 */
774/* We use connssl->connecting_state to keep track of the connection status;
775   there are three states: 'ssl_connect_1' (not started yet or complete),
776   'ssl_connect_2_reading' (waiting for data from server), and
777   'ssl_connect_2_writing' (waiting to be able to write).
778 */
779static CURLcode
780gtls_connect_common(struct connectdata *conn,
781                    int sockindex,
782                    bool nonblocking,
783                    bool *done)
784{
785  int rc;
786  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
787
788  /* Initiate the connection, if not already done */
789  if(ssl_connect_1==connssl->connecting_state) {
790    rc = gtls_connect_step1 (conn, sockindex);
791    if(rc)
792      return rc;
793  }
794
795  rc = handshake(conn, sockindex, TRUE, nonblocking);
796  if(rc)
797    /* handshake() sets its own error message with failf() */
798    return rc;
799
800  /* Finish connecting once the handshake is done */
801  if(ssl_connect_1==connssl->connecting_state) {
802    rc = gtls_connect_step3(conn, sockindex);
803    if(rc)
804      return rc;
805  }
806
807  *done = ssl_connect_1==connssl->connecting_state;
808
809  return CURLE_OK;
810}
811
812CURLcode
813Curl_gtls_connect_nonblocking(struct connectdata *conn,
814                              int sockindex,
815                              bool *done)
816{
817  return gtls_connect_common(conn, sockindex, TRUE, done);
818}
819
820CURLcode
821Curl_gtls_connect(struct connectdata *conn,
822                  int sockindex)
823
824{
825  CURLcode retcode;
826  bool done = FALSE;
827
828  retcode = gtls_connect_common(conn, sockindex, FALSE, &done);
829  if(retcode)
830    return retcode;
831
832  DEBUGASSERT(done);
833
834  return CURLE_OK;
835}
836
837static ssize_t gtls_send(struct connectdata *conn,
838                         int sockindex,
839                         const void *mem,
840                         size_t len,
841                         CURLcode *curlcode)
842{
843  ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
844
845  if(rc < 0 ) {
846    *curlcode = (rc == GNUTLS_E_AGAIN)
847      ? CURLE_AGAIN
848      : CURLE_SEND_ERROR;
849
850    rc = -1;
851  }
852
853  return rc;
854}
855
856void Curl_gtls_close_all(struct SessionHandle *data)
857{
858  /* FIX: make the OpenSSL code more generic and use parts of it here */
859  (void)data;
860}
861
862static void close_one(struct connectdata *conn,
863                      int idx)
864{
865  if(conn->ssl[idx].session) {
866    gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
867    gnutls_deinit(conn->ssl[idx].session);
868    conn->ssl[idx].session = NULL;
869  }
870  if(conn->ssl[idx].cred) {
871    gnutls_certificate_free_credentials(conn->ssl[idx].cred);
872    conn->ssl[idx].cred = NULL;
873  }
874#ifdef USE_TLS_SRP
875  if(conn->ssl[idx].srp_client_cred) {
876    gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred);
877    conn->ssl[idx].srp_client_cred = NULL;
878  }
879#endif
880}
881
882void Curl_gtls_close(struct connectdata *conn, int sockindex)
883{
884  close_one(conn, sockindex);
885}
886
887/*
888 * This function is called to shut down the SSL layer but keep the
889 * socket open (CCC - Clear Command Channel)
890 */
891int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
892{
893  ssize_t result;
894  int retval = 0;
895  struct SessionHandle *data = conn->data;
896  int done = 0;
897  char buf[120];
898
899  /* This has only been tested on the proftpd server, and the mod_tls code
900     sends a close notify alert without waiting for a close notify alert in
901     response. Thus we wait for a close notify alert from the server, but
902     we do not send one. Let's hope other servers do the same... */
903
904  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
905      gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
906
907  if(conn->ssl[sockindex].session) {
908    while(!done) {
909      int what = Curl_socket_ready(conn->sock[sockindex],
910                                   CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
911      if(what > 0) {
912        /* Something to read, let's do it and hope that it is the close
913           notify alert from the server */
914        result = gnutls_record_recv(conn->ssl[sockindex].session,
915                                    buf, sizeof(buf));
916        switch(result) {
917        case 0:
918          /* This is the expected response. There was no data but only
919             the close notify alert */
920          done = 1;
921          break;
922        case GNUTLS_E_AGAIN:
923        case GNUTLS_E_INTERRUPTED:
924          infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
925          break;
926        default:
927          retval = -1;
928          done = 1;
929          break;
930        }
931      }
932      else if(0 == what) {
933        /* timeout */
934        failf(data, "SSL shutdown timeout");
935        done = 1;
936        break;
937      }
938      else {
939        /* anything that gets here is fatally bad */
940        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
941        retval = -1;
942        done = 1;
943      }
944    }
945    gnutls_deinit(conn->ssl[sockindex].session);
946  }
947  gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
948
949#ifdef USE_TLS_SRP
950  if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
951     && data->set.ssl.username != NULL)
952    gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
953#endif
954
955  conn->ssl[sockindex].cred = NULL;
956  conn->ssl[sockindex].session = NULL;
957
958  return retval;
959}
960
961static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
962                         int num,                  /* socketindex */
963                         char *buf,                /* store read data here */
964                         size_t buffersize,        /* max amount to read */
965                         CURLcode *curlcode)
966{
967  ssize_t ret;
968
969  ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
970  if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
971    *curlcode = CURLE_AGAIN;
972    return -1;
973  }
974
975  if(ret == GNUTLS_E_REHANDSHAKE) {
976    /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
977       proper way" takes a whole lot of work. */
978    CURLcode rc = handshake(conn, num, FALSE, FALSE);
979    if(rc)
980      /* handshake() writes error message on its own */
981      *curlcode = rc;
982    else
983      *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
984    return -1;
985  }
986
987  if(ret < 0) {
988    failf(conn->data, "GnuTLS recv error (%d): %s",
989          (int)ret, gnutls_strerror((int)ret));
990    *curlcode = CURLE_RECV_ERROR;
991    return -1;
992  }
993
994  return ret;
995}
996
997void Curl_gtls_session_free(void *ptr)
998{
999  free(ptr);
1000}
1001
1002size_t Curl_gtls_version(char *buffer, size_t size)
1003{
1004  return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
1005}
1006
1007int Curl_gtls_seed(struct SessionHandle *data)
1008{
1009  /* we have the "SSL is seeded" boolean static to prevent multiple
1010     time-consuming seedings in vain */
1011  static bool ssl_seeded = FALSE;
1012
1013  /* Quickly add a bit of entropy */
1014  gcry_fast_random_poll();
1015
1016  if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
1017     data->set.str[STRING_SSL_EGDSOCKET]) {
1018
1019    /* TODO: to a good job seeding the RNG
1020       This may involve the gcry_control function and these options:
1021       GCRYCTL_SET_RANDOM_SEED_FILE
1022       GCRYCTL_SET_RNDEGD_SOCKET
1023    */
1024    ssl_seeded = TRUE;
1025  }
1026  return 0;
1027}
1028
1029#endif /* USE_GNUTLS */
1030