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