Imported Upstream version 7.53.1
[platform/upstream/curl.git] / lib / vtls / gskit.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 #ifdef USE_GSKIT
26
27 #include <gskssl.h>
28 #include <qsoasync.h>
29
30 /* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
31 #ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
32 #define GSK_SSL_EXTN_SERVERNAME_REQUEST         230
33 #endif
34
35 #ifndef GSK_TLSV10_CIPHER_SPECS
36 #define GSK_TLSV10_CIPHER_SPECS                 236
37 #endif
38
39 #ifndef GSK_TLSV11_CIPHER_SPECS
40 #define GSK_TLSV11_CIPHER_SPECS                 237
41 #endif
42
43 #ifndef GSK_TLSV12_CIPHER_SPECS
44 #define GSK_TLSV12_CIPHER_SPECS                 238
45 #endif
46
47 #ifndef GSK_PROTOCOL_TLSV11
48 #define GSK_PROTOCOL_TLSV11                     437
49 #endif
50
51 #ifndef GSK_PROTOCOL_TLSV12
52 #define GSK_PROTOCOL_TLSV12                     438
53 #endif
54
55 #ifndef GSK_FALSE
56 #define GSK_FALSE                               0
57 #endif
58
59 #ifndef GSK_TRUE
60 #define GSK_TRUE                                1
61 #endif
62
63
64 #ifdef HAVE_LIMITS_H
65 #  include <limits.h>
66 #endif
67
68 #include <curl/curl.h>
69 #include "urldata.h"
70 #include "sendf.h"
71 #include "gskit.h"
72 #include "vtls.h"
73 #include "connect.h" /* for the connect timeout */
74 #include "select.h"
75 #include "strcase.h"
76 #include "x509asn1.h"
77 #include "curl_printf.h"
78
79 #include "curl_memory.h"
80 /* The last #include file should be: */
81 #include "memdebug.h"
82
83
84 /* Directions. */
85 #define SOS_READ        0x01
86 #define SOS_WRITE       0x02
87
88 /* SSL version flags. */
89 #define CURL_GSKPROTO_SSLV2     0
90 #define CURL_GSKPROTO_SSLV2_MASK        (1 << CURL_GSKPROTO_SSLV2)
91 #define CURL_GSKPROTO_SSLV3     1
92 #define CURL_GSKPROTO_SSLV3_MASK        (1 << CURL_GSKPROTO_SSLV3)
93 #define CURL_GSKPROTO_TLSV10    2
94 #define CURL_GSKPROTO_TLSV10_MASK        (1 << CURL_GSKPROTO_TLSV10)
95 #define CURL_GSKPROTO_TLSV11    3
96 #define CURL_GSKPROTO_TLSV11_MASK        (1 << CURL_GSKPROTO_TLSV11)
97 #define CURL_GSKPROTO_TLSV12    4
98 #define CURL_GSKPROTO_TLSV12_MASK        (1 << CURL_GSKPROTO_TLSV12)
99 #define CURL_GSKPROTO_LAST      5
100
101
102 /* Supported ciphers. */
103 typedef struct {
104   const char *name;            /* Cipher name. */
105   const char *gsktoken;        /* Corresponding token for GSKit String. */
106   unsigned int versions;       /* SSL version flags. */
107 }  gskit_cipher;
108
109 static const gskit_cipher  ciphertable[] = {
110   { "null-md5",         "01",
111       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
112       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
113   { "null-sha",         "02",
114       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
115       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
116   { "exp-rc4-md5",      "03",
117       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
118   { "rc4-md5",          "04",
119       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
120       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
121   { "rc4-sha",          "05",
122       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
123       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
124   { "exp-rc2-cbc-md5",  "06",
125       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
126   { "exp-des-cbc-sha",  "09",
127       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
128       CURL_GSKPROTO_TLSV11_MASK },
129   { "des-cbc3-sha",     "0A",
130       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
131       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
132   { "aes128-sha",       "2F",
133       CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
134       CURL_GSKPROTO_TLSV12_MASK },
135   { "aes256-sha",       "35",
136       CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
137       CURL_GSKPROTO_TLSV12_MASK },
138   { "null-sha256",      "3B",   CURL_GSKPROTO_TLSV12_MASK },
139   { "aes128-sha256",    "3C",   CURL_GSKPROTO_TLSV12_MASK },
140   { "aes256-sha256",    "3D",   CURL_GSKPROTO_TLSV12_MASK },
141   { "aes128-gcm-sha256",
142                         "9C",   CURL_GSKPROTO_TLSV12_MASK },
143   { "aes256-gcm-sha384",
144                         "9D",   CURL_GSKPROTO_TLSV12_MASK },
145   { "rc4-md5",          "1",    CURL_GSKPROTO_SSLV2_MASK },
146   { "exp-rc4-md5",      "2",    CURL_GSKPROTO_SSLV2_MASK },
147   { "rc2-md5",          "3",    CURL_GSKPROTO_SSLV2_MASK },
148   { "exp-rc2-md5",      "4",    CURL_GSKPROTO_SSLV2_MASK },
149   { "des-cbc-md5",      "6",    CURL_GSKPROTO_SSLV2_MASK },
150   { "des-cbc3-md5",     "7",    CURL_GSKPROTO_SSLV2_MASK },
151   { (const char *) NULL, (const char *) NULL, 0       }
152 };
153
154
155 static bool is_separator(char c)
156 {
157   /* Return whether character is a cipher list separator. */
158   switch(c) {
159   case ' ':
160   case '\t':
161   case ':':
162   case ',':
163   case ';':
164     return true;
165   }
166   return false;
167 }
168
169
170 static CURLcode gskit_status(struct Curl_easy *data, int rc,
171                              const char *procname, CURLcode defcode)
172 {
173   /* Process GSKit status and map it to a CURLcode. */
174   switch(rc) {
175   case GSK_OK:
176   case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
177     return CURLE_OK;
178   case GSK_KEYRING_OPEN_ERROR:
179   case GSK_OS400_ERROR_NO_ACCESS:
180     return CURLE_SSL_CACERT_BADFILE;
181   case GSK_INSUFFICIENT_STORAGE:
182     return CURLE_OUT_OF_MEMORY;
183   case GSK_ERROR_BAD_V2_CIPHER:
184   case GSK_ERROR_BAD_V3_CIPHER:
185   case GSK_ERROR_NO_CIPHERS:
186     return CURLE_SSL_CIPHER;
187   case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
188   case GSK_ERROR_CERT_VALIDATION:
189     return CURLE_PEER_FAILED_VERIFICATION;
190   case GSK_OS400_ERROR_TIMED_OUT:
191     return CURLE_OPERATION_TIMEDOUT;
192   case GSK_WOULD_BLOCK:
193     return CURLE_AGAIN;
194   case GSK_OS400_ERROR_NOT_REGISTERED:
195     break;
196   case GSK_ERROR_IO:
197     switch(errno) {
198     case ENOMEM:
199       return CURLE_OUT_OF_MEMORY;
200     default:
201       failf(data, "%s I/O error: %s", procname, strerror(errno));
202       break;
203     }
204     break;
205   default:
206     failf(data, "%s: %s", procname, gsk_strerror(rc));
207     break;
208   }
209   return defcode;
210 }
211
212
213 static CURLcode set_enum(struct Curl_easy *data, gsk_handle h,
214                 GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
215 {
216   int rc = gsk_attribute_set_enum(h, id, value);
217
218   switch(rc) {
219   case GSK_OK:
220     return CURLE_OK;
221   case GSK_ERROR_IO:
222     failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
223     break;
224   case GSK_ATTRIBUTE_INVALID_ID:
225     if(unsupported_ok)
226       return CURLE_UNSUPPORTED_PROTOCOL;
227   default:
228     failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
229     break;
230   }
231   return CURLE_SSL_CONNECT_ERROR;
232 }
233
234
235 static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h,
236                         GSK_BUF_ID id, const char *buffer, bool unsupported_ok)
237 {
238   int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
239
240   switch(rc) {
241   case GSK_OK:
242     return CURLE_OK;
243   case GSK_ERROR_IO:
244     failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
245     break;
246   case GSK_ATTRIBUTE_INVALID_ID:
247     if(unsupported_ok)
248       return CURLE_UNSUPPORTED_PROTOCOL;
249   default:
250     failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
251     break;
252   }
253   return CURLE_SSL_CONNECT_ERROR;
254 }
255
256
257 static CURLcode set_numeric(struct Curl_easy *data,
258                             gsk_handle h, GSK_NUM_ID id, int value)
259 {
260   int rc = gsk_attribute_set_numeric_value(h, id, value);
261
262   switch(rc) {
263   case GSK_OK:
264     return CURLE_OK;
265   case GSK_ERROR_IO:
266     failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
267           strerror(errno));
268     break;
269   default:
270     failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
271     break;
272   }
273   return CURLE_SSL_CONNECT_ERROR;
274 }
275
276
277 static CURLcode set_callback(struct Curl_easy *data,
278                              gsk_handle h, GSK_CALLBACK_ID id, void *info)
279 {
280   int rc = gsk_attribute_set_callback(h, id, info);
281
282   switch(rc) {
283   case GSK_OK:
284     return CURLE_OK;
285   case GSK_ERROR_IO:
286     failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
287     break;
288   default:
289     failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
290     break;
291   }
292   return CURLE_SSL_CONNECT_ERROR;
293 }
294
295
296 static CURLcode set_ciphers(struct connectdata *conn,
297                                         gsk_handle h, unsigned int *protoflags)
298 {
299   struct Curl_easy *data = conn->data;
300   const char *cipherlist = SSL_CONN_CONFIG(cipher_list);
301   const char *clp;
302   const gskit_cipher *ctp;
303   int i;
304   int l;
305   bool unsupported;
306   CURLcode result;
307   struct {
308     char *buf;
309     char *ptr;
310   } ciphers[CURL_GSKPROTO_LAST];
311
312   /* Compile cipher list into GSKit-compatible cipher lists. */
313
314   if(!cipherlist)
315     return CURLE_OK;
316   while(is_separator(*cipherlist))     /* Skip initial separators. */
317     cipherlist++;
318   if(!*cipherlist)
319     return CURLE_OK;
320
321   /* We allocate GSKit buffers of the same size as the input string: since
322      GSKit tokens are always shorter than their cipher names, allocated buffers
323      will always be large enough to accomodate the result. */
324   l = strlen(cipherlist) + 1;
325   memset((char *) ciphers, 0, sizeof ciphers);
326   for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
327     ciphers[i].buf = malloc(l);
328     if(!ciphers[i].buf) {
329       while(i--)
330         free(ciphers[i].buf);
331       return CURLE_OUT_OF_MEMORY;
332     }
333     ciphers[i].ptr = ciphers[i].buf;
334     *ciphers[i].ptr = '\0';
335   }
336
337   /* Process each cipher in input string. */
338   unsupported = FALSE;
339   result = CURLE_OK;
340   for(;;) {
341     for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
342       cipherlist++;
343     l = cipherlist - clp;
344     if(!l)
345       break;
346     /* Search the cipher in our table. */
347     for(ctp = ciphertable; ctp->name; ctp++)
348       if(strncasecompare(ctp->name, clp, l) && !ctp->name[l])
349         break;
350     if(!ctp->name) {
351       failf(data, "Unknown cipher %.*s", l, clp);
352       result = CURLE_SSL_CIPHER;
353     }
354     else {
355       unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK |
356                         CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK));
357       for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
358         if(ctp->versions & (1 << i)) {
359           strcpy(ciphers[i].ptr, ctp->gsktoken);
360           ciphers[i].ptr += strlen(ctp->gsktoken);
361         }
362       }
363     }
364
365    /* Advance to next cipher name or end of string. */
366     while(is_separator(*cipherlist))
367       cipherlist++;
368   }
369
370   /* Disable protocols with empty cipher lists. */
371   for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
372     if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) {
373       *protoflags &= ~(1 << i);
374       ciphers[i].buf[0] = '\0';
375     }
376   }
377
378   /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */
379   if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) {
380     result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS,
381                         ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE);
382     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
383       result = CURLE_OK;
384       if(unsupported) {
385         failf(data, "TLSv1.1-only ciphers are not yet supported");
386         result = CURLE_SSL_CIPHER;
387       }
388     }
389   }
390   if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) {
391     result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS,
392                         ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE);
393     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
394       result = CURLE_OK;
395       if(unsupported) {
396         failf(data, "TLSv1.2-only ciphers are not yet supported");
397         result = CURLE_SSL_CIPHER;
398       }
399     }
400   }
401
402   /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to
403      the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */
404   if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) {
405     result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS,
406                         ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE);
407     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
408       result = CURLE_OK;
409       strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr,
410              ciphers[CURL_GSKPROTO_TLSV10].ptr);
411     }
412   }
413
414   /* Set-up other ciphers. */
415   if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK))
416     result = set_buffer(data, h, GSK_V3_CIPHER_SPECS,
417                         ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE);
418   if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK))
419     result = set_buffer(data, h, GSK_V2_CIPHER_SPECS,
420                         ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE);
421
422   /* Clean-up. */
423   for(i = 0; i < CURL_GSKPROTO_LAST; i++)
424     free(ciphers[i].buf);
425
426   return result;
427 }
428
429
430 int Curl_gskit_init(void)
431 {
432   /* No initialisation needed. */
433
434   return 1;
435 }
436
437
438 void Curl_gskit_cleanup(void)
439 {
440   /* Nothing to do. */
441 }
442
443
444 static CURLcode init_environment(struct Curl_easy *data,
445                                  gsk_handle *envir, const char *appid,
446                                  const char *file, const char *label,
447                                  const char *password)
448 {
449   int rc;
450   CURLcode result;
451   gsk_handle h;
452
453   /* Creates the GSKit environment. */
454
455   rc = gsk_environment_open(&h);
456   switch(rc) {
457   case GSK_OK:
458     break;
459   case GSK_INSUFFICIENT_STORAGE:
460     return CURLE_OUT_OF_MEMORY;
461   default:
462     failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
463     return CURLE_SSL_CONNECT_ERROR;
464   }
465
466   result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE);
467   if(!result && appid)
468     result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE);
469   if(!result && file)
470     result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE);
471   if(!result && label)
472     result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE);
473   if(!result && password)
474     result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE);
475
476   if(!result) {
477     /* Locate CAs, Client certificate and key according to our settings.
478        Note: this call may be blocking for some tenths of seconds. */
479     result = gskit_status(data, gsk_environment_init(h),
480                           "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
481     if(!result) {
482       *envir = h;
483       return result;
484     }
485   }
486   /* Error: rollback. */
487   gsk_environment_close(&h);
488   return result;
489 }
490
491
492 static void cancel_async_handshake(struct connectdata *conn, int sockindex)
493 {
494   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
495   Qso_OverlappedIO_t cstat;
496
497   if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
498     QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
499 }
500
501
502 static void close_async_handshake(struct ssl_connect_data *connssl)
503 {
504   QsoDestroyIOCompletionPort(connssl->iocport);
505   connssl->iocport = -1;
506 }
507
508 /* SSL over SSL
509  * Problems:
510  * 1) GSKit can only perform SSL on an AF_INET or AF_INET6 stream socket. To
511  *    pipe an SSL stream into another, it is therefore needed to have a pair
512  *    of such communicating sockets and handle the pipelining explicitly.
513  * 2) OS/400 socketpair() is only implemented for domain AF_UNIX, thus cannot
514  *    be used to produce the pipeline.
515  * The solution is to simulate socketpair() for AF_INET with low-level API
516  *    listen(), bind() and connect().
517  */
518
519 static int
520 inetsocketpair(int sv[2])
521 {
522   int lfd;      /* Listening socket. */
523   int sfd;      /* Server socket. */
524   int cfd;      /* Client socket. */
525   int len;
526   struct sockaddr_in addr1;
527   struct sockaddr_in addr2;
528
529   /* Create listening socket on a local dynamic port. */
530   lfd = socket(AF_INET, SOCK_STREAM, 0);
531   if(lfd < 0)
532     return -1;
533   memset((char *) &addr1, 0, sizeof addr1);
534   addr1.sin_family = AF_INET;
535   addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
536   addr1.sin_port = 0;
537   if(bind(lfd, (struct sockaddr *) &addr1, sizeof addr1) ||
538      listen(lfd, 2) < 0) {
539     close(lfd);
540     return -1;
541   }
542
543   /* Get the allocated port. */
544   len = sizeof addr1;
545   if(getsockname(lfd, (struct sockaddr *) &addr1, &len) < 0) {
546     close(lfd);
547     return -1;
548   }
549
550   /* Create the client socket. */
551   cfd = socket(AF_INET, SOCK_STREAM, 0);
552   if(cfd < 0) {
553     close(lfd);
554     return -1;
555   }
556
557   /* Request unblocking connection to the listening socket. */
558   curlx_nonblock(cfd, TRUE);
559   if(connect(cfd, (struct sockaddr *) &addr1, sizeof addr1) < 0 &&
560      errno != EINPROGRESS) {
561     close(lfd);
562     close(cfd);
563     return -1;
564   }
565
566   /* Get the client dynamic port for intrusion check below. */
567   len = sizeof addr2;
568   if(getsockname(cfd, (struct sockaddr *) &addr2, &len) < 0) {
569     close(lfd);
570     close(cfd);
571     return -1;
572   }
573
574   /* Accept the incoming connection and get the server socket. */
575   curlx_nonblock(lfd, TRUE);
576   for(;;) {
577     len = sizeof addr1;
578     sfd = accept(lfd, (struct sockaddr *) &addr1, &len);
579     if(sfd < 0) {
580       close(lfd);
581       close(cfd);
582       return -1;
583     }
584
585     /* Check for possible intrusion from an external process. */
586     if(addr1.sin_addr.s_addr == addr2.sin_addr.s_addr &&
587        addr1.sin_port == addr2.sin_port)
588       break;
589
590     /* Intrusion: reject incoming connection. */
591     close(sfd);
592   }
593
594   /* Done, return sockets and succeed. */
595   close(lfd);
596   curlx_nonblock(cfd, FALSE);
597   sv[0] = cfd;
598   sv[1] = sfd;
599   return 0;
600 }
601
602 static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
603                            int directions)
604 {
605   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
606   struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex];
607   fd_set fds_read;
608   fd_set fds_write;
609   int n;
610   int m;
611   int i;
612   int ret = 0;
613   struct timeval tv = {0, 0};
614   char buf[CURL_MAX_WRITE_SIZE];
615
616   if(!connssl->use || !connproxyssl->use)
617     return 0;   /* No SSL over SSL: OK. */
618
619   FD_ZERO(&fds_read);
620   FD_ZERO(&fds_write);
621   n = -1;
622   if(directions & SOS_READ) {
623     FD_SET(connssl->remotefd, &fds_write);
624     n = connssl->remotefd;
625   }
626   if(directions & SOS_WRITE) {
627     FD_SET(connssl->remotefd, &fds_read);
628     n = connssl->remotefd;
629     FD_SET(conn->sock[sockindex], &fds_write);
630     if(n < conn->sock[sockindex])
631       n = conn->sock[sockindex];
632   }
633   i = select(n + 1, &fds_read, &fds_write, NULL, &tv);
634   if(i < 0)
635     return -1;  /* Select error. */
636
637   if(FD_ISSET(connssl->remotefd, &fds_write)) {
638     /* Try getting data from HTTPS proxy and pipe it upstream. */
639     n = 0;
640     i = gsk_secure_soc_read(connproxyssl->handle, buf, sizeof buf, &n);
641     switch(i) {
642     case GSK_OK:
643       if(n) {
644         i = write(connssl->remotefd, buf, n);
645         if(i < 0)
646           return -1;
647         ret = 1;
648       }
649       break;
650     case GSK_OS400_ERROR_TIMED_OUT:
651     case GSK_WOULD_BLOCK:
652       break;
653     default:
654       return -1;
655     }
656   }
657
658   if(FD_ISSET(connssl->remotefd, &fds_read) &&
659      FD_ISSET(conn->sock[sockindex], &fds_write)) {
660     /* Pipe data to HTTPS proxy. */
661     n = read(connssl->remotefd, buf, sizeof buf);
662     if(n < 0)
663       return -1;
664     if(n) {
665       i = gsk_secure_soc_write(connproxyssl->handle, buf, n, &m);
666       if(i != GSK_OK || n != m)
667         return -1;
668       ret = 1;
669     }
670   }
671
672   return ret;  /* OK */
673 }
674
675
676 static void close_one(struct ssl_connect_data *connssl,
677                       struct connectdata *conn, int sockindex)
678 {
679   if(connssl->handle) {
680     gskit_status(conn->data, gsk_secure_soc_close(&connssl->handle),
681               "gsk_secure_soc_close()", 0);
682     /* Last chance to drain output. */
683     while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
684       ;
685     connssl->handle = (gsk_handle) NULL;
686     if(connssl->localfd >= 0) {
687       close(connssl->localfd);
688       connssl->localfd = -1;
689     }
690     if(connssl->remotefd >= 0) {
691       close(connssl->remotefd);
692       connssl->remotefd = -1;
693     }
694   }
695   if(connssl->iocport >= 0)
696     close_async_handshake(connssl);
697 }
698
699
700 static ssize_t gskit_send(struct connectdata *conn, int sockindex,
701                            const void *mem, size_t len, CURLcode *curlcode)
702 {
703   struct Curl_easy *data = conn->data;
704   CURLcode cc = CURLE_SEND_ERROR;
705   int written;
706
707   if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
708     cc = gskit_status(data,
709                       gsk_secure_soc_write(conn->ssl[sockindex].handle,
710                                            (char *) mem, (int) len, &written),
711                       "gsk_secure_soc_write()", CURLE_SEND_ERROR);
712     if(cc == CURLE_OK)
713       if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0)
714         cc = CURLE_SEND_ERROR;
715   }
716   if(cc != CURLE_OK) {
717     *curlcode = cc;
718     written = -1;
719   }
720   return (ssize_t) written; /* number of bytes */
721 }
722
723
724 static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
725                            size_t buffersize, CURLcode *curlcode)
726 {
727   struct Curl_easy *data = conn->data;
728   int buffsize;
729   int nread;
730   CURLcode cc = CURLE_RECV_ERROR;
731
732   if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
733     buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
734     cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
735                                                 buf, buffsize, &nread),
736                       "gsk_secure_soc_read()", CURLE_RECV_ERROR);
737   }
738   switch(cc) {
739   case CURLE_OK:
740     break;
741   case CURLE_OPERATION_TIMEDOUT:
742     cc = CURLE_AGAIN;
743   default:
744     *curlcode = cc;
745     nread = -1;
746     break;
747   }
748   return (ssize_t) nread;
749 }
750
751
752 static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
753 {
754   struct Curl_easy *data = conn->data;
755   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
756   gsk_handle envir;
757   CURLcode result;
758   int rc;
759   const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
760   const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
761   const char * const keyringlabel = SSL_SET_OPTION(cert);
762   const long int ssl_version = SSL_CONN_CONFIG(version);
763   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
764   const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
765     conn->host.name;
766   const char *sni;
767   unsigned int protoflags;
768   long timeout;
769   Qso_OverlappedIO_t commarea;
770   int sockpair[2];
771   static const int sobufsize = CURL_MAX_WRITE_SIZE;
772
773   /* Create SSL environment, start (preferably asynchronous) handshake. */
774
775   connssl->handle = (gsk_handle) NULL;
776   connssl->iocport = -1;
777   connssl->localfd = -1;
778   connssl->remotefd = -1;
779
780   /* GSKit supports two ways of specifying an SSL context: either by
781    *  application identifier (that should have been defined at the system
782    *  level) or by keyring file, password and certificate label.
783    * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
784    *  application identifier of the certificate label.
785    * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
786    * It is not possible to have different keyrings for the CAs and the
787    *  local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
788    *  the keyring file.
789    * If no key password is given and the keyring is the system keyring,
790    *  application identifier mode is tried first, as recommended in IBM doc.
791    */
792
793   envir = (gsk_handle) NULL;
794
795   if(keyringlabel && *keyringlabel && !keyringpwd &&
796       !strcmp(keyringfile, CURL_CA_BUNDLE)) {
797     /* Try application identifier mode. */
798     init_environment(data, &envir, keyringlabel, (const char *) NULL,
799                      (const char *) NULL, (const char *) NULL);
800   }
801
802   if(!envir) {
803     /* Use keyring mode. */
804     result = init_environment(data, &envir, (const char *) NULL,
805                               keyringfile, keyringlabel, keyringpwd);
806     if(result)
807       return result;
808   }
809
810   /* Create secure session. */
811   result = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
812                         "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
813   gsk_environment_close(&envir);
814   if(result)
815     return result;
816
817   /* Establish a pipelining socket pair for SSL over SSL. */
818   if(conn->proxy_ssl[sockindex].use) {
819     if(inetsocketpair(sockpair))
820       return CURLE_SSL_CONNECT_ERROR;
821     connssl->localfd = sockpair[0];
822     connssl->remotefd = sockpair[1];
823     setsockopt(connssl->localfd, SOL_SOCKET, SO_RCVBUF,
824                (void *) sobufsize, sizeof sobufsize);
825     setsockopt(connssl->remotefd, SOL_SOCKET, SO_RCVBUF,
826                (void *) sobufsize, sizeof sobufsize);
827     setsockopt(connssl->localfd, SOL_SOCKET, SO_SNDBUF,
828                (void *) sobufsize, sizeof sobufsize);
829     setsockopt(connssl->remotefd, SOL_SOCKET, SO_SNDBUF,
830                (void *) sobufsize, sizeof sobufsize);
831     curlx_nonblock(connssl->localfd, TRUE);
832     curlx_nonblock(connssl->remotefd, TRUE);
833   }
834
835   /* Determine which SSL/TLS version should be enabled. */
836   sni = hostname;
837   switch(ssl_version) {
838   case CURL_SSLVERSION_SSLv2:
839     protoflags = CURL_GSKPROTO_SSLV2_MASK;
840     sni = NULL;
841     break;
842   case CURL_SSLVERSION_SSLv3:
843     protoflags = CURL_GSKPROTO_SSLV3_MASK;
844     sni = NULL;
845     break;
846   case CURL_SSLVERSION_DEFAULT:
847   case CURL_SSLVERSION_TLSv1:
848     protoflags = CURL_GSKPROTO_TLSV10_MASK |
849                  CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
850     break;
851   case CURL_SSLVERSION_TLSv1_0:
852     protoflags = CURL_GSKPROTO_TLSV10_MASK;
853     break;
854   case CURL_SSLVERSION_TLSv1_1:
855     protoflags = CURL_GSKPROTO_TLSV11_MASK;
856     break;
857   case CURL_SSLVERSION_TLSv1_2:
858     protoflags = CURL_GSKPROTO_TLSV12_MASK;
859     break;
860   case CURL_SSLVERSION_TLSv1_3:
861     failf(data, "GSKit: TLS 1.3 is not yet supported");
862     return CURLE_SSL_CONNECT_ERROR;
863   default:
864     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
865     return CURLE_SSL_CONNECT_ERROR;
866   }
867
868   /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
869   if(sni) {
870     result = set_buffer(data, connssl->handle,
871                         GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
872     if(result == CURLE_UNSUPPORTED_PROTOCOL)
873       result = CURLE_OK;
874   }
875
876   /* Set session parameters. */
877   if(!result) {
878     /* Compute the handshake timeout. Since GSKit granularity is 1 second,
879        we round up the required value. */
880     timeout = Curl_timeleft(data, NULL, TRUE);
881     if(timeout < 0)
882       result = CURLE_OPERATION_TIMEDOUT;
883     else
884       result = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
885                            (timeout + 999) / 1000);
886   }
887   if(!result)
888     result = set_numeric(data, connssl->handle, GSK_OS400_READ_TIMEOUT, 1);
889   if(!result)
890     result = set_numeric(data, connssl->handle, GSK_FD, connssl->localfd >= 0?
891                          connssl->localfd: conn->sock[sockindex]);
892   if(!result)
893     result = set_ciphers(conn, connssl->handle, &protoflags);
894   if(!protoflags) {
895     failf(data, "No SSL protocol/cipher combination enabled");
896     result = CURLE_SSL_CIPHER;
897   }
898   if(!result)
899     result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
900                       (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
901                       GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
902   if(!result)
903     result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
904                       (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
905                       GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
906   if(!result)
907     result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
908                       (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
909                       GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
910   if(!result) {
911     result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11,
912                       (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
913                       GSK_TRUE: GSK_FALSE, TRUE);
914     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
915       result = CURLE_OK;
916       if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
917         failf(data, "TLS 1.1 not yet supported");
918         result = CURLE_SSL_CIPHER;
919       }
920     }
921   }
922   if(!result) {
923     result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12,
924                       (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
925                       GSK_TRUE: GSK_FALSE, TRUE);
926     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
927       result = CURLE_OK;
928       if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
929         failf(data, "TLS 1.2 not yet supported");
930         result = CURLE_SSL_CIPHER;
931       }
932     }
933   }
934   if(!result)
935     result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
936                       verifypeer? GSK_SERVER_AUTH_FULL:
937                       GSK_SERVER_AUTH_PASSTHRU, FALSE);
938
939   if(!result) {
940     /* Start handshake. Try asynchronous first. */
941     memset(&commarea, 0, sizeof commarea);
942     connssl->iocport = QsoCreateIOCompletionPort();
943     if(connssl->iocport != -1) {
944       result = gskit_status(data,
945                             gsk_secure_soc_startInit(connssl->handle,
946                                                      connssl->iocport,
947                                                      &commarea),
948                             "gsk_secure_soc_startInit()",
949                             CURLE_SSL_CONNECT_ERROR);
950       if(!result) {
951         connssl->connecting_state = ssl_connect_2;
952         return CURLE_OK;
953       }
954       else
955         close_async_handshake(connssl);
956     }
957     else if(errno != ENOBUFS)
958       result = gskit_status(data, GSK_ERROR_IO,
959                             "QsoCreateIOCompletionPort()", 0);
960     else if(conn->proxy_ssl[sockindex].use) {
961       /* Cannot pipeline while handshaking synchronously. */
962       result = CURLE_SSL_CONNECT_ERROR;
963     }
964     else {
965       /* No more completion port available. Use synchronous IO. */
966       result = gskit_status(data, gsk_secure_soc_init(connssl->handle),
967                             "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
968       if(!result) {
969         connssl->connecting_state = ssl_connect_3;
970         return CURLE_OK;
971       }
972     }
973   }
974
975   /* Error: rollback. */
976   close_one(connssl, conn, sockindex);
977   return result;
978 }
979
980
981 static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
982                                     bool nonblocking)
983 {
984   struct Curl_easy *data = conn->data;
985   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
986   Qso_OverlappedIO_t cstat;
987   long timeout_ms;
988   struct timeval stmv;
989   CURLcode result;
990
991   /* Poll or wait for end of SSL asynchronous handshake. */
992
993   for(;;) {
994     timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
995     if(timeout_ms < 0)
996       timeout_ms = 0;
997     stmv.tv_sec = timeout_ms / 1000;
998     stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
999     switch(QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
1000     case 1:             /* Operation complete. */
1001       break;
1002     case -1:            /* An error occurred: handshake still in progress. */
1003       if(errno == EINTR) {
1004         if(nonblocking)
1005           return CURLE_OK;
1006         continue;       /* Retry. */
1007       }
1008       if(errno != ETIME) {
1009         failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
1010         cancel_async_handshake(conn, sockindex);
1011         close_async_handshake(connssl);
1012         return CURLE_SSL_CONNECT_ERROR;
1013       }
1014       /* FALL INTO... */
1015     case 0:             /* Handshake in progress, timeout occurred. */
1016       if(nonblocking)
1017         return CURLE_OK;
1018       cancel_async_handshake(conn, sockindex);
1019       close_async_handshake(connssl);
1020       return CURLE_OPERATION_TIMEDOUT;
1021     }
1022     break;
1023   }
1024   result = gskit_status(data, cstat.returnValue, "SSL handshake",
1025                         CURLE_SSL_CONNECT_ERROR);
1026   if(!result)
1027     connssl->connecting_state = ssl_connect_3;
1028   close_async_handshake(connssl);
1029   return result;
1030 }
1031
1032
1033 static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
1034 {
1035   struct Curl_easy *data = conn->data;
1036   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1037   const gsk_cert_data_elem *cdev;
1038   int cdec;
1039   const gsk_cert_data_elem *p;
1040   const char *cert = (const char *) NULL;
1041   const char *certend;
1042   const char *ptr;
1043   int i;
1044   CURLcode result;
1045
1046   /* SSL handshake done: gather certificate info and verify host. */
1047
1048   if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
1049                                                     GSK_PARTNER_CERT_INFO,
1050                                                     &cdev, &cdec),
1051                   "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
1052      CURLE_OK) {
1053     infof(data, "Server certificate:\n");
1054     p = cdev;
1055     for(i = 0; i++ < cdec; p++)
1056       switch(p->cert_data_id) {
1057       case CERT_BODY_DER:
1058         cert = p->cert_data_p;
1059         certend = cert + cdev->cert_data_l;
1060         break;
1061       case CERT_DN_PRINTABLE:
1062         infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
1063         break;
1064       case CERT_ISSUER_DN_PRINTABLE:
1065         infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
1066         break;
1067       case CERT_VALID_FROM:
1068         infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
1069         break;
1070       case CERT_VALID_TO:
1071         infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
1072         break;
1073     }
1074   }
1075
1076   /* Verify host. */
1077   result = Curl_verifyhost(conn, cert, certend);
1078   if(result)
1079     return result;
1080
1081   /* The only place GSKit can get the whole CA chain is a validation
1082      callback where no user data pointer is available. Therefore it's not
1083      possible to copy this chain into our structures for CAINFO.
1084      However the server certificate may be available, thus we can return
1085      info about it. */
1086   if(data->set.ssl.certinfo) {
1087     result = Curl_ssl_init_certinfo(data, 1);
1088     if(result)
1089       return result;
1090
1091     if(cert) {
1092       result = Curl_extract_certinfo(conn, 0, cert, certend);
1093       if(result)
1094         return result;
1095     }
1096   }
1097
1098   /* Check pinned public key. */
1099   ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1100                          data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
1101   if(!result && ptr) {
1102     curl_X509certificate x509;
1103     curl_asn1Element *p;
1104
1105     if(Curl_parseX509(&x509, cert, certend))
1106       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1107     p = &x509.subjectPublicKeyInfo;
1108     result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
1109     if(result) {
1110       failf(data, "SSL: public key does not match pinned public key!");
1111       return result;
1112     }
1113   }
1114
1115   connssl->connecting_state = ssl_connect_done;
1116   return CURLE_OK;
1117 }
1118
1119
1120 static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
1121                                      bool nonblocking, bool *done)
1122 {
1123   struct Curl_easy *data = conn->data;
1124   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1125   long timeout_ms;
1126   Qso_OverlappedIO_t cstat;
1127   CURLcode result = CURLE_OK;
1128
1129   *done = connssl->state == ssl_connection_complete;
1130   if(*done)
1131     return CURLE_OK;
1132
1133   /* Step 1: create session, start handshake. */
1134   if(connssl->connecting_state == ssl_connect_1) {
1135     /* check allowed time left */
1136     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1137
1138     if(timeout_ms < 0) {
1139       /* no need to continue if time already is up */
1140       failf(data, "SSL connection timeout");
1141       result = CURLE_OPERATION_TIMEDOUT;
1142     }
1143     else
1144       result = gskit_connect_step1(conn, sockindex);
1145   }
1146
1147   /* Handle handshake pipelining. */
1148   if(!result)
1149     if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1150       result = CURLE_SSL_CONNECT_ERROR;
1151
1152   /* Step 2: check if handshake is over. */
1153   if(!result && connssl->connecting_state == ssl_connect_2) {
1154     /* check allowed time left */
1155     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1156
1157     if(timeout_ms < 0) {
1158       /* no need to continue if time already is up */
1159       failf(data, "SSL connection timeout");
1160       result = CURLE_OPERATION_TIMEDOUT;
1161     }
1162     else
1163       result = gskit_connect_step2(conn, sockindex, nonblocking);
1164   }
1165
1166   /* Handle handshake pipelining. */
1167   if(!result)
1168     if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1169       result = CURLE_SSL_CONNECT_ERROR;
1170
1171   /* Step 3: gather certificate info, verify host. */
1172   if(!result && connssl->connecting_state == ssl_connect_3)
1173     result = gskit_connect_step3(conn, sockindex);
1174
1175   if(result)
1176     close_one(connssl, conn, sockindex);
1177   else if(connssl->connecting_state == ssl_connect_done) {
1178     connssl->state = ssl_connection_complete;
1179     connssl->connecting_state = ssl_connect_1;
1180     conn->recv[sockindex] = gskit_recv;
1181     conn->send[sockindex] = gskit_send;
1182     *done = TRUE;
1183   }
1184
1185   return result;
1186 }
1187
1188
1189 CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
1190                                         int sockindex,
1191                                         bool *done)
1192 {
1193   CURLcode result;
1194
1195   result = gskit_connect_common(conn, sockindex, TRUE, done);
1196   if(*done || result)
1197     conn->ssl[sockindex].connecting_state = ssl_connect_1;
1198   return result;
1199 }
1200
1201
1202 CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
1203 {
1204   CURLcode result;
1205   bool done;
1206
1207   conn->ssl[sockindex].connecting_state = ssl_connect_1;
1208   result = gskit_connect_common(conn, sockindex, FALSE, &done);
1209   if(result)
1210     return result;
1211
1212   DEBUGASSERT(done);
1213
1214   return CURLE_OK;
1215 }
1216
1217
1218 void Curl_gskit_close(struct connectdata *conn, int sockindex)
1219 {
1220   close_one(&conn->ssl[sockindex], conn, sockindex);
1221   close_one(&conn->proxy_ssl[sockindex], conn, sockindex);
1222 }
1223
1224
1225 int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
1226 {
1227   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1228   struct Curl_easy *data = conn->data;
1229   ssize_t nread;
1230   int what;
1231   int rc;
1232   char buf[120];
1233
1234   if(!connssl->handle)
1235     return 0;
1236
1237   if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
1238     return 0;
1239
1240   close_one(connssl, conn, sockindex);
1241   rc = 0;
1242   what = SOCKET_READABLE(conn->sock[sockindex],
1243                          SSL_SHUTDOWN_TIMEOUT);
1244
1245   for(;;) {
1246     if(what < 0) {
1247       /* anything that gets here is fatally bad */
1248       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1249       rc = -1;
1250       break;
1251     }
1252
1253     if(!what) {                                /* timeout */
1254       failf(data, "SSL shutdown timeout");
1255       break;
1256     }
1257
1258     /* Something to read, let's do it and hope that it is the close
1259        notify alert from the server. No way to gsk_secure_soc_read() now, so
1260        use read(). */
1261
1262     nread = read(conn->sock[sockindex], buf, sizeof(buf));
1263
1264     if(nread < 0) {
1265       failf(data, "read: %s", strerror(errno));
1266       rc = -1;
1267     }
1268
1269     if(nread <= 0)
1270       break;
1271
1272     what = SOCKET_READABLE(conn->sock[sockindex], 0);
1273   }
1274
1275   return rc;
1276 }
1277
1278
1279 size_t Curl_gskit_version(char *buffer, size_t size)
1280 {
1281   strncpy(buffer, "GSKit", size);
1282   return strlen(buffer);
1283 }
1284
1285
1286 int Curl_gskit_check_cxn(struct connectdata *cxn)
1287 {
1288   int err;
1289   int errlen;
1290
1291   /* The only thing that can be tested here is at the socket level. */
1292
1293   if(!cxn->ssl[FIRSTSOCKET].handle)
1294     return 0; /* connection has been closed */
1295
1296   err = 0;
1297   errlen = sizeof err;
1298
1299   if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
1300                  (unsigned char *) &err, &errlen) ||
1301      errlen != sizeof err || err)
1302     return 0; /* connection has been closed */
1303
1304   return -1;  /* connection status unknown */
1305 }
1306
1307 #endif /* USE_GSKIT */