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