1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2013, 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 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
78#define _MPRINTF_REPLACE /* use our functions only */
79#include <curl/mprintf.h>
80
81#include "curl_memory.h"
82/* The last #include file should be: */
83#include "memdebug.h"
84
85
86/* SSL version flags. */
87#define CURL_GSKPROTO_SSLV2     0
88#define CURL_GSKPROTO_SSLV2_MASK        (1 << CURL_GSKPROTO_SSLV2)
89#define CURL_GSKPROTO_SSLV3     1
90#define CURL_GSKPROTO_SSLV3_MASK        (1 << CURL_GSKPROTO_SSLV3)
91#define CURL_GSKPROTO_TLSV10    2
92#define CURL_GSKPROTO_TLSV10_MASK        (1 << CURL_GSKPROTO_TLSV10)
93#define CURL_GSKPROTO_TLSV11    3
94#define CURL_GSKPROTO_TLSV11_MASK        (1 << CURL_GSKPROTO_TLSV11)
95#define CURL_GSKPROTO_TLSV12    4
96#define CURL_GSKPROTO_TLSV12_MASK        (1 << CURL_GSKPROTO_TLSV12)
97#define CURL_GSKPROTO_LAST      5
98
99
100/* Supported ciphers. */
101typedef struct {
102  const char *name;            /* Cipher name. */
103  const char *gsktoken;        /* Corresponding token for GSKit String. */
104  unsigned int versions;       /* SSL version flags. */
105}  gskit_cipher;
106
107static const gskit_cipher  ciphertable[] = {
108  { "null-md5",         "01",
109      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
110      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
111  { "null-sha",         "02",
112      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
113      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
114  { "exp-rc4-md5",      "03",
115      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
116  { "rc4-md5",          "04",
117      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
118      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
119  { "rc4-sha",          "05",
120      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
121      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
122  { "exp-rc2-cbc-md5",  "06",
123      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
124  { "exp-des-cbc-sha",  "09",
125      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
126      CURL_GSKPROTO_TLSV11_MASK },
127  { "des-cbc3-sha",     "0A",
128      CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
129      CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
130  { "aes128-sha",       "2F",
131      CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
132      CURL_GSKPROTO_TLSV12_MASK },
133  { "aes256-sha",       "35",
134      CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
135      CURL_GSKPROTO_TLSV12_MASK },
136  { "null-sha256",      "3B",   CURL_GSKPROTO_TLSV12_MASK },
137  { "aes128-sha256",    "3D",   CURL_GSKPROTO_TLSV12_MASK },
138  { "aes256-sha256",    "3D",   CURL_GSKPROTO_TLSV12_MASK },
139  { "rc4-md5",          "1",    CURL_GSKPROTO_SSLV2_MASK },
140  { "exp-rc4-md5",      "2",    CURL_GSKPROTO_SSLV2_MASK },
141  { "rc2-md5",          "3",    CURL_GSKPROTO_SSLV2_MASK },
142  { "exp-rc2-md5",      "4",    CURL_GSKPROTO_SSLV2_MASK },
143  { "des-cbc-md5",      "6",    CURL_GSKPROTO_SSLV2_MASK },
144  { "des-cbc3-md5",     "7",    CURL_GSKPROTO_SSLV2_MASK },
145  { (const char *) NULL, (const char *) NULL, 0       }
146};
147
148
149static bool is_separator(char c)
150{
151  /* Return whether character is a cipher list separator. */
152  switch (c) {
153  case ' ':
154  case '\t':
155  case ':':
156  case ',':
157  case ';':
158    return true;
159  }
160  return false;
161}
162
163
164static CURLcode gskit_status(struct SessionHandle *data, int rc,
165                             const char *procname, CURLcode defcode)
166{
167  CURLcode cc;
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 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
231static 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
253static 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
273static 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
292static 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 cc;
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  cc = 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      cc = 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    cc = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS,
376                    ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE);
377    if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
378      cc = CURLE_OK;
379      if(unsupported) {
380        failf(data, "TLSv1.1-only ciphers are not yet supported");
381        cc = CURLE_SSL_CIPHER;
382      }
383    }
384  }
385  if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) {
386    cc = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS,
387                    ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE);
388    if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
389      cc = CURLE_OK;
390      if(unsupported) {
391        failf(data, "TLSv1.2-only ciphers are not yet supported");
392        cc = 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(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) {
400    cc = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS,
401                    ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE);
402    if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
403      cc = 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(cc == CURLE_OK &&  (*protoflags & CURL_GSKPROTO_SSLV3_MASK))
411    cc = set_buffer(data, h, GSK_V3_CIPHER_SPECS,
412                    ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE);
413  if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_SSLV2_MASK))
414    cc = 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 cc;
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 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 c;
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  c = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE);
462  if(c == CURLE_OK && appid)
463    c = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE);
464  if(c == CURLE_OK && file)
465    c = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE);
466  if(c == CURLE_OK && label)
467    c = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE);
468  if(c == CURLE_OK && password)
469    c = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE);
470
471  if(c == CURLE_OK) {
472    /* Locate CAs, Client certificate and key according to our settings.
473       Note: this call may be blocking for some tenths of seconds. */
474    c = gskit_status(data, gsk_environment_init(h),
475                     "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
476    if(c == CURLE_OK) {
477      *envir = h;
478      return c;
479    }
480  }
481  /* Error: rollback. */
482  gsk_environment_close(&h);
483  return c;
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 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
517static 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
536static 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
556static 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 cc;
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    cc = init_environment(data, &envir, (const char *) NULL,
604                          keyringfile, keyringlabel, keyringpwd);
605    if(cc != CURLE_OK)
606      return cc;
607  }
608
609  /* Create secure session. */
610  cc = 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(cc != CURLE_OK)
614    return cc;
615
616  /* Determine which SSL/TLS version should be enabled. */
617  protoflags = CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
618               CURL_GSKPROTO_TLSV11_MASK | 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_SSLV2_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    cc = set_buffer(data, connssl->handle,
647                    GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
648    if(cc == CURLE_UNSUPPORTED_PROTOCOL)
649      cc = CURLE_OK;
650  }
651
652  /* Set session parameters. */
653  if(cc == CURLE_OK) {
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      cc = CURLE_OPERATION_TIMEDOUT;
659    else
660      cc = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
661                       (timeout + 999) / 1000);
662  }
663  if(cc == CURLE_OK)
664    cc = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]);
665  if(cc == CURLE_OK)
666    cc = set_ciphers(data, connssl->handle, &protoflags);
667  if(!protoflags) {
668    failf(data, "No SSL protocol/cipher combination enabled");
669    cc = CURLE_SSL_CIPHER;
670  }
671  if(cc == CURLE_OK)
672      cc = 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(cc == CURLE_OK)
676    cc = 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(cc == CURLE_OK)
680    cc = 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(cc == CURLE_OK) {
684    cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11,
685                   (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
686                   GSK_TRUE: GSK_FALSE, TRUE);
687    if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
688      cc = CURLE_OK;
689      if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
690        failf(data, "TLS 1.1 not yet supported");
691        cc = CURLE_SSL_CIPHER;
692      }
693    }
694  }
695  if(cc == CURLE_OK) {
696    cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12,
697                  (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
698                  GSK_TRUE: GSK_FALSE, TRUE);
699    if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
700      cc = CURLE_OK;
701      if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
702        failf(data, "TLS 1.2 not yet supported");
703        cc = CURLE_SSL_CIPHER;
704      }
705    }
706  }
707  if(cc == CURLE_OK)
708    cc = 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(cc == CURLE_OK) {
713    /* Start handshake. Try asynchronous first. */
714    memset(&commarea, 0, sizeof commarea);
715    connssl->iocport = QsoCreateIOCompletionPort();
716    if(connssl->iocport != -1) {
717      cc = gskit_status(data, gsk_secure_soc_startInit(connssl->handle,
718                        connssl->iocport, &commarea),
719                        "gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR);
720      if(cc == CURLE_OK) {
721        connssl->connecting_state = ssl_connect_2;
722        return CURLE_OK;
723      }
724      else
725        close_async_handshake(connssl);
726    }
727    else if(errno != ENOBUFS)
728      cc = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0);
729    else {
730      /* No more completion port available. Use synchronous IO. */
731      cc = gskit_status(data, gsk_secure_soc_init(connssl->handle),
732                       "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
733      if(cc == CURLE_OK) {
734        connssl->connecting_state = ssl_connect_3;
735        return CURLE_OK;
736      }
737    }
738  }
739
740  /* Error: rollback. */
741  close_one(connssl, data);
742  return cc;
743}
744
745
746static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
747                                    bool nonblocking)
748{
749  struct SessionHandle *data = conn->data;
750  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
751  Qso_OverlappedIO_t cstat;
752  long timeout_ms;
753  struct timeval stmv;
754  CURLcode cc;
755
756  /* Poll or wait for end of SSL asynchronous handshake. */
757
758  for(;;) {
759    timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
760    if(timeout_ms < 0)
761      timeout_ms = 0;
762    stmv.tv_sec = timeout_ms / 1000;
763    stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
764    switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
765    case 1:             /* Operation complete. */
766      break;
767    case -1:            /* An error occurred: handshake still in progress. */
768      if(errno == EINTR) {
769        if(nonblocking)
770          return CURLE_OK;
771        continue;       /* Retry. */
772      }
773      if(errno != ETIME) {
774        failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
775        cancel_async_handshake(conn, sockindex);
776        close_async_handshake(connssl);
777        return CURLE_SSL_CONNECT_ERROR;
778      }
779      /* FALL INTO... */
780    case 0:             /* Handshake in progress, timeout occurred. */
781      if(nonblocking)
782        return CURLE_OK;
783      cancel_async_handshake(conn, sockindex);
784      close_async_handshake(connssl);
785      return CURLE_OPERATION_TIMEDOUT;
786    }
787    break;
788  }
789  cc = gskit_status(data, cstat.returnValue, "SSL handshake",
790                    CURLE_SSL_CONNECT_ERROR);
791  if(cc == CURLE_OK)
792    connssl->connecting_state = ssl_connect_3;
793  close_async_handshake(connssl);
794  return cc;
795}
796
797
798static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
799{
800  struct SessionHandle *data = conn->data;
801  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
802  const gsk_cert_data_elem *cdev;
803  int cdec;
804  const gsk_cert_data_elem *p;
805  const char *cert = (const char *) NULL;
806  const char *certend;
807  int i;
808  CURLcode cc;
809
810  /* SSL handshake done: gather certificate info and verify host. */
811
812  if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
813                                                    GSK_PARTNER_CERT_INFO,
814                                                    &cdev, &cdec),
815                  "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
816     CURLE_OK) {
817    infof(data, "Server certificate:\n");
818    p = cdev;
819    for(i = 0; i++ < cdec; p++)
820      switch (p->cert_data_id) {
821      case CERT_BODY_DER:
822        cert = p->cert_data_p;
823        certend = cert + cdev->cert_data_l;
824        break;
825      case CERT_DN_PRINTABLE:
826        infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
827        break;
828      case CERT_ISSUER_DN_PRINTABLE:
829        infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
830        break;
831      case CERT_VALID_FROM:
832        infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
833        break;
834      case CERT_VALID_TO:
835        infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
836        break;
837    }
838  }
839
840  /* Verify host. */
841  cc = Curl_verifyhost(conn, cert, certend);
842  if(cc != CURLE_OK)
843    return cc;
844
845  /* The only place GSKit can get the whole CA chain is a validation
846     callback where no user data pointer is available. Therefore it's not
847     possible to copy this chain into our structures for CAINFO.
848     However the server certificate may be available, thus we can return
849     info about it. */
850  if(data->set.ssl.certinfo) {
851    if(Curl_ssl_init_certinfo(data, 1))
852      return CURLE_OUT_OF_MEMORY;
853    if(cert) {
854      cc = Curl_extract_certinfo(conn, 0, cert, certend);
855      if(cc != CURLE_OK)
856        return cc;
857    }
858  }
859
860  connssl->connecting_state = ssl_connect_done;
861  return CURLE_OK;
862}
863
864
865static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
866                                     bool nonblocking, bool *done)
867{
868  struct SessionHandle *data = conn->data;
869  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
870  long timeout_ms;
871  Qso_OverlappedIO_t cstat;
872  CURLcode cc = CURLE_OK;
873
874  *done = connssl->state == ssl_connection_complete;
875  if(*done)
876    return CURLE_OK;
877
878  /* Step 1: create session, start handshake. */
879  if(connssl->connecting_state == ssl_connect_1) {
880    /* check allowed time left */
881    timeout_ms = Curl_timeleft(data, NULL, TRUE);
882
883    if(timeout_ms < 0) {
884      /* no need to continue if time already is up */
885      failf(data, "SSL connection timeout");
886      cc = CURLE_OPERATION_TIMEDOUT;
887    }
888    else
889      cc = gskit_connect_step1(conn, sockindex);
890  }
891
892  /* Step 2: check if handshake is over. */
893  if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_2) {
894    /* check allowed time left */
895    timeout_ms = Curl_timeleft(data, NULL, TRUE);
896
897    if(timeout_ms < 0) {
898      /* no need to continue if time already is up */
899      failf(data, "SSL connection timeout");
900      cc = CURLE_OPERATION_TIMEDOUT;
901    }
902    else
903      cc = gskit_connect_step2(conn, sockindex, nonblocking);
904  }
905
906  /* Step 3: gather certificate info, verify host. */
907  if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_3)
908    cc = gskit_connect_step3(conn, sockindex);
909
910  if(cc != CURLE_OK)
911    close_one(connssl, data);
912  else if(connssl->connecting_state == ssl_connect_done) {
913    connssl->state = ssl_connection_complete;
914    connssl->connecting_state = ssl_connect_1;
915    conn->recv[sockindex] = gskit_recv;
916    conn->send[sockindex] = gskit_send;
917    *done = TRUE;
918  }
919
920  return cc;
921}
922
923
924CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
925                                        int sockindex,
926                                        bool *done)
927{
928  CURLcode cc;
929
930  cc = gskit_connect_common(conn, sockindex, TRUE, done);
931  if(*done || cc != CURLE_OK)
932    conn->ssl[sockindex].connecting_state = ssl_connect_1;
933  return cc;
934}
935
936
937CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
938{
939  CURLcode retcode;
940  bool done;
941
942  conn->ssl[sockindex].connecting_state = ssl_connect_1;
943  retcode = gskit_connect_common(conn, sockindex, FALSE, &done);
944  if(retcode)
945    return retcode;
946
947  DEBUGASSERT(done);
948
949  return CURLE_OK;
950}
951
952
953void Curl_gskit_close(struct connectdata *conn, int sockindex)
954{
955  struct SessionHandle *data = conn->data;
956  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
957
958  if(connssl->use)
959    close_one(connssl, data);
960}
961
962
963int Curl_gskit_close_all(struct SessionHandle *data)
964{
965  /* Unimplemented. */
966  (void) data;
967  return 0;
968}
969
970
971int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
972{
973  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
974  struct SessionHandle *data = conn->data;
975  ssize_t nread;
976  int what;
977  int rc;
978  char buf[120];
979
980  if(!connssl->handle)
981    return 0;
982
983  if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
984    return 0;
985
986  close_one(connssl, data);
987  rc = 0;
988  what = Curl_socket_ready(conn->sock[sockindex],
989                           CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
990
991  for(;;) {
992    if(what < 0) {
993      /* anything that gets here is fatally bad */
994      failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
995      rc = -1;
996      break;
997    }
998
999    if(!what) {                                /* timeout */
1000      failf(data, "SSL shutdown timeout");
1001      break;
1002    }
1003
1004    /* Something to read, let's do it and hope that it is the close
1005       notify alert from the server. No way to gsk_secure_soc_read() now, so
1006       use read(). */
1007
1008    nread = read(conn->sock[sockindex], buf, sizeof(buf));
1009
1010    if(nread < 0) {
1011      failf(data, "read: %s", strerror(errno));
1012      rc = -1;
1013    }
1014
1015    if(nread <= 0)
1016      break;
1017
1018    what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
1019  }
1020
1021  return rc;
1022}
1023
1024
1025size_t Curl_gskit_version(char *buffer, size_t size)
1026{
1027  strncpy(buffer, "GSKit", size);
1028  return strlen(buffer);
1029}
1030
1031
1032int Curl_gskit_check_cxn(struct connectdata *cxn)
1033{
1034  int err;
1035  int errlen;
1036
1037  /* The only thing that can be tested here is at the socket level. */
1038
1039  if(!cxn->ssl[FIRSTSOCKET].handle)
1040    return 0; /* connection has been closed */
1041
1042  err = 0;
1043  errlen = sizeof err;
1044
1045  if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
1046                 (unsigned char *) &err, &errlen) ||
1047     errlen != sizeof err || err)
1048    return 0; /* connection has been closed */
1049
1050  return -1;  /* connection status unknown */
1051}
1052
1053#endif /* USE_GSKIT */
1054