1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#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. */
99typedef 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
105static 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
151static 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
166static CURLcode gskit_status(struct Curl_easy *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
209static CURLcode set_enum(struct Curl_easy *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
231static CURLcode set_buffer(struct Curl_easy *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
253static CURLcode set_numeric(struct Curl_easy *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
273static CURLcode set_callback(struct Curl_easy *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
292static CURLcode set_ciphers(struct Curl_easy *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
425int Curl_gskit_init(void)
426{
427  /* No initialisation needed. */
428
429  return 1;
430}
431
432
433void Curl_gskit_cleanup(void)
434{
435  /* Nothing to do. */
436}
437
438
439static CURLcode init_environment(struct Curl_easy *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
487static 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
497static void close_async_handshake(struct ssl_connect_data *connssl)
498{
499  QsoDestroyIOCompletionPort(connssl->iocport);
500  connssl->iocport = -1;
501}
502
503
504static void close_one(struct ssl_connect_data *conn,
505                      struct Curl_easy *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
517static ssize_t gskit_send(struct connectdata *conn, int sockindex,
518                           const void *mem, size_t len, CURLcode *curlcode)
519{
520  struct Curl_easy *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
536static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
537                           size_t buffersize, CURLcode *curlcode)
538{
539  struct Curl_easy *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
556static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
557{
558  struct Curl_easy *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
750static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
751                                    bool nonblocking)
752{
753  struct Curl_easy *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
802static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
803{
804  struct Curl_easy *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(data, 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
889static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
890                                     bool nonblocking, bool *done)
891{
892  struct Curl_easy *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
948CURLcode 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
961CURLcode 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
977void Curl_gskit_close(struct connectdata *conn, int sockindex)
978{
979  struct Curl_easy *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
987int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
988{
989  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
990  struct Curl_easy *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
1041size_t Curl_gskit_version(char *buffer, size_t size)
1042{
1043  strncpy(buffer, "GSKit", size);
1044  return strlen(buffer);
1045}
1046
1047
1048int 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