Skip to content
gskit.c 31.5 KiB
Newer Older
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2014, 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.
 *
 ***************************************************************************/

#include "curl_setup.h"

#ifdef USE_GSKIT

#include <gskssl.h>
#include <qsoasync.h>

/* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
#ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
#define GSK_SSL_EXTN_SERVERNAME_REQUEST         230
#ifndef GSK_TLSV10_CIPHER_SPECS
#define GSK_TLSV10_CIPHER_SPECS                 236
#endif

#ifndef GSK_TLSV11_CIPHER_SPECS
#define GSK_TLSV11_CIPHER_SPECS                 237
#endif

#ifndef GSK_TLSV12_CIPHER_SPECS
#define GSK_TLSV12_CIPHER_SPECS                 238
#endif

#ifndef GSK_PROTOCOL_TLSV11
#define GSK_PROTOCOL_TLSV11                     437
#endif

#ifndef GSK_PROTOCOL_TLSV12
#define GSK_PROTOCOL_TLSV12                     438
#endif

#ifndef GSK_FALSE
#define GSK_FALSE                               0
#endif

#ifndef GSK_TRUE
#define GSK_TRUE                                1
#endif


#ifdef HAVE_LIMITS_H
#  include <limits.h>
#endif

#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
#include "gskit.h"
#include "vtls.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "strequal.h"
#include "x509asn1.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"


/* SSL version flags. */
#define CURL_GSKPROTO_SSLV2     0
#define CURL_GSKPROTO_SSLV2_MASK        (1 << CURL_GSKPROTO_SSLV2)
#define CURL_GSKPROTO_SSLV3     1
#define CURL_GSKPROTO_SSLV3_MASK        (1 << CURL_GSKPROTO_SSLV3)
#define CURL_GSKPROTO_TLSV10    2
#define CURL_GSKPROTO_TLSV10_MASK        (1 << CURL_GSKPROTO_TLSV10)
#define CURL_GSKPROTO_TLSV11    3
#define CURL_GSKPROTO_TLSV11_MASK        (1 << CURL_GSKPROTO_TLSV11)
#define CURL_GSKPROTO_TLSV12    4
#define CURL_GSKPROTO_TLSV12_MASK        (1 << CURL_GSKPROTO_TLSV12)
#define CURL_GSKPROTO_LAST      5


/* Supported ciphers. */
typedef struct {
  const char *name;            /* Cipher name. */
  const char *gsktoken;        /* Corresponding token for GSKit String. */
  unsigned int versions;       /* SSL version flags. */
}  gskit_cipher;

static const gskit_cipher  ciphertable[] = {
  { "null-md5",         "01",
      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
  { "null-sha",         "02",
      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
  { "exp-rc4-md5",      "03",
      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
  { "rc4-md5",          "04",
      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
  { "rc4-sha",          "05",
      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
  { "exp-rc2-cbc-md5",  "06",
      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
  { "exp-des-cbc-sha",  "09",
      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
      CURL_GSKPROTO_TLSV11_MASK },
  { "des-cbc3-sha",     "0A",
      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
  { "aes128-sha",       "2F",
      CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
      CURL_GSKPROTO_TLSV12_MASK },
  { "aes256-sha",       "35",
      CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
      CURL_GSKPROTO_TLSV12_MASK },
  { "null-sha256",      "3B",   CURL_GSKPROTO_TLSV12_MASK },
  { "aes128-sha256",    "3D",   CURL_GSKPROTO_TLSV12_MASK },
  { "aes256-sha256",    "3D",   CURL_GSKPROTO_TLSV12_MASK },
  { "rc4-md5",          "1",    CURL_GSKPROTO_SSLV2_MASK },
  { "exp-rc4-md5",      "2",    CURL_GSKPROTO_SSLV2_MASK },
  { "rc2-md5",          "3",    CURL_GSKPROTO_SSLV2_MASK },
  { "exp-rc2-md5",      "4",    CURL_GSKPROTO_SSLV2_MASK },
  { "des-cbc-md5",      "6",    CURL_GSKPROTO_SSLV2_MASK },
  { "des-cbc3-md5",     "7",    CURL_GSKPROTO_SSLV2_MASK },
  { (const char *) NULL, (const char *) NULL, 0       }
};


static bool is_separator(char c)
{
  /* Return whether character is a cipher list separator. */
  switch (c) {
  case ' ':
  case '\t':
  case ':':
  case ',':
  case ';':
    return true;
  }
  return false;
}


static CURLcode gskit_status(struct SessionHandle *data, int rc,
                             const char *procname, CURLcode defcode)
{
  CURLcode cc;

  /* Process GSKit status and map it to a CURLcode. */
  switch (rc) {
  case GSK_OK:
  case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
    return CURLE_OK;
  case GSK_KEYRING_OPEN_ERROR:
  case GSK_OS400_ERROR_NO_ACCESS:
    return CURLE_SSL_CACERT_BADFILE;
  case GSK_INSUFFICIENT_STORAGE:
    return CURLE_OUT_OF_MEMORY;
  case GSK_ERROR_BAD_V2_CIPHER:
  case GSK_ERROR_BAD_V3_CIPHER:
  case GSK_ERROR_NO_CIPHERS:
    return CURLE_SSL_CIPHER;
  case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
  case GSK_ERROR_CERT_VALIDATION:
    return CURLE_PEER_FAILED_VERIFICATION;
  case GSK_OS400_ERROR_TIMED_OUT:
    return CURLE_OPERATION_TIMEDOUT;
  case GSK_WOULD_BLOCK:
    return CURLE_AGAIN;
  case GSK_OS400_ERROR_NOT_REGISTERED:
    break;
  case GSK_ERROR_IO:
    switch (errno) {
    case ENOMEM:
      return CURLE_OUT_OF_MEMORY;
    default:
      failf(data, "%s I/O error: %s", procname, strerror(errno));
      break;
    }
    break;
Loading
Loading full blame…