diff -Naurp a/lib/config-os400.h b/lib/config-os400.h
--- a/lib/config-os400.h	2013-03-12 14:07:36.000000000 +0100
+++ b/lib/config-os400.h	2013-07-12 17:02:50.682677388 +0200
@@ -277,21 +277,27 @@
 /* Define if you have the <stdlib.h> header file. */
 #define HAVE_STDLIB_H
 
+
+/* The following define is needed on OS400 to enable strcmpi(), stricmp() and
+   strdup(). */
+#define __cplusplus__strings__
+
 /* Define if you have the `strcasecmp' function. */
 #undef HAVE_STRCASECMP
 
 /* Define if you have the `strcmpi' function. */
-#undef HAVE_STRCMPI
+#define HAVE_STRCMPI
+
+/* Define if you have the `stricmp' function. */
+#define HAVE_STRICMP
 
 /* Define if you have the `strdup' function. */
-#undef HAVE_STRDUP
+#define HAVE_STRDUP
+
 
 /* Define if you have the `strftime' function. */
 #define HAVE_STRFTIME
 
-/* Define if you have the `stricmp' function. */
-#undef HAVE_STRICMP
-
 /* Define if you have the <strings.h> header file. */
 #define HAVE_STRINGS_H
 
@@ -525,6 +531,9 @@
 /* Define to use the QsoSSL package. */
 #define USE_QSOSSL
 
+/* Define to use the GSKit package. */
+#undef USE_GSKIT
+
 /* Use the system keyring as the default CA bundle. */
 #define CURL_CA_BUNDLE  "/QIBM/UserData/ICSS/Cert/Server/DEFAULT.KDB"
 
diff -Naurp a/lib/cookie.c b/lib/cookie.c
--- a/lib/cookie.c	2013-07-09 11:59:59.888176495 +0200
+++ b/lib/cookie.c	2013-07-12 17:02:50.682677388 +0200
@@ -89,6 +89,7 @@ Example set of cookies:
 #include "strequal.h"
 #include "strtok.h"
 #include "sendf.h"
+#include "slist.h"
 #include "curl_memory.h"
 #include "share.h"
 #include "strtoofft.h"
@@ -1232,9 +1233,9 @@ struct curl_slist *Curl_cookie_list(stru
       curl_slist_free_all(list);
       return NULL;
     }
-    beg = curl_slist_append(list, line);
-    free(line);
+    beg = Curl_slist_append_nodup(list, line);
     if(!beg) {
+      free(line);
       curl_slist_free_all(list);
       return NULL;
     }
diff -Naurp a/lib/curl_setup.h b/lib/curl_setup.h
--- a/lib/curl_setup.h	2013-07-09 11:59:59.890176511 +0200
+++ b/lib/curl_setup.h	2013-07-12 17:02:50.682677388 +0200
@@ -617,7 +617,7 @@ int netware_init(void);
 #if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || \
     defined(USE_QSOSSL) || defined(USE_POLARSSL) || defined(USE_AXTLS) || \
     defined(USE_CYASSL) || defined(USE_SCHANNEL) || \
-    defined(USE_DARWINSSL)
+    defined(USE_DARWINSSL) || defined(USE_GSKIT)
 #define USE_SSL    /* SSL support has been enabled */
 #endif
 
diff -Naurp a/lib/gskit.c b/lib/gskit.c
--- a/lib/gskit.c	1970-01-01 01:00:00.000000000 +0100
+++ b/lib/gskit.c	2013-07-12 15:24:53.130309467 +0200
@@ -0,0 +1,897 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, 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
+#endif
+
+#ifdef HAVE_LIMITS_H
+#  include <limits.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "gskit.h"
+#include "sslgen.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"
+
+
+/* Supported ciphers. */
+typedef struct {
+  const char *  name;           /* Cipher name. */
+  const char *  gsktoken;       /* Corresponding token for GSKit String. */
+  int           sslver;         /* SSL version. */
+}  gskit_cipher;
+
+static const gskit_cipher  ciphertable[] = {
+  { "null-md5",         "01",   CURL_SSLVERSION_SSLv3 },
+  { "null-sha",         "02",   CURL_SSLVERSION_SSLv3 },
+  { "exp-rc4-md5",      "03",   CURL_SSLVERSION_SSLv3 },
+  { "rc4-md5",          "04",   CURL_SSLVERSION_SSLv3 },
+  { "rc4-sha",          "05",   CURL_SSLVERSION_SSLv3 },
+  { "exp-rc2-cbc-md5",  "06",   CURL_SSLVERSION_SSLv3 },
+  { "exp-des-cbc-sha",  "09",   CURL_SSLVERSION_SSLv3 },
+  { "des-cbc3-sha",     "0A",   CURL_SSLVERSION_SSLv3 },
+  { "aes128-sha",       "2F",   CURL_SSLVERSION_TLSv1 },
+  { "aes256-sha",       "35",   CURL_SSLVERSION_TLSv1 },
+  { "rc4-md5",          "1",    CURL_SSLVERSION_SSLv2 },
+  { "exp-rc4-md5",      "2",    CURL_SSLVERSION_SSLv2 },
+  { "rc2-md5",          "3",    CURL_SSLVERSION_SSLv2 },
+  { "exp-rc2-md5",      "4",    CURL_SSLVERSION_SSLv2 },
+  { "des-cbc-md5",      "6",    CURL_SSLVERSION_SSLv2 },
+  { "des-cbc3-md5",     "7",    CURL_SSLVERSION_SSLv2 },
+  { (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;
+  default:
+    failf(data, "%s: %s", procname, gsk_strerror(rc));
+    break;
+    }
+  return defcode;
+}
+
+
+static CURLcode set_enum(struct SessionHandle * data,
+                         gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value)
+{
+  int rc = gsk_attribute_set_enum(h, id, value);
+
+  switch (rc) {
+  case GSK_OK:
+    return CURLE_OK;
+  case GSK_ERROR_IO:
+    failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
+    break;
+  default:
+    failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
+    break;
+  }
+  return CURLE_SSL_CONNECT_ERROR;
+}
+
+
+static CURLcode set_buffer(struct SessionHandle * data,
+                           gsk_handle h, GSK_BUF_ID id, const char * buffer)
+{
+  int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
+
+  switch (rc) {
+  case GSK_OK:
+    return CURLE_OK;
+  case GSK_ERROR_IO:
+    failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
+    break;
+  default:
+    failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
+    break;
+  }
+  return CURLE_SSL_CONNECT_ERROR;
+}
+
+
+static CURLcode set_numeric(struct SessionHandle * data,
+                            gsk_handle h, GSK_NUM_ID id, int value)
+{
+  int rc = gsk_attribute_set_numeric_value(h, id, value);
+
+  switch (rc) {
+  case GSK_OK:
+    return CURLE_OK;
+  case GSK_ERROR_IO:
+    failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
+          strerror(errno));
+    break;
+  default:
+    failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
+    break;
+  }
+  return CURLE_SSL_CONNECT_ERROR;
+}
+
+
+static CURLcode set_callback(struct SessionHandle * data,
+                             gsk_handle h, GSK_CALLBACK_ID id, void * info)
+{
+  int rc = gsk_attribute_set_callback(h, id, info);
+
+  switch (rc) {
+  case GSK_OK:
+    return CURLE_OK;
+  case GSK_ERROR_IO:
+    failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
+    break;
+  default:
+    failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
+    break;
+  }
+  return CURLE_SSL_CONNECT_ERROR;
+}
+
+
+static CURLcode set_ciphers(struct SessionHandle * data, gsk_handle h)
+{
+  const char * cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
+  char * sslv2ciphers;
+  char * sslv3ciphers;
+  const char * clp;
+  const gskit_cipher * ctp;
+  char * v2p;
+  char * v3p;
+  int i;
+  CURLcode cc;
+
+  /* Compile cipher list into GSKit-compatible cipher lists. */
+
+  if(!cipherlist)
+    return CURLE_OK;
+  while (is_separator(*cipherlist))     /* Skip initial separators. */
+    cipherlist++;
+  if(!*cipherlist)
+    return CURLE_OK;
+
+  /* We allocate GSKit buffers of the same size as the input string: since
+     GSKit tokens are always shorter than their cipher names, allocated buffers
+     will always be large enough to accomodate the result. */
+  i = strlen(cipherlist) + 1;
+  if(!(v2p = malloc(i)))
+    return CURLE_OUT_OF_MEMORY;
+  if(!(v3p = malloc(i))) {
+    free(v2p);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  sslv2ciphers = v2p;
+  sslv3ciphers = v3p;
+
+  /* Process each cipher in input string. */
+  for (;;) {
+    for (clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
+      cipherlist++;
+    i = cipherlist - clp;
+    if(!i)
+      break;
+    /* Search the cipher in our table. */
+    for (ctp = ciphertable; ctp->name; ctp++)
+      if(strnequal(ctp->name, clp, i) && !ctp->name[i])
+        break;
+    if(!ctp->name)
+      failf(data, "Unknown cipher %.*s: ignored", i, clp);
+    else {
+      switch (ctp->sslver) {
+      case CURL_SSLVERSION_SSLv2:
+        strcpy(v2p, ctp->gsktoken);
+        v2p += strlen(v2p);
+        break;
+      default:
+        /* GSKit wants TLSv1 ciphers with SSLv3 ciphers. */
+        strcpy(v3p, ctp->gsktoken);
+        v3p += strlen(v3p);
+        break;
+      }
+    }
+
+   /* Advance to next cipher name or end of string. */
+    while (is_separator(*cipherlist))
+      cipherlist++;
+  }
+  *v2p = '\0';
+  *v3p = '\0';
+  if((cc = set_buffer(data, h, GSK_V2_CIPHER_SPECS, sslv2ciphers)) == CURLE_OK)
+    cc = set_buffer(data, h, GSK_V3_CIPHER_SPECS, sslv3ciphers);
+  free(sslv2ciphers);
+  free(sslv3ciphers);
+  return cc;
+}
+
+
+int Curl_gskit_init(void)
+{
+  /* No initialisation needed. */
+
+  return 1;
+}
+
+
+void Curl_gskit_cleanup(void)
+{
+  /* Nothing to do. */
+}
+
+
+static CURLcode init_environment(struct SessionHandle * data,
+                                 gsk_handle * envir, const char * appid,
+                                 const char * file, const char * label,
+                                 const char * password)
+{
+  int rc;
+  CURLcode c;
+  gsk_handle h;
+
+  /* Creates the GSKit environment. */
+
+  rc = gsk_environment_open(&h);
+  switch (rc) {
+  case GSK_OK:
+    break;
+  case GSK_INSUFFICIENT_STORAGE:
+    return CURLE_OUT_OF_MEMORY;
+  default:
+    failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if((c = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION)) != CURLE_OK)
+    ;
+  else if(appid && (c = set_buffer(data, h, GSK_OS400_APPLICATION_ID,
+                                   appid)) != CURLE_OK)
+    ;
+  else if(file && (c = set_buffer(data, h, GSK_KEYRING_FILE, file)) != CURLE_OK)
+    ;
+  else if(label && (c = set_buffer(data, h,
+                                   GSK_KEYRING_LABEL, label)) != CURLE_OK)
+    ;
+  else if(password && (c = set_buffer(data, h,
+                                      GSK_KEYRING_PW, password)) != CURLE_OK)
+    ;
+  else {
+    /* Locate CAs, Client certificate and key according to our settings.
+       Note: this call may be blocking for some tenths of seconds. */
+    c = gskit_status(data, gsk_environment_init(h),
+                     "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
+    if(c == CURLE_OK) {
+      *envir = h;
+      return c;
+    }
+  }
+  /* Error: rollback. */
+  gsk_environment_close(&h);
+  return c;
+}
+
+
+static void cancel_async_handshake(struct connectdata * conn, int sockindex)
+{
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+  Qso_OverlappedIO_t cstat;
+
+  if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
+    QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
+}
+
+
+static void close_async_handshake(struct ssl_connect_data * connssl)
+{
+  QsoDestroyIOCompletionPort(connssl->iocport);
+  connssl->iocport = -1;
+}
+
+
+static void close_one(struct ssl_connect_data * conn,
+                      struct SessionHandle * data)
+{
+  if(conn->handle) {
+    gskit_status(data, gsk_secure_soc_close(&conn->handle),
+              "gsk_secure_soc_close()", 0);
+    conn->handle = (gsk_handle) NULL;
+  }
+  if(conn->iocport >= 0)
+    close_async_handshake(conn);
+}
+
+
+static ssize_t gskit_send(struct connectdata * conn, int sockindex,
+                           const void * mem, size_t len, CURLcode * curlcode)
+{
+  struct SessionHandle * data = conn->data;
+  CURLcode cc;
+  int written;
+
+  cc = gskit_status(data,
+                    gsk_secure_soc_write(conn->ssl[sockindex].handle,
+                                         (char *) mem, (int) len, &written),
+                    "gsk_secure_soc_write()", CURLE_SEND_ERROR);
+  if(cc != CURLE_OK) {
+    *curlcode = cc;
+    written = -1;
+  }
+  return (ssize_t) written; /* number of bytes */
+}
+
+
+static ssize_t gskit_recv(struct connectdata * conn, int num, char * buf,
+                           size_t buffersize, CURLcode * curlcode)
+{
+  struct SessionHandle * data = conn->data;
+  int buffsize;
+  int nread;
+  CURLcode cc;
+
+  buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
+  cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
+                                              buf, buffsize, &nread),
+                    "gsk_secure_soc_read()", CURLE_RECV_ERROR);
+  if(cc != CURLE_OK) {
+    *curlcode = cc;
+    nread = -1;
+  }
+  return (ssize_t) nread;
+}
+
+
+static CURLcode gskit_connect_step1(struct connectdata * conn, int sockindex)
+{
+  struct SessionHandle * data = conn->data;
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+  gsk_handle envir;
+  CURLcode cc;
+  int rc;
+  char * keyringfile;
+  char * keyringpwd;
+  char * keyringlabel;
+  char * v2ciphers;
+  char * v3ciphers;
+  char * sni;
+  bool sslv2enable, sslv3enable, tlsv1enable;
+  long timeout;
+  Qso_OverlappedIO_t commarea;
+
+  /* Create SSL environment, start (preferably asynchronous) handshake. */
+
+  connssl->handle = (gsk_handle) NULL;
+  connssl->iocport = -1;
+
+  /* GSKit supports two ways of specifying an SSL context: either by application
+   *  identifier (that should have been defined at the system level) or by
+   *  keyring file, password and certificate label.
+   * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
+   *  application identifier of the certificate label.
+   * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
+   * It is not possible to have different keyrings for the CAs and the
+   *  local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
+   *  the keyring file.
+   * If no key password is given and the keyring is the system keyring,
+   *  application identifier mode is tried first, as recommended in IBM doc.
+   */
+
+  keyringfile = data->set.str[STRING_SSL_CAFILE];
+  keyringpwd = data->set.str[STRING_KEY_PASSWD];
+  keyringlabel = data->set.str[STRING_CERT];
+  envir = (gsk_handle) NULL;
+
+  if(keyringlabel && *keyringlabel && !keyringpwd &&
+      !strcmp(keyringfile, CURL_CA_BUNDLE)) {
+    /* Try application identifier mode. */
+    init_environment(data, &envir, keyringlabel, (const char *) NULL,
+                     (const char *) NULL, (const char *) NULL);
+  }
+
+  if(!envir) {
+    /* Use keyring mode. */
+    cc = init_environment(data, &envir, (const char *) NULL,
+                          keyringfile, keyringlabel, keyringpwd);
+    if(cc != CURLE_OK)
+      return cc;
+  }
+
+  /* Create secure session. */
+  cc = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
+                    "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
+  gsk_environment_close(&envir);
+  if(cc != CURLE_OK)
+    return cc;
+
+  /* Determine which SSL/TLS version should be enabled. */
+  sslv2enable = sslv3enable = tlsv1enable = false;
+  sni = conn->host.name;
+  switch (data->set.ssl.version) {
+  case CURL_SSLVERSION_SSLv2:
+    sslv2enable = true;
+    sni = (char *) NULL;
+    break;
+  case CURL_SSLVERSION_SSLv3:
+    sslv3enable = true;
+    sni = (char *) NULL;
+    break;
+  case CURL_SSLVERSION_TLSv1:
+    tlsv1enable = true;
+    break;
+  default:              /* CURL_SSLVERSION_DEFAULT. */
+    sslv3enable = true;
+    tlsv1enable = true;
+    break;
+  }
+
+  /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
+  if(sni) {
+    rc = gsk_attribute_set_buffer(connssl->handle,
+                                  GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, 0);
+    switch (rc) {
+    case GSK_OK:
+    case GSK_ATTRIBUTE_INVALID_ID:
+      break;
+    case GSK_ERROR_IO:
+      failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
+      cc = CURLE_SSL_CONNECT_ERROR;
+      break;
+    default:
+      failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
+      cc = CURLE_SSL_CONNECT_ERROR;
+      break;
+    }
+  }
+
+  /* Compute the handshake timeout. Since GSKit granularity is 1 second,
+     we round up the required value. */
+  timeout = Curl_timeleft(data, NULL, TRUE);
+
+  /* Set session parameters. */
+  if(cc != CURLE_OK)
+    ;
+  else if(timeout < 0)
+    cc = CURLE_OPERATION_TIMEDOUT;
+  else if((cc = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
+                            (timeout + 999) / 1000)) != CURLE_OK)
+    ;
+  else if((cc = set_numeric(data, connssl->handle,
+                       GSK_FD, conn->sock[sockindex])) != CURLE_OK)
+    ;
+  else if((cc = set_ciphers(data, connssl->handle)) != CURLE_OK)
+    ;
+  else if((cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2, sslv2enable?
+           GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF)) != CURLE_OK)
+    ;
+  else if((cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3, sslv3enable?
+           GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF)) != CURLE_OK)
+    ;
+  else if((cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1, sslv3enable?
+           GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF)) != CURLE_OK)
+    ;
+  else if((cc = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
+           data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL:
+           GSK_SERVER_AUTH_PASSTHRU)) != CURLE_OK)
+    ;
+  else {
+    /* Start handshake. Try asynchronous first. */
+    memset(&commarea, 0, sizeof commarea);
+    if((connssl->iocport = QsoCreateIOCompletionPort()) != -1) {
+      cc = gskit_status(data, gsk_secure_soc_startInit(connssl->handle,
+                        connssl->iocport, &commarea),
+                        "gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR);
+      if(cc == CURLE_OK) {
+        connssl->connecting_state = ssl_connect_2;
+        return CURLE_OK;
+      }
+      else
+        close_async_handshake(connssl);
+    }
+    else if(errno != ENOBUFS)
+      cc = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0);
+    else {
+      /* No more completion port available. Use synchronous IO. */
+      cc = gskit_status(data, gsk_secure_soc_init(connssl->handle),
+                       "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
+      if(cc == CURLE_OK) {
+        connssl->connecting_state = ssl_connect_3;
+        return CURLE_OK;
+      }
+    }
+  }
+  /* Error: rollback. */
+  close_one(connssl, data);
+  return cc;
+}
+
+
+static CURLcode gskit_connect_step2(struct connectdata * conn, int sockindex,
+                                    bool nonblocking)
+{
+  struct SessionHandle * data = conn->data;
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+  Qso_OverlappedIO_t cstat;
+  long timeout_ms;
+  struct timeval stmv;
+  CURLcode cc;
+
+  /* Poll or wait for end of SSL asynchronous handshake. */
+
+  for (;;) {
+    timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
+    if(timeout_ms < 0)
+      timeout_ms = 0;
+    stmv.tv_sec = timeout_ms / 1000;
+    stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
+    switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
+    case 1:             /* Operation complete. */
+      break;
+    case -1:            /* An error occurred: handshake still in progress. */
+      if(errno == EINTR) {
+        if(nonblocking)
+          return CURLE_OK;
+        continue;       /* Retry. */
+      }
+      if(errno != ETIME) {
+        failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
+        cancel_async_handshake(conn, sockindex);
+        close_async_handshake(connssl);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      /* FALL INTO... */
+    case 0:             /* Handshake in progress, timeout occurred. */
+      if(nonblocking)
+        return CURLE_OK;
+      cancel_async_handshake(conn, sockindex);
+      close_async_handshake(connssl);
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+    break;
+  }
+  if((cc = gskit_status(data, cstat.returnValue,
+      "SSL handshake", CURLE_SSL_CONNECT_ERROR)) == CURLE_OK)
+    connssl->connecting_state = ssl_connect_3;
+  close_async_handshake(connssl);
+  return cc;
+}
+
+
+static CURLcode gskit_connect_step3(struct connectdata * conn, int sockindex)
+{
+  struct SessionHandle * data = conn->data;
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+  const gsk_cert_data_elem * cdev;
+  int cdec;
+  const gsk_cert_data_elem * p;
+  const char * cert = (const char *) NULL;
+  const char * certend;
+  X509certificate x509cert;
+  int i;
+  CURLcode cc;
+
+  /* SSL handshake done: gather certificate info and verify host. */
+
+  if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
+                                                    GSK_PARTNER_CERT_INFO,
+                                                    &cdev, &cdec),
+                  "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
+     CURLE_OK) {
+    infof(data, "Server certificate:\n");
+    p = cdev;
+    for (i = 0; i++ < cdec; p++)
+      switch (p->cert_data_id) {
+      case CERT_BODY_DER:
+        cert = p->cert_data_p;
+        certend = cert + cdev->cert_data_l;
+        break;
+      case CERT_DN_PRINTABLE:
+        infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
+        break;
+      case CERT_ISSUER_DN_PRINTABLE:
+        infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
+        break;
+      case CERT_VALID_FROM:
+        infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
+        break;
+      case CERT_VALID_TO:
+        infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
+        break;
+    }
+  }
+
+  /* Verify host. */
+  if((cc = Curl_verifyhost(conn, cert, certend)) != CURLE_OK)
+    return cc;
+
+  /* The only place GSKit can get the whole CA chain is a validation
+     callback where no user data pointer is available. Therefore it's not
+     possible to copy this chain into our structures for CAINFO.
+     However the server certificate may be available, thus we can return
+     info about it. */
+  if(data->set.ssl.certinfo) {
+    if(Curl_ssl_init_certinfo(data, 1))
+      return CURLE_OUT_OF_MEMORY;
+    if(cert && (cc = Curl_extract_certinfo(conn, 0, cert, certend)) != CURLE_OK)
+      return cc;
+  }
+
+  connssl->connecting_state = ssl_connect_done;
+  return CURLE_OK;
+}
+
+
+static CURLcode gskit_connect_common(struct connectdata * conn, int sockindex,
+                                     bool nonblocking, bool * done)
+{
+  struct SessionHandle * data = conn->data;
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+  long timeout_ms;
+  Qso_OverlappedIO_t cstat;
+  CURLcode cc = CURLE_OK;
+
+  if((*done = connssl->state == ssl_connection_complete))
+    return CURLE_OK;
+
+  /* Step 1: create session, start handshake. */
+  if(connssl->connecting_state == ssl_connect_1) {
+    /* check allowed time left */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      cc = CURLE_OPERATION_TIMEDOUT;
+    }
+    else
+      cc = gskit_connect_step1(conn, sockindex);
+  }
+
+  /* Step 2: check if handshake is over. */
+  if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_2) {
+    /* check allowed time left */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      cc = CURLE_OPERATION_TIMEDOUT;
+    }
+    else
+      cc = gskit_connect_step2(conn, sockindex, nonblocking);
+  }
+
+  /* Step 3: gather certificate info, verify host. */
+  if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_3)
+    cc = gskit_connect_step3(conn, sockindex);
+
+  if(cc != CURLE_OK)
+    close_one(connssl, data);
+  else if(connssl->connecting_state == ssl_connect_done) {
+    connssl->state = ssl_connection_complete;
+    connssl->connecting_state = ssl_connect_1;
+    conn->recv[sockindex] = gskit_recv;
+    conn->send[sockindex] = gskit_send;
+    *done = TRUE;
+  }
+
+  return cc;
+}
+
+
+CURLcode Curl_gskit_connect_nonblocking(struct connectdata * conn,
+                                        int sockindex,
+                                        bool * done)
+{
+  CURLcode cc;
+
+  cc = gskit_connect_common(conn, sockindex, TRUE, done);
+  if(*done || cc != CURLE_OK)
+    conn->ssl[sockindex].connecting_state = ssl_connect_1;
+  return cc;
+}
+
+
+CURLcode Curl_gskit_connect(struct connectdata * conn, int sockindex)
+{
+  CURLcode retcode;
+  bool done;
+
+  conn->ssl[sockindex].connecting_state = ssl_connect_1;
+  retcode = gskit_connect_common(conn, sockindex, FALSE, &done);
+  if(retcode)
+    return retcode;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+
+void Curl_gskit_close(struct connectdata * conn, int sockindex)
+{
+  struct SessionHandle * data = conn->data;
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+
+  if(connssl->use)
+    close_one(connssl, data);
+}
+
+
+int Curl_gskit_close_all(struct SessionHandle * data)
+{
+  /* Unimplemented. */
+  (void) data;
+  return 0;
+}
+
+
+int Curl_gskit_shutdown(struct connectdata * conn, int sockindex)
+{
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+  struct SessionHandle * data = conn->data;
+  ssize_t nread;
+  int what;
+  int rc;
+  char buf[120];
+
+  if(!connssl->handle)
+    return 0;
+
+  if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
+    return 0;
+
+  close_one(connssl, data);
+  rc = 0;
+  what = Curl_socket_ready(conn->sock[sockindex],
+                           CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
+
+  for (;;) {
+    if(what < 0) {
+      /* anything that gets here is fatally bad */
+      failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+      rc = -1;
+      break;
+    }
+
+    if(!what) {                                /* timeout */
+      failf(data, "SSL shutdown timeout");
+      break;
+    }
+
+    /* Something to read, let's do it and hope that it is the close
+       notify alert from the server. No way to gsk_secure_soc_read() now, so use
+       read(). */
+
+    nread = read(conn->sock[sockindex], buf, sizeof(buf));
+
+    if(nread < 0) {
+      failf(data, "read: %s", strerror(errno));
+      rc = -1;
+    }
+
+    if(nread <= 0)
+      break;
+
+    what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
+  }
+
+  return rc;
+}
+
+
+size_t Curl_gskit_version(char * buffer, size_t size)
+{
+  strncpy(buffer, "GSKit", size);
+  return strlen(buffer);
+}
+
+
+int Curl_gskit_check_cxn(struct connectdata * cxn)
+{
+  int err;
+  int errlen;
+
+  /* The only thing that can be tested here is at the socket level. */
+
+  if(!cxn->ssl[FIRSTSOCKET].handle)
+    return 0; /* connection has been closed */
+
+  err = 0;
+  errlen = sizeof err;
+
+  if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
+                 (unsigned char *) &err, &errlen) ||
+     errlen != sizeof err || err)
+    return 0; /* connection has been closed */
+
+  return -1;  /* connection status unknown */
+}
+
+#endif /* USE_GSKIT */
diff -Naurp a/lib/gskit.h b/lib/gskit.h
--- a/lib/gskit.h	1970-01-01 01:00:00.000000000 +0100
+++ b/lib/gskit.h	2013-03-19 17:26:13.000000000 +0100
@@ -0,0 +1,64 @@
+#ifndef HEADER_CURL_GSKIT_H
+#define HEADER_CURL_GSKIT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, 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"
+
+/*
+ * This header should only be needed to get included by sslgen.c and gskit.c
+ */
+
+#include "urldata.h"
+
+#ifdef USE_GSKIT
+int Curl_gskit_init(void);
+void Curl_gskit_cleanup(void);
+CURLcode Curl_gskit_connect(struct connectdata * conn, int sockindex);
+CURLcode Curl_gskit_connect_nonblocking(struct connectdata * conn,
+                                        int sockindex, bool * done);
+void Curl_gskit_close(struct connectdata *conn, int sockindex);
+int Curl_gskit_close_all(struct SessionHandle * data);
+int Curl_gskit_shutdown(struct connectdata * conn, int sockindex);
+
+size_t Curl_gskit_version(char * buffer, size_t size);
+int Curl_gskit_check_cxn(struct connectdata * cxn);
+
+/* API setup for GSKit */
+#define curlssl_init Curl_gskit_init
+#define curlssl_cleanup Curl_gskit_cleanup
+#define curlssl_connect Curl_gskit_connect
+#define curlssl_connect_nonblocking Curl_gskit_connect_nonblocking
+
+/*  No session handling for GSKit */
+#define curlssl_session_free(x) Curl_nop_stmt
+#define curlssl_close_all Curl_gskit_close_all
+#define curlssl_close Curl_gskit_close
+#define curlssl_shutdown(x,y) Curl_gskit_shutdown(x,y)
+#define curlssl_set_engine(x,y) CURLE_NOT_BUILT_IN
+#define curlssl_set_engine_default(x) CURLE_NOT_BUILT_IN
+#define curlssl_engines_list(x) NULL
+#define curlssl_version Curl_gskit_version
+#define curlssl_check_cxn(x) Curl_gskit_check_cxn(x)
+#define curlssl_data_pending(x,y) 0
+#endif /* USE_GSKIT */
+
+#endif /* HEADER_CURL_GSKIT_H */
diff -Naurp a/lib/hostcheck.c b/lib/hostcheck.c
--- a/lib/hostcheck.c	2013-03-12 14:07:36.000000000 +0100
+++ b/lib/hostcheck.c	2013-07-12 17:02:50.683677396 +0200
@@ -22,8 +22,9 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_SSLEAY) || defined(USE_AXTLS)
-/* these two backends use functions from this file */
+#if defined(USE_SSLEAY) || defined(USE_AXTLS) || defined(USE_GSKIT) || \
+    defined(USE_QSOSSL)
+/* these three backends use functions from this file */
 
 #include "hostcheck.h"
 #include "rawstr.h"
@@ -93,4 +94,4 @@ int Curl_cert_hostcheck(const char *matc
   return 0;
 }
 
-#endif /* SSLEAY or AXTLS */
+#endif /* SSLEAY or AXTLS or GSKIT or QSOSSL */
diff -Naurp a/lib/Makefile.inc b/lib/Makefile.inc
--- a/lib/Makefile.inc	2013-07-09 11:59:59.886176478 +0200
+++ b/lib/Makefile.inc	2013-07-12 17:02:50.682677388 +0200
@@ -25,7 +25,8 @@ CSOURCES = file.c timeval.c base64.c hos
   http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c	\
   curl_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_ntlm_msgs.c		\
   curl_sasl.c curl_schannel.c curl_multibyte.c curl_darwinssl.c		\
-  hostcheck.c bundles.c conncache.c pipeline.c dotdot.c
+  hostcheck.c bundles.c conncache.c pipeline.c dotdot.c x509asn1.c      \
+  gskit.c
 
 HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h	\
   progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h	\
@@ -44,4 +45,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h
   asyn.h curl_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h	\
   curl_ntlm_msgs.h curl_sasl.h curl_schannel.h curl_multibyte.h		\
   curl_darwinssl.h hostcheck.h bundles.h conncache.h curl_setup_once.h	\
-  multihandle.h setup-vms.h pipeline.h dotdot.h
+  multihandle.h setup-vms.h pipeline.h dotdot.h x509asn1.h gskit.h
diff -Naurp a/lib/qssl.c b/lib/qssl.c
--- a/lib/qssl.c	2013-03-12 14:07:36.000000000 +0100
+++ b/lib/qssl.c	2013-07-12 17:02:50.683677396 +0200
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, 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
@@ -37,6 +37,7 @@
 #include "sslgen.h"
 #include "connect.h" /* for the connect timeout */
 #include "select.h"
+#include "x509asn1.h"
 #include "curl_memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -169,10 +170,7 @@ static CURLcode Curl_qsossl_handshake(st
   SSLHandle * h = connssl->handle;
   long timeout_ms;
 
-  h->exitPgm = NULL;
-
-  if(!data->set.ssl.verifyhost)
-    h->exitPgm = Curl_qsossl_trap_cert;
+  h->exitPgm = data->set.ssl.verifypeer? Curl_qsossl_trap_cert: NULL;
 
   /* figure out how long time we should wait at maximum */
   timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -208,6 +206,8 @@ static CURLcode Curl_qsossl_handshake(st
     break;
   }
 
+  h->peerCert = NULL;
+  h->peerCertLen = 0;
   rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT);
 
   switch (rc) {
@@ -238,6 +238,20 @@ static CURLcode Curl_qsossl_handshake(st
     return CURLE_SSL_CONNECT_ERROR;
   }
 
+  /* Verify host. */
+  rc = Curl_verifyhost(conn, h->peerCert, h->peerCert + h->peerCertLen);
+  if(rc != CURLE_OK)
+    return rc;
+
+  /* Gather certificate info. */
+  if(data->set.ssl.certinfo) {
+    if(Curl_ssl_init_certinfo(data, 1))
+      return CURLE_OUT_OF_MEMORY;
+    if(h->peerCert && (rc = Curl_extract_certinfo(conn, 0, h->peerCert,
+                       h->peerCert + h->peerCertLen)) != CURLE_OK)
+      return rc;
+  }
+
   return CURLE_OK;
 }
 
@@ -259,8 +273,10 @@ CURLcode Curl_qsossl_connect(struct conn
 
     if(rc == CURLE_OK)
       rc = Curl_qsossl_handshake(conn, sockindex);
-    else {
+    else
       SSL_Destroy(connssl->handle);
+
+    if(rc != CURLE_OK) {
       connssl->handle = NULL;
       connssl->use = FALSE;
       connssl->state = ssl_connection_none;
diff -Naurp a/lib/setup-os400.h b/lib/setup-os400.h
--- a/lib/setup-os400.h	2010-05-31 17:16:29.000000000 +0200
+++ b/lib/setup-os400.h	2013-07-12 17:02:50.683677396 +0200
@@ -38,6 +38,8 @@ typedef unsigned long   u_int32_t;
 #include <sys/socket.h>
 #include <netdb.h>
 #include <qsossl.h>
+#include <gskssl.h>
+#include <qsoasync.h>
 #include <gssapi.h>
 
 extern int      Curl_getaddrinfo_a(const char * nodename, const char * servname,
@@ -68,6 +70,93 @@ extern char *   Curl_SSL_Strerror_a(int
 #define SSL_Strerror            Curl_SSL_Strerror_a
 
 
+/* GSKit wrappers. */
+
+extern int      Curl_gsk_environment_open(gsk_handle * my_env_handle);
+#define gsk_environment_open    Curl_gsk_environment_open
+
+extern int      Curl_gsk_secure_soc_open(gsk_handle my_env_handle,
+                                         gsk_handle * my_session_handle);
+#define gsk_secure_soc_open     Curl_gsk_secure_soc_open
+
+extern int      Curl_gsk_environment_close(gsk_handle * my_env_handle);
+#define gsk_environment_close   Curl_gsk_environment_close
+
+extern int      Curl_gsk_secure_soc_close(gsk_handle * my_session_handle);
+#define gsk_secure_soc_close    Curl_gsk_secure_soc_close
+
+extern int      Curl_gsk_environment_init(gsk_handle my_env_handle);
+#define gsk_environment_init    Curl_gsk_environment_init
+
+extern int      Curl_gsk_secure_soc_init(gsk_handle my_session_handle);
+#define gsk_secure_soc_init     Curl_gsk_secure_soc_init
+
+extern int      Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle,
+                                                GSK_BUF_ID bufID,
+                                                const char * buffer,
+                                                int bufSize);
+#define gsk_attribute_set_buffer        Curl_gsk_attribute_set_buffer_a
+
+extern int      Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle,
+                                            GSK_ENUM_ID enumID,
+                                            GSK_ENUM_VALUE enumValue);
+#define gsk_attribute_set_enum  Curl_gsk_attribute_set_enum
+
+extern int      Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle,
+                                                     GSK_NUM_ID numID,
+                                                     int numValue);
+#define gsk_attribute_set_numeric_value Curl_gsk_attribute_set_numeric_value
+
+extern int      Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle,
+                                                GSK_CALLBACK_ID callBackID,
+                                                void * callBackAreaPtr);
+#define gsk_attribute_set_callback      Curl_gsk_attribute_set_callback
+
+extern int      Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle,
+                                                GSK_BUF_ID bufID,
+                                                const char * * buffer,
+                                                int * bufSize);
+#define gsk_attribute_get_buffer        Curl_gsk_attribute_get_buffer_a
+
+extern int      Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle,
+                                            GSK_ENUM_ID enumID,
+                                            GSK_ENUM_VALUE * enumValue);
+#define gsk_attribute_get_enum  Curl_gsk_attribute_get_enum
+
+extern int      Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle,
+                                                     GSK_NUM_ID numID,
+                                                     int * numValue);
+#define gsk_attribute_get_numeric_value Curl_gsk_attribute_get_numeric_value
+
+extern int      Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle,
+                                 GSK_CERT_ID certID,
+                                 const gsk_cert_data_elem * * certDataElem,
+                                 int * certDataElementCount);
+#define gsk_attribute_get_cert_info     Curl_gsk_attribute_get_cert_info
+
+extern int      Curl_gsk_secure_soc_misc(gsk_handle my_session_handle,
+                                         GSK_MISC_ID miscID);
+#define gsk_secure_soc_misc     Curl_gsk_secure_soc_misc
+
+extern int      Curl_gsk_secure_soc_read(gsk_handle my_session_handle,
+                                         char * readBuffer,
+                                         int readBufSize, int * amtRead);
+#define gsk_secure_soc_read     Curl_gsk_secure_soc_read
+
+extern int      Curl_gsk_secure_soc_write(gsk_handle my_session_handle,
+                                          char * writeBuffer,
+                                          int writeBufSize, int * amtWritten);
+#define gsk_secure_soc_write    Curl_gsk_secure_soc_write
+
+extern const char *     Curl_gsk_strerror_a(int gsk_return_value);
+#define gsk_strerror    Curl_gsk_strerror_a
+
+extern int      Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle,
+                                      int IOCompletionPort,
+                                      Qso_OverlappedIO_t * communicationsArea);
+#define gsk_secure_soc_startInit        Curl_gsk_secure_soc_startInit
+
+
 /* GSSAPI wrappers. */
 
 extern OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status,
@@ -107,6 +196,7 @@ extern OM_uint32 Curl_gss_delete_sec_con
                                                gss_buffer_t output_token);
 #define gss_delete_sec_context  Curl_gss_delete_sec_context_a
 
+
 /* LDAP wrappers. */
 
 #define BerValue                struct berval
diff -Naurp a/lib/slist.c b/lib/slist.c
--- a/lib/slist.c	2013-03-12 14:07:36.000000000 +0100
+++ b/lib/slist.c	2013-07-12 17:02:50.683677396 +0200
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, 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
@@ -46,6 +46,38 @@ static struct curl_slist *slist_get_last
 }
 
 /*
+ * Curl_slist_append_nodup() appends a string to the linked list. Rather than
+ * copying the string in dynamic storage, it takes its ownership. The string
+ * should have been malloc()ated. Curl_slist_append_nodup always returns
+ * the address of the first record, so that you can use this function as an
+ * initialization function as well as an append function.
+ * If an error occurs, NULL is returned and the string argument is NOT released.
+ */
+struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data)
+{
+  struct curl_slist     *last;
+  struct curl_slist     *new_item;
+
+  if(!data)
+    return NULL;
+
+  new_item = malloc(sizeof(struct curl_slist));
+  if(!new_item)
+    return NULL;
+
+  new_item->next = NULL;
+  new_item->data = data;
+
+  /* if this is the first item, then new_item *is* the list */
+  if(!list)
+    return new_item;
+
+  last = slist_get_last(list);
+  last->next = new_item;
+  return list;
+}
+
+/*
  * curl_slist_append() appends a string to the linked list. It always returns
  * the address of the first record, so that you can use this function as an
  * initialization function as well as an append function. If you find this
@@ -55,32 +87,16 @@ static struct curl_slist *slist_get_last
 struct curl_slist *curl_slist_append(struct curl_slist *list,
                                      const char *data)
 {
-  struct curl_slist     *last;
-  struct curl_slist     *new_item;
+  char *dupdata = strdup(data);
 
-  new_item = malloc(sizeof(struct curl_slist));
-  if(new_item) {
-    char *dupdata = strdup(data);
-    if(dupdata) {
-      new_item->next = NULL;
-      new_item->data = dupdata;
-    }
-    else {
-      free(new_item);
-      return NULL;
-    }
-  }
-  else
+  if(!data)
     return NULL;
 
-  if(list) {
-    last = slist_get_last(list);
-    last->next = new_item;
-    return list;
-  }
+  list = Curl_slist_append_nodup(list, dupdata);
+  if(!list)
+    free(dupdata);
 
-  /* if this is the first item, then new_item *is* the list */
-  return new_item;
+  return list;
 }
 
 /*
diff -Naurp a/lib/slist.h b/lib/slist.h
--- a/lib/slist.h	2013-03-12 14:07:36.000000000 +0100
+++ b/lib/slist.h	2013-07-12 17:02:50.683677396 +0200
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, 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
@@ -29,5 +29,11 @@
  */
 struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist);
 
+/*
+ * Curl_slist_append_nodup() takes ownership of the given string and appends
+ * it to the list.
+ */
+struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data);
+
 #endif /* HEADER_CURL_SLIST_H */
 
diff -Naurp a/lib/sslgen.c b/lib/sslgen.c
--- a/lib/sslgen.c	2013-07-09 11:59:59.897176567 +0200
+++ b/lib/sslgen.c	2013-07-12 17:02:50.683677396 +0200
@@ -31,6 +31,8 @@
    Curl_ossl_ - prefix for OpenSSL ones
    Curl_gtls_ - prefix for GnuTLS ones
    Curl_nss_ - prefix for NSS ones
+   Curl_qssl_ - prefix for QsoSSL ones
+   Curl_gskit_ - prefix for GSKit ones
    Curl_polarssl_ - prefix for PolarSSL ones
    Curl_cyassl_ - prefix for CyaSSL ones
    Curl_schannel_ - prefix for Schannel SSPI ones
@@ -62,11 +64,13 @@
 #include "gtls.h"   /* GnuTLS versions */
 #include "nssg.h"   /* NSS versions */
 #include "qssl.h"   /* QSOSSL versions */
+#include "gskit.h"  /* Global Secure ToolKit versions */
 #include "polarssl.h" /* PolarSSL versions */
 #include "axtls.h"  /* axTLS versions */
 #include "cyassl.h"  /* CyaSSL versions */
 #include "curl_schannel.h" /* Schannel SSPI version */
 #include "curl_darwinssl.h" /* SecureTransport (Darwin) version */
+#include "slist.h"
 #include "sendf.h"
 #include "rawstr.h"
 #include "url.h"
@@ -74,6 +78,10 @@
 #include "progress.h"
 #include "share.h"
 #include "timeval.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -586,6 +594,65 @@ void Curl_ssl_free_certinfo(struct Sessi
   }
 }
 
+int Curl_ssl_init_certinfo(struct SessionHandle * data,
+                           int num)
+{
+  struct curl_certinfo * ci = &data->info.certs;
+  struct curl_slist * * table;
+
+  /* Initialize the certificate information structures. Return 0 if OK, else 1.
+   */
+  Curl_ssl_free_certinfo(data);
+  ci->num_of_certs = num;
+  table = calloc((size_t) num, sizeof(struct curl_slist *));
+  if(!table)
+    return 1;
+
+  ci->certinfo = table;
+  return 0;
+}
+
+CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data,
+                                    int certnum,
+                                    const char *label,
+                                    const char *value,
+                                    size_t valuelen)
+{
+  struct curl_certinfo * ci = &data->info.certs;
+  char * output;
+  struct curl_slist * nl;
+  CURLcode res = CURLE_OK;
+
+  /* Add an information record for a particular certificate. */
+  output = curl_maprintf("%s:%.*s", label, valuelen, value);
+  if(!output)
+    return CURLE_OUT_OF_MEMORY;
+
+  nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
+  if(!nl) {
+    free(output);
+    curl_slist_free_all(ci->certinfo[certnum]);
+    res = CURLE_OUT_OF_MEMORY;
+  }
+
+  ci->certinfo[certnum] = nl;
+  return res;
+}
+
+/*
+ * This is a convenience function for push_certinfo_len that takes a zero
+ * terminated value.
+ */
+CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data,
+                                int certnum,
+                                const char *label,
+                                const char *value)
+{
+  size_t valuelen = strlen(value);
+
+  return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
+}
+
 /* these functions are only provided by some SSL backends */
 
 #ifdef have_curlssl_random
diff -Naurp a/lib/sslgen.h b/lib/sslgen.h
--- a/lib/sslgen.h	2013-07-09 11:59:59.897176567 +0200
+++ b/lib/sslgen.h	2013-07-12 17:02:50.683677396 +0200
@@ -58,7 +58,16 @@ size_t Curl_ssl_version(char *buffer, si
 bool Curl_ssl_data_pending(const struct connectdata *conn,
                            int connindex);
 int Curl_ssl_check_cxn(struct connectdata *conn);
+
+/* Certificate information list handling. */
+
 void Curl_ssl_free_certinfo(struct SessionHandle *data);
+int Curl_ssl_init_certinfo(struct SessionHandle * data, int num);
+CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle * data, int certnum,
+                                    const char * label, const char * value,
+                                    size_t valuelen);
+CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum,
+                                const char * label, const char * value);
 
 /* Functions to be used by SSL library adaptation functions */
 
diff -Naurp a/lib/ssluse.c b/lib/ssluse.c
--- a/lib/ssluse.c	2013-07-09 11:59:59.898176574 +0200
+++ b/lib/ssluse.c	2013-07-12 17:02:50.684677405 +0200
@@ -43,6 +43,7 @@
 #include "inet_pton.h"
 #include "ssluse.h"
 #include "connect.h"
+#include "slist.h"
 #include "strequal.h"
 #include "select.h"
 #include "sslgen.h"
@@ -1790,60 +1791,6 @@ static int asn1_object_dump(ASN1_OBJECT
   return 0;
 }
 
-static CURLcode push_certinfo_len(struct SessionHandle *data,
-                                  int certnum,
-                                  const char *label,
-                                  const char *value,
-                                  size_t valuelen)
-{
-  struct curl_certinfo *ci = &data->info.certs;
-  char *output;
-  struct curl_slist *nl;
-  CURLcode res = CURLE_OK;
-  size_t labellen = strlen(label);
-  size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
-
-  output = malloc(outlen);
-  if(!output)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* sprintf the label and colon */
-  snprintf(output, outlen, "%s:", label);
-
-  /* memcpy the value (it might not be zero terminated) */
-  memcpy(&output[labellen+1], value, valuelen);
-
-  /* zero terminate the output */
-  output[labellen + 1 + valuelen] = 0;
-
-  /* TODO: we should rather introduce an internal API that can do the
-     equivalent of curl_slist_append but doesn't strdup() the given data as
-     like in this place the extra malloc/free is totally pointless */
-  nl = curl_slist_append(ci->certinfo[certnum], output);
-  free(output);
-  if(!nl) {
-    curl_slist_free_all(ci->certinfo[certnum]);
-    ci->certinfo[certnum] = NULL;
-    res = CURLE_OUT_OF_MEMORY;
-  }
-  else
-    ci->certinfo[certnum] = nl;
-
-  return res;
-}
-
-/* this is a convenience function for push_certinfo_len that takes a zero
-   terminated value */
-static CURLcode push_certinfo(struct SessionHandle *data,
-                              int certnum,
-                              const char *label,
-                              const char *value)
-{
-  size_t valuelen = strlen(value);
-
-  return push_certinfo_len(data, certnum, label, value, valuelen);
-}
-
 static void pubkey_show(struct SessionHandle *data,
                         int num,
                         const char *type,
@@ -1867,7 +1814,7 @@ static void pubkey_show(struct SessionHa
       left -= 3;
     }
     infof(data, "   %s: %s\n", namebuf, buffer);
-    push_certinfo(data, num, namebuf, buffer);
+    Curl_ssl_push_certinfo(data, num, namebuf, buffer);
     free(buffer);
   }
 }
@@ -1936,7 +1883,7 @@ static int X509V3_ext(struct SessionHand
     }
     infof(data, "  %s\n", buf);
 
-    push_certinfo(data, certnum, namebuf, buf);
+    Curl_ssl_push_certinfo(data, certnum, namebuf, buf);
 
     BIO_free(bio_out);
 
@@ -1956,7 +1903,7 @@ static void X509_signature(struct Sessio
     ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]);
 
   infof(data, " Signature: %s\n", buf);
-  push_certinfo(data, numcert, "Signature", buf);
+  Curl_ssl_push_certinfo(data, numcert, "Signature", buf);
 }
 
 static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)
@@ -1972,30 +1919,13 @@ static void dumpcert(struct SessionHandl
 
   infof(data, "%s\n", biomem->data);
 
-  push_certinfo_len(data, numcert, "Cert", biomem->data, biomem->length);
+  Curl_ssl_push_certinfo_len(data, numcert,
+                             "Cert", biomem->data, biomem->length);
 
   BIO_free(bio_out);
 
 }
 
-
-static int init_certinfo(struct SessionHandle *data,
-                         int num)
-{
-  struct curl_certinfo *ci = &data->info.certs;
-  struct curl_slist **table;
-
-  Curl_ssl_free_certinfo(data);
-
-  ci->num_of_certs = num;
-  table = calloc((size_t)num, sizeof(struct curl_slist *));
-  if(!table)
-    return 1;
-
-  ci->certinfo = table;
-  return 0;
-}
-
 /*
  * This size was previously 512 which has been reported "too small" without
  * any specifics, so it was enlarged to allow more data to get shown uncut.
@@ -2024,7 +1954,7 @@ static CURLcode get_cert_chain(struct co
   }
 
   numcerts = sk_X509_num(sk);
-  if(init_certinfo(data, numcerts)) {
+  if(Curl_ssl_init_certinfo(data, numcerts)) {
     free(bufp);
     return CURLE_OUT_OF_MEMORY;
   }
@@ -2049,16 +1979,16 @@ static CURLcode get_cert_chain(struct co
 
     (void)x509_name_oneline(X509_get_subject_name(x), bufp, CERTBUFFERSIZE);
     infof(data, "%2d Subject: %s\n", i, bufp);
-    push_certinfo(data, i, "Subject", bufp);
+    Curl_ssl_push_certinfo(data, i, "Subject", bufp);
 
     (void)x509_name_oneline(X509_get_issuer_name(x), bufp, CERTBUFFERSIZE);
     infof(data, "   Issuer: %s\n", bufp);
-    push_certinfo(data, i, "Issuer", bufp);
+    Curl_ssl_push_certinfo(data, i, "Issuer", bufp);
 
     value = X509_get_version(x);
     infof(data, "   Version: %lu (0x%lx)\n", value+1, value);
     snprintf(bufp, CERTBUFFERSIZE, "%lx", value);
-    push_certinfo(data, i, "Version", bufp); /* hex */
+    Curl_ssl_push_certinfo(data, i, "Version", bufp); /* hex */
 
     num=X509_get_serialNumber(x);
     if(num->length <= 4) {
@@ -2087,30 +2017,30 @@ static CURLcode get_cert_chain(struct co
         bufp[0]=0;
     }
     if(bufp[0])
-      push_certinfo(data, i, "Serial Number", bufp); /* hex */
+      Curl_ssl_push_certinfo(data, i, "Serial Number", bufp); /* hex */
 
     cinf = x->cert_info;
 
     j = asn1_object_dump(cinf->signature->algorithm, bufp, CERTBUFFERSIZE);
     if(!j) {
       infof(data, "   Signature Algorithm: %s\n", bufp);
-      push_certinfo(data, i, "Signature Algorithm", bufp);
+      Curl_ssl_push_certinfo(data, i, "Signature Algorithm", bufp);
     }
 
     certdate = X509_get_notBefore(x);
     asn1_output(certdate, bufp, CERTBUFFERSIZE);
     infof(data, "   Start date: %s\n", bufp);
-    push_certinfo(data, i, "Start date", bufp);
+    Curl_ssl_push_certinfo(data, i, "Start date", bufp);
 
     certdate = X509_get_notAfter(x);
     asn1_output(certdate, bufp, CERTBUFFERSIZE);
     infof(data, "   Expire date: %s\n", bufp);
-    push_certinfo(data, i, "Expire date", bufp);
+    Curl_ssl_push_certinfo(data, i, "Expire date", bufp);
 
     j = asn1_object_dump(cinf->key->algor->algorithm, bufp, CERTBUFFERSIZE);
     if(!j) {
       infof(data, "   Public Key Algorithm: %s\n", bufp);
-      push_certinfo(data, i, "Public Key Algorithm", bufp);
+      Curl_ssl_push_certinfo(data, i, "Public Key Algorithm", bufp);
     }
 
     pubkey = X509_get_pubkey(x);
@@ -2122,7 +2052,7 @@ static CURLcode get_cert_chain(struct co
         infof(data,  "   RSA Public Key (%d bits)\n",
               BN_num_bits(pubkey->pkey.rsa->n));
         snprintf(bufp, CERTBUFFERSIZE, "%d", BN_num_bits(pubkey->pkey.rsa->n));
-        push_certinfo(data, i, "RSA Public Key", bufp);
+        Curl_ssl_push_certinfo(data, i, "RSA Public Key", bufp);
 
         print_pubkey_BN(rsa, n, i);
         print_pubkey_BN(rsa, e, i);
diff -Naurp a/lib/url.c b/lib/url.c
--- a/lib/url.c	2013-07-12 17:01:20.178943857 +0200
+++ b/lib/url.c	2013-07-12 17:02:50.700677535 +0200
@@ -1900,6 +1900,8 @@ CURLcode Curl_setopt(struct SessionHandl
      */
     data->set.ssl.fsslctxp = va_arg(param, void *);
     break;
+#endif
+#if defined(USE_SSLEAY) || defined(USE_QSOSSL)|| defined(USE_GSKIT)
   case CURLOPT_CERTINFO:
     data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE;
     break;
diff -Naurp a/lib/urldata.h b/lib/urldata.h
--- a/lib/urldata.h	2013-07-09 11:59:59.901176599 +0200
+++ b/lib/urldata.h	2013-07-12 17:02:50.685677413 +0200
@@ -134,6 +134,10 @@
 #include <qsossl.h>
 #endif
 
+#ifdef USE_GSKIT
+#include <gskssl.h>
+#endif
+
 #ifdef USE_AXTLS
 #include <axTLS/ssl.h>
 #undef malloc
@@ -322,6 +326,11 @@ struct ssl_connect_data {
 #ifdef USE_QSOSSL
   SSLHandle *handle;
 #endif /* USE_QSOSSL */
+#ifdef USE_GSKIT
+  gsk_handle handle;
+  int iocport;
+  ssl_connect_state connecting_state;
+#endif
 #ifdef USE_AXTLS
   SSL_CTX* ssl_ctx;
   SSL*     ssl;
diff -Naurp a/lib/x509asn1.c b/lib/x509asn1.c
--- a/lib/x509asn1.c	1970-01-01 01:00:00.000000000 +0100
+++ b/lib/x509asn1.c	2013-07-12 16:29:37.479668090 +0200
@@ -0,0 +1,1119 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, 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"
+
+#if defined(USE_QSOSSL) || defined(USE_GSKIT)
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "strequal.h"
+#include "hostcheck.h"
+#include "sslgen.h"
+#include "sendf.h"
+#include "inet_pton.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"
+
+
+/* ASN.1 OIDs. */
+static const char       cnOID[] = "2.5.4.3";    /* Common name. */
+static const char       sanOID[] = "2.5.29.17"; /* Subject alternative name. */
+
+static const OID        OIDtable[] = {
+  { "1.2.840.10040.4.1",        "dsa" },
+  { "1.2.840.10040.4.3",        "dsa-with-sha1" },
+  { "1.2.840.10045.2.1",        "ecPublicKey" },
+  { "1.2.840.10045.3.0.1",      "c2pnb163v1" },
+  { "1.2.840.10045.4.1",        "ecdsa-with-SHA1" },
+  { "1.2.840.10046.2.1",        "dhpublicnumber" },
+  { "1.2.840.113549.1.1.1",     "rsaEncryption" },
+  { "1.2.840.113549.1.1.2",     "md2WithRSAEncryption" },
+  { "1.2.840.113549.1.1.4",     "md5WithRSAEncryption" },
+  { "1.2.840.113549.1.1.5",     "sha1WithRSAEncryption" },
+  { "1.2.840.113549.1.1.10",    "RSASSA-PSS" },
+  { "1.2.840.113549.1.1.14",    "sha224WithRSAEncryption" },
+  { "1.2.840.113549.1.1.11",    "sha256WithRSAEncryption" },
+  { "1.2.840.113549.1.1.12",    "sha384WithRSAEncryption" },
+  { "1.2.840.113549.1.1.13",    "sha512WithRSAEncryption" },
+  { "1.2.840.113549.2.2",       "md2" },
+  { "1.2.840.113549.2.5",       "md5" },
+  { "1.3.14.3.2.26",            "sha1" },
+  { cnOID,                      "CN" },
+  { "2.5.4.4",                  "SN" },
+  { "2.5.4.5",                  "serialNumber" },
+  { "2.5.4.6",                  "C" },
+  { "2.5.4.7",                  "L" },
+  { "2.5.4.8",                  "ST" },
+  { "2.5.4.9",                  "streetAddress" },
+  { "2.5.4.10",                 "O" },
+  { "2.5.4.11",                 "OU" },
+  { "2.5.4.12",                 "title" },
+  { "2.5.4.13",                 "description" },
+  { "2.5.4.17",                 "postalCode" },
+  { "2.5.4.41",                 "name" },
+  { "2.5.4.42",                 "givenName" },
+  { "2.5.4.43",                 "initials" },
+  { "2.5.4.44",                 "generationQualifier" },
+  { "2.5.4.45",                 "X500UniqueIdentifier" },
+  { "2.5.4.46",                 "dnQualifier" },
+  { "2.5.4.65",                 "pseudonym" },
+  { "1.2.840.113549.1.9.1",     "emailAddress" },
+  { "2.5.4.72",                 "role" },
+  { sanOID,                     "subjectAltName" },
+  { "2.5.29.18",                "issuerAltName" },
+  { "2.5.29.19",                "basicConstraints" },
+  { "2.16.840.1.101.3.4.2.4",   "sha224" },
+  { "2.16.840.1.101.3.4.2.1",   "sha256" },
+  { "2.16.840.1.101.3.4.2.2",   "sha384" },
+  { "2.16.840.1.101.3.4.2.3",   "sha512" },
+  { (const char *) NULL,        (const char *) NULL }
+};
+
+/*
+ * Lightweight ASN.1 parser.
+ * In particular, it does not check for syntactic/lexical errors.
+ * It is intended to support certificate information gathering for SSL backends
+ * that offer a mean to get certificates as a whole, but do not supply
+ * entry points to get particular certificate sub-fields.
+ * Please note there is no pretention here to rewrite a full SSL library.
+ */
+
+
+const char * Curl_getASN1Element(asn1Element * elem,
+                                 const char * beg, const char * end)
+{
+  unsigned char b;
+  unsigned long len;
+  asn1Element lelem;
+
+  /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
+     ending at `end'.
+     Returns a pointer in source string after the parsed element, or NULL
+     if an error occurs. */
+
+  if(beg >= end || !*beg)
+    return (const char *) NULL;
+
+  /* Process header byte. */
+  b = (unsigned char) *beg++;
+  elem->constructed = (b & 0x20) != 0;
+  elem->class = (b >> 6) & 3;
+  b &= 0x1F;
+  if(b == 0x1F)
+    return (const char *) NULL; /* Long tag values not supported here. */
+  elem->tag = b;
+
+  /* Process length. */
+  if(beg >= end)
+    return (const char *) NULL;
+  b = (unsigned char) *beg++;
+  if(!(b & 0x80))
+    len = b;
+  else if(!(b &= 0x7F)) {
+    /* Unspecified length. Since we have all the data, we can determine the
+       effective length by skipping element until an end element is found. */
+    if(!elem->constructed)
+      return (const char *) NULL;
+    elem->beg = beg;
+    while (beg < end && *beg)
+      if(!(beg = Curl_getASN1Element(&lelem, beg, end)))
+        return (const char *) NULL;
+    if(beg >= end)
+      return (const char *) NULL;
+    elem->end = beg;
+    return beg + 1;
+  }
+  else if(beg + b > end)
+    return (const char *) NULL; /* Does not fit in source. */
+  else {
+    /* Get long length. */
+    len = 0;
+    do {
+      if(len & 0xFF000000L)
+        return (const char *) NULL;  /* Lengths > 32 bits are not supported. */
+      len = (len << 8) | (unsigned char) *beg++;
+    } while (--b);
+  }
+  if(end - beg < len)
+    return (const char *) NULL;  /* Element data does not fit in source. */
+  elem->beg = beg;
+  elem->end = beg + len;
+  return elem->end;
+}
+
+static const OID * searchOID(const char * oid)
+{
+  const OID * op;
+
+  /* Search the null terminated OID or OID identifier in local table.
+     Return the table entry pointer or NULL if not found. */
+
+  for (op = OIDtable; op->numoid; op++)
+    if(!strcmp(op->numoid, oid) || curl_strequal(op->textoid, oid))
+      return op;
+
+  return (const OID *) NULL;
+}
+
+static const char * bool2str(const char * beg, const char * end)
+{
+  /* Convert an ASN.1 Boolean value into its string representation.
+     Return the dynamically allocated string, or NULL if source is not an
+     ASN.1 Boolean value. */
+
+  if(end - beg != 1)
+    return (const char *) NULL;
+  return strdup(*beg? "TRUE": "FALSE");
+}
+
+static const char * octet2str(const char * beg, const char * end)
+{
+  int n = end - beg;
+  char * buf;
+
+  /* Convert an ASN.1 octet string to a printable string.
+     Return the dynamically allocated string, or NULL if an error occurs. */
+
+  buf = malloc(3 * n + 1);
+  if(buf)
+    for (n = 0; beg < end; n += 3)
+      snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++);
+  return buf;
+}
+
+static const char * bit2str(const char * beg, const char * end)
+
+{
+  /* Convert an ASN.1 bit string to a printable string.
+     Return the dynamically allocated string, or NULL if an error occurs. */
+
+  if(++beg > end)
+    return (const char *) NULL;
+  return octet2str(beg, end);
+}
+
+static const char * int2str(const char * beg, const char * end)
+{
+  long val = 0;
+  size_t n = end - beg;
+
+  /* Convert an ASN.1 integer value into its string representation.
+     Return the dynamically allocated string, or NULL if source is not an
+     ASN.1 integer value. */
+
+  if(!n)
+    return (const char *) NULL;
+
+  if(n > 4)
+    return octet2str(beg, end);
+
+  /* Represent integers <= 32-bit as a single value. */
+  if(*beg & 0x80)
+    val = ~val;
+
+  do
+    val = (val << 8) | *(const unsigned char *) beg++;
+  while (beg < end);
+  return curl_maprintf("%s%lx", (val < 0 || val >= 10)? "0x": "", val);
+}
+
+static int
+utf8asn1str(char * * to, int type, const char * from, const char * end)
+{
+  int inlength = end - from;
+  int size = 1;
+  int outlength;
+  int chsize;
+  unsigned int wc;
+  char * buf;
+
+  /* Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the
+     destination buffer dynamically. The allocation size will normally be too
+     large: this is to avoid buffer overflows.
+     Terminate the string with a nul byte and return the converted
+     string length. */
+
+  *to = (char *) NULL;
+  switch (type) {
+  case ASN1_BMP_STRING:
+    size = 2;
+    break;
+  case ASN1_UNIVERSAL_STRING:
+    size = 4;
+    break;
+  case ASN1_NUMERIC_STRING:
+  case ASN1_PRINTABLE_STRING:
+  case ASN1_TELETEX_STRING:
+  case ASN1_IA5_STRING:
+  case ASN1_VISIBLE_STRING:
+  case ASN1_UTF8_STRING:
+    break;
+  default:
+    return -1;  /* Conversion not supported. */
+  }
+
+  if(inlength % size)
+    return -1;  /* Length inconsistent with character size. */
+  if(!(buf = malloc(4 * (inlength / size) + 1)))
+    return -1;  /* Not enough memory. */
+
+  if(type == ASN1_UTF8_STRING) {
+    /* Just copy. */
+    if((outlength = inlength))
+      memcpy(buf, from, outlength);
+  }
+  else {
+    for (outlength = 0; from < end;) {
+      wc = 0;
+      switch (size) {
+      case 4:
+        wc = (wc << 8) | *(const unsigned char *) from++;
+        wc = (wc << 8) | *(const unsigned char *) from++;
+      case 2:
+        wc = (wc << 8) | *(const unsigned char *) from++;
+      default: /* case 1: */
+        wc = (wc << 8) | *(const unsigned char *) from++;
+      }
+      chsize = 1;
+      if(wc >= 0x00000080) {
+        if(wc >= 0x00000800) {
+          if(wc >= 0x00010000) {
+            if(wc >= 0x00200000) {
+              free(buf);
+              return -1;        /* Invalid char. size for target encoding. */
+            }
+            buf[outlength + 3] = 0x80 | (wc & 0x3F);
+            wc = (wc >> 6) | 0x00010000;
+            chsize++;
+          }
+          buf[outlength + 2] = 0x80 | (wc & 0x3F);
+          wc = (wc >> 6) | 0x00000800;
+          chsize++;
+        }
+        buf[outlength + 1] = 0x80 | (wc & 0x3F);
+        wc = (wc >> 6) | 0x000000C0;
+        chsize++;
+      }
+      buf[outlength] = wc;
+      outlength += chsize;
+    }
+  }
+  buf[outlength] = '\0';
+  *to = buf;
+  return outlength;
+}
+
+static const char * string2str(int type, const char * beg, const char * end)
+{
+  char * buf;
+
+  /* Convert an ASN.1 String into its UTF-8 string representation.
+     Return the dynamically allocated string, or NULL if an error occurs. */
+
+  if(utf8asn1str(&buf, type, beg, end) < 0)
+    return (const char *) NULL;
+  return buf;
+}
+
+static int encodeUint(char * buf, int n, unsigned int x)
+{
+  int i = 0;
+  unsigned int y = x / 10;
+
+  /* Decimal ASCII encode unsigned integer `x' in the `n'-byte buffer at `buf'.
+     Return the total number of encoded digits, even if larger than `n'. */
+
+  if(y) {
+    i += encodeUint(buf, n, y);
+    x -= y * 10;
+  }
+  if(i < n)
+    buf[i] = '0' + x;
+  i++;
+  if(i < n)
+    buf[i] = '\0';      /* Store a terminator if possible. */
+  return i;
+}
+
+static int encodeOID(char * buf, int n, const char * beg, const char * end)
+{
+  int i = 0;
+  unsigned int x;
+  unsigned int y;
+
+  /* Convert an ASN.1 OID into its dotted string representation.
+     Store the result in th `n'-byte buffer at `buf'.
+     Return the converted string length, or -1 if an error occurs. */
+
+  /* Process the first two numbers. */
+  y = *(const unsigned char *) beg++;
+  x = y / 40;
+  y -= x * 40;
+  i += encodeUint(buf + i, n - i, x);
+  if(i < n)
+    buf[i] = '.';
+  i++;
+  i += encodeUint(buf + i, n - i, y);
+
+  /* Process the trailing numbers. */
+  while (beg < end) {
+    if(i < n)
+      buf[i] = '.';
+    i++;
+    x = 0;
+    do {
+      if(x & 0xFF000000)
+        return -1;
+      y = *(const unsigned char *) beg++;
+      x = (x << 7) | (y & 0x7F);
+    } while (y & 0x80);
+    i += encodeUint(buf + i, n - i, x);
+  }
+  if(i < n)
+    buf[i] = '\0';
+  return i;
+}
+
+static const char * OID2str(const char * beg, const char * end, bool symbolic)
+{
+  char * buf = (char *) NULL;
+  const OID * op;
+  int n;
+
+  /* Convert an ASN.1 OID into its dotted or symbolic string representation.
+     Return the dynamically allocated string, or NULL if an error occurs. */
+
+  if(beg < end) {
+    n = encodeOID((char *) NULL, -1, beg, end);
+    if(n >= 0) {
+      buf = malloc(n + 1);
+      if(buf) {
+        encodeOID(buf, n, beg, end);
+        buf[n] = '\0';
+
+        if(symbolic) {
+          op = searchOID(buf);
+          if(op) {
+            free(buf);
+            buf = strdup(op->textoid);
+          }
+        }
+      }
+    }
+  }
+  return buf;
+}
+
+static const char * GTime2str(const char * beg, const char * end)
+{
+  const char * tzp;
+  const char * fracp;
+  char sec1, sec2;
+  size_t fracl;
+  size_t tzl;
+  char * sep = "";
+
+  /* Convert an ASN.1 Generalized time to a printable string.
+     Return the dynamically allocated string, or NULL if an error occurs. */
+
+  for (fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++)
+    ;
+
+  /* Get seconds digits. */
+  sec1 = '0';
+  switch (fracp - beg - 12) {
+  case 0:
+    sec2 = '0';
+    break;
+  case 2:
+    sec1 = fracp[-2];
+  case 1:
+    sec2 = fracp[-1];
+    break;
+  default:
+    return (const char *) NULL;
+  }
+
+  /* Scan for timezone, measure fractional seconds. */
+  tzp = fracp;
+  fracl = 0;
+  if(fracp < end && (*fracp == '.' || *fracp == ',')) {
+    fracp++;
+    do
+      tzp++;
+    while (tzp < end && *tzp >= '0' && *tzp <= '9');
+    /* Strip leading zeroes in fractional seconds. */
+    for (fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
+      ;
+  }
+
+  /* Process timezone. */
+  if(tzp >= end)
+    ;           /* Nothing to do. */
+  else if(*tzp == 'Z') {
+    tzp = " GMT";
+    end = tzp + 4;
+  }
+  else {
+    sep = " ";
+    tzp++;
+  }
+
+  tzl = end - tzp;
+  return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
+                       beg, beg + 4, beg + 6,
+                       beg + 8, beg + 10, sec1, sec2,
+                       fracl? ".": "", fracl, fracp,
+                       sep, tzl, tzp);
+}
+
+static const char * UTime2str(const char * beg, const char * end)
+{
+  const char * tzp;
+  size_t tzl;
+  const char * sec;
+
+  /* Convert an ASN.1 UTC time to a printable string.
+     Return the dynamically allocated string, or NULL if an error occurs. */
+
+  for (tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
+    ;
+  /* Get the seconds. */
+  sec = beg + 10;
+  switch (tzp - sec) {
+  case 0:
+    sec = "00";
+  case 2:
+    break;
+  default:
+    return (const char *) NULL;
+  }
+
+  /* Process timezone. */
+  if(tzp >= end)
+    return (const char *) NULL;
+  if(*tzp == 'Z') {
+    tzp = "GMT";
+    end = tzp + 3;
+  }
+  else
+    tzp++;
+
+  tzl = end - tzp;
+  return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
+                       20 - (*beg >= '5'), beg, beg + 2, beg + 4,
+                       beg + 6, beg + 8, sec,
+                       tzl, tzp);
+}
+
+const char * Curl_ASN1tostr(asn1Element * elem, int type)
+{
+  static const char zero = '\0';
+
+  /* Convert an ASN.1 element to a printable string.
+     Return the dynamically allocated string, or NULL if an error occurs. */
+
+  if(elem->constructed)
+    return (const char *) NULL; /* No conversion of structured elements. */
+
+  if(!type)
+    type = elem->tag;   /* Type not forced: use element tag as type. */
+
+  switch (type) {
+  case ASN1_BOOLEAN:
+    return bool2str(elem->beg, elem->end);
+  case ASN1_INTEGER:
+  case ASN1_ENUMERATED:
+    return int2str(elem->beg, elem->end);
+  case ASN1_BIT_STRING:
+    return bit2str(elem->beg, elem->end);
+  case ASN1_OCTET_STRING:
+    return octet2str(elem->beg, elem->end);
+  case ASN1_NULL:
+    return strdup(&zero);
+  case ASN1_OBJECT_IDENTIFIER:
+    return OID2str(elem->beg, elem->end, TRUE);
+  case ASN1_UTC_TIME:
+    return UTime2str(elem->beg, elem->end);
+  case ASN1_GENERALIZED_TIME:
+    return GTime2str(elem->beg, elem->end);
+  case ASN1_UTF8_STRING:
+  case ASN1_NUMERIC_STRING:
+  case ASN1_PRINTABLE_STRING:
+  case ASN1_TELETEX_STRING:
+  case ASN1_IA5_STRING:
+  case ASN1_VISIBLE_STRING:
+  case ASN1_UNIVERSAL_STRING:
+  case ASN1_BMP_STRING:
+    return string2str(type, elem->beg, elem->end);
+  }
+
+  return (const char *) NULL;   /* Unsupported. */
+}
+
+static int encodeDN(char * buf, size_t n, asn1Element * dn)
+{
+  asn1Element rdn;
+  asn1Element atv;
+  asn1Element oid;
+  asn1Element value;
+  size_t l = 0;
+  const char * p1;
+  const char * p2;
+  const char * p3;
+  const char * str;
+
+  /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'.
+     Return the total string length, even if larger than `n'. */
+
+  for (p1 = dn->beg; p1 < dn->end;) {
+    p1 = Curl_getASN1Element(&rdn, p1, dn->end);
+    for (p2 = rdn.beg; p2 < rdn.end;) {
+      p2 = Curl_getASN1Element(&atv, p2, rdn.end);
+      p3 = Curl_getASN1Element(&oid, atv.beg, atv.end);
+      Curl_getASN1Element(&value, p3, atv.end);
+      str = Curl_ASN1tostr(&oid, 0);
+      if(!str)
+        return -1;
+
+      /* Encode delimiter.
+         If attribute has a short uppercase name, delimiter is ", ". */
+      if(l) {
+        for (p3 = str; isupper(*p3); p3++)
+          ;
+        for (p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) {
+          if(l < n)
+            buf[l] = *p3;
+          l++;
+        }
+      }
+
+      /* Encode attribute name. */
+      for (p3 = str; *p3; p3++) {
+        if(l < n)
+          buf[l] = *p3;
+        l++;
+      }
+      free((char *) str);
+
+      /* Generate equal sign. */
+      if(l < n)
+        buf[l] = '=';
+      l++;
+
+      /* Generate value. */
+      if(!(str = Curl_ASN1tostr(&value, 0)))
+        return -1;
+      for (p3 = str; *p3; p3++) {
+        if(l < n)
+          buf[l] = *p3;
+        l++;
+      }
+      free((char *) str);
+    }
+  }
+
+  return l;
+}
+
+const char * Curl_DNtostr(asn1Element * dn)
+{
+  char * buf = (char *) NULL;
+  int n = encodeDN(buf, 0, dn);
+
+  /* Convert an ASN.1 distinguished name into a printable string.
+     Return the dynamically allocated string, or NULL if an error occurs. */
+
+  if(n >= 0)
+    if((buf = malloc(n + 1))) {
+      encodeDN(buf, n + 1, dn);
+      buf[n] = '\0';
+    }
+  return (const char *) buf;
+}
+
+static const char * checkOID(const char * beg, const char * end,
+                             const char * oid)
+{
+  asn1Element e;
+  const char * ccp;
+  const char * p;
+  bool matched;
+
+  /* Check if first ASN.1 element at `beg' is the given OID.
+     Return a pointer in the source string after the OID if found, else NULL. */
+
+  if(!(ccp = Curl_getASN1Element(&e, beg, end)) ||
+     e.tag != ASN1_OBJECT_IDENTIFIER)
+    return (const char *) NULL;
+
+  if(!(p = OID2str(e.beg, e.end, FALSE)))
+    return (const char *) NULL;
+
+  matched = !strcmp(p, oid);
+  free((char *) p);
+  return matched? ccp: (const char *) NULL;
+}
+
+
+/*
+ * X509 parser.
+ */
+
+void Curl_parseX509(X509certificate * cert, const char * beg, const char * end)
+{
+  asn1Element elem;
+  asn1Element tbsCertificate;
+  const char * ccp;
+  static const char defaultVersion = 0;  /* v1. */
+
+  /* ASN.1 parse an X509 certificate into structure subfields.
+     Syntax is assumed to have already been checked by the SSL backend.
+     See RFC 5280. */
+
+  cert->certificate.beg = beg;
+  cert->certificate.end = end;
+
+  /* Get the sequence content. */
+  Curl_getASN1Element(&elem, beg, end);
+  beg = elem.beg;
+  end = elem.end;
+
+  /* Get tbsCertificate. */
+  beg = Curl_getASN1Element(&tbsCertificate, beg, end);
+  /* Skip the signatureAlgorithm. */
+  beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
+  /* Get the signatureValue. */
+  Curl_getASN1Element(&cert->signature, beg, end);
+
+  /* Parse TBSCertificate. */
+  beg = tbsCertificate.beg;
+  end = tbsCertificate.end;
+  /* Get optional version, get serialNumber. */
+  cert->version.beg = &defaultVersion;
+  cert->version.end = &defaultVersion + sizeof defaultVersion;;
+  beg = Curl_getASN1Element(&elem, beg, end);
+  if(elem.tag == 0) {
+    Curl_getASN1Element(&cert->version, elem.beg, elem.end);
+    beg = Curl_getASN1Element(&elem, beg, end);
+  }
+  cert->serialNumber = elem;
+  /* Get signature algorithm. */
+  beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
+  /* Get issuer. */
+  beg = Curl_getASN1Element(&cert->issuer, beg, end);
+  /* Get notBefore and notAfter. */
+  beg = Curl_getASN1Element(&elem, beg, end);
+  ccp = Curl_getASN1Element(&cert->notBefore, elem.beg, elem.end);
+  Curl_getASN1Element(&cert->notAfter, ccp, elem.end);
+  /* Get subject. */
+  beg = Curl_getASN1Element(&cert->subject, beg, end);
+  /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
+  beg = Curl_getASN1Element(&elem, beg, end);
+  ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm,
+                            elem.beg, elem.end);
+  Curl_getASN1Element(&cert->subjectPublicKey, ccp, elem.end);
+  /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
+  cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
+  cert->extensions.tag = elem.tag = 0;
+  cert->issuerUniqueID.beg = cert->issuerUniqueID.end = "";
+  cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
+  cert->extensions.beg = cert->extensions.end = "";
+  if(beg < end)
+    beg = Curl_getASN1Element(&elem, beg, end);
+  if(elem.tag == 1) {
+    cert->issuerUniqueID = elem;
+    if(beg < end)
+      beg = Curl_getASN1Element(&elem, beg, end);
+  }
+  if(elem.tag == 2) {
+    cert->subjectUniqueID = elem;
+    if(beg < end)
+      beg = Curl_getASN1Element(&elem, beg, end);
+  }
+  if(elem.tag == 3)
+    Curl_getASN1Element(&cert->extensions, elem.beg, elem.end);
+}
+
+static int copySubstring(char * to, const char * from)
+{
+  int i;
+
+  /* Copy at most 64-characters, terminate with a newline and returns the
+     effective number of stored characters. */
+
+  for (i = 0; i < 64; i++)
+    if(!(to[i] = *from++))
+      break;
+
+  to[i++] = '\n';
+  return i;
+}
+
+static const char * dumpAlgo(asn1Element * param,
+                             const char * beg, const char * end)
+{
+  asn1Element oid;
+
+  /* Get algorithm parameters and return algorithm name. */
+
+  beg = Curl_getASN1Element(&oid, beg, end);
+  param->tag = 0;
+  param->beg = param->end = end;
+  if(beg < end)
+    Curl_getASN1Element(param, beg, end);
+  return OID2str(oid.beg, oid.end, TRUE);
+}
+
+static void do_pubkey_field(struct SessionHandle *data, int certnum,
+                            const char * label, asn1Element * elem)
+{
+  const char * output;
+
+  /* Generate a certificate information record for the public key. */
+
+  if((output = Curl_ASN1tostr(elem, 0))) {
+    Curl_ssl_push_certinfo(data, certnum, label, output);
+    infof(data, "   %s: %s\n", label, output);
+    free((char *) output);
+  }
+}
+
+static void do_pubkey(struct SessionHandle * data, int certnum,
+                      const char * algo, asn1Element * param,
+                      asn1Element * pubkey)
+{
+  asn1Element elem;
+  asn1Element pk;
+  const char * p;
+  const char * q;
+  unsigned int len;
+  unsigned int i;
+
+  /* Generate all information records for the public key. */
+
+  /* Get the public key (single element). */
+  Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end);
+
+  if(curl_strequal(algo, "rsaEncryption")) {
+    p = Curl_getASN1Element(&elem, pk.beg, pk.end);
+    /* Compute key length. */
+    for (q = elem.beg; !*q && q < elem.end; q++)
+      ;
+    if((len = (elem.end - q) * 8))
+      for (i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
+        len--;
+    if(len > 32)
+      elem.beg = q;     /* Strip leading zero bytes. */
+    infof(data, "   RSA Public Key (%u bits)\n", len);
+    if((q = curl_maprintf("%u", len))) {
+      Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
+      free((char *) q);
+    }
+    /* Generate coefficients. */
+    do_pubkey_field(data, certnum, "rsa(n)", &elem);
+    Curl_getASN1Element(&elem, p, pk.end);
+    do_pubkey_field(data, certnum, "rsa(e)", &elem);
+  }
+  else if(curl_strequal(algo, "dsa")) {
+    p = Curl_getASN1Element(&elem, param->beg, param->end);
+    do_pubkey_field(data, certnum, "dsa(p)", &elem);
+    p = Curl_getASN1Element(&elem, p, param->end);
+    do_pubkey_field(data, certnum, "dsa(q)", &elem);
+    Curl_getASN1Element(&elem, p, param->end);
+    do_pubkey_field(data, certnum, "dsa(g)", &elem);
+    do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
+  }
+  else if(curl_strequal(algo, "dhpublicnumber")) {
+    p = Curl_getASN1Element(&elem, param->beg, param->end);
+    do_pubkey_field(data, certnum, "dh(p)", &elem);
+    Curl_getASN1Element(&elem, param->beg, param->end);
+    do_pubkey_field(data, certnum, "dh(g)", &elem);
+    do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
+  }
+#if 0 /* Patent-encumbered. */
+  else if(curl_strequal(algo, "ecPublicKey")) {
+    /* Left TODO. */
+  }
+#endif
+}
+
+CURLcode Curl_extract_certinfo(struct connectdata * conn,
+                               int certnum,
+                               const char * beg,
+                               const char * end)
+{
+  X509certificate cert;
+  struct SessionHandle * data = conn->data;
+  asn1Element param;
+  const char * ccp;
+  char * cp1;
+  size_t cl1;
+  char * cp2;
+  CURLcode cc;
+  unsigned long version;
+  int i;
+  size_t j;
+
+  /* Prepare the certificate information for curl_easy_getinfo(). */
+
+  /* Extract the certificate ASN.1 elements. */
+  Curl_parseX509(&cert, beg, end);
+
+  /* Subject. */
+  if(!(ccp = Curl_DNtostr(&cert.subject)))
+    return CURLE_OUT_OF_MEMORY;
+  Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
+  infof(data, "%2d Subject: %s\n", certnum, ccp);
+  free((char *) ccp);
+
+  /* Issuer. */
+  if(!(ccp = Curl_DNtostr(&cert.issuer)))
+    return CURLE_OUT_OF_MEMORY;
+  Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
+  infof(data, "   Issuer: %s\n", ccp);
+  free((char *) ccp);
+
+  /* Version (always fits in less than 32 bits). */
+  version = 0;
+  for (ccp = cert.version.beg; ccp < cert.version.end; ccp++)
+    version = (version << 8) | *(const unsigned char *) ccp;
+  if(!(ccp = curl_maprintf("%lx", version)))
+    return CURLE_OUT_OF_MEMORY;
+  Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
+  free((char *) ccp);
+  infof(data, "   Version: %lu (0x%lx)\n", version + 1, version);
+
+  /* Serial number. */
+  if(!(ccp = Curl_ASN1tostr(&cert.serialNumber, 0)))
+    return CURLE_OUT_OF_MEMORY;
+  Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
+  infof(data, "   Serial Number: %s\n", ccp);
+  free((char *) ccp);
+
+  /* Signature algorithm .*/
+  if(!(ccp = dumpAlgo(&param, cert.signatureAlgorithm.beg,
+                      cert.signatureAlgorithm.end)))
+    return CURLE_OUT_OF_MEMORY;
+  Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
+  infof(data, "   Signature Algorithm: %s\n", ccp);
+  free((char *) ccp);
+
+  /* Start Date. */
+  if(!(ccp = Curl_ASN1tostr(&cert.notBefore, 0)))
+    return CURLE_OUT_OF_MEMORY;
+  Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
+  infof(data, "   Start Date: %s\n", ccp);
+  free((char *) ccp);
+
+  /* Expire Date. */
+  if(!(ccp = Curl_ASN1tostr(&cert.notAfter, 0)))
+    return CURLE_OUT_OF_MEMORY;
+  Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
+  infof(data, "   Expire Date: %s\n", ccp);
+  free((char *) ccp);
+
+  /* Public Key Algorithm. */
+  if(!(ccp = dumpAlgo(&param, cert.subjectPublicKeyAlgorithm.beg,
+                      cert.subjectPublicKeyAlgorithm.end)))
+    return CURLE_OUT_OF_MEMORY;
+  Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
+  infof(data, "   Public Key Algorithm: %s\n", ccp);
+  do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
+  free((char *) ccp);
+
+/* TODO: extensions. */
+
+  /* Signature. */
+  if(!(ccp = Curl_ASN1tostr(&cert.signature, 0)))
+    return CURLE_OUT_OF_MEMORY;
+  Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
+  infof(data, "   Signature: %s\n", ccp);
+  free((char *) ccp);
+
+  /* Generate PEM certificate. */
+  if((cc = Curl_base64_encode(data, cert.certificate.beg,
+                              cert.certificate.end - cert.certificate.beg,
+                              &cp1, &cl1)) != CURLE_OK)
+    return cc;
+  /* Compute the number of charaters in final certificate string. Format is:
+     -----BEGIN CERTIFICATE-----\n
+     <max 64 base64 characters>\n
+     .
+     .
+     .
+     -----END CERTIFICATE-----\n
+   */
+  i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26;
+  if(!(cp2 = malloc(i + 1))) {
+    free(cp1);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  /* Build the certificate string. */
+  i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----");
+  for (j = 0; j < cl1; j += 64)
+    i += copySubstring(cp2 + i, cp1 + j);
+  i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
+  cp2[i] = '\0';
+  free(cp1);
+  Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
+  infof(data, "%s\n", cp2);
+  free(cp2);
+  return CURLE_OK;
+}
+
+
+CURLcode Curl_verifyhost(struct connectdata * conn,
+                         const char * beg, const char * end)
+{
+  struct SessionHandle * data = conn->data;
+  X509certificate cert;
+  asn1Element dn;
+  asn1Element elem;
+  asn1Element ext;
+  asn1Element name;
+  int i;
+  const char * p;
+  const char * q;
+  char * dnsname;
+  int matched = -1;
+  size_t addrlen = (size_t) -1;
+#ifdef ENABLE_IPV6
+  struct in6_addr addr;
+#else
+  struct in_addr addr;
+#endif
+
+  /* Verify that connection server matches info in X509 certificate at
+     `beg'..`end'. */
+
+  if(!data->set.ssl.verifyhost)
+    return CURLE_OK;
+
+  if(!beg)
+    return CURLE_PEER_FAILED_VERIFICATION;
+  Curl_parseX509(&cert, beg, end);
+
+  /* Get the server IP address. */
+#ifdef ENABLE_IPV6
+  if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, conn->host.name, &addr))
+    addrlen = sizeof(struct in6_addr);
+  else
+#endif
+  if(Curl_inet_pton(AF_INET, conn->host.name, &addr))
+    addrlen = sizeof(struct in_addr);
+
+  /* Process extensions. */
+  for (p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) {
+    p = Curl_getASN1Element(&ext, p, cert.extensions.end);
+    /* Check if extension is a subjectAlternativeName. */
+    if((ext.beg = checkOID(ext.beg, ext.end, sanOID))) {
+      ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
+      /* Skip critical if present. */
+      if(elem.tag == ASN1_BOOLEAN)
+        ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
+      /* Parse the octet string contents: is a single sequence. */
+      Curl_getASN1Element(&elem, elem.beg, elem.end);
+      /* Check all GeneralNames. */
+      for (q = elem.beg; matched != 1 && q < elem.end;) {
+        q = Curl_getASN1Element(&name, q, elem.end);
+        switch (name.tag) {
+        case 2: /* DNS name. */
+          i = utf8asn1str(&dnsname, ASN1_IA5_STRING, name.beg, name.end);
+          if(i > 0)
+            if(strlen(dnsname) != i)
+              i = -1;
+            else
+              i = Curl_cert_hostcheck((const char *) dnsname, conn->host.name);
+          if(dnsname)
+            free(dnsname);
+          if(i < 0)
+            return CURLE_PEER_FAILED_VERIFICATION;
+          matched = i;
+          break;
+
+        case 7: /* IP address. */
+          matched = name.end - q == addrlen && !memcmp(&addr, q, addrlen);
+          break;
+        }
+      }
+    }
+  }
+
+  if(matched == 1) {
+    /* an alternative name matched the server hostname */
+    infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
+    return CURLE_OK;
+  }
+  else if(matched == 0) {
+    /* an alternative name field existed, but didn't match and then
+       we MUST fail */
+    infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname);
+    return CURLE_PEER_FAILED_VERIFICATION;
+  }
+
+  /* Process subject. */
+  name.beg = name.end = "";
+  q = cert.subject.beg;
+  /* we have to look to the last occurrence of a commonName in the
+     distinguished one to get the most significant one. */
+  while (q < cert.subject.end) {
+    q = Curl_getASN1Element(&dn, q, cert.subject.end);
+    for (p = dn.beg; p < dn.end;) {
+      p = Curl_getASN1Element(&elem, p, dn.end);
+      /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */
+      if((elem.beg = checkOID(elem.beg, elem.end, cnOID)))
+        name = elem;    /* Latch CN. */
+    }
+  }
+
+  /* Check the CN if found. */
+  if(!Curl_getASN1Element(&elem, name.beg, name.end))
+    failf(data, "SSL: unable to obtain common name from peer certificate");
+  else if((i = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end)) < 0)
+    ;
+  else if(strlen(dnsname) != i) {       /* Nul byte in string ? */
+    free(dnsname);
+    failf(data, "SSL: illegal cert name field");
+  }
+  else if(Curl_cert_hostcheck((const char *) dnsname, conn->host.name)) {
+     infof(data, "\t common name: %s (matched)\n", dnsname);
+     free(dnsname);
+     return CURLE_OK;
+  }
+  else {
+    failf(data, "SSL: certificate subject name '%s' does not match "
+          "target host name '%s'", dnsname, conn->host.dispname);
+    free(dnsname);
+  }
+
+  return CURLE_PEER_FAILED_VERIFICATION;
+}
+
+#endif /* USE_QSOSSL or USE_GSKIT */
diff -Naurp a/lib/x509asn1.h b/lib/x509asn1.h
--- a/lib/x509asn1.h	1970-01-01 01:00:00.000000000 +0100
+++ b/lib/x509asn1.h	2013-07-12 15:22:32.240159949 +0200
@@ -0,0 +1,128 @@
+#ifndef HEADER_CURL_X509ASN1_H
+#define HEADER_CURL_X509ASN1_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, 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"
+
+#if defined(USE_QSOSSL) || defined(USE_GSKIT)
+
+#include "urldata.h"
+
+/*
+ * Constants.
+ */
+
+/* ASN.1 classes. */
+#define ASN1_UNIVERSAL          0
+#define ASN1_APPLICATION        1
+#define ASN1_CONTEXT_SPECIFIC   2
+#define ASN1_PRIVATE            3
+
+/* ASN.1 types. */
+#define ASN1_BOOLEAN            1
+#define ASN1_INTEGER            2
+#define ASN1_BIT_STRING         3
+#define ASN1_OCTET_STRING       4
+#define ASN1_NULL               5
+#define ASN1_OBJECT_IDENTIFIER  6
+#define ASN1_OBJECT_DESCRIPTOR  7
+#define ASN1_INSTANCE_OF        8
+#define ASN1_REAL               9
+#define ASN1_ENUMERATED         10
+#define ASN1_EMBEDDED           11
+#define ASN1_UTF8_STRING        12
+#define ASN1_RELATIVE_OID       13
+#define ASN1_SEQUENCE           16
+#define ASN1_SET                17
+#define ASN1_NUMERIC_STRING     18
+#define ASN1_PRINTABLE_STRING   19
+#define ASN1_TELETEX_STRING     20
+#define ASN1_VIDEOTEX_STRING    21
+#define ASN1_IA5_STRING         22
+#define ASN1_UTC_TIME           23
+#define ASN1_GENERALIZED_TIME   24
+#define ASN1_GRAPHIC_STRING     25
+#define ASN1_VISIBLE_STRING     26
+#define ASN1_GENERAL_STRING     27
+#define ASN1_UNIVERSAL_STRING   28
+#define ASN1_CHARACTER_STRING   29
+#define ASN1_BMP_STRING         30
+
+
+/*
+ * Types.
+ */
+
+/* ASN.1 parsed element. */
+typedef struct {
+  const char *  beg;            /* Pointer to element data. */
+  const char *  end;            /* Pointer to 1st byte after element data. */
+  unsigned char class;          /* ASN.1 element class. */
+  unsigned char tag;            /* ASN.1 element tag. */
+  bool          constructed;    /* Element is constructed. */
+}  asn1Element;
+
+
+/* ASN.1 OID table entry. */
+typedef struct {
+  const char *  numoid;         /* Dotted-numeric OID. */
+  const char *  textoid;        /* OID name. */
+}  OID;
+
+
+/* X509 certificate: RFC 5280. */
+typedef struct {
+  asn1Element   certificate;
+  asn1Element   version;
+  asn1Element   serialNumber;
+  asn1Element   signatureAlgorithm;
+  asn1Element   signature;
+  asn1Element   issuer;
+  asn1Element   notBefore;
+  asn1Element   notAfter;
+  asn1Element   subject;
+  asn1Element   subjectPublicKeyAlgorithm;
+  asn1Element   subjectPublicKey;
+  asn1Element   issuerUniqueID;
+  asn1Element   subjectUniqueID;
+  asn1Element   extensions;
+}  X509certificate;
+
+
+/*
+ * Prototypes.
+ */
+
+const char * Curl_getASN1Element(asn1Element * elem,
+                                 const char * beg, const char * end);
+const char * Curl_ASN1tostr(asn1Element * elem, int type);
+const char * Curl_DNtostr(asn1Element * dn);
+void Curl_parseX509(X509certificate * cert, const char * beg, const char * end);
+CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum,
+                               const char * beg, const char * end);
+CURLcode Curl_verifyhost(struct connectdata * conn,
+                         const char * beg, const char * end);
+
+#endif /* USE_QSOSSL or USE_GSKIT */
+#endif /* HEADER_CURL_X509ASN1_H */
diff -Naurp a/packages/OS400/ccsidcurl.c b/packages/OS400/ccsidcurl.c
--- a/packages/OS400/ccsidcurl.c	2012-11-08 16:51:26.000000000 +0100
+++ b/packages/OS400/ccsidcurl.c	2013-07-12 17:02:50.685677413 +0200
@@ -33,6 +33,7 @@
 
 #include "curl.h"
 #include "mprintf.h"
+#include "slist.h"
 #include "urldata.h"
 #include "url.h"
 #include "getinfo.h"
@@ -67,7 +68,7 @@ makeOS400IconvCode(char buf[ICONV_ID_SIZ
 
   ccsid &= 0xFFFF;
 
-  if (ccsid == NOCONV_CCSID)
+  if(ccsid == NOCONV_CCSID)
     ccsid = ASCII_CCSID;
 
   memset(buf, 0, ICONV_ID_SIZE);
@@ -93,7 +94,7 @@ iconv_open_CCSID(unsigned int ccsidout,
   makeOS400IconvCode(tocode, ccsidout);
   memset(tocode + 13, 0, sizeof tocode - 13);   /* Dest. code id format. */
 
-  if (cstr)
+  if(cstr)
     fromcode[18] = '1';                         /* Set null-terminator flag. */
 
   return iconv_open(tocode, fromcode);
@@ -117,23 +118,23 @@ convert(char * d, size_t dlen, int dccsi
   ***  Return the converted destination byte count, or -1 if error.
   **/
 
-  if (sccsid == 65535)
+  if(sccsid == 65535)
     sccsid = ASCII_CCSID;
 
-  if (dccsid == 65535)
+  if(dccsid == 65535)
     dccsid = ASCII_CCSID;
 
-  if (sccsid == dccsid) {
+  if(sccsid == dccsid) {
     lslen = slen >= 0? slen: strlen(s) + 1;
     i = lslen < dlen? lslen: dlen;
 
-    if (s != d && i > 0)
+    if(s != d && i > 0)
       memcpy(d, s, i);
 
     return i;
     }
 
-  if (slen < 0) {
+  if(slen < 0) {
     lslen = 0;
     cd = iconv_open_CCSID(dccsid, sccsid, 1);
     }
@@ -142,12 +143,12 @@ convert(char * d, size_t dlen, int dccsi
     cd = iconv_open_CCSID(dccsid, sccsid, 0);
     }
 
-  if (ICONV_OPEN_ERROR(cd))
+  if(ICONV_OPEN_ERROR(cd))
     return -1;
 
   i = dlen;
 
-  if ((int) iconv(cd, (char * *) &s, &lslen, &d, &dlen) < 0)
+  if((int) iconv(cd, (char * *) &s, &lslen, &d, &dlen) < 0)
     i = -1;
   else
     i -= dlen;
@@ -174,24 +175,24 @@ dynconvert(int dccsid, const char * s, i
   dlen *= MAX_CONV_EXPANSION;           /* Allow some expansion. */
   d = malloc(dlen);
 
-  if (!d)
+  if(!d)
     return (char *) NULL;
 
   l = convert(d, dlen, dccsid, s, slen, sccsid);
 
-  if (l < 0) {
+  if(l < 0) {
     free(d);
     return (char *) NULL;
     }
 
-  if (slen < 0) {
+  if(slen < 0) {
     /* Need to null-terminate even when source length is given.
        Since destination code size is unknown, use a conversion to generate
        terminator. */
 
     l2 = convert(d + l, dlen - l, dccsid, &nullbyte, -1, ASCII_CCSID);
 
-    if (l2 < 0) {
+    if(l2 < 0) {
       free(d);
       return (char *) NULL;
       }
@@ -199,10 +200,10 @@ dynconvert(int dccsid, const char * s, i
     l += l2;
     }
 
-  if ((size_t) l < dlen) {
+  if((size_t) l < dlen) {
     cp = realloc(d, l);         /* Shorten to minimum needed. */
 
-    if (cp)
+    if(cp)
       d = cp;
     }
 
@@ -210,6 +211,24 @@ dynconvert(int dccsid, const char * s, i
 }
 
 
+static struct curl_slist *
+slist_convert(int dccsid, struct curl_slist * from, int sccsid)
+
+{
+  struct curl_slist * to = (struct curl_slist *) NULL;
+  char * cp;
+
+  for (; from; from = from->next) {
+    if(!(cp = dynconvert(dccsid, from->data, -1, sccsid))) {
+      curl_slist_free_all(to);
+      return (struct curl_slist *) NULL;
+    }
+    to = Curl_slist_append_nodup(to, cp);
+  }
+  return to;
+}
+
+
 char *
 curl_version_ccsid(unsigned int ccsid)
 
@@ -220,16 +239,16 @@ curl_version_ccsid(unsigned int ccsid)
 
   aversion = curl_version();
 
-  if (!aversion)
+  if(!aversion)
     return aversion;
 
   i = strlen(aversion) + 1;
   i *= MAX_CONV_EXPANSION;
 
-  if (!(eversion = Curl_thread_buffer(LK_CURL_VERSION, i)))
+  if(!(eversion = Curl_thread_buffer(LK_CURL_VERSION, i)))
     return (char *) NULL;
 
-  if (convert(eversion, i, ccsid, aversion, -1, ASCII_CCSID) < 0)
+  if(convert(eversion, i, ccsid, aversion, -1, ASCII_CCSID) < 0)
     return (char *) NULL;
 
   return eversion;
@@ -244,20 +263,20 @@ curl_easy_escape_ccsid(CURL * handle, co
   char * s;
   char * d;
 
-  if (!string) {
+  if(!string) {
     errno = EINVAL;
     return (char *) NULL;
     }
 
   s = dynconvert(ASCII_CCSID, s, length? length: -1, sccsid);
 
-  if (!s)
+  if(!s)
     return (char *) NULL;
 
   d = curl_easy_escape(handle, s, 0);
   free(s);
 
-  if (!d)
+  if(!d)
     return (char *) NULL;
 
   s = dynconvert(dccsid, d, -1, ASCII_CCSID);
@@ -275,26 +294,26 @@ curl_easy_unescape_ccsid(CURL * handle,
   char * s;
   char * d;
 
-  if (!string) {
+  if(!string) {
     errno = EINVAL;
     return (char *) NULL;
     }
 
   s = dynconvert(ASCII_CCSID, s, length? length: -1, sccsid);
 
-  if (!s)
+  if(!s)
     return (char *) NULL;
 
   d = curl_easy_unescape(handle, s, 0, outlength);
   free(s);
 
-  if (!d)
+  if(!d)
     return (char *) NULL;
 
   s = dynconvert(dccsid, d, -1, ASCII_CCSID);
   free(d);
 
-  if (s && outlength)
+  if(s && outlength)
     *outlength = strlen(s);
 
   return s;
@@ -310,12 +329,12 @@ curl_slist_append_ccsid(struct curl_slis
 
   s = (char *) NULL;
 
-  if (!data)
+  if(!data)
     return curl_slist_append(list, data);
 
   s = dynconvert(ASCII_CCSID, data, -1, ccsid);
 
-  if (!s)
+  if(!s)
     return (struct curl_slist *) NULL;
 
   list = curl_slist_append(list, s);
@@ -331,12 +350,12 @@ curl_getdate_ccsid(const char * p, const
   char * s;
   time_t t;
 
-  if (!p)
+  if(!p)
     return curl_getdate(p, unused);
 
   s = dynconvert(ASCII_CCSID, p, -1, ccsid);
 
-  if (!s)
+  if(!s)
     return (time_t) -1;
 
   t = curl_getdate(s, unused);
@@ -357,10 +376,10 @@ convert_version_info_string(const char *
      `*bufp' and `*left' are updated accordingly.
      Return 0 if ok, else -1. */
 
-  if (*stringp) {
+  if(*stringp) {
     l = convert(*bufp, *left, ccsid, *stringp, -1, ASCII_CCSID);
 
-    if (l <= 0)
+    if(l <= 0)
       return -1;
 
     *stringp = *bufp;
@@ -393,12 +412,12 @@ curl_version_info_ccsid(CURLversion stam
 
   /* If caller has been compiled with a new version, error. */
 
-  if (stamp > CURLVERSION_NOW)
+  if(stamp > CURLVERSION_NOW)
     return (curl_version_info_data *) NULL;
 
   p = curl_version_info(stamp);
 
-  if (!p)
+  if(!p)
     return p;
 
   /* Measure thread space needed. */
@@ -406,53 +425,53 @@ curl_version_info_ccsid(CURLversion stam
   n = 0;
   nproto = 0;
 
-  if (p->protocols) {
+  if(p->protocols) {
     while (p->protocols[nproto])
       n += strlen(p->protocols[nproto++]);
 
     n += nproto++;
     }
 
-  if (p->version)
+  if(p->version)
     n += strlen(p->version) + 1;
 
-  if (p->host)
+  if(p->host)
     n += strlen(p->host) + 1;
 
-  if (p->ssl_version)
+  if(p->ssl_version)
     n += strlen(p->ssl_version) + 1;
 
-  if (p->libz_version)
+  if(p->libz_version)
     n += strlen(p->libz_version) + 1;
 
-  if (p->ares)
+  if(p->ares)
     n += strlen(p->ares) + 1;
 
-  if (p->libidn)
+  if(p->libidn)
     n += strlen(p->libidn) + 1;
 
-  if (p->libssh_version)
+  if(p->libssh_version)
     n += strlen(p->libssh_version) + 1;
 
   /* Allocate thread space. */
 
   n *= MAX_CONV_EXPANSION;
 
-  if (nproto)
+  if(nproto)
     n += nproto * sizeof(const char *);
 
   cp = Curl_thread_buffer(LK_VERSION_INFO_DATA, n);
   id = (curl_version_info_data *) Curl_thread_buffer(LK_VERSION_INFO,
                                                      sizeof *id);
 
-  if (!id || !cp)
+  if(!id || !cp)
     return (curl_version_info_data *) NULL;
 
   /* Copy data and convert strings. */
 
   memcpy((char *) id, (char *) p, sizeof *p);
 
-  if (id->protocols) {
+  if(id->protocols) {
     id->protocols = (const char * const *) cp;
     i = nproto * sizeof id->protocols[0];
     memcpy(cp, (char *) p->protocols, i);
@@ -460,30 +479,30 @@ curl_version_info_ccsid(CURLversion stam
     n -= i;
 
     for (i = 0; id->protocols[i]; i++)
-      if (convert_version_info_string(((const char * *) id->protocols) + i,
+      if(convert_version_info_string(((const char * *) id->protocols) + i,
                                       &cp, &n, ccsid))
         return (curl_version_info_data *) NULL;
     }
 
-  if (convert_version_info_string(&id->version, &cp, &n, ccsid))
+  if(convert_version_info_string(&id->version, &cp, &n, ccsid))
     return (curl_version_info_data *) NULL;
 
-  if (convert_version_info_string(&id->host, &cp, &n, ccsid))
+  if(convert_version_info_string(&id->host, &cp, &n, ccsid))
     return (curl_version_info_data *) NULL;
 
-  if (convert_version_info_string(&id->ssl_version, &cp, &n, ccsid))
+  if(convert_version_info_string(&id->ssl_version, &cp, &n, ccsid))
     return (curl_version_info_data *) NULL;
 
-  if (convert_version_info_string(&id->libz_version, &cp, &n, ccsid))
+  if(convert_version_info_string(&id->libz_version, &cp, &n, ccsid))
     return (curl_version_info_data *) NULL;
 
-  if (convert_version_info_string(&id->ares, &cp, &n, ccsid))
+  if(convert_version_info_string(&id->ares, &cp, &n, ccsid))
     return (curl_version_info_data *) NULL;
 
-  if (convert_version_info_string(&id->libidn, &cp, &n, ccsid))
+  if(convert_version_info_string(&id->libidn, &cp, &n, ccsid))
     return (curl_version_info_data *) NULL;
 
-  if (convert_version_info_string(&id->libssh_version, &cp, &n, ccsid))
+  if(convert_version_info_string(&id->libssh_version, &cp, &n, ccsid))
     return (curl_version_info_data *) NULL;
 
   return id;
@@ -500,15 +519,15 @@ curl_easy_strerror_ccsid(CURLcode error,
 
   s = curl_easy_strerror(error);
 
-  if (!s)
+  if(!s)
     return s;
 
   i = MAX_CONV_EXPANSION * (strlen(s) + 1);
 
-  if (!(buf = Curl_thread_buffer(LK_EASY_STRERROR, i)))
+  if(!(buf = Curl_thread_buffer(LK_EASY_STRERROR, i)))
     return (const char *) NULL;
 
-  if (convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
+  if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
     return (const char *) NULL;
 
   return (const char *) buf;
@@ -525,15 +544,15 @@ curl_share_strerror_ccsid(CURLSHcode err
 
   s = curl_share_strerror(error);
 
-  if (!s)
+  if(!s)
     return s;
 
   i = MAX_CONV_EXPANSION * (strlen(s) + 1);
 
-  if (!(buf = Curl_thread_buffer(LK_SHARE_STRERROR, i)))
+  if(!(buf = Curl_thread_buffer(LK_SHARE_STRERROR, i)))
     return (const char *) NULL;
 
-  if (convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
+  if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
     return (const char *) NULL;
 
   return (const char *) buf;
@@ -550,21 +569,39 @@ curl_multi_strerror_ccsid(CURLMcode erro
 
   s = curl_multi_strerror(error);
 
-  if (!s)
+  if(!s)
     return s;
 
   i = MAX_CONV_EXPANSION * (strlen(s) + 1);
 
-  if (!(buf = Curl_thread_buffer(LK_MULTI_STRERROR, i)))
+  if(!(buf = Curl_thread_buffer(LK_MULTI_STRERROR, i)))
     return (const char *) NULL;
 
-  if (convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
+  if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
     return (const char *) NULL;
 
   return (const char *) buf;
 }
 
 
+void
+curl_certinfo_free_all(struct curl_certinfo *info)
+
+{
+  int i;
+
+  /* Free all memory used by certificate info. */
+  if(info) {
+    if(info->certinfo) {
+      for (i = 0; i < info->num_of_certs; i++)
+        curl_slist_free_all(info->certinfo[i]);
+      free((char *) info->certinfo);
+    }
+    free((char *) info);
+  }
+}
+
+
 CURLcode
 curl_easy_getinfo_ccsid(CURL * curl, CURLINFO info, ...)
 
@@ -577,6 +614,10 @@ curl_easy_getinfo_ccsid(CURL * curl, CUR
   char * s;
   char * d;
   struct SessionHandle * data;
+  struct curl_slist * * slp;
+  struct curl_certinfo * cipf;
+  struct curl_certinfo * cipt;
+  int i;
 
   /* WARNING: unlike curl_easy_get_info(), the strings returned by this
      procedure have to be free'ed. */
@@ -586,25 +627,66 @@ curl_easy_getinfo_ccsid(CURL * curl, CUR
   paramp = va_arg(arg, void *);
   ret = Curl_getinfo(data, info, paramp);
 
-  if (ret != CURLE_OK || ((int) info & CURLINFO_TYPEMASK) != CURLINFO_STRING) {
-    va_end(arg);
-    return ret;
-    }
+  if(ret == CURLE_OK)
+    switch ((int) info & CURLINFO_TYPEMASK) {
 
-  ccsid = va_arg(arg, unsigned int);
-  va_end(arg);
-  cpp = (char * *) paramp;
-  s = *cpp;
+    case CURLINFO_STRING:
+      ccsid = va_arg(arg, unsigned int);
+      cpp = (char * *) paramp;
+      s = *cpp;
+
+      if(s) {
+        d = dynconvert(ccsid, s, -1, ASCII_CCSID);
+        *cpp = d;
+
+        if(!d)
+          ret = CURLE_OUT_OF_MEMORY;
+      }
 
-  if (!s)
-    return ret;
+      break;
 
-  d = dynconvert(ccsid, s, -1, ASCII_CCSID);
-  *cpp = d;
+    case CURLINFO_SLIST:
+      ccsid = va_arg(arg, unsigned int);
+      if(info == CURLINFO_CERTINFO) {
+        cipf = *(struct curl_certinfo * *) paramp;
+        if(cipf) {
+          if(!(cipt = (struct curl_certinfo *) malloc(sizeof *cipt)))
+            ret = CURLE_OUT_OF_MEMORY;
+          else {
+            cipt->certinfo = (struct curl_slist * *) calloc(cipf->num_of_certs +
+                             1, sizeof(struct curl_slist *));
+            if(!cipt->certinfo)
+              ret = CURLE_OUT_OF_MEMORY;
+            else {
+              cipt->num_of_certs = cipf->num_of_certs;
+              for (i = 0; i < cipf->num_of_certs; i++)
+                if(cipf->certinfo[i])
+                  if(!(cipt->certinfo[i] = slist_convert(ccsid,
+                                                          cipf->certinfo[i],
+                                                          ASCII_CCSID))) {
+                    ret = CURLE_OUT_OF_MEMORY;
+                    break;
+                  }
+              }
+            }
+
+          if(ret != CURLE_OK) {
+            curl_certinfo_free_all(cipt);
+            cipt = (struct curl_certinfo *) NULL;
+          }
 
-  if (!d)
-    return CURLE_OUT_OF_MEMORY;
+          *(struct curl_certinfo * *) paramp = cipt;
+        }
+      }
+      else {
+        slp = (struct curl_slist * *) paramp;
+        if(*slp)
+          if(!(*slp = slist_convert(ccsid, *slp, ASCII_CCSID)))
+            ret = CURLE_OUT_OF_MEMORY;
+      }
+    }
 
+  va_end(arg);
   return ret;
 }
 
@@ -615,15 +697,15 @@ Curl_is_formadd_string(CURLformoption op
 {
   switch (option) {
 
-    case CURLFORM_FILENAME:
-    case CURLFORM_CONTENTTYPE:
-    case CURLFORM_BUFFER:
-    case CURLFORM_FILE:
-    case CURLFORM_FILECONTENT:
-    case CURLFORM_COPYCONTENTS:
-    case CURLFORM_COPYNAME:
-      return 1;
-    }
+  case CURLFORM_FILENAME:
+  case CURLFORM_CONTENTTYPE:
+  case CURLFORM_BUFFER:
+  case CURLFORM_FILE:
+  case CURLFORM_FILECONTENT:
+  case CURLFORM_COPYCONTENTS:
+  case CURLFORM_COPYNAME:
+    return 1;
+  }
 
   return 0;
 }
@@ -634,9 +716,9 @@ Curl_formadd_release_local(struct curl_f
 
 {
   while (nargs--)
-    if (nargs != skip)
-      if (Curl_is_formadd_string(forms[nargs].option))
-        if (forms[nargs].value)
+    if(nargs != skip)
+      if(Curl_is_formadd_string(forms[nargs].option))
+        if(forms[nargs].value)
           free((char *) forms[nargs].value);
 
   free((char *) forms);
@@ -652,35 +734,35 @@ Curl_formadd_convert(struct curl_forms *
   char * cp;
   char * cp2;
 
-  if (formx < 0 || !forms[formx].value)
+  if(formx < 0 || !forms[formx].value)
     return 0;
 
-  if (lengthx >= 0)
+  if(lengthx >= 0)
     l = (int) forms[lengthx].value;
   else
     l = strlen(forms[formx].value) + 1;
 
   cp = malloc(MAX_CONV_EXPANSION * l);
 
-  if (!cp)
+  if(!cp)
     return -1;
 
   l = convert(cp, MAX_CONV_EXPANSION * l, ASCII_CCSID,
               forms[formx].value, l, ccsid);
 
-  if (l < 0) {
+  if(l < 0) {
     free(cp);
     return -1;
     }
 
   cp2 = realloc(cp, l);                 /* Shorten buffer to the string size. */
 
-  if (cp2)
+  if(cp2)
     cp = cp2;
 
   forms[formx].value = cp;
 
-  if (lengthx >= 0)
+  if(lengthx >= 0)
     forms[lengthx].value = (char *) l;  /* Update to length after conversion. */
 
   return l;
@@ -729,7 +811,7 @@ curl_formadd_ccsid(struct curl_httppost
   lformlen = ALLOC_GRANULE;
   lforms = malloc(lformlen * sizeof *lforms);
 
-  if (!lforms)
+  if(!lforms)
     return CURL_FORMADD_MEMORY;
 
   /* Process the arguments, copying them into local array, latching conversion
@@ -747,11 +829,11 @@ curl_formadd_ccsid(struct curl_httppost
   for (;;) {
     /* Make sure there is still room for an item in local array. */
 
-    if (nargs >= lformlen) {
+    if(nargs >= lformlen) {
       lformlen += ALLOC_GRANULE;
       tforms = realloc(lforms, lformlen * sizeof *lforms);
 
-      if (!tforms) {
+      if(!tforms) {
         result = CURL_FORMADD_MEMORY;
         break;
         }
@@ -761,7 +843,7 @@ curl_formadd_ccsid(struct curl_httppost
 
     /* Get next option. */
 
-    if (forms) {
+    if(forms) {
       /* Get option from array. */
 
       option = forms->option;
@@ -773,7 +855,7 @@ curl_formadd_ccsid(struct curl_httppost
 
       option = va_arg(arg, CURLformoption);
 
-      if (option == CURLFORM_END)
+      if(option == CURLFORM_END)
         break;
       }
 
@@ -786,7 +868,7 @@ curl_formadd_ccsid(struct curl_httppost
       continue;
 
     case CURLFORM_ARRAY:
-      if (!forms) {
+      if(!forms) {
         forms = va_arg(arg, struct curl_forms *);
         continue;
         }
@@ -798,12 +880,12 @@ curl_formadd_ccsid(struct curl_httppost
       option = CURLFORM_PTRNAME;                /* Static for now. */
 
     case CURLFORM_PTRNAME:
-      if (namex >= 0)
+      if(namex >= 0)
         result = CURL_FORMADD_OPTION_TWICE;
 
       namex = nargs;
 
-      if (!forms) {
+      if(!forms) {
         value = va_arg(arg, char *);
         nameccsid = (unsigned int) va_arg(arg, long);
         }
@@ -815,12 +897,12 @@ curl_formadd_ccsid(struct curl_httppost
       break;
 
     case CURLFORM_COPYCONTENTS:
-      if (contentx >= 0)
+      if(contentx >= 0)
         result = CURL_FORMADD_OPTION_TWICE;
 
       contentx = nargs;
 
-      if (!forms) {
+      if(!forms) {
         value = va_arg(arg, char *);
         contentccsid = (unsigned int) va_arg(arg, long);
         }
@@ -833,7 +915,7 @@ curl_formadd_ccsid(struct curl_httppost
 
     case CURLFORM_PTRCONTENTS:
     case CURLFORM_BUFFERPTR:
-      if (!forms)
+      if(!forms)
         value = va_arg(arg, char *);            /* No conversion. */
 
       break;
@@ -841,7 +923,7 @@ curl_formadd_ccsid(struct curl_httppost
     case CURLFORM_CONTENTSLENGTH:
       lengthx = nargs;
 
-      if (!forms)
+      if(!forms)
         value = (char *) va_arg(arg, long);
 
       break;
@@ -849,25 +931,25 @@ curl_formadd_ccsid(struct curl_httppost
     case CURLFORM_NAMELENGTH:
       namelengthx = nargs;
 
-      if (!forms)
+      if(!forms)
         value = (char *) va_arg(arg, long);
 
       break;
 
     case CURLFORM_BUFFERLENGTH:
-      if (!forms)
+      if(!forms)
         value = (char *) va_arg(arg, long);
 
       break;
 
     case CURLFORM_CONTENTHEADER:
-      if (!forms)
+      if(!forms)
         value = (char *) va_arg(arg, struct curl_slist *);
 
       break;
 
     case CURLFORM_STREAM:
-      if (!forms)
+      if(!forms)
         value = (char *) va_arg(arg, void *);
 
       break;
@@ -875,7 +957,7 @@ curl_formadd_ccsid(struct curl_httppost
     case CURLFORM_CONTENTTYPE:
       /* If a previous content has been encountered, convert it now. */
 
-      if (Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) {
+      if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) {
         result = CURL_FORMADD_MEMORY;
         break;
         }
@@ -887,12 +969,12 @@ curl_formadd_ccsid(struct curl_httppost
     default:
       /* Must be a convertible string. */
 
-      if (!Curl_is_formadd_string(option)) {
+      if(!Curl_is_formadd_string(option)) {
         result = CURL_FORMADD_UNKNOWN_OPTION;
         break;
         }
 
-      if (!forms) {
+      if(!forms) {
         value = va_arg(arg, char *);
         ccsid = (unsigned int) va_arg(arg, long);
         }
@@ -905,7 +987,7 @@ curl_formadd_ccsid(struct curl_httppost
 
       lforms[nargs].value = value;
 
-      if (Curl_formadd_convert(lforms, nargs, -1, ccsid) < 0) {
+      if(Curl_formadd_convert(lforms, nargs, -1, ccsid) < 0) {
         result = CURL_FORMADD_MEMORY;
         break;
         }
@@ -913,7 +995,7 @@ curl_formadd_ccsid(struct curl_httppost
       value = lforms[nargs].value;
       }
 
-    if (result != CURL_FORMADD_OK)
+    if(result != CURL_FORMADD_OK)
       break;
 
     lforms[nargs].value = value;
@@ -924,15 +1006,15 @@ curl_formadd_ccsid(struct curl_httppost
 
   /* Convert the name and the last content, now that we know their lengths. */
 
-  if (result == CURL_FORMADD_OK && namex >= 0) {
-    if (Curl_formadd_convert(lforms, namex, namelengthx, nameccsid) < 0)
+  if(result == CURL_FORMADD_OK && namex >= 0) {
+    if(Curl_formadd_convert(lforms, namex, namelengthx, nameccsid) < 0)
       result = CURL_FORMADD_MEMORY;
     else
       lforms[namex].option = CURLFORM_COPYNAME;         /* Force copy. */
     }
 
-  if (result == CURL_FORMADD_OK) {
-    if (Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0)
+  if(result == CURL_FORMADD_OK) {
+    if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0)
       result = CURL_FORMADD_MEMORY;
     else
       contentx = -1;
@@ -940,7 +1022,7 @@ curl_formadd_ccsid(struct curl_httppost
 
   /* Do the formadd with our converted parameters. */
 
-  if (result == CURL_FORMADD_OK) {
+  if(result == CURL_FORMADD_OK) {
     lforms[nargs].option = CURLFORM_END;
     result = curl_formadd(httppost, last_post,
                           CURLFORM_ARRAY, lforms, CURLFORM_END);
@@ -971,17 +1053,17 @@ Curl_formget_callback_ccsid(void * arg,
 
   p = (cfcdata *) arg;
 
-  if ((long) len <= 0)
+  if((long) len <= 0)
     return (*p->append)(p->arg, buf, len);
 
   b = malloc(MAX_CONV_EXPANSION * len);
 
-  if (!b)
+  if(!b)
     return (size_t) -1;
 
   l = convert(b, MAX_CONV_EXPANSION * len, p->ccsid, buf, len, ASCII_CCSID);
 
-  if (l < 0) {
+  if(l < 0) {
     free(b);
     return (size_t) -1;
     }
@@ -1026,13 +1108,13 @@ curl_easy_setopt_ccsid(CURL * curl, CURL
      the same message; but since threadsafeness is not handled here,
      this may occur (and we don't care!). */
 
-  if (testwarn) {
+  if(testwarn) {
     testwarn = 0;
 
 #ifdef USE_TLS_SRP
-    if ((int) STRING_LAST != (int) STRING_TLSAUTH_PASSWORD + 1)
+    if((int) STRING_LAST != (int) STRING_TLSAUTH_PASSWORD + 1)
 #else
-    if ((int) STRING_LAST != (int) STRING_MAIL_AUTH + 1)
+    if((int) STRING_LAST != (int) STRING_MAIL_AUTH + 1)
 #endif
       curl_mfprintf(stderr,
        "*** WARNING: curl_easy_setopt_ccsid() should be reworked ***\n");
@@ -1097,10 +1179,10 @@ curl_easy_setopt_ccsid(CURL * curl, CURL
     s = va_arg(arg, char *);
     ccsid = va_arg(arg, unsigned int);
 
-    if (s) {
+    if(s) {
       s = dynconvert(ASCII_CCSID, s, -1, ccsid);
 
-      if (!s) {
+      if(!s) {
         result = CURLE_OUT_OF_MEMORY;
         break;
         }
@@ -1108,7 +1190,7 @@ curl_easy_setopt_ccsid(CURL * curl, CURL
 
     result = curl_easy_setopt(curl, tag, s);
 
-    if (s)
+    if(s)
       free(s);
 
     break;
@@ -1122,16 +1204,16 @@ curl_easy_setopt_ccsid(CURL * curl, CURL
 
     pfsize = data->set.postfieldsize;
 
-    if (!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) {
+    if(!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) {
       result = curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, s);
       break;
       }
 
-    if (pfsize == -1) {
+    if(pfsize == -1) {
       /* Data is null-terminated. */
       s = dynconvert(ASCII_CCSID, s, -1, ccsid);
 
-      if (!s) {
+      if(!s) {
         result = CURLE_OUT_OF_MEMORY;
         break;
         }
@@ -1139,7 +1221,7 @@ curl_easy_setopt_ccsid(CURL * curl, CURL
     else {
       /* Data length specified. */
 
-      if (pfsize < 0 || pfsize > SIZE_MAX) {
+      if(pfsize < 0 || pfsize > SIZE_MAX) {
         result = CURLE_OUT_OF_MEMORY;
         break;
         }
@@ -1147,19 +1229,19 @@ curl_easy_setopt_ccsid(CURL * curl, CURL
       len = pfsize;
       pfsize = len * MAX_CONV_EXPANSION;
 
-      if (pfsize > SIZE_MAX)
+      if(pfsize > SIZE_MAX)
         pfsize = SIZE_MAX;
 
       cp = malloc(pfsize);
 
-      if (!cp) {
+      if(!cp) {
         result = CURLE_OUT_OF_MEMORY;
         break;
         }
 
       pfsize = convert(cp, pfsize, ASCII_CCSID, s, len, ccsid);
 
-      if (pfsize < 0) {
+      if(pfsize < 0) {
         free(cp);
         result = CURLE_OUT_OF_MEMORY;
         break;
diff -Naurp a/packages/OS400/ccsidcurl.h b/packages/OS400/ccsidcurl.h
--- a/packages/OS400/ccsidcurl.h	2010-05-31 17:16:29.000000000 +0200
+++ b/packages/OS400/ccsidcurl.h	2013-07-12 17:02:50.685677413 +0200
@@ -60,5 +60,6 @@ CURL_EXTERN int curl_formget_ccsid(struc
                                    curl_formget_callback append,
                                    unsigned int ccsid);
 CURL_EXTERN CURLcode curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...);
+CURL_EXTERN void curl_certinfo_free_all(struct curl_certinfo *info);
 
 #endif
diff -Naurp a/packages/OS400/curl.inc.in b/packages/OS400/curl.inc.in
--- a/packages/OS400/curl.inc.in	2013-03-12 14:19:42.000000000 +0100
+++ b/packages/OS400/curl.inc.in	2013-07-12 17:02:50.686677421 +0200
@@ -2109,14 +2109,19 @@
      d  code                               value like(CURLMcode)
      d  ccsid                        10u 0 value
       *
+      * May be used for strings and structures.
      d curl_easy_getinfo_ccsid...
      d                 pr                  extproc('curl_easy_getinfo_ccsid')
      d                                     like(CURLcode)
      d  curl                           *   value                                CURL *
      d  info                               value like(CURLINFO)
-     d  stringarg                      *   options(*nopass)                     char *
+     d  ptrarg                         *   options(*nopass)                     char *
      d  ccsid                        10u 0 value options(*nopass)
       *
+     d curl_certinfo_free_all...
+     d                 pr                  extproc('curl_certinfo_free_all')
+     d  info                           *   value
+      *
      d curl_formadd_ccsid...
      d                 pr                  extproc('curl_formadd_ccsid')
      d                                     like(CURLFORMcode)
diff -Naurp a/packages/OS400/os400sys.c b/packages/OS400/os400sys.c
--- a/packages/OS400/os400sys.c	2013-03-12 14:07:36.000000000 +0100
+++ b/packages/OS400/os400sys.c	2013-07-12 17:02:50.686677421 +0200
@@ -42,6 +42,11 @@
 #include <qsossl.h>
 #endif
 
+#ifdef USE_GSKIT
+#include <gskssl.h>
+#include <qsoasync.h>
+#endif
+
 #ifdef HAVE_GSSAPI
 #include <gssapi.h>
 #endif
@@ -451,6 +456,412 @@ Curl_SSL_Strerror_a(int sslreturnvalue,
 #endif /* USE_QSOSSL */
 
 
+#ifdef USE_GSKIT
+
+/* ASCII wrappers for the GSKit procedures. */
+
+/*
+ * EBCDIC --> ASCII string mapping table.
+ * Some strings returned by GSKit are dynamically allocated and automatically
+ * released when closing the handle.
+ * To provide the same functionality, we use a "private" handle that
+ * holds the GSKit handle and a list of string mappings. This will allow
+ * avoid conversion of already converted strings and releasing them upon
+ * close time.
+ */
+
+struct gskstrlist {
+  struct gskstrlist * next;
+  const char * ebcdicstr;
+  const char * asciistr;
+};
+
+struct Curl_gsk_descriptor {
+  gsk_handle h;
+  struct gskstrlist * strlist;
+};
+
+
+int
+Curl_gsk_environment_open(gsk_handle * my_env_handle)
+
+{
+  struct Curl_gsk_descriptor * p;
+  gsk_handle h;
+  int rc;
+
+  if(!my_env_handle)
+    return GSK_OS400_ERROR_INVALID_POINTER;
+  if(!(p = (struct Curl_gsk_descriptor *) malloc(sizeof *p)))
+    return GSK_INSUFFICIENT_STORAGE;
+  p->strlist = (struct gskstrlist *) NULL;
+  if((rc = gsk_environment_open(&p->h)) != GSK_OK)
+    free(p);
+  else
+    *my_env_handle = (gsk_handle) p;
+  return rc;
+}
+
+
+int
+Curl_gsk_secure_soc_open(gsk_handle my_env_handle,
+                         gsk_handle * my_session_handle)
+
+{
+  struct Curl_gsk_descriptor * p;
+  gsk_handle h;
+  int rc;
+
+  if(!my_env_handle)
+    return GSK_INVALID_HANDLE;
+  if(!my_session_handle)
+    return GSK_OS400_ERROR_INVALID_POINTER;
+  h = ((struct Curl_gsk_descriptor *) my_env_handle)->h;
+  if(!(p = (struct Curl_gsk_descriptor *) malloc(sizeof *p)))
+    return GSK_INSUFFICIENT_STORAGE;
+  p->strlist = (struct gskstrlist *) NULL;
+  if((rc = gsk_secure_soc_open(h, &p->h)) != GSK_OK)
+    free(p);
+  else
+    *my_session_handle = (gsk_handle) p;
+  return rc;
+}
+
+
+static void
+gsk_free_handle(struct Curl_gsk_descriptor * p)
+
+{
+  struct gskstrlist * q;
+
+  while ((q = p->strlist)) {
+    p->strlist = q;
+    free((void *) q->asciistr);
+    free(q);
+  }
+  free(p);
+}
+
+
+int
+Curl_gsk_environment_close(gsk_handle * my_env_handle)
+
+{
+  struct Curl_gsk_descriptor * p;
+  int rc;
+
+  if(!my_env_handle)
+    return GSK_OS400_ERROR_INVALID_POINTER;
+  if(!*my_env_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) *my_env_handle;
+  if ((rc = gsk_environment_close(&p->h)) == GSK_OK) {
+    gsk_free_handle(p);
+    *my_env_handle = (gsk_handle) NULL;
+  }
+  return rc;
+}
+
+
+int
+Curl_gsk_secure_soc_close(gsk_handle * my_session_handle)
+
+{
+  struct Curl_gsk_descriptor * p;
+  int rc;
+
+  if(!my_session_handle)
+    return GSK_OS400_ERROR_INVALID_POINTER;
+  if(!*my_session_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) *my_session_handle;
+  if ((rc = gsk_secure_soc_close(&p->h)) == GSK_OK) {
+    gsk_free_handle(p);
+    *my_session_handle = (gsk_handle) NULL;
+  }
+  return rc;
+}
+
+
+int
+Curl_gsk_environment_init(gsk_handle my_env_handle)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_env_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_env_handle;
+  return gsk_environment_init(p->h);
+}
+
+
+int
+Curl_gsk_secure_soc_init(gsk_handle my_session_handle)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_session_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_session_handle;
+  return gsk_secure_soc_init(p->h);
+}
+
+
+int
+Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID,
+                                const char * buffer, int bufSize)
+
+{
+  struct Curl_gsk_descriptor * p;
+  char * ebcdicbuf;
+  int rc;
+
+  if(!my_gsk_handle)
+    return GSK_INVALID_HANDLE;
+  if(!buffer)
+    return GSK_OS400_ERROR_INVALID_POINTER;
+  if(bufSize < 0)
+    return GSK_ATTRIBUTE_INVALID_LENGTH;
+  p = (struct Curl_gsk_descriptor *) my_gsk_handle;
+  if(!bufSize)
+    bufSize = strlen(buffer);
+  if (!(ebcdicbuf = malloc(bufSize + 1)))
+      return GSK_INSUFFICIENT_STORAGE;
+  QadrtConvertA2E(ebcdicbuf, buffer, bufSize, bufSize);
+  ebcdicbuf[bufSize] = '\0';
+  rc = gsk_attribute_set_buffer(p->h, bufID, ebcdicbuf, bufSize);
+  free(ebcdicbuf);
+  return rc;
+}
+
+
+int
+Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID,
+                            GSK_ENUM_VALUE enumValue)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_gsk_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_gsk_handle;
+  return gsk_attribute_set_enum(p->h, enumID, enumValue);
+}
+
+
+int
+Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle,
+                                     GSK_NUM_ID numID, int numValue)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_gsk_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_gsk_handle;
+  return gsk_attribute_set_numeric_value(p->h, numID, numValue);
+}
+
+
+int
+Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle,
+                                GSK_CALLBACK_ID callBackID,
+                                void * callBackAreaPtr)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_gsk_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_gsk_handle;
+  return gsk_attribute_set_callback(p->h, callBackID, callBackAreaPtr);
+}
+
+
+static int
+cachestring(struct Curl_gsk_descriptor * p,
+            const char * ebcdicbuf, int bufsize, const char * * buffer)
+
+{
+  int rc;
+  char * asciibuf;
+  struct gskstrlist * sp;
+
+  for (sp = p->strlist; sp; sp = sp->next)
+    if(sp->ebcdicstr == ebcdicbuf)
+      break;
+  if(!sp) {
+    if(!(sp = (struct gskstrlist *) malloc(sizeof *sp)))
+      return GSK_INSUFFICIENT_STORAGE;
+    if(!(asciibuf = malloc(bufsize + 1))) {
+      free(sp);
+      return GSK_INSUFFICIENT_STORAGE;
+    }
+    QadrtConvertE2A(asciibuf, ebcdicbuf, bufsize, bufsize);
+    asciibuf[bufsize] = '\0';
+    sp->ebcdicstr = ebcdicbuf;
+    sp->asciistr = asciibuf;
+    sp->next = p->strlist;
+    p->strlist = sp;
+  }
+  *buffer = sp->asciistr;
+  return GSK_OK;
+}
+
+
+int
+Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID,
+                                const char * * buffer, int * bufSize)
+
+{
+  struct Curl_gsk_descriptor * p;
+  int rc;
+  const char * mybuf;
+  int mylen;
+
+  if(!my_gsk_handle)
+    return GSK_INVALID_HANDLE;
+  if(!buffer || !bufSize)
+    return GSK_OS400_ERROR_INVALID_POINTER;
+  p = (struct Curl_gsk_descriptor *) my_gsk_handle;
+  if ((rc = gsk_attribute_get_buffer(p->h, bufID, &mybuf, &mylen)) != GSK_OK)
+    return rc;
+  if((rc = cachestring(p, mybuf, mylen, buffer)) == GSK_OK)
+    *bufSize = mylen;
+  return rc;
+}
+
+
+int
+Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID,
+                            GSK_ENUM_VALUE * enumValue)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_gsk_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_gsk_handle;
+  return gsk_attribute_get_enum(p->h, enumID, enumValue);
+}
+
+
+int
+Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle,
+                                     GSK_NUM_ID numID, int * numValue)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_gsk_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_gsk_handle;
+  return gsk_attribute_get_numeric_value(p->h, numID, numValue);
+}
+
+
+int
+Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle,
+                                 GSK_CERT_ID certID,
+                                 const gsk_cert_data_elem * * certDataElem,
+                                 int * certDataElementCount)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_gsk_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_gsk_handle;
+  /* No need to convert code: text results are already in ASCII. */
+  return gsk_attribute_get_cert_info(p->h, certID,
+                                     certDataElem, certDataElementCount);
+}
+
+
+int
+Curl_gsk_secure_soc_misc(gsk_handle my_session_handle, GSK_MISC_ID miscID)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_session_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_session_handle;
+  return gsk_secure_soc_misc(p->h, miscID);
+}
+
+
+int
+Curl_gsk_secure_soc_read(gsk_handle my_session_handle, char * readBuffer,
+                         int readBufSize, int * amtRead)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_session_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_session_handle;
+  return gsk_secure_soc_read(p->h, readBuffer, readBufSize, amtRead);
+}
+
+
+int
+Curl_gsk_secure_soc_write(gsk_handle my_session_handle, char * writeBuffer,
+                          int writeBufSize, int * amtWritten)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_session_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_session_handle;
+  return gsk_secure_soc_write(p->h, writeBuffer, writeBufSize, amtWritten);
+}
+
+
+const char *
+Curl_gsk_strerror_a(int gsk_return_value)
+
+{
+  int i;
+  const char * cp;
+  char * cp2;
+
+  cp = gsk_strerror(gsk_return_value);
+
+  if (!cp)
+    return cp;
+
+  i = strlen(cp);
+
+  if (!(cp2 = Curl_thread_buffer(LK_GSK_ERROR, MAX_CONV_EXPANSION * i + 1)))
+    return cp2;
+
+  i = QadrtConvertE2A(cp2, cp, MAX_CONV_EXPANSION * i, i);
+  cp2[i] = '\0';
+  return cp2;
+}
+
+int
+Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle,
+                              int IOCompletionPort,
+                              Qso_OverlappedIO_t * communicationsArea)
+
+{
+  struct Curl_gsk_descriptor * p;
+
+  if(!my_session_handle)
+    return GSK_INVALID_HANDLE;
+  p = (struct Curl_gsk_descriptor *) my_session_handle;
+  return gsk_secure_soc_startInit(p->h, IOCompletionPort, communicationsArea);
+}
+
+#endif /* USE_GSKIT */
+
+
+
 #ifdef HAVE_GSSAPI
 
 /* ASCII wrappers for the GSSAPI procedures. */
diff -Naurp a/packages/OS400/os400sys.h b/packages/OS400/os400sys.h
--- a/packages/OS400/os400sys.h	2010-05-31 17:16:29.000000000 +0200
+++ b/packages/OS400/os400sys.h	2013-07-12 17:02:50.686677421 +0200
@@ -31,6 +31,7 @@
 
 typedef enum {
         LK_SSL_ERROR,
+        LK_GSK_ERROR,
         LK_LDAP_ERROR,
         LK_CURL_VERSION,
         LK_VERSION_INFO,
diff -Naurp a/packages/OS400/README.OS400 b/packages/OS400/README.OS400
--- a/packages/OS400/README.OS400	2012-11-08 16:52:02.000000000 +0100
+++ b/packages/OS400/README.OS400	2013-07-12 17:02:50.685677413 +0200
@@ -39,22 +39,24 @@ header files are thus altered during bui
 order to force libcurl enums of being type int (the pragma disposition in use
 before inclusion is restored before resuming the including unit compilation).
 
-  Three SSL implementations were present in libcurl. Nevertheless, none of them
-is available on OS/400. To support SSL on OS/400, a fourth implementation has
-been added (qssl.[ch]). There is no way to have different certificate stores
-for CAs and for personal/application certificates/key. More, the SSL context
-may be defined as an application identifier in the main certificate store,
-or as a keyring file. As a consequence, the meaning of some fields have been
-slightly altered:
-_ The "certificate identifier" is taken from CURLOPT_SSLCERT if defined, else
-from CURLOPT_CAINFO.
-_ The certificate identifier is then used as an application identifier in the
-main certificate store. If successful, this context is used.
-_ If the previous step failed, the certificate identifier is used as the file
-name of a keyring. CURLOPT_KEYPASSWD is used here as the keyring password.
-_ The default ca-bundle (CURLOPT_CAINFO) is set to the main certificate store's
-keyring file name: this allows to use the system global CAs by default. (In that
-case, the keyring password is safely recovered from the system... IBM dixit!)
+  Two SSL implementations are available to libcurl on OS/400: QsoSSL which is
+obsolescent, does not support asynchronous I/O and only allows a single SSL
+context within a job, and GSKit that does not suffer from these limitations
+and is able to provide some information about the server certificate.
+  Both implementations of SSL are working on "certificate stores" or keyrings,
+rather than individual certificate/key files. Certificate stores, as weel as
+"certificate labels" are managed by external IBM-defined applications.
+  There are two ways to specify an SSL context:
+- By an application identifier.
+- By a keyring file pathname and (optionally) certificate label.
+  To identify an SSL context by application identifier, use option
+SETOPT_SSLCERT to specify the application identifier.
+  To address an SSL context by keyring and certificate label, use CURLOPT_CAINFO
+to set-up the keyring pathname, CURLOPT_SSLCERT to define the certificate label
+(omitting it will cause the default certificate in keyring to be used) and
+CURLOPT_KEYPASSWD to give the keyring password. If SSL is used without
+defining any of these options, the default (i.e.: system) keyring is used for
+server certificate validation.
 
   Non-standard EBCDIC wrapper prototypes are defined in an additional header
 file: ccsidcurl.h. These should be self-explanatory to an OS/400-aware
@@ -154,6 +156,14 @@ use:
         CURLINFO_PRIMARY_IP
         CURLINFO_RTSP_SESSION_ID
         CURLINFO_LOCAL_IP
+  Likewise, the following options are followed by a struct curl_slist * * and a
+CCSID.
+        CURLINFO_SSL_ENGINES
+        CURLINFO_COOKIELIST
+Lists returned should be released with curl_slist_free_all() after use.
+  Option CURLINFO_CERTINFO is followed by a struct curl_certinfo * * and a
+CCSID. Returned structures sould be free'ed using curl_certinfo_free_all() after
+use.
   Other options are processed like in curl_easy_getinfo().
 
   Standard compilation environment does support neither autotools nor make;
@@ -200,6 +210,8 @@ _ As a prerequisite, QADRT development e
 _ Install the curl source directory in IFS.
 _ Enter shell (QSH)
 _ Change current directory to the curl installation directory
+- If the SSL backend has to be changed, edit file lib/config-os400.h
+  accordingly.
 _ Change current directory to ./packages/OS400
 _ Edit file iniscript.sh. You may want to change tunable configuration
   parameters, like debug info generation, optimisation level, listing option,
