~ubuntu-branches/ubuntu/trusty/curl/trusty-updates

« back to all changes in this revision

Viewing changes to lib/gskit.c

  • Committer: Package Import Robot
  • Author(s): Ubuntu Merge-o-Matic
  • Date: 2013-08-12 15:39:32 UTC
  • mfrom: (3.4.41 sid)
  • Revision ID: package-import@ubuntu.com-20130812153932-pmn0qwvy9vghe66x
Tags: 7.32.0-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - Drop dependencies not in main:
    + Build-Depends: Drop stunnel4 and libssh2-1-dev.
    + Drop libssh2-1-dev from binary package Depends.
  - Add new libcurl3-udeb package.
  - Add new curl-udeb package.
* Fixes freeipa-client join. (LP: #1220928)

Show diffs side-by-side

added added

removed removed

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