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