• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2019, 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 https://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 vtls.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 "curl_setup.h"
32 
33 #ifdef USE_GNUTLS
34 
35 #include <gnutls/abstract.h>
36 #include <gnutls/gnutls.h>
37 #include <gnutls/x509.h>
38 
39 #ifdef USE_GNUTLS_NETTLE
40 #include <gnutls/crypto.h>
41 #include <nettle/md5.h>
42 #include <nettle/sha2.h>
43 #else
44 #include <gcrypt.h>
45 #endif
46 
47 #include "urldata.h"
48 #include "sendf.h"
49 #include "inet_pton.h"
50 #include "gtls.h"
51 #include "vtls.h"
52 #include "parsedate.h"
53 #include "connect.h" /* for the connect timeout */
54 #include "select.h"
55 #include "strcase.h"
56 #include "warnless.h"
57 #include "x509asn1.h"
58 #include "curl_printf.h"
59 #include "curl_memory.h"
60 /* The last #include file should be: */
61 #include "memdebug.h"
62 
63 /* Enable GnuTLS debugging by defining GTLSDEBUG */
64 /*#define GTLSDEBUG */
65 
66 #ifdef GTLSDEBUG
tls_log_func(int level,const char * str)67 static void tls_log_func(int level, const char *str)
68 {
69     fprintf(stderr, "|<%d>| %s", level, str);
70 }
71 #endif
72 static bool gtls_inited = FALSE;
73 
74 #if defined(GNUTLS_VERSION_NUMBER)
75 #  if (GNUTLS_VERSION_NUMBER >= 0x020c00)
76 #    undef gnutls_transport_set_lowat
77 #    define gnutls_transport_set_lowat(A,B) Curl_nop_stmt
78 #    define USE_GNUTLS_PRIORITY_SET_DIRECT 1
79 #  endif
80 #  if (GNUTLS_VERSION_NUMBER >= 0x020c03)
81 #    define GNUTLS_MAPS_WINSOCK_ERRORS 1
82 #  endif
83 
84 #  if HAVE_GNUTLS_ALPN_SET_PROTOCOLS
85 #    define HAS_ALPN
86 #  endif
87 
88 #  if HAVE_GNUTLS_OCSP_REQ_INIT
89 #    define HAS_OCSP
90 #  endif
91 
92 #  if (GNUTLS_VERSION_NUMBER >= 0x030306)
93 #    define HAS_CAPATH
94 #  endif
95 #endif
96 
97 #if (GNUTLS_VERSION_NUMBER >= 0x030603)
98 #define HAS_TLS13
99 #endif
100 
101 #ifdef HAS_OCSP
102 # include <gnutls/ocsp.h>
103 #endif
104 
105 struct ssl_backend_data {
106   gnutls_session_t session;
107   gnutls_certificate_credentials_t cred;
108 #ifdef USE_TLS_SRP
109   gnutls_srp_client_credentials_t srp_client_cred;
110 #endif
111 };
112 
113 #define BACKEND connssl->backend
114 
115 /*
116  * Custom push and pull callback functions used by GNU TLS to read and write
117  * to the socket.  These functions are simple wrappers to send() and recv()
118  * (although here using the sread/swrite macros as defined by
119  * curl_setup_once.h).
120  * We use custom functions rather than the GNU TLS defaults because it allows
121  * us to get specific about the fourth "flags" argument, and to use arbitrary
122  * private data with gnutls_transport_set_ptr if we wish.
123  *
124  * When these custom push and pull callbacks fail, GNU TLS checks its own
125  * session-specific error variable, and when not set also its own global
126  * errno variable, in order to take appropriate action. GNU TLS does not
127  * require that the transport is actually a socket. This implies that for
128  * Windows builds these callbacks should ideally set the session-specific
129  * error variable using function gnutls_transport_set_errno or as a last
130  * resort global errno variable using gnutls_transport_set_global_errno,
131  * with a transport agnostic error value. This implies that some winsock
132  * error translation must take place in these callbacks.
133  *
134  * Paragraph above applies to GNU TLS versions older than 2.12.3, since
135  * this version GNU TLS does its own internal winsock error translation
136  * using system_errno() function.
137  */
138 
139 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
140 #  define gtls_EINTR  4
141 #  define gtls_EIO    5
142 #  define gtls_EAGAIN 11
gtls_mapped_sockerrno(void)143 static int gtls_mapped_sockerrno(void)
144 {
145   switch(SOCKERRNO) {
146   case WSAEWOULDBLOCK:
147     return gtls_EAGAIN;
148   case WSAEINTR:
149     return gtls_EINTR;
150   default:
151     break;
152   }
153   return gtls_EIO;
154 }
155 #endif
156 
Curl_gtls_push(void * s,const void * buf,size_t len)157 static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
158 {
159   curl_socket_t sock = *(curl_socket_t *)s;
160   ssize_t ret = swrite(sock, buf, len);
161 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
162   if(ret < 0)
163     gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
164 #endif
165   return ret;
166 }
167 
Curl_gtls_pull(void * s,void * buf,size_t len)168 static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
169 {
170   curl_socket_t sock = *(curl_socket_t *)s;
171   ssize_t ret = sread(sock, buf, len);
172 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
173   if(ret < 0)
174     gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
175 #endif
176   return ret;
177 }
178 
Curl_gtls_push_ssl(void * s,const void * buf,size_t len)179 static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len)
180 {
181   return gnutls_record_send((gnutls_session_t) s, buf, len);
182 }
183 
Curl_gtls_pull_ssl(void * s,void * buf,size_t len)184 static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len)
185 {
186   return gnutls_record_recv((gnutls_session_t) s, buf, len);
187 }
188 
189 /* Curl_gtls_init()
190  *
191  * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
192  * are not thread-safe and thus this function itself is not thread-safe and
193  * must only be called from within curl_global_init() to keep the thread
194  * situation under control!
195  */
Curl_gtls_init(void)196 static int Curl_gtls_init(void)
197 {
198   int ret = 1;
199   if(!gtls_inited) {
200     ret = gnutls_global_init()?0:1;
201 #ifdef GTLSDEBUG
202     gnutls_global_set_log_function(tls_log_func);
203     gnutls_global_set_log_level(2);
204 #endif
205     gtls_inited = TRUE;
206   }
207   return ret;
208 }
209 
Curl_gtls_cleanup(void)210 static void Curl_gtls_cleanup(void)
211 {
212   if(gtls_inited) {
213     gnutls_global_deinit();
214     gtls_inited = FALSE;
215   }
216 }
217 
218 #ifndef CURL_DISABLE_VERBOSE_STRINGS
showtime(struct Curl_easy * data,const char * text,time_t stamp)219 static void showtime(struct Curl_easy *data,
220                      const char *text,
221                      time_t stamp)
222 {
223   struct tm buffer;
224   const struct tm *tm = &buffer;
225   char str[96];
226   CURLcode result = Curl_gmtime(stamp, &buffer);
227   if(result)
228     return;
229 
230   msnprintf(str,
231             sizeof(str),
232             "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
233             text,
234             Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
235             tm->tm_mday,
236             Curl_month[tm->tm_mon],
237             tm->tm_year + 1900,
238             tm->tm_hour,
239             tm->tm_min,
240             tm->tm_sec);
241   infof(data, "%s\n", str);
242 }
243 #endif
244 
load_file(const char * file)245 static gnutls_datum_t load_file(const char *file)
246 {
247   FILE *f;
248   gnutls_datum_t loaded_file = { NULL, 0 };
249   long filelen;
250   void *ptr;
251 
252   f = fopen(file, "rb");
253   if(!f)
254     return loaded_file;
255   if(fseek(f, 0, SEEK_END) != 0
256      || (filelen = ftell(f)) < 0
257      || fseek(f, 0, SEEK_SET) != 0
258      || !(ptr = malloc((size_t)filelen)))
259     goto out;
260   if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
261     free(ptr);
262     goto out;
263   }
264 
265   loaded_file.data = ptr;
266   loaded_file.size = (unsigned int)filelen;
267 out:
268   fclose(f);
269   return loaded_file;
270 }
271 
unload_file(gnutls_datum_t data)272 static void unload_file(gnutls_datum_t data)
273 {
274   free(data.data);
275 }
276 
277 
278 /* this function does a SSL/TLS (re-)handshake */
handshake(struct connectdata * conn,int sockindex,bool duringconnect,bool nonblocking)279 static CURLcode handshake(struct connectdata *conn,
280                           int sockindex,
281                           bool duringconnect,
282                           bool nonblocking)
283 {
284   struct Curl_easy *data = conn->data;
285   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
286   gnutls_session_t session = BACKEND->session;
287   curl_socket_t sockfd = conn->sock[sockindex];
288   time_t timeout_ms;
289   int rc;
290   int what;
291 
292   for(;;) {
293     /* check allowed time left */
294     timeout_ms = Curl_timeleft(data, NULL, duringconnect);
295 
296     if(timeout_ms < 0) {
297       /* no need to continue if time already is up */
298       failf(data, "SSL connection timeout");
299       return CURLE_OPERATION_TIMEDOUT;
300     }
301 
302     /* if ssl is expecting something, check if it's available. */
303     if(connssl->connecting_state == ssl_connect_2_reading
304        || connssl->connecting_state == ssl_connect_2_writing) {
305 
306       curl_socket_t writefd = ssl_connect_2_writing ==
307         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
308       curl_socket_t readfd = ssl_connect_2_reading ==
309         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
310 
311       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
312                                nonblocking?0:
313                                timeout_ms?timeout_ms:1000);
314       if(what < 0) {
315         /* fatal error */
316         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
317         return CURLE_SSL_CONNECT_ERROR;
318       }
319       else if(0 == what) {
320         if(nonblocking)
321           return CURLE_OK;
322         else if(timeout_ms) {
323           /* timeout */
324           failf(data, "SSL connection timeout at %ld", (long)timeout_ms);
325           return CURLE_OPERATION_TIMEDOUT;
326         }
327       }
328       /* socket is readable or writable */
329     }
330 
331     rc = gnutls_handshake(session);
332 
333     if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
334       connssl->connecting_state =
335         gnutls_record_get_direction(session)?
336         ssl_connect_2_writing:ssl_connect_2_reading;
337       continue;
338     }
339     else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
340       const char *strerr = NULL;
341 
342       if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
343         int alert = gnutls_alert_get(session);
344         strerr = gnutls_alert_get_name(alert);
345       }
346 
347       if(strerr == NULL)
348         strerr = gnutls_strerror(rc);
349 
350       infof(data, "gnutls_handshake() warning: %s\n", strerr);
351       continue;
352     }
353     else if(rc < 0) {
354       const char *strerr = NULL;
355 
356       if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
357         int alert = gnutls_alert_get(session);
358         strerr = gnutls_alert_get_name(alert);
359       }
360 
361       if(strerr == NULL)
362         strerr = gnutls_strerror(rc);
363 
364       failf(data, "gnutls_handshake() failed: %s", strerr);
365       return CURLE_SSL_CONNECT_ERROR;
366     }
367 
368     /* Reset our connect state machine */
369     connssl->connecting_state = ssl_connect_1;
370     return CURLE_OK;
371   }
372 }
373 
do_file_type(const char * type)374 static gnutls_x509_crt_fmt_t do_file_type(const char *type)
375 {
376   if(!type || !type[0])
377     return GNUTLS_X509_FMT_PEM;
378   if(strcasecompare(type, "PEM"))
379     return GNUTLS_X509_FMT_PEM;
380   if(strcasecompare(type, "DER"))
381     return GNUTLS_X509_FMT_DER;
382   return -1;
383 }
384 
385 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
386 static CURLcode
set_ssl_version_min_max(int * list,size_t list_size,struct connectdata * conn)387 set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn)
388 {
389   struct Curl_easy *data = conn->data;
390   long ssl_version = SSL_CONN_CONFIG(version);
391   long ssl_version_max = SSL_CONN_CONFIG(version_max);
392   long i = ssl_version;
393   long protocol_priority_idx = 0;
394 
395   switch(ssl_version_max) {
396     case CURL_SSLVERSION_MAX_NONE:
397     case CURL_SSLVERSION_MAX_DEFAULT:
398 #ifdef HAS_TLS13
399       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
400 #endif
401       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
402       break;
403   }
404 
405   for(; i <= (ssl_version_max >> 16) &&
406         protocol_priority_idx < list_size; ++i) {
407     switch(i) {
408       case CURL_SSLVERSION_TLSv1_0:
409         protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0;
410         break;
411       case CURL_SSLVERSION_TLSv1_1:
412         protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1;
413         break;
414       case CURL_SSLVERSION_TLSv1_2:
415         protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2;
416         break;
417       case CURL_SSLVERSION_TLSv1_3:
418 #ifdef HAS_TLS13
419         protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_3;
420         break;
421 #else
422         failf(data, "GnuTLS: TLS 1.3 is not yet supported");
423         return CURLE_SSL_CONNECT_ERROR;
424 #endif
425     }
426   }
427   return CURLE_OK;
428 }
429 #else
430 #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
431 /* If GnuTLS was compiled without support for SRP it will error out if SRP is
432    requested in the priority string, so treat it specially
433  */
434 #define GNUTLS_SRP "+SRP"
435 
436 static CURLcode
set_ssl_version_min_max(const char ** prioritylist,struct connectdata * conn)437 set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn)
438 {
439   struct Curl_easy *data = conn->data;
440   long ssl_version = SSL_CONN_CONFIG(version);
441   long ssl_version_max = SSL_CONN_CONFIG(version_max);
442 
443   if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) {
444     ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;
445   }
446   switch(ssl_version | ssl_version_max) {
447     case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0:
448       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
449                       "+VERS-TLS1.0:" GNUTLS_SRP;
450       return CURLE_OK;
451     case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1:
452       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
453                       "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP;
454       return CURLE_OK;
455     case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2:
456       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
457                       "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
458       return CURLE_OK;
459     case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1:
460       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
461                       "+VERS-TLS1.1:" GNUTLS_SRP;
462       return CURLE_OK;
463     case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2:
464       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
465                       "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
466       return CURLE_OK;
467     case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2:
468       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
469                       "+VERS-TLS1.2:" GNUTLS_SRP;
470       return CURLE_OK;
471     case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3:
472 #ifdef HAS_TLS13
473        *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
474                        "+VERS-TLS1.3:" GNUTLS_SRP;
475       return CURLE_OK;
476 #else
477        failf(data, "GnuTLS: TLS 1.3 is not yet supported");
478       return CURLE_SSL_CONNECT_ERROR;
479 #endif
480     case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT:
481       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
482                       "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:"
483 #ifdef HAS_TLS13
484                       "+VERS-TLS1.3:"
485 #endif
486                       GNUTLS_SRP;
487       return CURLE_OK;
488     case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT:
489       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
490                       "+VERS-TLS1.1:+VERS-TLS1.2:"
491 #ifdef HAS_TLS13
492                       "+VERS-TLS1.3:"
493 #endif
494                       GNUTLS_SRP;
495       return CURLE_OK;
496     case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT:
497       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
498                       "+VERS-TLS1.2:"
499 #ifdef HAS_TLS13
500                       "+VERS-TLS1.3:"
501 #endif
502                       GNUTLS_SRP;
503       return CURLE_OK;
504     case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT:
505       *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
506                       "+VERS-TLS1.2:"
507 #ifdef HAS_TLS13
508                       "+VERS-TLS1.3:"
509 #endif
510                       GNUTLS_SRP;
511       return CURLE_OK;
512   }
513 
514   failf(data, "GnuTLS: cannot set ssl protocol");
515   return CURLE_SSL_CONNECT_ERROR;
516 }
517 #endif
518 
519 static CURLcode
gtls_connect_step1(struct connectdata * conn,int sockindex)520 gtls_connect_step1(struct connectdata *conn,
521                    int sockindex)
522 {
523   struct Curl_easy *data = conn->data;
524   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
525   unsigned int init_flags;
526   gnutls_session_t session;
527   int rc;
528   bool sni = TRUE; /* default is SNI enabled */
529   void *transport_ptr = NULL;
530   gnutls_push_func gnutls_transport_push = NULL;
531   gnutls_pull_func gnutls_transport_pull = NULL;
532 #ifdef ENABLE_IPV6
533   struct in6_addr addr;
534 #else
535   struct in_addr addr;
536 #endif
537 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
538   static const int cipher_priority[] = {
539   /* These two ciphers were added to GnuTLS as late as ver. 3.0.1,
540      but this code path is only ever used for ver. < 2.12.0.
541      GNUTLS_CIPHER_AES_128_GCM,
542      GNUTLS_CIPHER_AES_256_GCM,
543   */
544     GNUTLS_CIPHER_AES_128_CBC,
545     GNUTLS_CIPHER_AES_256_CBC,
546     GNUTLS_CIPHER_CAMELLIA_128_CBC,
547     GNUTLS_CIPHER_CAMELLIA_256_CBC,
548     GNUTLS_CIPHER_3DES_CBC,
549   };
550   static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
551   int protocol_priority[] = { 0, 0, 0, 0 };
552 #else
553   const char *prioritylist;
554   const char *err = NULL;
555 #endif
556 
557   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
558     conn->host.name;
559 
560   if(connssl->state == ssl_connection_complete)
561     /* to make us tolerant against being called more than once for the
562        same connection */
563     return CURLE_OK;
564 
565   if(!gtls_inited)
566     Curl_gtls_init();
567 
568   if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
569     failf(data, "GnuTLS does not support SSLv2");
570     return CURLE_SSL_CONNECT_ERROR;
571   }
572   else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)
573     sni = FALSE; /* SSLv3 has no SNI */
574 
575   /* allocate a cred struct */
576   rc = gnutls_certificate_allocate_credentials(&BACKEND->cred);
577   if(rc != GNUTLS_E_SUCCESS) {
578     failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
579     return CURLE_SSL_CONNECT_ERROR;
580   }
581 
582 #ifdef USE_TLS_SRP
583   if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
584     infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
585 
586     rc = gnutls_srp_allocate_client_credentials(
587            &BACKEND->srp_client_cred);
588     if(rc != GNUTLS_E_SUCCESS) {
589       failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
590             gnutls_strerror(rc));
591       return CURLE_OUT_OF_MEMORY;
592     }
593 
594     rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred,
595                                            SSL_SET_OPTION(username),
596                                            SSL_SET_OPTION(password));
597     if(rc != GNUTLS_E_SUCCESS) {
598       failf(data, "gnutls_srp_set_client_cred() failed: %s",
599             gnutls_strerror(rc));
600       return CURLE_BAD_FUNCTION_ARGUMENT;
601     }
602   }
603 #endif
604 
605   if(SSL_CONN_CONFIG(CAfile)) {
606     /* set the trusted CA cert bundle file */
607     gnutls_certificate_set_verify_flags(BACKEND->cred,
608                                         GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
609 
610     rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred,
611                                                 SSL_CONN_CONFIG(CAfile),
612                                                 GNUTLS_X509_FMT_PEM);
613     if(rc < 0) {
614       infof(data, "error reading ca cert file %s (%s)\n",
615             SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
616       if(SSL_CONN_CONFIG(verifypeer))
617         return CURLE_SSL_CACERT_BADFILE;
618     }
619     else
620       infof(data, "found %d certificates in %s\n", rc,
621             SSL_CONN_CONFIG(CAfile));
622   }
623 
624 #ifdef HAS_CAPATH
625   if(SSL_CONN_CONFIG(CApath)) {
626     /* set the trusted CA cert directory */
627     rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred,
628                                                SSL_CONN_CONFIG(CApath),
629                                                GNUTLS_X509_FMT_PEM);
630     if(rc < 0) {
631       infof(data, "error reading ca cert file %s (%s)\n",
632             SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
633       if(SSL_CONN_CONFIG(verifypeer))
634         return CURLE_SSL_CACERT_BADFILE;
635     }
636     else
637       infof(data, "found %d certificates in %s\n",
638             rc, SSL_CONN_CONFIG(CApath));
639   }
640 #endif
641 
642 #ifdef CURL_CA_FALLBACK
643   /* use system ca certificate store as fallback */
644   if(SSL_CONN_CONFIG(verifypeer) &&
645      !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
646     gnutls_certificate_set_x509_system_trust(BACKEND->cred);
647   }
648 #endif
649 
650   if(SSL_SET_OPTION(CRLfile)) {
651     /* set the CRL list file */
652     rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred,
653                                               SSL_SET_OPTION(CRLfile),
654                                               GNUTLS_X509_FMT_PEM);
655     if(rc < 0) {
656       failf(data, "error reading crl file %s (%s)",
657             SSL_SET_OPTION(CRLfile), gnutls_strerror(rc));
658       return CURLE_SSL_CRL_BADFILE;
659     }
660     else
661       infof(data, "found %d CRL in %s\n",
662             rc, SSL_SET_OPTION(CRLfile));
663   }
664 
665   /* Initialize TLS session as a client */
666   init_flags = GNUTLS_CLIENT;
667 
668 #if defined(GNUTLS_NO_TICKETS)
669   /* Disable TLS session tickets */
670   init_flags |= GNUTLS_NO_TICKETS;
671 #endif
672 
673   rc = gnutls_init(&BACKEND->session, init_flags);
674   if(rc != GNUTLS_E_SUCCESS) {
675     failf(data, "gnutls_init() failed: %d", rc);
676     return CURLE_SSL_CONNECT_ERROR;
677   }
678 
679   /* convenient assign */
680   session = BACKEND->session;
681 
682   if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
683 #ifdef ENABLE_IPV6
684      (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
685 #endif
686      sni &&
687      (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname,
688                              strlen(hostname)) < 0))
689     infof(data, "WARNING: failed to configure server name indication (SNI) "
690           "TLS extension\n");
691 
692   /* Use default priorities */
693   rc = gnutls_set_default_priority(session);
694   if(rc != GNUTLS_E_SUCCESS)
695     return CURLE_SSL_CONNECT_ERROR;
696 
697 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
698   rc = gnutls_cipher_set_priority(session, cipher_priority);
699   if(rc != GNUTLS_E_SUCCESS)
700     return CURLE_SSL_CONNECT_ERROR;
701 
702   /* Sets the priority on the certificate types supported by gnutls. Priority
703    is higher for types specified before others. After specifying the types
704    you want, you must append a 0. */
705   rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
706   if(rc != GNUTLS_E_SUCCESS)
707     return CURLE_SSL_CONNECT_ERROR;
708 
709   if(SSL_CONN_CONFIG(cipher_list) != NULL) {
710     failf(data, "can't pass a custom cipher list to older GnuTLS"
711           " versions");
712     return CURLE_SSL_CONNECT_ERROR;
713   }
714 
715   switch(SSL_CONN_CONFIG(version)) {
716     case CURL_SSLVERSION_SSLv3:
717       protocol_priority[0] = GNUTLS_SSL3;
718       break;
719     case CURL_SSLVERSION_DEFAULT:
720     case CURL_SSLVERSION_TLSv1:
721       protocol_priority[0] = GNUTLS_TLS1_0;
722       protocol_priority[1] = GNUTLS_TLS1_1;
723       protocol_priority[2] = GNUTLS_TLS1_2;
724 #ifdef HAS_TLS13
725       protocol_priority[3] = GNUTLS_TLS1_3;
726 #endif
727       break;
728     case CURL_SSLVERSION_TLSv1_0:
729     case CURL_SSLVERSION_TLSv1_1:
730     case CURL_SSLVERSION_TLSv1_2:
731     case CURL_SSLVERSION_TLSv1_3:
732       {
733         CURLcode result = set_ssl_version_min_max(protocol_priority,
734                 sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn);
735         if(result != CURLE_OK)
736           return result;
737         break;
738       }
739     case CURL_SSLVERSION_SSLv2:
740       failf(data, "GnuTLS does not support SSLv2");
741       return CURLE_SSL_CONNECT_ERROR;
742     default:
743       failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
744       return CURLE_SSL_CONNECT_ERROR;
745   }
746   rc = gnutls_protocol_set_priority(session, protocol_priority);
747   if(rc != GNUTLS_E_SUCCESS) {
748     failf(data, "Did you pass a valid GnuTLS cipher list?");
749     return CURLE_SSL_CONNECT_ERROR;
750   }
751 
752 #else
753   /* Ensure +SRP comes at the *end* of all relevant strings so that it can be
754    * removed if a run-time error indicates that SRP is not supported by this
755    * GnuTLS version */
756   switch(SSL_CONN_CONFIG(version)) {
757     case CURL_SSLVERSION_SSLv3:
758       prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
759       break;
760     case CURL_SSLVERSION_DEFAULT:
761     case CURL_SSLVERSION_TLSv1:
762       prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:"
763 #ifdef HAS_TLS13
764                      "+VERS-TLS1.3:"
765 #endif
766                      GNUTLS_SRP;
767       break;
768     case CURL_SSLVERSION_TLSv1_0:
769     case CURL_SSLVERSION_TLSv1_1:
770     case CURL_SSLVERSION_TLSv1_2:
771     case CURL_SSLVERSION_TLSv1_3:
772       {
773         CURLcode result = set_ssl_version_min_max(&prioritylist, conn);
774         if(result != CURLE_OK)
775           return result;
776         break;
777       }
778     case CURL_SSLVERSION_SSLv2:
779       failf(data, "GnuTLS does not support SSLv2");
780       return CURLE_SSL_CONNECT_ERROR;
781     default:
782       failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
783       return CURLE_SSL_CONNECT_ERROR;
784   }
785   rc = gnutls_priority_set_direct(session, prioritylist, &err);
786   if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
787     if(!strcmp(err, GNUTLS_SRP)) {
788       /* This GnuTLS was probably compiled without support for SRP.
789        * Note that fact and try again without it. */
790       int validprioritylen = curlx_uztosi(err - prioritylist);
791       char *prioritycopy = strdup(prioritylist);
792       if(!prioritycopy)
793         return CURLE_OUT_OF_MEMORY;
794 
795       infof(data, "This GnuTLS does not support SRP\n");
796       if(validprioritylen)
797         /* Remove the :+SRP */
798         prioritycopy[validprioritylen - 1] = 0;
799       rc = gnutls_priority_set_direct(session, prioritycopy, &err);
800       free(prioritycopy);
801     }
802   }
803   if(rc != GNUTLS_E_SUCCESS) {
804     failf(data, "Error %d setting GnuTLS cipher list starting with %s",
805           rc, err);
806     return CURLE_SSL_CONNECT_ERROR;
807   }
808 #endif
809 
810 #ifdef HAS_ALPN
811   if(conn->bits.tls_enable_alpn) {
812     int cur = 0;
813     gnutls_datum_t protocols[2];
814 
815 #ifdef USE_NGHTTP2
816     if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
817        (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
818       protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
819       protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
820       cur++;
821       infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
822     }
823 #endif
824 
825     protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
826     protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
827     cur++;
828     infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
829 
830     gnutls_alpn_set_protocols(session, protocols, cur, 0);
831   }
832 #endif
833 
834   if(SSL_SET_OPTION(cert)) {
835     if(SSL_SET_OPTION(key_passwd)) {
836 #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2
837       const unsigned int supported_key_encryption_algorithms =
838         GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
839         GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
840         GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
841         GNUTLS_PKCS_USE_PBES2_AES_256;
842       rc = gnutls_certificate_set_x509_key_file2(
843            BACKEND->cred,
844            SSL_SET_OPTION(cert),
845            SSL_SET_OPTION(key) ?
846            SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
847            do_file_type(SSL_SET_OPTION(cert_type)),
848            SSL_SET_OPTION(key_passwd),
849            supported_key_encryption_algorithms);
850       if(rc != GNUTLS_E_SUCCESS) {
851         failf(data,
852               "error reading X.509 potentially-encrypted key file: %s",
853               gnutls_strerror(rc));
854         return CURLE_SSL_CONNECT_ERROR;
855       }
856 #else
857       failf(data, "gnutls lacks support for encrypted key files");
858       return CURLE_SSL_CONNECT_ERROR;
859 #endif
860     }
861     else {
862       if(gnutls_certificate_set_x509_key_file(
863            BACKEND->cred,
864            SSL_SET_OPTION(cert),
865            SSL_SET_OPTION(key) ?
866            SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
867            do_file_type(SSL_SET_OPTION(cert_type)) ) !=
868          GNUTLS_E_SUCCESS) {
869         failf(data, "error reading X.509 key or certificate file");
870         return CURLE_SSL_CONNECT_ERROR;
871       }
872     }
873   }
874 
875 #ifdef USE_TLS_SRP
876   /* put the credentials to the current session */
877   if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
878     rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
879                                 BACKEND->srp_client_cred);
880     if(rc != GNUTLS_E_SUCCESS) {
881       failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
882       return CURLE_SSL_CONNECT_ERROR;
883     }
884   }
885   else
886 #endif
887   {
888     rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
889                                 BACKEND->cred);
890     if(rc != GNUTLS_E_SUCCESS) {
891       failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
892       return CURLE_SSL_CONNECT_ERROR;
893     }
894   }
895 
896   if(conn->proxy_ssl[sockindex].use) {
897     transport_ptr = conn->proxy_ssl[sockindex].backend->session;
898     gnutls_transport_push = Curl_gtls_push_ssl;
899     gnutls_transport_pull = Curl_gtls_pull_ssl;
900   }
901   else {
902     /* file descriptor for the socket */
903     transport_ptr = &conn->sock[sockindex];
904     gnutls_transport_push = Curl_gtls_push;
905     gnutls_transport_pull = Curl_gtls_pull;
906   }
907 
908   /* set the connection handle */
909   gnutls_transport_set_ptr(session, transport_ptr);
910 
911   /* register callback functions to send and receive data. */
912   gnutls_transport_set_push_function(session, gnutls_transport_push);
913   gnutls_transport_set_pull_function(session, gnutls_transport_pull);
914 
915   /* lowat must be set to zero when using custom push and pull functions. */
916   gnutls_transport_set_lowat(session, 0);
917 
918 #ifdef HAS_OCSP
919   if(SSL_CONN_CONFIG(verifystatus)) {
920     rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
921     if(rc != GNUTLS_E_SUCCESS) {
922       failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
923       return CURLE_SSL_CONNECT_ERROR;
924     }
925   }
926 #endif
927 
928   /* This might be a reconnect, so we check for a session ID in the cache
929      to speed up things */
930   if(SSL_SET_OPTION(primary.sessionid)) {
931     void *ssl_sessionid;
932     size_t ssl_idsize;
933 
934     Curl_ssl_sessionid_lock(conn);
935     if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) {
936       /* we got a session id, use it! */
937       gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
938 
939       /* Informational message */
940       infof(data, "SSL re-using session ID\n");
941     }
942     Curl_ssl_sessionid_unlock(conn);
943   }
944 
945   return CURLE_OK;
946 }
947 
pkp_pin_peer_pubkey(struct Curl_easy * data,gnutls_x509_crt_t cert,const char * pinnedpubkey)948 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
949                                     gnutls_x509_crt_t cert,
950                                     const char *pinnedpubkey)
951 {
952   /* Scratch */
953   size_t len1 = 0, len2 = 0;
954   unsigned char *buff1 = NULL;
955 
956   gnutls_pubkey_t key = NULL;
957 
958   /* Result is returned to caller */
959   int ret = 0;
960   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
961 
962   /* if a path wasn't specified, don't pin */
963   if(NULL == pinnedpubkey)
964     return CURLE_OK;
965 
966   if(NULL == cert)
967     return result;
968 
969   do {
970     /* Begin Gyrations to get the public key     */
971     gnutls_pubkey_init(&key);
972 
973     ret = gnutls_pubkey_import_x509(key, cert, 0);
974     if(ret < 0)
975       break; /* failed */
976 
977     ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1);
978     if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
979       break; /* failed */
980 
981     buff1 = malloc(len1);
982     if(NULL == buff1)
983       break; /* failed */
984 
985     len2 = len1;
986 
987     ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2);
988     if(ret < 0 || len1 != len2)
989       break; /* failed */
990 
991     /* End Gyrations */
992 
993     /* The one good exit point */
994     result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
995   } while(0);
996 
997   if(NULL != key)
998     gnutls_pubkey_deinit(key);
999 
1000   Curl_safefree(buff1);
1001 
1002   return result;
1003 }
1004 
1005 static Curl_recv gtls_recv;
1006 static Curl_send gtls_send;
1007 
1008 static CURLcode
gtls_connect_step3(struct connectdata * conn,int sockindex)1009 gtls_connect_step3(struct connectdata *conn,
1010                    int sockindex)
1011 {
1012   unsigned int cert_list_size;
1013   const gnutls_datum_t *chainp;
1014   unsigned int verify_status = 0;
1015   gnutls_x509_crt_t x509_cert, x509_issuer;
1016   gnutls_datum_t issuerp;
1017   char certbuf[256] = ""; /* big enough? */
1018   size_t size;
1019   time_t certclock;
1020   const char *ptr;
1021   struct Curl_easy *data = conn->data;
1022   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1023   gnutls_session_t session = BACKEND->session;
1024   int rc;
1025 #ifdef HAS_ALPN
1026   gnutls_datum_t proto;
1027 #endif
1028   CURLcode result = CURLE_OK;
1029 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1030   unsigned int algo;
1031   unsigned int bits;
1032   gnutls_protocol_t version = gnutls_protocol_get_version(session);
1033 #endif
1034   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1035     conn->host.name;
1036 
1037   /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
1038   ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
1039                                      gnutls_cipher_get(session),
1040                                      gnutls_mac_get(session));
1041 
1042   infof(data, "SSL connection using %s / %s\n",
1043         gnutls_protocol_get_name(version), ptr);
1044 
1045   /* This function will return the peer's raw certificate (chain) as sent by
1046      the peer. These certificates are in raw format (DER encoded for
1047      X.509). In case of a X.509 then a certificate list may be present. The
1048      first certificate in the list is the peer's certificate, following the
1049      issuer's certificate, then the issuer's issuer etc. */
1050 
1051   chainp = gnutls_certificate_get_peers(session, &cert_list_size);
1052   if(!chainp) {
1053     if(SSL_CONN_CONFIG(verifypeer) ||
1054        SSL_CONN_CONFIG(verifyhost) ||
1055        SSL_SET_OPTION(issuercert)) {
1056 #ifdef USE_TLS_SRP
1057       if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
1058          && SSL_SET_OPTION(username) != NULL
1059          && !SSL_CONN_CONFIG(verifypeer)
1060          && gnutls_cipher_get(session)) {
1061         /* no peer cert, but auth is ok if we have SRP user and cipher and no
1062            peer verify */
1063       }
1064       else {
1065 #endif
1066         failf(data, "failed to get server cert");
1067         return CURLE_PEER_FAILED_VERIFICATION;
1068 #ifdef USE_TLS_SRP
1069       }
1070 #endif
1071     }
1072     infof(data, "\t common name: WARNING couldn't obtain\n");
1073   }
1074 
1075   if(data->set.ssl.certinfo && chainp) {
1076     unsigned int i;
1077 
1078     result = Curl_ssl_init_certinfo(data, cert_list_size);
1079     if(result)
1080       return result;
1081 
1082     for(i = 0; i < cert_list_size; i++) {
1083       const char *beg = (const char *) chainp[i].data;
1084       const char *end = beg + chainp[i].size;
1085 
1086       result = Curl_extract_certinfo(conn, i, beg, end);
1087       if(result)
1088         return result;
1089     }
1090   }
1091 
1092   if(SSL_CONN_CONFIG(verifypeer)) {
1093     /* This function will try to verify the peer's certificate and return its
1094        status (trusted, invalid etc.). The value of status should be one or
1095        more of the gnutls_certificate_status_t enumerated elements bitwise
1096        or'd. To avoid denial of service attacks some default upper limits
1097        regarding the certificate key size and chain size are set. To override
1098        them use gnutls_certificate_set_verify_limits(). */
1099 
1100     rc = gnutls_certificate_verify_peers2(session, &verify_status);
1101     if(rc < 0) {
1102       failf(data, "server cert verify failed: %d", rc);
1103       return CURLE_SSL_CONNECT_ERROR;
1104     }
1105 
1106     /* verify_status is a bitmask of gnutls_certificate_status bits */
1107     if(verify_status & GNUTLS_CERT_INVALID) {
1108       if(SSL_CONN_CONFIG(verifypeer)) {
1109         failf(data, "server certificate verification failed. CAfile: %s "
1110               "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
1111               "none",
1112               SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none");
1113         return CURLE_PEER_FAILED_VERIFICATION;
1114       }
1115       else
1116         infof(data, "\t server certificate verification FAILED\n");
1117     }
1118     else
1119       infof(data, "\t server certificate verification OK\n");
1120   }
1121   else
1122     infof(data, "\t server certificate verification SKIPPED\n");
1123 
1124 #ifdef HAS_OCSP
1125   if(SSL_CONN_CONFIG(verifystatus)) {
1126     if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
1127       gnutls_datum_t status_request;
1128       gnutls_ocsp_resp_t ocsp_resp;
1129 
1130       gnutls_ocsp_cert_status_t status;
1131       gnutls_x509_crl_reason_t reason;
1132 
1133       rc = gnutls_ocsp_status_request_get(session, &status_request);
1134 
1135       infof(data, "\t server certificate status verification FAILED\n");
1136 
1137       if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1138         failf(data, "No OCSP response received");
1139         return CURLE_SSL_INVALIDCERTSTATUS;
1140       }
1141 
1142       if(rc < 0) {
1143         failf(data, "Invalid OCSP response received");
1144         return CURLE_SSL_INVALIDCERTSTATUS;
1145       }
1146 
1147       gnutls_ocsp_resp_init(&ocsp_resp);
1148 
1149       rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
1150       if(rc < 0) {
1151         failf(data, "Invalid OCSP response received");
1152         return CURLE_SSL_INVALIDCERTSTATUS;
1153       }
1154 
1155       (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
1156                                         &status, NULL, NULL, NULL, &reason);
1157 
1158       switch(status) {
1159       case GNUTLS_OCSP_CERT_GOOD:
1160         break;
1161 
1162       case GNUTLS_OCSP_CERT_REVOKED: {
1163         const char *crl_reason;
1164 
1165         switch(reason) {
1166           default:
1167           case GNUTLS_X509_CRLREASON_UNSPECIFIED:
1168             crl_reason = "unspecified reason";
1169             break;
1170 
1171           case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
1172             crl_reason = "private key compromised";
1173             break;
1174 
1175           case GNUTLS_X509_CRLREASON_CACOMPROMISE:
1176             crl_reason = "CA compromised";
1177             break;
1178 
1179           case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
1180             crl_reason = "affiliation has changed";
1181             break;
1182 
1183           case GNUTLS_X509_CRLREASON_SUPERSEDED:
1184             crl_reason = "certificate superseded";
1185             break;
1186 
1187           case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
1188             crl_reason = "operation has ceased";
1189             break;
1190 
1191           case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
1192             crl_reason = "certificate is on hold";
1193             break;
1194 
1195           case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
1196             crl_reason = "will be removed from delta CRL";
1197             break;
1198 
1199           case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
1200             crl_reason = "privilege withdrawn";
1201             break;
1202 
1203           case GNUTLS_X509_CRLREASON_AACOMPROMISE:
1204             crl_reason = "AA compromised";
1205             break;
1206         }
1207 
1208         failf(data, "Server certificate was revoked: %s", crl_reason);
1209         break;
1210       }
1211 
1212       default:
1213       case GNUTLS_OCSP_CERT_UNKNOWN:
1214         failf(data, "Server certificate status is unknown");
1215         break;
1216       }
1217 
1218       gnutls_ocsp_resp_deinit(ocsp_resp);
1219 
1220       return CURLE_SSL_INVALIDCERTSTATUS;
1221     }
1222     else
1223       infof(data, "\t server certificate status verification OK\n");
1224   }
1225   else
1226     infof(data, "\t server certificate status verification SKIPPED\n");
1227 #endif
1228 
1229   /* initialize an X.509 certificate structure. */
1230   gnutls_x509_crt_init(&x509_cert);
1231 
1232   if(chainp)
1233     /* convert the given DER or PEM encoded Certificate to the native
1234        gnutls_x509_crt_t format */
1235     gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
1236 
1237   if(SSL_SET_OPTION(issuercert)) {
1238     gnutls_x509_crt_init(&x509_issuer);
1239     issuerp = load_file(SSL_SET_OPTION(issuercert));
1240     gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
1241     rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
1242     gnutls_x509_crt_deinit(x509_issuer);
1243     unload_file(issuerp);
1244     if(rc <= 0) {
1245       failf(data, "server certificate issuer check failed (IssuerCert: %s)",
1246             SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
1247       gnutls_x509_crt_deinit(x509_cert);
1248       return CURLE_SSL_ISSUER_ERROR;
1249     }
1250     infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
1251           SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
1252   }
1253 
1254   size = sizeof(certbuf);
1255   rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
1256                                      0, /* the first and only one */
1257                                      FALSE,
1258                                      certbuf,
1259                                      &size);
1260   if(rc) {
1261     infof(data, "error fetching CN from cert:%s\n",
1262           gnutls_strerror(rc));
1263   }
1264 
1265   /* This function will check if the given certificate's subject matches the
1266      given hostname. This is a basic implementation of the matching described
1267      in RFC2818 (HTTPS), which takes into account wildcards, and the subject
1268      alternative name PKIX extension. Returns non zero on success, and zero on
1269      failure. */
1270   rc = gnutls_x509_crt_check_hostname(x509_cert, hostname);
1271 #if GNUTLS_VERSION_NUMBER < 0x030306
1272   /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
1273      addresses. */
1274   if(!rc) {
1275 #ifdef ENABLE_IPV6
1276     #define use_addr in6_addr
1277 #else
1278     #define use_addr in_addr
1279 #endif
1280     unsigned char addrbuf[sizeof(struct use_addr)];
1281     unsigned char certaddr[sizeof(struct use_addr)];
1282     size_t addrlen = 0, certaddrlen;
1283     int i;
1284     int ret = 0;
1285 
1286     if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0)
1287       addrlen = 4;
1288 #ifdef ENABLE_IPV6
1289     else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0)
1290       addrlen = 16;
1291 #endif
1292 
1293     if(addrlen) {
1294       for(i = 0; ; i++) {
1295         certaddrlen = sizeof(certaddr);
1296         ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
1297                                                    &certaddrlen, NULL);
1298         /* If this happens, it wasn't an IP address. */
1299         if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
1300           continue;
1301         if(ret < 0)
1302           break;
1303         if(ret != GNUTLS_SAN_IPADDRESS)
1304           continue;
1305         if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
1306           rc = 1;
1307           break;
1308         }
1309       }
1310     }
1311   }
1312 #endif
1313   if(!rc) {
1314     const char * const dispname = SSL_IS_PROXY() ?
1315       conn->http_proxy.host.dispname : conn->host.dispname;
1316 
1317     if(SSL_CONN_CONFIG(verifyhost)) {
1318       failf(data, "SSL: certificate subject name (%s) does not match "
1319             "target host name '%s'", certbuf, dispname);
1320       gnutls_x509_crt_deinit(x509_cert);
1321       return CURLE_PEER_FAILED_VERIFICATION;
1322     }
1323     else
1324       infof(data, "\t common name: %s (does not match '%s')\n",
1325             certbuf, dispname);
1326   }
1327   else
1328     infof(data, "\t common name: %s (matched)\n", certbuf);
1329 
1330   /* Check for time-based validity */
1331   certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
1332 
1333   if(certclock == (time_t)-1) {
1334     if(SSL_CONN_CONFIG(verifypeer)) {
1335       failf(data, "server cert expiration date verify failed");
1336       gnutls_x509_crt_deinit(x509_cert);
1337       return CURLE_SSL_CONNECT_ERROR;
1338     }
1339     else
1340       infof(data, "\t server certificate expiration date verify FAILED\n");
1341   }
1342   else {
1343     if(certclock < time(NULL)) {
1344       if(SSL_CONN_CONFIG(verifypeer)) {
1345         failf(data, "server certificate expiration date has passed.");
1346         gnutls_x509_crt_deinit(x509_cert);
1347         return CURLE_PEER_FAILED_VERIFICATION;
1348       }
1349       else
1350         infof(data, "\t server certificate expiration date FAILED\n");
1351     }
1352     else
1353       infof(data, "\t server certificate expiration date OK\n");
1354   }
1355 
1356   certclock = gnutls_x509_crt_get_activation_time(x509_cert);
1357 
1358   if(certclock == (time_t)-1) {
1359     if(SSL_CONN_CONFIG(verifypeer)) {
1360       failf(data, "server cert activation date verify failed");
1361       gnutls_x509_crt_deinit(x509_cert);
1362       return CURLE_SSL_CONNECT_ERROR;
1363     }
1364     else
1365       infof(data, "\t server certificate activation date verify FAILED\n");
1366   }
1367   else {
1368     if(certclock > time(NULL)) {
1369       if(SSL_CONN_CONFIG(verifypeer)) {
1370         failf(data, "server certificate not activated yet.");
1371         gnutls_x509_crt_deinit(x509_cert);
1372         return CURLE_PEER_FAILED_VERIFICATION;
1373       }
1374       else
1375         infof(data, "\t server certificate activation date FAILED\n");
1376     }
1377     else
1378       infof(data, "\t server certificate activation date OK\n");
1379   }
1380 
1381   ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1382         data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
1383   if(ptr) {
1384     result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
1385     if(result != CURLE_OK) {
1386       failf(data, "SSL: public key does not match pinned public key!");
1387       gnutls_x509_crt_deinit(x509_cert);
1388       return result;
1389     }
1390   }
1391 
1392   /* Show:
1393 
1394   - subject
1395   - start date
1396   - expire date
1397   - common name
1398   - issuer
1399 
1400   */
1401 
1402 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1403   /* public key algorithm's parameters */
1404   algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
1405   infof(data, "\t certificate public key: %s\n",
1406         gnutls_pk_algorithm_get_name(algo));
1407 
1408   /* version of the X.509 certificate. */
1409   infof(data, "\t certificate version: #%d\n",
1410         gnutls_x509_crt_get_version(x509_cert));
1411 
1412 
1413   size = sizeof(certbuf);
1414   gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
1415   infof(data, "\t subject: %s\n", certbuf);
1416 
1417   certclock = gnutls_x509_crt_get_activation_time(x509_cert);
1418   showtime(data, "start date", certclock);
1419 
1420   certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
1421   showtime(data, "expire date", certclock);
1422 
1423   size = sizeof(certbuf);
1424   gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
1425   infof(data, "\t issuer: %s\n", certbuf);
1426 #endif
1427 
1428   gnutls_x509_crt_deinit(x509_cert);
1429 
1430 #ifdef HAS_ALPN
1431   if(conn->bits.tls_enable_alpn) {
1432     rc = gnutls_alpn_get_selected_protocol(session, &proto);
1433     if(rc == 0) {
1434       infof(data, "ALPN, server accepted to use %.*s\n", proto.size,
1435           proto.data);
1436 
1437 #ifdef USE_NGHTTP2
1438       if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN &&
1439          !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data,
1440                  NGHTTP2_PROTO_VERSION_ID_LEN)) {
1441         conn->negnpn = CURL_HTTP_VERSION_2;
1442       }
1443       else
1444 #endif
1445       if(proto.size == ALPN_HTTP_1_1_LENGTH &&
1446          !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) {
1447         conn->negnpn = CURL_HTTP_VERSION_1_1;
1448       }
1449     }
1450     else
1451       infof(data, "ALPN, server did not agree to a protocol\n");
1452   }
1453 #endif
1454 
1455   conn->ssl[sockindex].state = ssl_connection_complete;
1456   conn->recv[sockindex] = gtls_recv;
1457   conn->send[sockindex] = gtls_send;
1458 
1459   if(SSL_SET_OPTION(primary.sessionid)) {
1460     /* we always unconditionally get the session id here, as even if we
1461        already got it from the cache and asked to use it in the connection, it
1462        might've been rejected and then a new one is in use now and we need to
1463        detect that. */
1464     bool incache;
1465     void *ssl_sessionid;
1466     void *connect_sessionid;
1467     size_t connect_idsize = 0;
1468 
1469     /* get the session ID data size */
1470     gnutls_session_get_data(session, NULL, &connect_idsize);
1471     connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
1472 
1473     if(connect_sessionid) {
1474       /* extract session ID to the allocated buffer */
1475       gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
1476 
1477       Curl_ssl_sessionid_lock(conn);
1478       incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL,
1479                                         sockindex));
1480       if(incache) {
1481         /* there was one before in the cache, so instead of risking that the
1482            previous one was rejected, we just kill that and store the new */
1483         Curl_ssl_delsessionid(conn, ssl_sessionid);
1484       }
1485 
1486       /* store this session id */
1487       result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize,
1488                                      sockindex);
1489       Curl_ssl_sessionid_unlock(conn);
1490       if(result) {
1491         free(connect_sessionid);
1492         result = CURLE_OUT_OF_MEMORY;
1493       }
1494     }
1495     else
1496       result = CURLE_OUT_OF_MEMORY;
1497   }
1498 
1499   return result;
1500 }
1501 
1502 
1503 /*
1504  * This function is called after the TCP connect has completed. Setup the TLS
1505  * layer and do all necessary magic.
1506  */
1507 /* We use connssl->connecting_state to keep track of the connection status;
1508    there are three states: 'ssl_connect_1' (not started yet or complete),
1509    'ssl_connect_2_reading' (waiting for data from server), and
1510    'ssl_connect_2_writing' (waiting to be able to write).
1511  */
1512 static CURLcode
gtls_connect_common(struct connectdata * conn,int sockindex,bool nonblocking,bool * done)1513 gtls_connect_common(struct connectdata *conn,
1514                     int sockindex,
1515                     bool nonblocking,
1516                     bool *done)
1517 {
1518   int rc;
1519   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1520 
1521   /* Initiate the connection, if not already done */
1522   if(ssl_connect_1 == connssl->connecting_state) {
1523     rc = gtls_connect_step1(conn, sockindex);
1524     if(rc)
1525       return rc;
1526   }
1527 
1528   rc = handshake(conn, sockindex, TRUE, nonblocking);
1529   if(rc)
1530     /* handshake() sets its own error message with failf() */
1531     return rc;
1532 
1533   /* Finish connecting once the handshake is done */
1534   if(ssl_connect_1 == connssl->connecting_state) {
1535     rc = gtls_connect_step3(conn, sockindex);
1536     if(rc)
1537       return rc;
1538   }
1539 
1540   *done = ssl_connect_1 == connssl->connecting_state;
1541 
1542   return CURLE_OK;
1543 }
1544 
Curl_gtls_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)1545 static CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
1546                                               int sockindex, bool *done)
1547 {
1548   return gtls_connect_common(conn, sockindex, TRUE, done);
1549 }
1550 
Curl_gtls_connect(struct connectdata * conn,int sockindex)1551 static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex)
1552 {
1553   CURLcode result;
1554   bool done = FALSE;
1555 
1556   result = gtls_connect_common(conn, sockindex, FALSE, &done);
1557   if(result)
1558     return result;
1559 
1560   DEBUGASSERT(done);
1561 
1562   return CURLE_OK;
1563 }
1564 
Curl_gtls_data_pending(const struct connectdata * conn,int connindex)1565 static bool Curl_gtls_data_pending(const struct connectdata *conn,
1566                                    int connindex)
1567 {
1568   const struct ssl_connect_data *connssl = &conn->ssl[connindex];
1569   bool res = FALSE;
1570   if(BACKEND->session &&
1571      0 != gnutls_record_check_pending(BACKEND->session))
1572     res = TRUE;
1573 
1574   connssl = &conn->proxy_ssl[connindex];
1575   if(BACKEND->session &&
1576      0 != gnutls_record_check_pending(BACKEND->session))
1577     res = TRUE;
1578 
1579   return res;
1580 }
1581 
gtls_send(struct connectdata * conn,int sockindex,const void * mem,size_t len,CURLcode * curlcode)1582 static ssize_t gtls_send(struct connectdata *conn,
1583                          int sockindex,
1584                          const void *mem,
1585                          size_t len,
1586                          CURLcode *curlcode)
1587 {
1588   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1589   ssize_t rc = gnutls_record_send(BACKEND->session, mem, len);
1590 
1591   if(rc < 0) {
1592     *curlcode = (rc == GNUTLS_E_AGAIN)
1593       ? CURLE_AGAIN
1594       : CURLE_SEND_ERROR;
1595 
1596     rc = -1;
1597   }
1598 
1599   return rc;
1600 }
1601 
close_one(struct ssl_connect_data * connssl)1602 static void close_one(struct ssl_connect_data *connssl)
1603 {
1604   if(BACKEND->session) {
1605     gnutls_bye(BACKEND->session, GNUTLS_SHUT_RDWR);
1606     gnutls_deinit(BACKEND->session);
1607     BACKEND->session = NULL;
1608   }
1609   if(BACKEND->cred) {
1610     gnutls_certificate_free_credentials(BACKEND->cred);
1611     BACKEND->cred = NULL;
1612   }
1613 #ifdef USE_TLS_SRP
1614   if(BACKEND->srp_client_cred) {
1615     gnutls_srp_free_client_credentials(BACKEND->srp_client_cred);
1616     BACKEND->srp_client_cred = NULL;
1617   }
1618 #endif
1619 }
1620 
Curl_gtls_close(struct connectdata * conn,int sockindex)1621 static void Curl_gtls_close(struct connectdata *conn, int sockindex)
1622 {
1623   close_one(&conn->ssl[sockindex]);
1624   close_one(&conn->proxy_ssl[sockindex]);
1625 }
1626 
1627 /*
1628  * This function is called to shut down the SSL layer but keep the
1629  * socket open (CCC - Clear Command Channel)
1630  */
Curl_gtls_shutdown(struct connectdata * conn,int sockindex)1631 static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
1632 {
1633   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1634   ssize_t result;
1635   int retval = 0;
1636   struct Curl_easy *data = conn->data;
1637   bool done = FALSE;
1638   char buf[120];
1639 
1640   /* This has only been tested on the proftpd server, and the mod_tls code
1641      sends a close notify alert without waiting for a close notify alert in
1642      response. Thus we wait for a close notify alert from the server, but
1643      we do not send one. Let's hope other servers do the same... */
1644 
1645   if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
1646       gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR);
1647 
1648   if(BACKEND->session) {
1649     while(!done) {
1650       int what = SOCKET_READABLE(conn->sock[sockindex],
1651                                  SSL_SHUTDOWN_TIMEOUT);
1652       if(what > 0) {
1653         /* Something to read, let's do it and hope that it is the close
1654            notify alert from the server */
1655         result = gnutls_record_recv(BACKEND->session,
1656                                     buf, sizeof(buf));
1657         switch(result) {
1658         case 0:
1659           /* This is the expected response. There was no data but only
1660              the close notify alert */
1661           done = TRUE;
1662           break;
1663         case GNUTLS_E_AGAIN:
1664         case GNUTLS_E_INTERRUPTED:
1665           infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
1666           break;
1667         default:
1668           retval = -1;
1669           done = TRUE;
1670           break;
1671         }
1672       }
1673       else if(0 == what) {
1674         /* timeout */
1675         failf(data, "SSL shutdown timeout");
1676         done = TRUE;
1677       }
1678       else {
1679         /* anything that gets here is fatally bad */
1680         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1681         retval = -1;
1682         done = TRUE;
1683       }
1684     }
1685     gnutls_deinit(BACKEND->session);
1686   }
1687   gnutls_certificate_free_credentials(BACKEND->cred);
1688 
1689 #ifdef USE_TLS_SRP
1690   if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
1691      && SSL_SET_OPTION(username) != NULL)
1692     gnutls_srp_free_client_credentials(BACKEND->srp_client_cred);
1693 #endif
1694 
1695   BACKEND->cred = NULL;
1696   BACKEND->session = NULL;
1697 
1698   return retval;
1699 }
1700 
gtls_recv(struct connectdata * conn,int num,char * buf,size_t buffersize,CURLcode * curlcode)1701 static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
1702                          int num,                  /* socketindex */
1703                          char *buf,                /* store read data here */
1704                          size_t buffersize,        /* max amount to read */
1705                          CURLcode *curlcode)
1706 {
1707   struct ssl_connect_data *connssl = &conn->ssl[num];
1708   ssize_t ret;
1709 
1710   ret = gnutls_record_recv(BACKEND->session, buf, buffersize);
1711   if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
1712     *curlcode = CURLE_AGAIN;
1713     return -1;
1714   }
1715 
1716   if(ret == GNUTLS_E_REHANDSHAKE) {
1717     /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
1718        proper way" takes a whole lot of work. */
1719     CURLcode result = handshake(conn, num, FALSE, FALSE);
1720     if(result)
1721       /* handshake() writes error message on its own */
1722       *curlcode = result;
1723     else
1724       *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
1725     return -1;
1726   }
1727 
1728   if(ret < 0) {
1729     failf(conn->data, "GnuTLS recv error (%d): %s",
1730 
1731           (int)ret, gnutls_strerror((int)ret));
1732     *curlcode = CURLE_RECV_ERROR;
1733     return -1;
1734   }
1735 
1736   return ret;
1737 }
1738 
Curl_gtls_session_free(void * ptr)1739 static void Curl_gtls_session_free(void *ptr)
1740 {
1741   free(ptr);
1742 }
1743 
Curl_gtls_version(char * buffer,size_t size)1744 static size_t Curl_gtls_version(char *buffer, size_t size)
1745 {
1746   return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
1747 }
1748 
1749 #ifndef USE_GNUTLS_NETTLE
Curl_gtls_seed(struct Curl_easy * data)1750 static int Curl_gtls_seed(struct Curl_easy *data)
1751 {
1752   /* we have the "SSL is seeded" boolean static to prevent multiple
1753      time-consuming seedings in vain */
1754   static bool ssl_seeded = FALSE;
1755 
1756   /* Quickly add a bit of entropy */
1757   gcry_fast_random_poll();
1758 
1759   if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
1760      data->set.str[STRING_SSL_EGDSOCKET]) {
1761 
1762     /* TODO: to a good job seeding the RNG
1763        This may involve the gcry_control function and these options:
1764        GCRYCTL_SET_RANDOM_SEED_FILE
1765        GCRYCTL_SET_RNDEGD_SOCKET
1766     */
1767     ssl_seeded = TRUE;
1768   }
1769   return 0;
1770 }
1771 #endif
1772 
1773 /* data might be NULL! */
Curl_gtls_random(struct Curl_easy * data,unsigned char * entropy,size_t length)1774 static CURLcode Curl_gtls_random(struct Curl_easy *data,
1775                                  unsigned char *entropy, size_t length)
1776 {
1777 #if defined(USE_GNUTLS_NETTLE)
1778   int rc;
1779   (void)data;
1780   rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
1781   return rc?CURLE_FAILED_INIT:CURLE_OK;
1782 #elif defined(USE_GNUTLS)
1783   if(data)
1784     Curl_gtls_seed(data); /* Initiate the seed if not already done */
1785   gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
1786 #endif
1787   return CURLE_OK;
1788 }
1789 
Curl_gtls_md5sum(unsigned char * tmp,size_t tmplen,unsigned char * md5sum,size_t md5len)1790 static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */
1791                                  size_t tmplen,
1792                                  unsigned char *md5sum, /* output */
1793                                  size_t md5len)
1794 {
1795 #if defined(USE_GNUTLS_NETTLE)
1796   struct md5_ctx MD5pw;
1797   md5_init(&MD5pw);
1798   md5_update(&MD5pw, (unsigned int)tmplen, tmp);
1799   md5_digest(&MD5pw, (unsigned int)md5len, md5sum);
1800 #elif defined(USE_GNUTLS)
1801   gcry_md_hd_t MD5pw;
1802   gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
1803   gcry_md_write(MD5pw, tmp, tmplen);
1804   memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len);
1805   gcry_md_close(MD5pw);
1806 #endif
1807   return CURLE_OK;
1808 }
1809 
Curl_gtls_sha256sum(const unsigned char * tmp,size_t tmplen,unsigned char * sha256sum,size_t sha256len)1810 static CURLcode Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
1811                                 size_t tmplen,
1812                                 unsigned char *sha256sum, /* output */
1813                                 size_t sha256len)
1814 {
1815 #if defined(USE_GNUTLS_NETTLE)
1816   struct sha256_ctx SHA256pw;
1817   sha256_init(&SHA256pw);
1818   sha256_update(&SHA256pw, (unsigned int)tmplen, tmp);
1819   sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum);
1820 #elif defined(USE_GNUTLS)
1821   gcry_md_hd_t SHA256pw;
1822   gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0);
1823   gcry_md_write(SHA256pw, tmp, tmplen);
1824   memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len);
1825   gcry_md_close(SHA256pw);
1826 #endif
1827   return CURLE_OK;
1828 }
1829 
Curl_gtls_cert_status_request(void)1830 static bool Curl_gtls_cert_status_request(void)
1831 {
1832 #ifdef HAS_OCSP
1833   return TRUE;
1834 #else
1835   return FALSE;
1836 #endif
1837 }
1838 
Curl_gtls_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)1839 static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl,
1840                                      CURLINFO info UNUSED_PARAM)
1841 {
1842   (void)info;
1843   return BACKEND->session;
1844 }
1845 
1846 const struct Curl_ssl Curl_ssl_gnutls = {
1847   { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */
1848 
1849   SSLSUPP_CA_PATH  |
1850   SSLSUPP_CERTINFO |
1851   SSLSUPP_PINNEDPUBKEY |
1852   SSLSUPP_HTTPS_PROXY,
1853 
1854   sizeof(struct ssl_backend_data),
1855 
1856   Curl_gtls_init,                /* init */
1857   Curl_gtls_cleanup,             /* cleanup */
1858   Curl_gtls_version,             /* version */
1859   Curl_none_check_cxn,           /* check_cxn */
1860   Curl_gtls_shutdown,            /* shutdown */
1861   Curl_gtls_data_pending,        /* data_pending */
1862   Curl_gtls_random,              /* random */
1863   Curl_gtls_cert_status_request, /* cert_status_request */
1864   Curl_gtls_connect,             /* connect */
1865   Curl_gtls_connect_nonblocking, /* connect_nonblocking */
1866   Curl_gtls_get_internals,       /* get_internals */
1867   Curl_gtls_close,               /* close_one */
1868   Curl_none_close_all,           /* close_all */
1869   Curl_gtls_session_free,        /* session_free */
1870   Curl_none_set_engine,          /* set_engine */
1871   Curl_none_set_engine_default,  /* set_engine_default */
1872   Curl_none_engines_list,        /* engines_list */
1873   Curl_none_false_start,         /* false_start */
1874   Curl_gtls_md5sum,              /* md5sum */
1875   Curl_gtls_sha256sum            /* sha256sum */
1876 };
1877 
1878 #endif /* USE_GNUTLS */
1879