Home | History | Annotate | Download | only in vtls
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at http://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 
     23 #include "curl_setup.h"
     24 
     25 #ifdef USE_GSKIT
     26 
     27 #include <gskssl.h>
     28 #include <qsoasync.h>
     29 
     30 /* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
     31 #ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
     32 #define GSK_SSL_EXTN_SERVERNAME_REQUEST         230
     33 #endif
     34 
     35 #ifndef GSK_TLSV10_CIPHER_SPECS
     36 #define GSK_TLSV10_CIPHER_SPECS                 236
     37 #endif
     38 
     39 #ifndef GSK_TLSV11_CIPHER_SPECS
     40 #define GSK_TLSV11_CIPHER_SPECS                 237
     41 #endif
     42 
     43 #ifndef GSK_TLSV12_CIPHER_SPECS
     44 #define GSK_TLSV12_CIPHER_SPECS                 238
     45 #endif
     46 
     47 #ifndef GSK_PROTOCOL_TLSV11
     48 #define GSK_PROTOCOL_TLSV11                     437
     49 #endif
     50 
     51 #ifndef GSK_PROTOCOL_TLSV12
     52 #define GSK_PROTOCOL_TLSV12                     438
     53 #endif
     54 
     55 #ifndef GSK_FALSE
     56 #define GSK_FALSE                               0
     57 #endif
     58 
     59 #ifndef GSK_TRUE
     60 #define GSK_TRUE                                1
     61 #endif
     62 
     63 
     64 #ifdef HAVE_LIMITS_H
     65 #  include <limits.h>
     66 #endif
     67 
     68 #include <curl/curl.h>
     69 #include "urldata.h"
     70 #include "sendf.h"
     71 #include "gskit.h"
     72 #include "vtls.h"
     73 #include "connect.h" /* for the connect timeout */
     74 #include "select.h"
     75 #include "strequal.h"
     76 #include "x509asn1.h"
     77 #include "curl_printf.h"
     78 
     79 #include "curl_memory.h"
     80 /* The last #include file should be: */
     81 #include "memdebug.h"
     82 
     83 
     84 /* SSL version flags. */
     85 #define CURL_GSKPROTO_SSLV2     0
     86 #define CURL_GSKPROTO_SSLV2_MASK        (1 << CURL_GSKPROTO_SSLV2)
     87 #define CURL_GSKPROTO_SSLV3     1
     88 #define CURL_GSKPROTO_SSLV3_MASK        (1 << CURL_GSKPROTO_SSLV3)
     89 #define CURL_GSKPROTO_TLSV10    2
     90 #define CURL_GSKPROTO_TLSV10_MASK        (1 << CURL_GSKPROTO_TLSV10)
     91 #define CURL_GSKPROTO_TLSV11    3
     92 #define CURL_GSKPROTO_TLSV11_MASK        (1 << CURL_GSKPROTO_TLSV11)
     93 #define CURL_GSKPROTO_TLSV12    4
     94 #define CURL_GSKPROTO_TLSV12_MASK        (1 << CURL_GSKPROTO_TLSV12)
     95 #define CURL_GSKPROTO_LAST      5
     96 
     97 
     98 /* Supported ciphers. */
     99 typedef struct {
    100   const char *name;            /* Cipher name. */
    101   const char *gsktoken;        /* Corresponding token for GSKit String. */
    102   unsigned int versions;       /* SSL version flags. */
    103 }  gskit_cipher;
    104 
    105 static const gskit_cipher  ciphertable[] = {
    106   { "null-md5",         "01",
    107       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
    108       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
    109   { "null-sha",         "02",
    110       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
    111       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
    112   { "exp-rc4-md5",      "03",
    113       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
    114   { "rc4-md5",          "04",
    115       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
    116       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
    117   { "rc4-sha",          "05",
    118       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
    119       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
    120   { "exp-rc2-cbc-md5",  "06",
    121       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
    122   { "exp-des-cbc-sha",  "09",
    123       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
    124       CURL_GSKPROTO_TLSV11_MASK },
    125   { "des-cbc3-sha",     "0A",
    126       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
    127       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
    128   { "aes128-sha",       "2F",
    129       CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
    130       CURL_GSKPROTO_TLSV12_MASK },
    131   { "aes256-sha",       "35",
    132       CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
    133       CURL_GSKPROTO_TLSV12_MASK },
    134   { "null-sha256",      "3B",   CURL_GSKPROTO_TLSV12_MASK },
    135   { "aes128-sha256",    "3C",   CURL_GSKPROTO_TLSV12_MASK },
    136   { "aes256-sha256",    "3D",   CURL_GSKPROTO_TLSV12_MASK },
    137   { "aes128-gcm-sha256",
    138                         "9C",   CURL_GSKPROTO_TLSV12_MASK },
    139   { "aes256-gcm-sha384",
    140                         "9D",   CURL_GSKPROTO_TLSV12_MASK },
    141   { "rc4-md5",          "1",    CURL_GSKPROTO_SSLV2_MASK },
    142   { "exp-rc4-md5",      "2",    CURL_GSKPROTO_SSLV2_MASK },
    143   { "rc2-md5",          "3",    CURL_GSKPROTO_SSLV2_MASK },
    144   { "exp-rc2-md5",      "4",    CURL_GSKPROTO_SSLV2_MASK },
    145   { "des-cbc-md5",      "6",    CURL_GSKPROTO_SSLV2_MASK },
    146   { "des-cbc3-md5",     "7",    CURL_GSKPROTO_SSLV2_MASK },
    147   { (const char *) NULL, (const char *) NULL, 0       }
    148 };
    149 
    150 
    151 static bool is_separator(char c)
    152 {
    153   /* Return whether character is a cipher list separator. */
    154   switch (c) {
    155   case ' ':
    156   case '\t':
    157   case ':':
    158   case ',':
    159   case ';':
    160     return true;
    161   }
    162   return false;
    163 }
    164 
    165 
    166 static CURLcode gskit_status(struct SessionHandle *data, int rc,
    167                              const char *procname, CURLcode defcode)
    168 {
    169   /* Process GSKit status and map it to a CURLcode. */
    170   switch (rc) {
    171   case GSK_OK:
    172   case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
    173     return CURLE_OK;
    174   case GSK_KEYRING_OPEN_ERROR:
    175   case GSK_OS400_ERROR_NO_ACCESS:
    176     return CURLE_SSL_CACERT_BADFILE;
    177   case GSK_INSUFFICIENT_STORAGE:
    178     return CURLE_OUT_OF_MEMORY;
    179   case GSK_ERROR_BAD_V2_CIPHER:
    180   case GSK_ERROR_BAD_V3_CIPHER:
    181   case GSK_ERROR_NO_CIPHERS:
    182     return CURLE_SSL_CIPHER;
    183   case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
    184   case GSK_ERROR_CERT_VALIDATION:
    185     return CURLE_PEER_FAILED_VERIFICATION;
    186   case GSK_OS400_ERROR_TIMED_OUT:
    187     return CURLE_OPERATION_TIMEDOUT;
    188   case GSK_WOULD_BLOCK:
    189     return CURLE_AGAIN;
    190   case GSK_OS400_ERROR_NOT_REGISTERED:
    191     break;
    192   case GSK_ERROR_IO:
    193     switch (errno) {
    194     case ENOMEM:
    195       return CURLE_OUT_OF_MEMORY;
    196     default:
    197       failf(data, "%s I/O error: %s", procname, strerror(errno));
    198       break;
    199     }
    200     break;
    201   default:
    202     failf(data, "%s: %s", procname, gsk_strerror(rc));
    203     break;
    204   }
    205   return defcode;
    206 }
    207 
    208 
    209 static CURLcode set_enum(struct SessionHandle *data, gsk_handle h,
    210                 GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
    211 {
    212   int rc = gsk_attribute_set_enum(h, id, value);
    213 
    214   switch (rc) {
    215   case GSK_OK:
    216     return CURLE_OK;
    217   case GSK_ERROR_IO:
    218     failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
    219     break;
    220   case GSK_ATTRIBUTE_INVALID_ID:
    221     if(unsupported_ok)
    222       return CURLE_UNSUPPORTED_PROTOCOL;
    223   default:
    224     failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
    225     break;
    226   }
    227   return CURLE_SSL_CONNECT_ERROR;
    228 }
    229 
    230 
    231 static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h,
    232                         GSK_BUF_ID id, const char *buffer, bool unsupported_ok)
    233 {
    234   int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
    235 
    236   switch (rc) {
    237   case GSK_OK:
    238     return CURLE_OK;
    239   case GSK_ERROR_IO:
    240     failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
    241     break;
    242   case GSK_ATTRIBUTE_INVALID_ID:
    243     if(unsupported_ok)
    244       return CURLE_UNSUPPORTED_PROTOCOL;
    245   default:
    246     failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
    247     break;
    248   }
    249   return CURLE_SSL_CONNECT_ERROR;
    250 }
    251 
    252 
    253 static CURLcode set_numeric(struct SessionHandle *data,
    254                             gsk_handle h, GSK_NUM_ID id, int value)
    255 {
    256   int rc = gsk_attribute_set_numeric_value(h, id, value);
    257 
    258   switch (rc) {
    259   case GSK_OK:
    260     return CURLE_OK;
    261   case GSK_ERROR_IO:
    262     failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
    263           strerror(errno));
    264     break;
    265   default:
    266     failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
    267     break;
    268   }
    269   return CURLE_SSL_CONNECT_ERROR;
    270 }
    271 
    272 
    273 static CURLcode set_callback(struct SessionHandle *data,
    274                              gsk_handle h, GSK_CALLBACK_ID id, void *info)
    275 {
    276   int rc = gsk_attribute_set_callback(h, id, info);
    277 
    278   switch (rc) {
    279   case GSK_OK:
    280     return CURLE_OK;
    281   case GSK_ERROR_IO:
    282     failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
    283     break;
    284   default:
    285     failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
    286     break;
    287   }
    288   return CURLE_SSL_CONNECT_ERROR;
    289 }
    290 
    291 
    292 static CURLcode set_ciphers(struct SessionHandle *data,
    293                                         gsk_handle h, unsigned int *protoflags)
    294 {
    295   const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
    296   const char *clp;
    297   const gskit_cipher *ctp;
    298   int i;
    299   int l;
    300   bool unsupported;
    301   CURLcode result;
    302   struct {
    303     char *buf;
    304     char *ptr;
    305   } ciphers[CURL_GSKPROTO_LAST];
    306 
    307   /* Compile cipher list into GSKit-compatible cipher lists. */
    308 
    309   if(!cipherlist)
    310     return CURLE_OK;
    311   while(is_separator(*cipherlist))     /* Skip initial separators. */
    312     cipherlist++;
    313   if(!*cipherlist)
    314     return CURLE_OK;
    315 
    316   /* We allocate GSKit buffers of the same size as the input string: since
    317      GSKit tokens are always shorter than their cipher names, allocated buffers
    318      will always be large enough to accomodate the result. */
    319   l = strlen(cipherlist) + 1;
    320   memset((char *) ciphers, 0, sizeof ciphers);
    321   for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
    322     ciphers[i].buf = malloc(l);
    323     if(!ciphers[i].buf) {
    324       while(i--)
    325         free(ciphers[i].buf);
    326       return CURLE_OUT_OF_MEMORY;
    327     }
    328     ciphers[i].ptr = ciphers[i].buf;
    329     *ciphers[i].ptr = '\0';
    330   }
    331 
    332   /* Process each cipher in input string. */
    333   unsupported = FALSE;
    334   result = CURLE_OK;
    335   for(;;) {
    336     for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
    337       cipherlist++;
    338     l = cipherlist - clp;
    339     if(!l)
    340       break;
    341     /* Search the cipher in our table. */
    342     for(ctp = ciphertable; ctp->name; ctp++)
    343       if(strnequal(ctp->name, clp, l) && !ctp->name[l])
    344         break;
    345     if(!ctp->name) {
    346       failf(data, "Unknown cipher %.*s", l, clp);
    347       result = CURLE_SSL_CIPHER;
    348     }
    349     else {
    350       unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK |
    351                         CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK));
    352       for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
    353         if(ctp->versions & (1 << i)) {
    354           strcpy(ciphers[i].ptr, ctp->gsktoken);
    355           ciphers[i].ptr += strlen(ctp->gsktoken);
    356         }
    357       }
    358     }
    359 
    360    /* Advance to next cipher name or end of string. */
    361     while(is_separator(*cipherlist))
    362       cipherlist++;
    363   }
    364 
    365   /* Disable protocols with empty cipher lists. */
    366   for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
    367     if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) {
    368       *protoflags &= ~(1 << i);
    369       ciphers[i].buf[0] = '\0';
    370     }
    371   }
    372 
    373   /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */
    374   if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) {
    375     result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS,
    376                         ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE);
    377     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
    378       result = CURLE_OK;
    379       if(unsupported) {
    380         failf(data, "TLSv1.1-only ciphers are not yet supported");
    381         result = CURLE_SSL_CIPHER;
    382       }
    383     }
    384   }
    385   if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) {
    386     result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS,
    387                         ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE);
    388     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
    389       result = CURLE_OK;
    390       if(unsupported) {
    391         failf(data, "TLSv1.2-only ciphers are not yet supported");
    392         result = CURLE_SSL_CIPHER;
    393       }
    394     }
    395   }
    396 
    397   /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to
    398      the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */
    399   if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) {
    400     result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS,
    401                         ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE);
    402     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
    403       result = CURLE_OK;
    404       strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr,
    405              ciphers[CURL_GSKPROTO_TLSV10].ptr);
    406     }
    407   }
    408 
    409   /* Set-up other ciphers. */
    410   if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK))
    411     result = set_buffer(data, h, GSK_V3_CIPHER_SPECS,
    412                         ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE);
    413   if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK))
    414     result = set_buffer(data, h, GSK_V2_CIPHER_SPECS,
    415                         ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE);
    416 
    417   /* Clean-up. */
    418   for(i = 0; i < CURL_GSKPROTO_LAST; i++)
    419     free(ciphers[i].buf);
    420 
    421   return result;
    422 }
    423 
    424 
    425 int Curl_gskit_init(void)
    426 {
    427   /* No initialisation needed. */
    428 
    429   return 1;
    430 }
    431 
    432 
    433 void Curl_gskit_cleanup(void)
    434 {
    435   /* Nothing to do. */
    436 }
    437 
    438 
    439 static CURLcode init_environment(struct SessionHandle *data,
    440                                  gsk_handle *envir, const char *appid,
    441                                  const char *file, const char *label,
    442                                  const char *password)
    443 {
    444   int rc;
    445   CURLcode result;
    446   gsk_handle h;
    447 
    448   /* Creates the GSKit environment. */
    449 
    450   rc = gsk_environment_open(&h);
    451   switch (rc) {
    452   case GSK_OK:
    453     break;
    454   case GSK_INSUFFICIENT_STORAGE:
    455     return CURLE_OUT_OF_MEMORY;
    456   default:
    457     failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
    458     return CURLE_SSL_CONNECT_ERROR;
    459   }
    460 
    461   result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE);
    462   if(!result && appid)
    463     result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE);
    464   if(!result && file)
    465     result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE);
    466   if(!result && label)
    467     result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE);
    468   if(!result && password)
    469     result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE);
    470 
    471   if(!result) {
    472     /* Locate CAs, Client certificate and key according to our settings.
    473        Note: this call may be blocking for some tenths of seconds. */
    474     result = gskit_status(data, gsk_environment_init(h),
    475                           "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
    476     if(!result) {
    477       *envir = h;
    478       return result;
    479     }
    480   }
    481   /* Error: rollback. */
    482   gsk_environment_close(&h);
    483   return result;
    484 }
    485 
    486 
    487 static void cancel_async_handshake(struct connectdata *conn, int sockindex)
    488 {
    489   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    490   Qso_OverlappedIO_t cstat;
    491 
    492   if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
    493     QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
    494 }
    495 
    496 
    497 static void close_async_handshake(struct ssl_connect_data *connssl)
    498 {
    499   QsoDestroyIOCompletionPort(connssl->iocport);
    500   connssl->iocport = -1;
    501 }
    502 
    503 
    504 static void close_one(struct ssl_connect_data *conn,
    505                       struct SessionHandle *data)
    506 {
    507   if(conn->handle) {
    508     gskit_status(data, gsk_secure_soc_close(&conn->handle),
    509               "gsk_secure_soc_close()", 0);
    510     conn->handle = (gsk_handle) NULL;
    511   }
    512   if(conn->iocport >= 0)
    513     close_async_handshake(conn);
    514 }
    515 
    516 
    517 static ssize_t gskit_send(struct connectdata *conn, int sockindex,
    518                            const void *mem, size_t len, CURLcode *curlcode)
    519 {
    520   struct SessionHandle *data = conn->data;
    521   CURLcode cc;
    522   int written;
    523 
    524   cc = gskit_status(data,
    525                     gsk_secure_soc_write(conn->ssl[sockindex].handle,
    526                                          (char *) mem, (int) len, &written),
    527                     "gsk_secure_soc_write()", CURLE_SEND_ERROR);
    528   if(cc != CURLE_OK) {
    529     *curlcode = cc;
    530     written = -1;
    531   }
    532   return (ssize_t) written; /* number of bytes */
    533 }
    534 
    535 
    536 static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
    537                            size_t buffersize, CURLcode *curlcode)
    538 {
    539   struct SessionHandle *data = conn->data;
    540   int buffsize;
    541   int nread;
    542   CURLcode cc;
    543 
    544   buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
    545   cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
    546                                               buf, buffsize, &nread),
    547                     "gsk_secure_soc_read()", CURLE_RECV_ERROR);
    548   if(cc != CURLE_OK) {
    549     *curlcode = cc;
    550     nread = -1;
    551   }
    552   return (ssize_t) nread;
    553 }
    554 
    555 
    556 static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
    557 {
    558   struct SessionHandle *data = conn->data;
    559   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    560   gsk_handle envir;
    561   CURLcode result;
    562   int rc;
    563   char *keyringfile;
    564   char *keyringpwd;
    565   char *keyringlabel;
    566   char *sni;
    567   unsigned int protoflags;
    568   long timeout;
    569   Qso_OverlappedIO_t commarea;
    570 
    571   /* Create SSL environment, start (preferably asynchronous) handshake. */
    572 
    573   connssl->handle = (gsk_handle) NULL;
    574   connssl->iocport = -1;
    575 
    576   /* GSKit supports two ways of specifying an SSL context: either by
    577    *  application identifier (that should have been defined at the system
    578    *  level) or by keyring file, password and certificate label.
    579    * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
    580    *  application identifier of the certificate label.
    581    * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
    582    * It is not possible to have different keyrings for the CAs and the
    583    *  local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
    584    *  the keyring file.
    585    * If no key password is given and the keyring is the system keyring,
    586    *  application identifier mode is tried first, as recommended in IBM doc.
    587    */
    588 
    589   keyringfile = data->set.str[STRING_SSL_CAFILE];
    590   keyringpwd = data->set.str[STRING_KEY_PASSWD];
    591   keyringlabel = data->set.str[STRING_CERT];
    592   envir = (gsk_handle) NULL;
    593 
    594   if(keyringlabel && *keyringlabel && !keyringpwd &&
    595       !strcmp(keyringfile, CURL_CA_BUNDLE)) {
    596     /* Try application identifier mode. */
    597     init_environment(data, &envir, keyringlabel, (const char *) NULL,
    598                      (const char *) NULL, (const char *) NULL);
    599   }
    600 
    601   if(!envir) {
    602     /* Use keyring mode. */
    603     result = init_environment(data, &envir, (const char *) NULL,
    604                               keyringfile, keyringlabel, keyringpwd);
    605     if(result)
    606       return result;
    607   }
    608 
    609   /* Create secure session. */
    610   result = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
    611                         "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
    612   gsk_environment_close(&envir);
    613   if(result)
    614     return result;
    615 
    616   /* Determine which SSL/TLS version should be enabled. */
    617   protoflags = CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
    618                CURL_GSKPROTO_TLSV12_MASK;
    619   sni = conn->host.name;
    620   switch (data->set.ssl.version) {
    621   case CURL_SSLVERSION_SSLv2:
    622     protoflags = CURL_GSKPROTO_SSLV2_MASK;
    623     sni = (char *) NULL;
    624     break;
    625   case CURL_SSLVERSION_SSLv3:
    626     protoflags = CURL_GSKPROTO_SSLV3_MASK;
    627     sni = (char *) NULL;
    628     break;
    629   case CURL_SSLVERSION_TLSv1:
    630     protoflags = CURL_GSKPROTO_TLSV10_MASK |
    631                  CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
    632     break;
    633   case CURL_SSLVERSION_TLSv1_0:
    634     protoflags = CURL_GSKPROTO_TLSV10_MASK;
    635     break;
    636   case CURL_SSLVERSION_TLSv1_1:
    637     protoflags = CURL_GSKPROTO_TLSV11_MASK;
    638     break;
    639   case CURL_SSLVERSION_TLSv1_2:
    640     protoflags = CURL_GSKPROTO_TLSV12_MASK;
    641     break;
    642   }
    643 
    644   /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
    645   if(sni) {
    646     result = set_buffer(data, connssl->handle,
    647                         GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
    648     if(result == CURLE_UNSUPPORTED_PROTOCOL)
    649       result = CURLE_OK;
    650   }
    651 
    652   /* Set session parameters. */
    653   if(!result) {
    654     /* Compute the handshake timeout. Since GSKit granularity is 1 second,
    655        we round up the required value. */
    656     timeout = Curl_timeleft(data, NULL, TRUE);
    657     if(timeout < 0)
    658       result = CURLE_OPERATION_TIMEDOUT;
    659     else
    660       result = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
    661                            (timeout + 999) / 1000);
    662   }
    663   if(!result)
    664     result = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]);
    665   if(!result)
    666     result = set_ciphers(data, connssl->handle, &protoflags);
    667   if(!protoflags) {
    668     failf(data, "No SSL protocol/cipher combination enabled");
    669     result = CURLE_SSL_CIPHER;
    670   }
    671   if(!result)
    672     result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
    673                       (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
    674                       GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
    675   if(!result)
    676     result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
    677                       (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
    678                       GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
    679   if(!result)
    680     result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
    681                       (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
    682                       GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
    683   if(!result) {
    684     result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11,
    685                       (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
    686                       GSK_TRUE: GSK_FALSE, TRUE);
    687     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
    688       result = CURLE_OK;
    689       if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
    690         failf(data, "TLS 1.1 not yet supported");
    691         result = CURLE_SSL_CIPHER;
    692       }
    693     }
    694   }
    695   if(!result) {
    696     result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12,
    697                       (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
    698                       GSK_TRUE: GSK_FALSE, TRUE);
    699     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
    700       result = CURLE_OK;
    701       if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
    702         failf(data, "TLS 1.2 not yet supported");
    703         result = CURLE_SSL_CIPHER;
    704       }
    705     }
    706   }
    707   if(!result)
    708     result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
    709                       data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL:
    710                       GSK_SERVER_AUTH_PASSTHRU, FALSE);
    711 
    712   if(!result) {
    713     /* Start handshake. Try asynchronous first. */
    714     memset(&commarea, 0, sizeof commarea);
    715     connssl->iocport = QsoCreateIOCompletionPort();
    716     if(connssl->iocport != -1) {
    717       result = gskit_status(data,
    718                             gsk_secure_soc_startInit(connssl->handle,
    719                                                      connssl->iocport,
    720                                                      &commarea),
    721                             "gsk_secure_soc_startInit()",
    722                             CURLE_SSL_CONNECT_ERROR);
    723       if(!result) {
    724         connssl->connecting_state = ssl_connect_2;
    725         return CURLE_OK;
    726       }
    727       else
    728         close_async_handshake(connssl);
    729     }
    730     else if(errno != ENOBUFS)
    731       result = gskit_status(data, GSK_ERROR_IO,
    732                             "QsoCreateIOCompletionPort()", 0);
    733     else {
    734       /* No more completion port available. Use synchronous IO. */
    735       result = gskit_status(data, gsk_secure_soc_init(connssl->handle),
    736                             "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
    737       if(!result) {
    738         connssl->connecting_state = ssl_connect_3;
    739         return CURLE_OK;
    740       }
    741     }
    742   }
    743 
    744   /* Error: rollback. */
    745   close_one(connssl, data);
    746   return result;
    747 }
    748 
    749 
    750 static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
    751                                     bool nonblocking)
    752 {
    753   struct SessionHandle *data = conn->data;
    754   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    755   Qso_OverlappedIO_t cstat;
    756   long timeout_ms;
    757   struct timeval stmv;
    758   CURLcode result;
    759 
    760   /* Poll or wait for end of SSL asynchronous handshake. */
    761 
    762   for(;;) {
    763     timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
    764     if(timeout_ms < 0)
    765       timeout_ms = 0;
    766     stmv.tv_sec = timeout_ms / 1000;
    767     stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
    768     switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
    769     case 1:             /* Operation complete. */
    770       break;
    771     case -1:            /* An error occurred: handshake still in progress. */
    772       if(errno == EINTR) {
    773         if(nonblocking)
    774           return CURLE_OK;
    775         continue;       /* Retry. */
    776       }
    777       if(errno != ETIME) {
    778         failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
    779         cancel_async_handshake(conn, sockindex);
    780         close_async_handshake(connssl);
    781         return CURLE_SSL_CONNECT_ERROR;
    782       }
    783       /* FALL INTO... */
    784     case 0:             /* Handshake in progress, timeout occurred. */
    785       if(nonblocking)
    786         return CURLE_OK;
    787       cancel_async_handshake(conn, sockindex);
    788       close_async_handshake(connssl);
    789       return CURLE_OPERATION_TIMEDOUT;
    790     }
    791     break;
    792   }
    793   result = gskit_status(data, cstat.returnValue, "SSL handshake",
    794                         CURLE_SSL_CONNECT_ERROR);
    795   if(!result)
    796     connssl->connecting_state = ssl_connect_3;
    797   close_async_handshake(connssl);
    798   return result;
    799 }
    800 
    801 
    802 static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
    803 {
    804   struct SessionHandle *data = conn->data;
    805   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    806   const gsk_cert_data_elem *cdev;
    807   int cdec;
    808   const gsk_cert_data_elem *p;
    809   const char *cert = (const char *) NULL;
    810   const char *certend;
    811   const char *ptr;
    812   int i;
    813   CURLcode result;
    814 
    815   /* SSL handshake done: gather certificate info and verify host. */
    816 
    817   if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
    818                                                     GSK_PARTNER_CERT_INFO,
    819                                                     &cdev, &cdec),
    820                   "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
    821      CURLE_OK) {
    822     infof(data, "Server certificate:\n");
    823     p = cdev;
    824     for(i = 0; i++ < cdec; p++)
    825       switch (p->cert_data_id) {
    826       case CERT_BODY_DER:
    827         cert = p->cert_data_p;
    828         certend = cert + cdev->cert_data_l;
    829         break;
    830       case CERT_DN_PRINTABLE:
    831         infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
    832         break;
    833       case CERT_ISSUER_DN_PRINTABLE:
    834         infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
    835         break;
    836       case CERT_VALID_FROM:
    837         infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
    838         break;
    839       case CERT_VALID_TO:
    840         infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
    841         break;
    842     }
    843   }
    844 
    845   /* Verify host. */
    846   result = Curl_verifyhost(conn, cert, certend);
    847   if(result)
    848     return result;
    849 
    850   /* The only place GSKit can get the whole CA chain is a validation
    851      callback where no user data pointer is available. Therefore it's not
    852      possible to copy this chain into our structures for CAINFO.
    853      However the server certificate may be available, thus we can return
    854      info about it. */
    855   if(data->set.ssl.certinfo) {
    856     result = Curl_ssl_init_certinfo(data, 1);
    857     if(result)
    858       return result;
    859 
    860     if(cert) {
    861       result = Curl_extract_certinfo(conn, 0, cert, certend);
    862       if(result)
    863         return result;
    864     }
    865   }
    866 
    867   /* Check pinned public key. */
    868   ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
    869   if(!result && ptr) {
    870     curl_X509certificate x509;
    871     curl_asn1Element *p;
    872 
    873     if(!cert)
    874       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
    875     Curl_parseX509(&x509, cert, certend);
    876     p = &x509.subjectPublicKeyInfo;
    877     result = Curl_pin_peer_pubkey(ptr, p->header, p->end - p->header);
    878     if(result) {
    879       failf(data, "SSL: public key does not match pinned public key!");
    880       return result;
    881     }
    882   }
    883 
    884   connssl->connecting_state = ssl_connect_done;
    885   return CURLE_OK;
    886 }
    887 
    888 
    889 static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
    890                                      bool nonblocking, bool *done)
    891 {
    892   struct SessionHandle *data = conn->data;
    893   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    894   long timeout_ms;
    895   Qso_OverlappedIO_t cstat;
    896   CURLcode result = CURLE_OK;
    897 
    898   *done = connssl->state == ssl_connection_complete;
    899   if(*done)
    900     return CURLE_OK;
    901 
    902   /* Step 1: create session, start handshake. */
    903   if(connssl->connecting_state == ssl_connect_1) {
    904     /* check allowed time left */
    905     timeout_ms = Curl_timeleft(data, NULL, TRUE);
    906 
    907     if(timeout_ms < 0) {
    908       /* no need to continue if time already is up */
    909       failf(data, "SSL connection timeout");
    910       result = CURLE_OPERATION_TIMEDOUT;
    911     }
    912     else
    913       result = gskit_connect_step1(conn, sockindex);
    914   }
    915 
    916   /* Step 2: check if handshake is over. */
    917   if(!result && connssl->connecting_state == ssl_connect_2) {
    918     /* check allowed time left */
    919     timeout_ms = Curl_timeleft(data, NULL, TRUE);
    920 
    921     if(timeout_ms < 0) {
    922       /* no need to continue if time already is up */
    923       failf(data, "SSL connection timeout");
    924       result = CURLE_OPERATION_TIMEDOUT;
    925     }
    926     else
    927       result = gskit_connect_step2(conn, sockindex, nonblocking);
    928   }
    929 
    930   /* Step 3: gather certificate info, verify host. */
    931   if(!result && connssl->connecting_state == ssl_connect_3)
    932     result = gskit_connect_step3(conn, sockindex);
    933 
    934   if(result)
    935     close_one(connssl, data);
    936   else if(connssl->connecting_state == ssl_connect_done) {
    937     connssl->state = ssl_connection_complete;
    938     connssl->connecting_state = ssl_connect_1;
    939     conn->recv[sockindex] = gskit_recv;
    940     conn->send[sockindex] = gskit_send;
    941     *done = TRUE;
    942   }
    943 
    944   return result;
    945 }
    946 
    947 
    948 CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
    949                                         int sockindex,
    950                                         bool *done)
    951 {
    952   CURLcode result;
    953 
    954   result = gskit_connect_common(conn, sockindex, TRUE, done);
    955   if(*done || result)
    956     conn->ssl[sockindex].connecting_state = ssl_connect_1;
    957   return result;
    958 }
    959 
    960 
    961 CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
    962 {
    963   CURLcode result;
    964   bool done;
    965 
    966   conn->ssl[sockindex].connecting_state = ssl_connect_1;
    967   result = gskit_connect_common(conn, sockindex, FALSE, &done);
    968   if(result)
    969     return result;
    970 
    971   DEBUGASSERT(done);
    972 
    973   return CURLE_OK;
    974 }
    975 
    976 
    977 void Curl_gskit_close(struct connectdata *conn, int sockindex)
    978 {
    979   struct SessionHandle *data = conn->data;
    980   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    981 
    982   if(connssl->use)
    983     close_one(connssl, data);
    984 }
    985 
    986 
    987 int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
    988 {
    989   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    990   struct SessionHandle *data = conn->data;
    991   ssize_t nread;
    992   int what;
    993   int rc;
    994   char buf[120];
    995 
    996   if(!connssl->handle)
    997     return 0;
    998 
    999   if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
   1000     return 0;
   1001 
   1002   close_one(connssl, data);
   1003   rc = 0;
   1004   what = Curl_socket_ready(conn->sock[sockindex],
   1005                            CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
   1006 
   1007   for(;;) {
   1008     if(what < 0) {
   1009       /* anything that gets here is fatally bad */
   1010       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
   1011       rc = -1;
   1012       break;
   1013     }
   1014 
   1015     if(!what) {                                /* timeout */
   1016       failf(data, "SSL shutdown timeout");
   1017       break;
   1018     }
   1019 
   1020     /* Something to read, let's do it and hope that it is the close
   1021        notify alert from the server. No way to gsk_secure_soc_read() now, so
   1022        use read(). */
   1023 
   1024     nread = read(conn->sock[sockindex], buf, sizeof(buf));
   1025 
   1026     if(nread < 0) {
   1027       failf(data, "read: %s", strerror(errno));
   1028       rc = -1;
   1029     }
   1030 
   1031     if(nread <= 0)
   1032       break;
   1033 
   1034     what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
   1035   }
   1036 
   1037   return rc;
   1038 }
   1039 
   1040 
   1041 size_t Curl_gskit_version(char *buffer, size_t size)
   1042 {
   1043   strncpy(buffer, "GSKit", size);
   1044   return strlen(buffer);
   1045 }
   1046 
   1047 
   1048 int Curl_gskit_check_cxn(struct connectdata *cxn)
   1049 {
   1050   int err;
   1051   int errlen;
   1052 
   1053   /* The only thing that can be tested here is at the socket level. */
   1054 
   1055   if(!cxn->ssl[FIRSTSOCKET].handle)
   1056     return 0; /* connection has been closed */
   1057 
   1058   err = 0;
   1059   errlen = sizeof err;
   1060 
   1061   if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
   1062                  (unsigned char *) &err, &errlen) ||
   1063      errlen != sizeof err || err)
   1064     return 0; /* connection has been closed */
   1065 
   1066   return -1;  /* connection status unknown */
   1067 }
   1068 
   1069 #endif /* USE_GSKIT */
   1070