7a65f92f205323a6f9776964e823aa18b79e1953
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / vtls / gskit.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, 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.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 #undef HAVE_SOCKETPAIR /* because the native one isn't good enough */
30 #include "socketpair.h"
31 #include "strerror.h"
32
33 /* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
34 #ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
35 #define GSK_SSL_EXTN_SERVERNAME_REQUEST         230
36 #endif
37
38 #ifndef GSK_TLSV10_CIPHER_SPECS
39 #define GSK_TLSV10_CIPHER_SPECS                 236
40 #endif
41
42 #ifndef GSK_TLSV11_CIPHER_SPECS
43 #define GSK_TLSV11_CIPHER_SPECS                 237
44 #endif
45
46 #ifndef GSK_TLSV12_CIPHER_SPECS
47 #define GSK_TLSV12_CIPHER_SPECS                 238
48 #endif
49
50 #ifndef GSK_PROTOCOL_TLSV11
51 #define GSK_PROTOCOL_TLSV11                     437
52 #endif
53
54 #ifndef GSK_PROTOCOL_TLSV12
55 #define GSK_PROTOCOL_TLSV12                     438
56 #endif
57
58 #ifndef GSK_FALSE
59 #define GSK_FALSE                               0
60 #endif
61
62 #ifndef GSK_TRUE
63 #define GSK_TRUE                                1
64 #endif
65
66
67 #include <limits.h>
68
69 #include <curl/curl.h>
70 #include "urldata.h"
71 #include "sendf.h"
72 #include "gskit.h"
73 #include "vtls.h"
74 #include "connect.h" /* for the connect timeout */
75 #include "select.h"
76 #include "strcase.h"
77 #include "timediff.h"
78 #include "x509asn1.h"
79 #include "curl_printf.h"
80
81 #include "curl_memory.h"
82 /* The last #include file should be: */
83 #include "memdebug.h"
84
85
86 /* Directions. */
87 #define SOS_READ        0x01
88 #define SOS_WRITE       0x02
89
90 /* SSL version flags. */
91 #define CURL_GSKPROTO_SSLV2     0
92 #define CURL_GSKPROTO_SSLV2_MASK        (1 << CURL_GSKPROTO_SSLV2)
93 #define CURL_GSKPROTO_SSLV3     1
94 #define CURL_GSKPROTO_SSLV3_MASK        (1 << CURL_GSKPROTO_SSLV3)
95 #define CURL_GSKPROTO_TLSV10    2
96 #define CURL_GSKPROTO_TLSV10_MASK        (1 << CURL_GSKPROTO_TLSV10)
97 #define CURL_GSKPROTO_TLSV11    3
98 #define CURL_GSKPROTO_TLSV11_MASK        (1 << CURL_GSKPROTO_TLSV11)
99 #define CURL_GSKPROTO_TLSV12    4
100 #define CURL_GSKPROTO_TLSV12_MASK        (1 << CURL_GSKPROTO_TLSV12)
101 #define CURL_GSKPROTO_LAST      5
102
103 struct ssl_backend_data {
104   gsk_handle handle;
105   int iocport;
106 #ifndef CURL_DISABLE_PROXY
107   int localfd;
108   int remotefd;
109 #endif
110 };
111
112 #define BACKEND connssl->backend
113
114 /* Supported ciphers. */
115 struct gskit_cipher {
116   const char *name;            /* Cipher name. */
117   const char *gsktoken;        /* Corresponding token for GSKit String. */
118   unsigned int versions;       /* SSL version flags. */
119 };
120
121 static const struct gskit_cipher  ciphertable[] = {
122   { "null-md5",         "01",
123       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
124       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
125   { "null-sha",         "02",
126       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
127       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
128   { "exp-rc4-md5",      "03",
129       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
130   { "rc4-md5",          "04",
131       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
132       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
133   { "rc4-sha",          "05",
134       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
135       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
136   { "exp-rc2-cbc-md5",  "06",
137       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
138   { "exp-des-cbc-sha",  "09",
139       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
140       CURL_GSKPROTO_TLSV11_MASK },
141   { "des-cbc3-sha",     "0A",
142       CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
143       CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
144   { "aes128-sha",       "2F",
145       CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
146       CURL_GSKPROTO_TLSV12_MASK },
147   { "aes256-sha",       "35",
148       CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
149       CURL_GSKPROTO_TLSV12_MASK },
150   { "null-sha256",      "3B",   CURL_GSKPROTO_TLSV12_MASK },
151   { "aes128-sha256",    "3C",   CURL_GSKPROTO_TLSV12_MASK },
152   { "aes256-sha256",    "3D",   CURL_GSKPROTO_TLSV12_MASK },
153   { "aes128-gcm-sha256",
154                         "9C",   CURL_GSKPROTO_TLSV12_MASK },
155   { "aes256-gcm-sha384",
156                         "9D",   CURL_GSKPROTO_TLSV12_MASK },
157   { "rc4-md5",          "1",    CURL_GSKPROTO_SSLV2_MASK },
158   { "exp-rc4-md5",      "2",    CURL_GSKPROTO_SSLV2_MASK },
159   { "rc2-md5",          "3",    CURL_GSKPROTO_SSLV2_MASK },
160   { "exp-rc2-md5",      "4",    CURL_GSKPROTO_SSLV2_MASK },
161   { "des-cbc-md5",      "6",    CURL_GSKPROTO_SSLV2_MASK },
162   { "des-cbc3-md5",     "7",    CURL_GSKPROTO_SSLV2_MASK },
163   { (const char *) NULL, (const char *) NULL, 0       }
164 };
165
166
167 static bool is_separator(char c)
168 {
169   /* Return whether character is a cipher list separator. */
170   switch(c) {
171   case ' ':
172   case '\t':
173   case ':':
174   case ',':
175   case ';':
176     return true;
177   }
178   return false;
179 }
180
181
182 static CURLcode gskit_status(struct Curl_easy *data, int rc,
183                              const char *procname, CURLcode defcode)
184 {
185   char buffer[STRERROR_LEN];
186   /* Process GSKit status and map it to a CURLcode. */
187   switch(rc) {
188   case GSK_OK:
189   case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
190     return CURLE_OK;
191   case GSK_KEYRING_OPEN_ERROR:
192   case GSK_OS400_ERROR_NO_ACCESS:
193     return CURLE_SSL_CACERT_BADFILE;
194   case GSK_INSUFFICIENT_STORAGE:
195     return CURLE_OUT_OF_MEMORY;
196   case GSK_ERROR_BAD_V2_CIPHER:
197   case GSK_ERROR_BAD_V3_CIPHER:
198   case GSK_ERROR_NO_CIPHERS:
199     return CURLE_SSL_CIPHER;
200   case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
201   case GSK_ERROR_CERT_VALIDATION:
202     return CURLE_PEER_FAILED_VERIFICATION;
203   case GSK_OS400_ERROR_TIMED_OUT:
204     return CURLE_OPERATION_TIMEDOUT;
205   case GSK_WOULD_BLOCK:
206     return CURLE_AGAIN;
207   case GSK_OS400_ERROR_NOT_REGISTERED:
208     break;
209   case GSK_ERROR_IO:
210     switch(errno) {
211     case ENOMEM:
212       return CURLE_OUT_OF_MEMORY;
213     default:
214       failf(data, "%s I/O error: %s", procname,
215             Curl_strerror(errno, buffer, sizeof(buffer)));
216       break;
217     }
218     break;
219   default:
220     failf(data, "%s: %s", procname, gsk_strerror(rc));
221     break;
222   }
223   return defcode;
224 }
225
226
227 static CURLcode set_enum(struct Curl_easy *data, gsk_handle h,
228                 GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
229 {
230   char buffer[STRERROR_LEN];
231   int rc = gsk_attribute_set_enum(h, id, value);
232
233   switch(rc) {
234   case GSK_OK:
235     return CURLE_OK;
236   case GSK_ERROR_IO:
237     failf(data, "gsk_attribute_set_enum() I/O error: %s",
238           Curl_strerror(errno, buffer, sizeof(buffer)));
239     break;
240   case GSK_ATTRIBUTE_INVALID_ID:
241     if(unsupported_ok)
242       return CURLE_UNSUPPORTED_PROTOCOL;
243   default:
244     failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
245     break;
246   }
247   return CURLE_SSL_CONNECT_ERROR;
248 }
249
250
251 static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h,
252                         GSK_BUF_ID id, const char *buf, bool unsupported_ok)
253 {
254   char buffer[STRERROR_LEN];
255   int rc = gsk_attribute_set_buffer(h, id, buf, 0);
256
257   switch(rc) {
258   case GSK_OK:
259     return CURLE_OK;
260   case GSK_ERROR_IO:
261     failf(data, "gsk_attribute_set_buffer() I/O error: %s",
262           Curl_strerror(errno, buffer, sizeof(buffer)));
263     break;
264   case GSK_ATTRIBUTE_INVALID_ID:
265     if(unsupported_ok)
266       return CURLE_UNSUPPORTED_PROTOCOL;
267   default:
268     failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
269     break;
270   }
271   return CURLE_SSL_CONNECT_ERROR;
272 }
273
274
275 static CURLcode set_numeric(struct Curl_easy *data,
276                             gsk_handle h, GSK_NUM_ID id, int value)
277 {
278   char buffer[STRERROR_LEN];
279   int rc = gsk_attribute_set_numeric_value(h, id, value);
280
281   switch(rc) {
282   case GSK_OK:
283     return CURLE_OK;
284   case GSK_ERROR_IO:
285     failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
286           Curl_strerror(errno, buffer, sizeof(buffer)));
287     break;
288   default:
289     failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
290     break;
291   }
292   return CURLE_SSL_CONNECT_ERROR;
293 }
294
295
296 static CURLcode set_ciphers(struct Curl_easy *data,
297                             gsk_handle h, unsigned int *protoflags)
298 {
299   struct connectdata *conn = data->conn;
300   const char *cipherlist = SSL_CONN_CONFIG(cipher_list);
301   const char *clp;
302   const struct 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 accommodate 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 static int gskit_init(void)
431 {
432   /* No initialization needed. */
433   return 1;
434 }
435
436
437 static void gskit_cleanup(void)
438 {
439   /* Nothing to do. */
440 }
441
442
443 static CURLcode init_environment(struct Curl_easy *data,
444                                  gsk_handle *envir, const char *appid,
445                                  const char *file, const char *label,
446                                  const char *password)
447 {
448   int rc;
449   CURLcode result;
450   gsk_handle h;
451
452   /* Creates the GSKit environment. */
453
454   rc = gsk_environment_open(&h);
455   switch(rc) {
456   case GSK_OK:
457     break;
458   case GSK_INSUFFICIENT_STORAGE:
459     return CURLE_OUT_OF_MEMORY;
460   default:
461     failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
462     return CURLE_SSL_CONNECT_ERROR;
463   }
464
465   result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE);
466   if(!result && appid)
467     result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE);
468   if(!result && file)
469     result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE);
470   if(!result && label)
471     result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE);
472   if(!result && password)
473     result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE);
474
475   if(!result) {
476     /* Locate CAs, Client certificate and key according to our settings.
477        Note: this call may be blocking for some tenths of seconds. */
478     result = gskit_status(data, gsk_environment_init(h),
479                           "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
480     if(!result) {
481       *envir = h;
482       return result;
483     }
484   }
485   /* Error: rollback. */
486   gsk_environment_close(&h);
487   return result;
488 }
489
490
491 static void cancel_async_handshake(struct connectdata *conn, int sockindex)
492 {
493   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
494   Qso_OverlappedIO_t cstat;
495
496   DEBUGASSERT(BACKEND);
497
498   if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
499     QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL);
500 }
501
502
503 static void close_async_handshake(struct ssl_connect_data *connssl)
504 {
505   DEBUGASSERT(BACKEND);
506   QsoDestroyIOCompletionPort(BACKEND->iocport);
507   BACKEND->iocport = -1;
508 }
509
510 static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
511                            int directions)
512 {
513 #ifndef CURL_DISABLE_PROXY
514   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
515   struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex];
516   struct pollfd fds[2];
517   int n;
518   int m;
519   int i;
520   int ret = 0;
521   char buf[CURL_MAX_WRITE_SIZE];
522
523   DEBUGASSERT(BACKEND);
524   DEBUGASSERT(connproxyssl->backend);
525
526   if(!connssl->use || !connproxyssl->use)
527     return 0;   /* No SSL over SSL: OK. */
528
529   n = 1;
530   fds[0].fd = BACKEND->remotefd;
531   fds[1].fd = conn->sock[sockindex];
532
533   if(directions & SOS_READ) {
534     fds[0].events |= POLLOUT;
535   }
536   if(directions & SOS_WRITE) {
537     n = 2;
538     fds[0].events |= POLLIN;
539     fds[1].events |= POLLOUT;
540   }
541   i = Curl_poll(fds, n, 0);
542   if(i < 0)
543     return -1;  /* Select error. */
544
545   if(fds[0].revents & POLLOUT) {
546     /* Try getting data from HTTPS proxy and pipe it upstream. */
547     n = 0;
548     i = gsk_secure_soc_read(connproxyssl->backend->handle,
549                             buf, sizeof(buf), &n);
550     switch(i) {
551     case GSK_OK:
552       if(n) {
553         i = write(BACKEND->remotefd, buf, n);
554         if(i < 0)
555           return -1;
556         ret = 1;
557       }
558       break;
559     case GSK_OS400_ERROR_TIMED_OUT:
560     case GSK_WOULD_BLOCK:
561       break;
562     default:
563       return -1;
564     }
565   }
566
567   if((fds[0].revents & POLLIN) && (fds[1].revents & POLLOUT)) {
568     /* Pipe data to HTTPS proxy. */
569     n = read(BACKEND->remotefd, buf, sizeof(buf));
570     if(n < 0)
571       return -1;
572     if(n) {
573       i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m);
574       if(i != GSK_OK || n != m)
575         return -1;
576       ret = 1;
577     }
578   }
579
580   return ret;  /* OK */
581 #else
582   return 0;
583 #endif
584 }
585
586
587 static void close_one(struct ssl_connect_data *connssl, struct Curl_easy *data,
588                       struct connectdata *conn, int sockindex)
589 {
590   DEBUGASSERT(BACKEND);
591   if(BACKEND->handle) {
592     gskit_status(data, gsk_secure_soc_close(&BACKEND->handle),
593               "gsk_secure_soc_close()", 0);
594     /* Last chance to drain output. */
595     while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
596       ;
597     BACKEND->handle = (gsk_handle) NULL;
598 #ifndef CURL_DISABLE_PROXY
599     if(BACKEND->localfd >= 0) {
600       close(BACKEND->localfd);
601       BACKEND->localfd = -1;
602     }
603     if(BACKEND->remotefd >= 0) {
604       close(BACKEND->remotefd);
605       BACKEND->remotefd = -1;
606     }
607 #endif
608   }
609   if(BACKEND->iocport >= 0)
610     close_async_handshake(connssl);
611 }
612
613
614 static ssize_t gskit_send(struct Curl_easy *data, int sockindex,
615                           const void *mem, size_t len, CURLcode *curlcode)
616 {
617   struct connectdata *conn = data->conn;
618   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
619   CURLcode cc = CURLE_SEND_ERROR;
620   int written;
621
622   DEBUGASSERT(BACKEND);
623
624   if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
625     cc = gskit_status(data,
626                       gsk_secure_soc_write(BACKEND->handle,
627                                            (char *) mem, (int) len, &written),
628                       "gsk_secure_soc_write()", CURLE_SEND_ERROR);
629     if(cc == CURLE_OK)
630       if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0)
631         cc = CURLE_SEND_ERROR;
632   }
633   if(cc != CURLE_OK) {
634     *curlcode = cc;
635     written = -1;
636   }
637   return (ssize_t) written; /* number of bytes */
638 }
639
640
641 static ssize_t gskit_recv(struct Curl_easy *data, int num, char *buf,
642                                size_t buffersize, CURLcode *curlcode)
643 {
644   struct connectdata *conn = data->conn;
645   struct ssl_connect_data *connssl = &conn->ssl[num];
646   int nread;
647   CURLcode cc = CURLE_RECV_ERROR;
648
649   DEBUGASSERT(BACKEND);
650
651   if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
652     int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
653     cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
654                                                 buf, buffsize, &nread),
655                       "gsk_secure_soc_read()", CURLE_RECV_ERROR);
656   }
657   switch(cc) {
658   case CURLE_OK:
659     break;
660   case CURLE_OPERATION_TIMEDOUT:
661     cc = CURLE_AGAIN;
662   default:
663     *curlcode = cc;
664     nread = -1;
665     break;
666   }
667   return (ssize_t) nread;
668 }
669
670 static CURLcode
671 set_ssl_version_min_max(unsigned int *protoflags, struct Curl_easy *data)
672 {
673   struct connectdata *conn = data->conn;
674   long ssl_version = SSL_CONN_CONFIG(version);
675   long ssl_version_max = SSL_CONN_CONFIG(version_max);
676   long i = ssl_version;
677   switch(ssl_version_max) {
678     case CURL_SSLVERSION_MAX_NONE:
679     case CURL_SSLVERSION_MAX_DEFAULT:
680       ssl_version_max = CURL_SSLVERSION_TLSv1_2;
681       break;
682   }
683   for(; i <= (ssl_version_max >> 16); ++i) {
684     switch(i) {
685       case CURL_SSLVERSION_TLSv1_0:
686         *protoflags |= CURL_GSKPROTO_TLSV10_MASK;
687         break;
688       case CURL_SSLVERSION_TLSv1_1:
689         *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
690         break;
691       case CURL_SSLVERSION_TLSv1_2:
692         *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
693         break;
694       case CURL_SSLVERSION_TLSv1_3:
695         failf(data, "GSKit: TLS 1.3 is not yet supported");
696         return CURLE_SSL_CONNECT_ERROR;
697     }
698   }
699
700   return CURLE_OK;
701 }
702
703 static CURLcode gskit_connect_step1(struct Curl_easy *data,
704                                     struct connectdata *conn, int sockindex)
705 {
706   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
707   gsk_handle envir;
708   CURLcode result;
709   const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
710   const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
711   const char * const keyringlabel = SSL_SET_OPTION(primary.clientcert);
712   const long int ssl_version = SSL_CONN_CONFIG(version);
713   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
714   const char * const hostname = SSL_HOST_NAME();
715   const char *sni;
716   unsigned int protoflags = 0;
717   Qso_OverlappedIO_t commarea;
718 #ifndef CURL_DISABLE_PROXY
719   int sockpair[2];
720   static const int sobufsize = CURL_MAX_WRITE_SIZE;
721 #endif
722
723   /* Create SSL environment, start (preferably asynchronous) handshake. */
724   DEBUGASSERT(BACKEND);
725
726   BACKEND->handle = (gsk_handle) NULL;
727   BACKEND->iocport = -1;
728 #ifndef CURL_DISABLE_PROXY
729   BACKEND->localfd = -1;
730   BACKEND->remotefd = -1;
731 #endif
732
733   /* GSKit supports two ways of specifying an SSL context: either by
734    *  application identifier (that should have been defined at the system
735    *  level) or by keyring file, password and certificate label.
736    * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
737    *  application identifier of the certificate label.
738    * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
739    * It is not possible to have different keyrings for the CAs and the
740    *  local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
741    *  the keyring file.
742    * If no key password is given and the keyring is the system keyring,
743    *  application identifier mode is tried first, as recommended in IBM doc.
744    */
745
746   envir = (gsk_handle) NULL;
747
748   if(keyringlabel && *keyringlabel && !keyringpwd &&
749       !strcmp(keyringfile, CURL_CA_BUNDLE)) {
750     /* Try application identifier mode. */
751     init_environment(data, &envir, keyringlabel, (const char *) NULL,
752                      (const char *) NULL, (const char *) NULL);
753   }
754
755   if(!envir) {
756     /* Use keyring mode. */
757     result = init_environment(data, &envir, (const char *) NULL,
758                               keyringfile, keyringlabel, keyringpwd);
759     if(result)
760       return result;
761   }
762
763   /* Create secure session. */
764   result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle),
765                         "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
766   gsk_environment_close(&envir);
767   if(result)
768     return result;
769
770 #ifndef CURL_DISABLE_PROXY
771   /* Establish a pipelining socket pair for SSL over SSL. */
772   if(conn->proxy_ssl[sockindex].use) {
773     if(Curl_socketpair(0, 0, 0, sockpair))
774       return CURLE_SSL_CONNECT_ERROR;
775     BACKEND->localfd = sockpair[0];
776     BACKEND->remotefd = sockpair[1];
777     setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF,
778                (void *) &sobufsize, sizeof(sobufsize));
779     setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF,
780                (void *) &sobufsize, sizeof(sobufsize));
781     setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF,
782                (void *) &sobufsize, sizeof(sobufsize));
783     setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF,
784                (void *) &sobufsize, sizeof(sobufsize));
785     curlx_nonblock(BACKEND->localfd, TRUE);
786     curlx_nonblock(BACKEND->remotefd, TRUE);
787   }
788 #endif
789
790   /* Determine which SSL/TLS version should be enabled. */
791   sni = hostname;
792   switch(ssl_version) {
793   case CURL_SSLVERSION_SSLv2:
794     protoflags = CURL_GSKPROTO_SSLV2_MASK;
795     sni = NULL;
796     break;
797   case CURL_SSLVERSION_SSLv3:
798     protoflags = CURL_GSKPROTO_SSLV3_MASK;
799     sni = NULL;
800     break;
801   case CURL_SSLVERSION_DEFAULT:
802   case CURL_SSLVERSION_TLSv1:
803     protoflags = CURL_GSKPROTO_TLSV10_MASK |
804                  CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
805     break;
806   case CURL_SSLVERSION_TLSv1_0:
807   case CURL_SSLVERSION_TLSv1_1:
808   case CURL_SSLVERSION_TLSv1_2:
809   case CURL_SSLVERSION_TLSv1_3:
810     result = set_ssl_version_min_max(&protoflags, data);
811     if(result != CURLE_OK)
812       return result;
813     break;
814   default:
815     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
816     return CURLE_SSL_CONNECT_ERROR;
817   }
818
819   /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
820   if(sni) {
821     char *snihost = Curl_ssl_snihost(data, sni, NULL);
822     if(!snihost) {
823       failf(data, "Failed to set SNI");
824       return CURLE_SSL_CONNECT_ERROR;
825     }
826     result = set_buffer(data, BACKEND->handle,
827                         GSK_SSL_EXTN_SERVERNAME_REQUEST, snihost, TRUE);
828     if(result == CURLE_UNSUPPORTED_PROTOCOL)
829       result = CURLE_OK;
830   }
831
832   /* Set session parameters. */
833   if(!result) {
834     /* Compute the handshake timeout. Since GSKit granularity is 1 second,
835        we round up the required value. */
836     timediff_t timeout = Curl_timeleft(data, NULL, TRUE);
837     if(timeout < 0)
838       result = CURLE_OPERATION_TIMEDOUT;
839     else
840       result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT,
841                            (timeout + 999) / 1000);
842   }
843   if(!result)
844     result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
845   if(!result)
846 #ifndef CURL_DISABLE_PROXY
847     result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
848                          BACKEND->localfd: conn->sock[sockindex]);
849 #else
850     result = set_numeric(data, BACKEND->handle, GSK_FD,
851                          conn->sock[sockindex]);
852 #endif
853   if(!result)
854     result = set_ciphers(data, BACKEND->handle, &protoflags);
855   if(!protoflags) {
856     failf(data, "No SSL protocol/cipher combination enabled");
857     result = CURLE_SSL_CIPHER;
858   }
859   if(!result)
860     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2,
861                       (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
862                       GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
863   if(!result)
864     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3,
865                       (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
866                       GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
867   if(!result)
868     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1,
869                       (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
870                       GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
871   if(!result) {
872     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11,
873                       (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
874                       GSK_TRUE: GSK_FALSE, TRUE);
875     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
876       result = CURLE_OK;
877       if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
878         failf(data, "TLS 1.1 not yet supported");
879         result = CURLE_SSL_CIPHER;
880       }
881     }
882   }
883   if(!result) {
884     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12,
885                       (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
886                       GSK_TRUE: GSK_FALSE, TRUE);
887     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
888       result = CURLE_OK;
889       if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
890         failf(data, "TLS 1.2 not yet supported");
891         result = CURLE_SSL_CIPHER;
892       }
893     }
894   }
895   if(!result)
896     result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE,
897                       verifypeer? GSK_SERVER_AUTH_FULL:
898                       GSK_SERVER_AUTH_PASSTHRU, FALSE);
899
900   if(!result) {
901     /* Start handshake. Try asynchronous first. */
902     memset(&commarea, 0, sizeof(commarea));
903     BACKEND->iocport = QsoCreateIOCompletionPort();
904     if(BACKEND->iocport != -1) {
905       result = gskit_status(data,
906                             gsk_secure_soc_startInit(BACKEND->handle,
907                                                      BACKEND->iocport,
908                                                      &commarea),
909                             "gsk_secure_soc_startInit()",
910                             CURLE_SSL_CONNECT_ERROR);
911       if(!result) {
912         connssl->connecting_state = ssl_connect_2;
913         return CURLE_OK;
914       }
915       else
916         close_async_handshake(connssl);
917     }
918     else if(errno != ENOBUFS)
919       result = gskit_status(data, GSK_ERROR_IO,
920                             "QsoCreateIOCompletionPort()", 0);
921 #ifndef CURL_DISABLE_PROXY
922     else if(conn->proxy_ssl[sockindex].use) {
923       /* Cannot pipeline while handshaking synchronously. */
924       result = CURLE_SSL_CONNECT_ERROR;
925     }
926 #endif
927     else {
928       /* No more completion port available. Use synchronous IO. */
929       result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
930                             "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
931       if(!result) {
932         connssl->connecting_state = ssl_connect_3;
933         return CURLE_OK;
934       }
935     }
936   }
937
938   /* Error: rollback. */
939   close_one(connssl, data, conn, sockindex);
940   return result;
941 }
942
943
944 static CURLcode gskit_connect_step2(struct Curl_easy *data,
945                                     struct connectdata *conn, int sockindex,
946                                     bool nonblocking)
947 {
948   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
949   Qso_OverlappedIO_t cstat;
950   struct timeval stmv;
951   CURLcode result;
952
953   /* Poll or wait for end of SSL asynchronous handshake. */
954   DEBUGASSERT(BACKEND);
955
956   for(;;) {
957     timediff_t timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
958     stmv.tv_sec = 0;
959     stmv.tv_usec = 0;
960     if(timeout_ms < 0)
961       timeout_ms = 0;
962     switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat,
963                                   curlx_mstotv(&stmv, timeout_ms))) {
964     case 1:             /* Operation complete. */
965       break;
966     case -1:            /* An error occurred: handshake still in progress. */
967       if(errno == EINTR) {
968         if(nonblocking)
969           return CURLE_OK;
970         continue;       /* Retry. */
971       }
972       if(errno != ETIME) {
973         char buffer[STRERROR_LEN];
974         failf(data, "QsoWaitForIOCompletion() I/O error: %s",
975               Curl_strerror(errno, buffer, sizeof(buffer)));
976         cancel_async_handshake(conn, sockindex);
977         close_async_handshake(connssl);
978         return CURLE_SSL_CONNECT_ERROR;
979       }
980       /* FALL INTO... */
981     case 0:             /* Handshake in progress, timeout occurred. */
982       if(nonblocking)
983         return CURLE_OK;
984       cancel_async_handshake(conn, sockindex);
985       close_async_handshake(connssl);
986       return CURLE_OPERATION_TIMEDOUT;
987     }
988     break;
989   }
990   result = gskit_status(data, cstat.returnValue, "SSL handshake",
991                         CURLE_SSL_CONNECT_ERROR);
992   if(!result)
993     connssl->connecting_state = ssl_connect_3;
994   close_async_handshake(connssl);
995   return result;
996 }
997
998
999 static CURLcode gskit_connect_step3(struct Curl_easy *data,
1000                                     struct connectdata *conn, int sockindex)
1001 {
1002   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1003   const gsk_cert_data_elem *cdev;
1004   int cdec;
1005   const gsk_cert_data_elem *p;
1006   const char *cert = (const char *) NULL;
1007   const char *certend;
1008   const char *ptr;
1009   CURLcode result;
1010
1011   /* SSL handshake done: gather certificate info and verify host. */
1012   DEBUGASSERT(BACKEND);
1013
1014   if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle,
1015                                                     GSK_PARTNER_CERT_INFO,
1016                                                     &cdev, &cdec),
1017                   "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
1018      CURLE_OK) {
1019     int i;
1020
1021     infof(data, "Server certificate:");
1022     p = cdev;
1023     for(i = 0; i++ < cdec; p++)
1024       switch(p->cert_data_id) {
1025       case CERT_BODY_DER:
1026         cert = p->cert_data_p;
1027         certend = cert + cdev->cert_data_l;
1028         break;
1029       case CERT_DN_PRINTABLE:
1030         infof(data, "\t subject: %.*s", p->cert_data_l, p->cert_data_p);
1031         break;
1032       case CERT_ISSUER_DN_PRINTABLE:
1033         infof(data, "\t issuer: %.*s", p->cert_data_l, p->cert_data_p);
1034         break;
1035       case CERT_VALID_FROM:
1036         infof(data, "\t start date: %.*s", p->cert_data_l, p->cert_data_p);
1037         break;
1038       case CERT_VALID_TO:
1039         infof(data, "\t expire date: %.*s", p->cert_data_l, p->cert_data_p);
1040         break;
1041     }
1042   }
1043
1044   /* Verify host. */
1045   result = Curl_verifyhost(data, conn, cert, certend);
1046   if(result)
1047     return result;
1048
1049   /* The only place GSKit can get the whole CA chain is a validation
1050      callback where no user data pointer is available. Therefore it's not
1051      possible to copy this chain into our structures for CAINFO.
1052      However the server certificate may be available, thus we can return
1053      info about it. */
1054   if(data->set.ssl.certinfo) {
1055     result = Curl_ssl_init_certinfo(data, 1);
1056     if(result)
1057       return result;
1058
1059     if(cert) {
1060       result = Curl_extract_certinfo(data, 0, cert, certend);
1061       if(result)
1062         return result;
1063     }
1064   }
1065
1066   /* Check pinned public key. */
1067   ptr = SSL_PINNED_PUB_KEY();
1068   if(!result && ptr) {
1069     struct Curl_X509certificate x509;
1070     struct Curl_asn1Element *p;
1071
1072     memset(&x509, 0, sizeof(x509));
1073     if(Curl_parseX509(&x509, cert, certend))
1074       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1075     p = &x509.subjectPublicKeyInfo;
1076     result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
1077     if(result) {
1078       failf(data, "SSL: public key does not match pinned public key");
1079       return result;
1080     }
1081   }
1082
1083   connssl->connecting_state = ssl_connect_done;
1084   return CURLE_OK;
1085 }
1086
1087
1088 static CURLcode gskit_connect_common(struct Curl_easy *data,
1089                                      struct connectdata *conn, int sockindex,
1090                                      bool nonblocking, bool *done)
1091 {
1092   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1093   timediff_t timeout_ms;
1094   CURLcode result = CURLE_OK;
1095
1096   *done = connssl->state == ssl_connection_complete;
1097   if(*done)
1098     return CURLE_OK;
1099
1100   /* Step 1: create session, start handshake. */
1101   if(connssl->connecting_state == ssl_connect_1) {
1102     /* check allowed time left */
1103     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1104
1105     if(timeout_ms < 0) {
1106       /* no need to continue if time already is up */
1107       failf(data, "SSL connection timeout");
1108       result = CURLE_OPERATION_TIMEDOUT;
1109     }
1110     else
1111       result = gskit_connect_step1(data, conn, sockindex);
1112   }
1113
1114   /* Handle handshake pipelining. */
1115   if(!result)
1116     if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1117       result = CURLE_SSL_CONNECT_ERROR;
1118
1119   /* Step 2: check if handshake is over. */
1120   if(!result && connssl->connecting_state == ssl_connect_2) {
1121     /* check allowed time left */
1122     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1123
1124     if(timeout_ms < 0) {
1125       /* no need to continue if time already is up */
1126       failf(data, "SSL connection timeout");
1127       result = CURLE_OPERATION_TIMEDOUT;
1128     }
1129     else
1130       result = gskit_connect_step2(data, conn, sockindex, nonblocking);
1131   }
1132
1133   /* Handle handshake pipelining. */
1134   if(!result)
1135     if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1136       result = CURLE_SSL_CONNECT_ERROR;
1137
1138   /* Step 3: gather certificate info, verify host. */
1139   if(!result && connssl->connecting_state == ssl_connect_3)
1140     result = gskit_connect_step3(data, conn, sockindex);
1141
1142   if(result)
1143     close_one(connssl, data, conn, sockindex);
1144   else if(connssl->connecting_state == ssl_connect_done) {
1145     connssl->state = ssl_connection_complete;
1146     connssl->connecting_state = ssl_connect_1;
1147     conn->recv[sockindex] = gskit_recv;
1148     conn->send[sockindex] = gskit_send;
1149     *done = TRUE;
1150   }
1151
1152   return result;
1153 }
1154
1155
1156 static CURLcode gskit_connect_nonblocking(struct Curl_easy *data,
1157                                           struct connectdata *conn,
1158                                           int sockindex, bool *done)
1159 {
1160   CURLcode result;
1161
1162   result = gskit_connect_common(data, conn, sockindex, TRUE, done);
1163   if(*done || result)
1164     conn->ssl[sockindex].connecting_state = ssl_connect_1;
1165   return result;
1166 }
1167
1168
1169 static CURLcode gskit_connect(struct Curl_easy *data,
1170                               struct connectdata *conn, int sockindex)
1171 {
1172   CURLcode result;
1173   bool done;
1174
1175   conn->ssl[sockindex].connecting_state = ssl_connect_1;
1176   result = gskit_connect_common(data, conn, sockindex, FALSE, &done);
1177   if(result)
1178     return result;
1179
1180   DEBUGASSERT(done);
1181
1182   return CURLE_OK;
1183 }
1184
1185
1186 static void gskit_close(struct Curl_easy *data, struct connectdata *conn,
1187                         int sockindex)
1188 {
1189   close_one(&conn->ssl[sockindex], data, conn, sockindex);
1190 #ifndef CURL_DISABLE_PROXY
1191   close_one(&conn->proxy_ssl[sockindex], data, conn, sockindex);
1192 #endif
1193 }
1194
1195
1196 static int gskit_shutdown(struct Curl_easy *data,
1197                           struct connectdata *conn, int sockindex)
1198 {
1199   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1200   int what;
1201   int rc;
1202   char buf[120];
1203   int loop = 10; /* don't get stuck */
1204
1205   DEBUGASSERT(BACKEND);
1206
1207   if(!BACKEND->handle)
1208     return 0;
1209
1210 #ifndef CURL_DISABLE_FTP
1211   if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
1212     return 0;
1213 #endif
1214
1215   close_one(connssl, data, conn, sockindex);
1216   rc = 0;
1217   what = SOCKET_READABLE(conn->sock[sockindex],
1218                          SSL_SHUTDOWN_TIMEOUT);
1219
1220   while(loop--) {
1221     ssize_t nread;
1222
1223     if(what < 0) {
1224       /* anything that gets here is fatally bad */
1225       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1226       rc = -1;
1227       break;
1228     }
1229
1230     if(!what) {                                /* timeout */
1231       failf(data, "SSL shutdown timeout");
1232       break;
1233     }
1234
1235     /* Something to read, let's do it and hope that it is the close
1236        notify alert from the server. No way to gsk_secure_soc_read() now, so
1237        use read(). */
1238
1239     nread = read(conn->sock[sockindex], buf, sizeof(buf));
1240
1241     if(nread < 0) {
1242       char buffer[STRERROR_LEN];
1243       failf(data, "read: %s", Curl_strerror(errno, buffer, sizeof(buffer)));
1244       rc = -1;
1245     }
1246
1247     if(nread <= 0)
1248       break;
1249
1250     what = SOCKET_READABLE(conn->sock[sockindex], 0);
1251   }
1252
1253   return rc;
1254 }
1255
1256
1257 static size_t gskit_version(char *buffer, size_t size)
1258 {
1259   return msnprintf(buffer, size, "GSKit");
1260 }
1261
1262
1263 static int gskit_check_cxn(struct connectdata *cxn)
1264 {
1265   struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET];
1266   int err;
1267   int errlen;
1268
1269   /* The only thing that can be tested here is at the socket level. */
1270   DEBUGASSERT(BACKEND);
1271
1272   if(!BACKEND->handle)
1273     return 0; /* connection has been closed */
1274
1275   err = 0;
1276   errlen = sizeof(err);
1277
1278   if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
1279                  (unsigned char *) &err, &errlen) ||
1280      errlen != sizeof(err) || err)
1281     return 0; /* connection has been closed */
1282
1283   return -1;  /* connection status unknown */
1284 }
1285
1286 static void *gskit_get_internals(struct ssl_connect_data *connssl,
1287                                  CURLINFO info UNUSED_PARAM)
1288 {
1289   (void)info;
1290   DEBUGASSERT(BACKEND);
1291   return BACKEND->handle;
1292 }
1293
1294 const struct Curl_ssl Curl_ssl_gskit = {
1295   { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */
1296
1297   SSLSUPP_CERTINFO |
1298   SSLSUPP_PINNEDPUBKEY,
1299
1300   sizeof(struct ssl_backend_data),
1301
1302   gskit_init,                     /* init */
1303   gskit_cleanup,                  /* cleanup */
1304   gskit_version,                  /* version */
1305   gskit_check_cxn,                /* check_cxn */
1306   gskit_shutdown,                 /* shutdown */
1307   Curl_none_data_pending,         /* data_pending */
1308   Curl_none_random,               /* random */
1309   Curl_none_cert_status_request,  /* cert_status_request */
1310   gskit_connect,                  /* connect */
1311   gskit_connect_nonblocking,      /* connect_nonblocking */
1312   Curl_ssl_getsock,               /* getsock */
1313   gskit_get_internals,            /* get_internals */
1314   gskit_close,                    /* close_one */
1315   Curl_none_close_all,            /* close_all */
1316   /* No session handling for GSKit */
1317   Curl_none_session_free,         /* session_free */
1318   Curl_none_set_engine,           /* set_engine */
1319   Curl_none_set_engine_default,   /* set_engine_default */
1320   Curl_none_engines_list,         /* engines_list */
1321   Curl_none_false_start,          /* false_start */
1322   NULL,                           /* sha256sum */
1323   NULL,                           /* associate_connection */
1324   NULL                            /* disassociate_connection */
1325 };
1326
1327 #endif /* USE_GSKIT */