Annotation of embedaddon/curl/lib/vtls/gtls.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>