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