Revert "Update to 7.40.1"
[platform/upstream/curl.git] / lib / vtls / gskit.c
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. */
101 typedef 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
107 static 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
149 static 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
164 static 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
209 static CURLcode set_enum(struct SessionHandle *data, gsk_handle h,
210                 GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
211 {
212   int rc = gsk_attribute_set_enum(h, id, value);
213
214   switch (rc) {
215   case GSK_OK:
216     return CURLE_OK;
217   case GSK_ERROR_IO:
218     failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
219     break;
220   case GSK_ATTRIBUTE_INVALID_ID:
221     if(unsupported_ok)
222       return CURLE_UNSUPPORTED_PROTOCOL;
223   default:
224     failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
225     break;
226   }
227   return CURLE_SSL_CONNECT_ERROR;
228 }
229
230
231 static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h,
232                         GSK_BUF_ID id, const char *buffer, bool unsupported_ok)
233 {
234   int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
235
236   switch (rc) {
237   case GSK_OK:
238     return CURLE_OK;
239   case GSK_ERROR_IO:
240     failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
241     break;
242   case GSK_ATTRIBUTE_INVALID_ID:
243     if(unsupported_ok)
244       return CURLE_UNSUPPORTED_PROTOCOL;
245   default:
246     failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
247     break;
248   }
249   return CURLE_SSL_CONNECT_ERROR;
250 }
251
252
253 static CURLcode set_numeric(struct SessionHandle *data,
254                             gsk_handle h, GSK_NUM_ID id, int value)
255 {
256   int rc = gsk_attribute_set_numeric_value(h, id, value);
257
258   switch (rc) {
259   case GSK_OK:
260     return CURLE_OK;
261   case GSK_ERROR_IO:
262     failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
263           strerror(errno));
264     break;
265   default:
266     failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
267     break;
268   }
269   return CURLE_SSL_CONNECT_ERROR;
270 }
271
272
273 static CURLcode set_callback(struct SessionHandle *data,
274                              gsk_handle h, GSK_CALLBACK_ID id, void *info)
275 {
276   int rc = gsk_attribute_set_callback(h, id, info);
277
278   switch (rc) {
279   case GSK_OK:
280     return CURLE_OK;
281   case GSK_ERROR_IO:
282     failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
283     break;
284   default:
285     failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
286     break;
287   }
288   return CURLE_SSL_CONNECT_ERROR;
289 }
290
291
292 static CURLcode set_ciphers(struct SessionHandle *data,
293                                         gsk_handle h, unsigned int *protoflags)
294 {
295   const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
296   const char *clp;
297   const gskit_cipher *ctp;
298   int i;
299   int l;
300   bool unsupported;
301   CURLcode 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
425 int Curl_gskit_init(void)
426 {
427   /* No initialisation needed. */
428
429   return 1;
430 }
431
432
433 void Curl_gskit_cleanup(void)
434 {
435   /* Nothing to do. */
436 }
437
438
439 static CURLcode init_environment(struct SessionHandle *data,
440                                  gsk_handle *envir, const char *appid,
441                                  const char *file, const char *label,
442                                  const char *password)
443 {
444   int rc;
445   CURLcode 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
487 static void cancel_async_handshake(struct connectdata *conn, int sockindex)
488 {
489   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
490   Qso_OverlappedIO_t cstat;
491
492   if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
493     QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
494 }
495
496
497 static void close_async_handshake(struct ssl_connect_data *connssl)
498 {
499   QsoDestroyIOCompletionPort(connssl->iocport);
500   connssl->iocport = -1;
501 }
502
503
504 static void close_one(struct ssl_connect_data *conn,
505                       struct SessionHandle *data)
506 {
507   if(conn->handle) {
508     gskit_status(data, gsk_secure_soc_close(&conn->handle),
509               "gsk_secure_soc_close()", 0);
510     conn->handle = (gsk_handle) NULL;
511   }
512   if(conn->iocport >= 0)
513     close_async_handshake(conn);
514 }
515
516
517 static ssize_t gskit_send(struct connectdata *conn, int sockindex,
518                            const void *mem, size_t len, CURLcode *curlcode)
519 {
520   struct SessionHandle *data = conn->data;
521   CURLcode cc;
522   int written;
523
524   cc = gskit_status(data,
525                     gsk_secure_soc_write(conn->ssl[sockindex].handle,
526                                          (char *) mem, (int) len, &written),
527                     "gsk_secure_soc_write()", CURLE_SEND_ERROR);
528   if(cc != CURLE_OK) {
529     *curlcode = cc;
530     written = -1;
531   }
532   return (ssize_t) written; /* number of bytes */
533 }
534
535
536 static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
537                            size_t buffersize, CURLcode *curlcode)
538 {
539   struct SessionHandle *data = conn->data;
540   int buffsize;
541   int nread;
542   CURLcode cc;
543
544   buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
545   cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
546                                               buf, buffsize, &nread),
547                     "gsk_secure_soc_read()", CURLE_RECV_ERROR);
548   if(cc != CURLE_OK) {
549     *curlcode = cc;
550     nread = -1;
551   }
552   return (ssize_t) nread;
553 }
554
555
556 static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
557 {
558   struct SessionHandle *data = conn->data;
559   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
560   gsk_handle envir;
561   CURLcode 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
746 static 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
798 static 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
865 static 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
924 CURLcode 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
937 CURLcode 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
953 void 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
963 int Curl_gskit_close_all(struct SessionHandle *data)
964 {
965   /* Unimplemented. */
966   (void) data;
967   return 0;
968 }
969
970
971 int 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
1025 size_t Curl_gskit_version(char *buffer, size_t size)
1026 {
1027   strncpy(buffer, "GSKit", size);
1028   return strlen(buffer);
1029 }
1030
1031
1032 int 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 */