Skip to content
gtls.c 42.8 KiB
Newer Older
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at http://curl.haxx.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ***************************************************************************/

/*
 * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
 * but vtls.c should ever call or use these functions.
 *
 * Note: don't use the GnuTLS' *_t variable type names in this source code,
 * since they were not present in 1.0.X.
 */

#include "curl_setup.h"
#include <gnutls/abstract.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#ifdef USE_GNUTLS_NETTLE
#include <gnutls/crypto.h>
#include <nettle/md5.h>
#else
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
#include "gtls.h"
#include "vtls.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "rawstr.h"
#include "warnless.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"
/*
 Some hackish cast macros based on:
 http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html
*/
#ifndef GNUTLS_POINTER_TO_INT_CAST
#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
#endif
#ifndef GNUTLS_INT_TO_POINTER_CAST
#define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
#endif

/* Enable GnuTLS debugging by defining GTLSDEBUG */
/*#define GTLSDEBUG */

#ifdef GTLSDEBUG
static void tls_log_func(int level, const char *str)
{
    fprintf(stderr, "|<%d>| %s", level, str);
}
#endif
#if defined(GNUTLS_VERSION_NUMBER)
#  if (GNUTLS_VERSION_NUMBER >= 0x020c00)
#    undef gnutls_transport_set_lowat
#    define gnutls_transport_set_lowat(A,B) Curl_nop_stmt
#    define USE_GNUTLS_PRIORITY_SET_DIRECT 1
#  if (GNUTLS_VERSION_NUMBER >= 0x020c03)
#    define GNUTLS_MAPS_WINSOCK_ERRORS 1
Fabian Frank's avatar
Fabian Frank committed

#  ifdef USE_NGHTTP2
#    undef HAS_ALPN
#    if (GNUTLS_VERSION_NUMBER >= 0x030200)
#      define HAS_ALPN
#    endif
#  endif

#  if (GNUTLS_VERSION_NUMBER >= 0x03020d)
#    define HAS_OCSP
#  endif
#endif

#ifdef HAS_OCSP
# include <gnutls/ocsp.h>
/*
 * Custom push and pull callback functions used by GNU TLS to read and write
 * to the socket.  These functions are simple wrappers to send() and recv()
 * (although here using the sread/swrite macros as defined by
 * curl_setup_once.h).
 * We use custom functions rather than the GNU TLS defaults because it allows
 * us to get specific about the fourth "flags" argument, and to use arbitrary
 * private data with gnutls_transport_set_ptr if we wish.
 * When these custom push and pull callbacks fail, GNU TLS checks its own
 * session-specific error variable, and when not set also its own global
 * errno variable, in order to take appropriate action. GNU TLS does not
 * require that the transport is actually a socket. This implies that for
 * Windows builds these callbacks should ideally set the session-specific
 * error variable using function gnutls_transport_set_errno or as a last
 * resort global errno variable using gnutls_transport_set_global_errno,
 * with a transport agnostic error value. This implies that some winsock
 * error translation must take place in these callbacks.
 *
 * Paragraph above applies to GNU TLS versions older than 2.12.3, since
 * this version GNU TLS does its own internal winsock error translation
 * using system_errno() function.
#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
#  define gtls_EINTR  4
#  define gtls_EIO    5
#  define gtls_EAGAIN 11
static int gtls_mapped_sockerrno(void)
  case WSAEWOULDBLOCK:
static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
{
  ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
  if(ret < 0)
    gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
}

static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
{
  ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
  if(ret < 0)
    gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
/* Curl_gtls_init()
 *
 * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
 * are not thread-safe and thus this function itself is not thread-safe and
 * must only be called from within curl_global_init() to keep the thread
 * situation under control!
Daniel Stenberg's avatar
Daniel Stenberg committed
  if(!gtls_inited) {
    gnutls_global_set_log_function(tls_log_func);
    gnutls_global_set_log_level(2);
Loading
Loading full blame…