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