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