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