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