• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2019, 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.haxx.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 typedef struct {
112   const char *name;            /* Cipher name. */
113   const char *gsktoken;        /* Corresponding token for GSKit String. */
114   unsigned int versions;       /* SSL version flags. */
115 }  gskit_cipher;
116 
117 static const 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 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   struct timeval tv = {0, 0};
528   char buf[CURL_MAX_WRITE_SIZE];
529 
530   if(!connssl->use || !connproxyssl->use)
531     return 0;   /* No SSL over SSL: OK. */
532 
533   FD_ZERO(&fds_read);
534   FD_ZERO(&fds_write);
535   n = -1;
536   if(directions & SOS_READ) {
537     FD_SET(BACKEND->remotefd, &fds_write);
538     n = BACKEND->remotefd;
539   }
540   if(directions & SOS_WRITE) {
541     FD_SET(BACKEND->remotefd, &fds_read);
542     n = BACKEND->remotefd;
543     FD_SET(conn->sock[sockindex], &fds_write);
544     if(n < conn->sock[sockindex])
545       n = conn->sock[sockindex];
546   }
547   i = select(n + 1, &fds_read, &fds_write, NULL, &tv);
548   if(i < 0)
549     return -1;  /* Select error. */
550 
551   if(FD_ISSET(BACKEND->remotefd, &fds_write)) {
552     /* Try getting data from HTTPS proxy and pipe it upstream. */
553     n = 0;
554     i = gsk_secure_soc_read(connproxyssl->backend->handle,
555                             buf, sizeof(buf), &n);
556     switch(i) {
557     case GSK_OK:
558       if(n) {
559         i = write(BACKEND->remotefd, buf, n);
560         if(i < 0)
561           return -1;
562         ret = 1;
563       }
564       break;
565     case GSK_OS400_ERROR_TIMED_OUT:
566     case GSK_WOULD_BLOCK:
567       break;
568     default:
569       return -1;
570     }
571   }
572 
573   if(FD_ISSET(BACKEND->remotefd, &fds_read) &&
574      FD_ISSET(conn->sock[sockindex], &fds_write)) {
575     /* Pipe data to HTTPS proxy. */
576     n = read(BACKEND->remotefd, buf, sizeof(buf));
577     if(n < 0)
578       return -1;
579     if(n) {
580       i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m);
581       if(i != GSK_OK || n != m)
582         return -1;
583       ret = 1;
584     }
585   }
586 
587   return ret;  /* OK */
588 }
589 
590 
close_one(struct ssl_connect_data * connssl,struct connectdata * conn,int sockindex)591 static void close_one(struct ssl_connect_data *connssl,
592                       struct connectdata *conn, int sockindex)
593 {
594   if(BACKEND->handle) {
595     gskit_status(conn->data, gsk_secure_soc_close(&BACKEND->handle),
596               "gsk_secure_soc_close()", 0);
597     /* Last chance to drain output. */
598     while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
599       ;
600     BACKEND->handle = (gsk_handle) NULL;
601     if(BACKEND->localfd >= 0) {
602       close(BACKEND->localfd);
603       BACKEND->localfd = -1;
604     }
605     if(BACKEND->remotefd >= 0) {
606       close(BACKEND->remotefd);
607       BACKEND->remotefd = -1;
608     }
609   }
610   if(BACKEND->iocport >= 0)
611     close_async_handshake(connssl);
612 }
613 
614 
gskit_send(struct connectdata * conn,int sockindex,const void * mem,size_t len,CURLcode * curlcode)615 static ssize_t gskit_send(struct connectdata *conn, int sockindex,
616                            const void *mem, size_t len, CURLcode *curlcode)
617 {
618   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
619   struct Curl_easy *data = conn->data;
620   CURLcode cc = CURLE_SEND_ERROR;
621   int written;
622 
623   if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
624     cc = gskit_status(data,
625                       gsk_secure_soc_write(BACKEND->handle,
626                                            (char *) mem, (int) len, &written),
627                       "gsk_secure_soc_write()", CURLE_SEND_ERROR);
628     if(cc == CURLE_OK)
629       if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0)
630         cc = CURLE_SEND_ERROR;
631   }
632   if(cc != CURLE_OK) {
633     *curlcode = cc;
634     written = -1;
635   }
636   return (ssize_t) written; /* number of bytes */
637 }
638 
639 
gskit_recv(struct connectdata * conn,int num,char * buf,size_t buffersize,CURLcode * curlcode)640 static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
641                            size_t buffersize, CURLcode *curlcode)
642 {
643   struct ssl_connect_data *connssl = &conn->ssl[num];
644   struct Curl_easy *data = conn->data;
645   int nread;
646   CURLcode cc = CURLE_RECV_ERROR;
647 
648   if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
649     int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
650     cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
651                                                 buf, buffsize, &nread),
652                       "gsk_secure_soc_read()", CURLE_RECV_ERROR);
653   }
654   switch(cc) {
655   case CURLE_OK:
656     break;
657   case CURLE_OPERATION_TIMEDOUT:
658     cc = CURLE_AGAIN;
659   default:
660     *curlcode = cc;
661     nread = -1;
662     break;
663   }
664   return (ssize_t) nread;
665 }
666 
667 static CURLcode
set_ssl_version_min_max(unsigned int * protoflags,struct connectdata * conn)668 set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn)
669 {
670   struct Curl_easy *data = conn->data;
671   long ssl_version = SSL_CONN_CONFIG(version);
672   long ssl_version_max = SSL_CONN_CONFIG(version_max);
673   long i = ssl_version;
674   switch(ssl_version_max) {
675     case CURL_SSLVERSION_MAX_NONE:
676     case CURL_SSLVERSION_MAX_DEFAULT:
677       ssl_version_max = CURL_SSLVERSION_TLSv1_2;
678       break;
679   }
680   for(; i <= (ssl_version_max >> 16); ++i) {
681     switch(i) {
682       case CURL_SSLVERSION_TLSv1_0:
683         *protoflags |= CURL_GSKPROTO_TLSV10_MASK;
684         break;
685       case CURL_SSLVERSION_TLSv1_1:
686         *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
687         break;
688       case CURL_SSLVERSION_TLSv1_2:
689         *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
690         break;
691       case CURL_SSLVERSION_TLSv1_3:
692         failf(data, "GSKit: TLS 1.3 is not yet supported");
693         return CURLE_SSL_CONNECT_ERROR;
694     }
695   }
696 
697   return CURLE_OK;
698 }
699 
gskit_connect_step1(struct connectdata * conn,int sockindex)700 static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
701 {
702   struct Curl_easy *data = conn->data;
703   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
704   gsk_handle envir;
705   CURLcode result;
706   int rc;
707   const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
708   const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
709   const char * const keyringlabel = SSL_SET_OPTION(cert);
710   const long int ssl_version = SSL_CONN_CONFIG(version);
711   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
712   const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
713     conn->host.name;
714   const char *sni;
715   unsigned int protoflags = 0;
716   Qso_OverlappedIO_t commarea;
717   int sockpair[2];
718   static const int sobufsize = CURL_MAX_WRITE_SIZE;
719 
720   /* Create SSL environment, start (preferably asynchronous) handshake. */
721 
722   BACKEND->handle = (gsk_handle) NULL;
723   BACKEND->iocport = -1;
724   BACKEND->localfd = -1;
725   BACKEND->remotefd = -1;
726 
727   /* GSKit supports two ways of specifying an SSL context: either by
728    *  application identifier (that should have been defined at the system
729    *  level) or by keyring file, password and certificate label.
730    * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
731    *  application identifier of the certificate label.
732    * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
733    * It is not possible to have different keyrings for the CAs and the
734    *  local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
735    *  the keyring file.
736    * If no key password is given and the keyring is the system keyring,
737    *  application identifier mode is tried first, as recommended in IBM doc.
738    */
739 
740   envir = (gsk_handle) NULL;
741 
742   if(keyringlabel && *keyringlabel && !keyringpwd &&
743       !strcmp(keyringfile, CURL_CA_BUNDLE)) {
744     /* Try application identifier mode. */
745     init_environment(data, &envir, keyringlabel, (const char *) NULL,
746                      (const char *) NULL, (const char *) NULL);
747   }
748 
749   if(!envir) {
750     /* Use keyring mode. */
751     result = init_environment(data, &envir, (const char *) NULL,
752                               keyringfile, keyringlabel, keyringpwd);
753     if(result)
754       return result;
755   }
756 
757   /* Create secure session. */
758   result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle),
759                         "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
760   gsk_environment_close(&envir);
761   if(result)
762     return result;
763 
764   /* Establish a pipelining socket pair for SSL over SSL. */
765   if(conn->proxy_ssl[sockindex].use) {
766     if(Curl_socketpair(0, 0, 0, sockpair))
767       return CURLE_SSL_CONNECT_ERROR;
768     BACKEND->localfd = sockpair[0];
769     BACKEND->remotefd = sockpair[1];
770     setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF,
771                (void *) sobufsize, sizeof(sobufsize));
772     setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF,
773                (void *) sobufsize, sizeof(sobufsize));
774     setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF,
775                (void *) sobufsize, sizeof(sobufsize));
776     setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF,
777                (void *) sobufsize, sizeof(sobufsize));
778     curlx_nonblock(BACKEND->localfd, TRUE);
779     curlx_nonblock(BACKEND->remotefd, TRUE);
780   }
781 
782   /* Determine which SSL/TLS version should be enabled. */
783   sni = hostname;
784   switch(ssl_version) {
785   case CURL_SSLVERSION_SSLv2:
786     protoflags = CURL_GSKPROTO_SSLV2_MASK;
787     sni = NULL;
788     break;
789   case CURL_SSLVERSION_SSLv3:
790     protoflags = CURL_GSKPROTO_SSLV3_MASK;
791     sni = NULL;
792     break;
793   case CURL_SSLVERSION_DEFAULT:
794   case CURL_SSLVERSION_TLSv1:
795     protoflags = CURL_GSKPROTO_TLSV10_MASK |
796                  CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
797     break;
798   case CURL_SSLVERSION_TLSv1_0:
799   case CURL_SSLVERSION_TLSv1_1:
800   case CURL_SSLVERSION_TLSv1_2:
801   case CURL_SSLVERSION_TLSv1_3:
802     result = set_ssl_version_min_max(&protoflags, conn);
803     if(result != CURLE_OK)
804       return result;
805     break;
806   default:
807     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
808     return CURLE_SSL_CONNECT_ERROR;
809   }
810 
811   /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
812   if(sni) {
813     result = set_buffer(data, BACKEND->handle,
814                         GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
815     if(result == CURLE_UNSUPPORTED_PROTOCOL)
816       result = CURLE_OK;
817   }
818 
819   /* Set session parameters. */
820   if(!result) {
821     /* Compute the handshake timeout. Since GSKit granularity is 1 second,
822        we round up the required value. */
823     long timeout = Curl_timeleft(data, NULL, TRUE);
824     if(timeout < 0)
825       result = CURLE_OPERATION_TIMEDOUT;
826     else
827       result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT,
828                            (timeout + 999) / 1000);
829   }
830   if(!result)
831     result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
832   if(!result)
833     result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
834                          BACKEND->localfd: conn->sock[sockindex]);
835   if(!result)
836     result = set_ciphers(conn, BACKEND->handle, &protoflags);
837   if(!protoflags) {
838     failf(data, "No SSL protocol/cipher combination enabled");
839     result = CURLE_SSL_CIPHER;
840   }
841   if(!result)
842     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2,
843                       (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
844                       GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
845   if(!result)
846     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3,
847                       (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
848                       GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
849   if(!result)
850     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1,
851                       (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
852                       GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
853   if(!result) {
854     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11,
855                       (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
856                       GSK_TRUE: GSK_FALSE, TRUE);
857     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
858       result = CURLE_OK;
859       if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
860         failf(data, "TLS 1.1 not yet supported");
861         result = CURLE_SSL_CIPHER;
862       }
863     }
864   }
865   if(!result) {
866     result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12,
867                       (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
868                       GSK_TRUE: GSK_FALSE, TRUE);
869     if(result == CURLE_UNSUPPORTED_PROTOCOL) {
870       result = CURLE_OK;
871       if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
872         failf(data, "TLS 1.2 not yet supported");
873         result = CURLE_SSL_CIPHER;
874       }
875     }
876   }
877   if(!result)
878     result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE,
879                       verifypeer? GSK_SERVER_AUTH_FULL:
880                       GSK_SERVER_AUTH_PASSTHRU, FALSE);
881 
882   if(!result) {
883     /* Start handshake. Try asynchronous first. */
884     memset(&commarea, 0, sizeof(commarea));
885     BACKEND->iocport = QsoCreateIOCompletionPort();
886     if(BACKEND->iocport != -1) {
887       result = gskit_status(data,
888                             gsk_secure_soc_startInit(BACKEND->handle,
889                                                      BACKEND->iocport,
890                                                      &commarea),
891                             "gsk_secure_soc_startInit()",
892                             CURLE_SSL_CONNECT_ERROR);
893       if(!result) {
894         connssl->connecting_state = ssl_connect_2;
895         return CURLE_OK;
896       }
897       else
898         close_async_handshake(connssl);
899     }
900     else if(errno != ENOBUFS)
901       result = gskit_status(data, GSK_ERROR_IO,
902                             "QsoCreateIOCompletionPort()", 0);
903     else if(conn->proxy_ssl[sockindex].use) {
904       /* Cannot pipeline while handshaking synchronously. */
905       result = CURLE_SSL_CONNECT_ERROR;
906     }
907     else {
908       /* No more completion port available. Use synchronous IO. */
909       result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
910                             "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
911       if(!result) {
912         connssl->connecting_state = ssl_connect_3;
913         return CURLE_OK;
914       }
915     }
916   }
917 
918   /* Error: rollback. */
919   close_one(connssl, conn, sockindex);
920   return result;
921 }
922 
923 
gskit_connect_step2(struct connectdata * conn,int sockindex,bool nonblocking)924 static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
925                                     bool nonblocking)
926 {
927   struct Curl_easy *data = conn->data;
928   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
929   Qso_OverlappedIO_t cstat;
930   struct timeval stmv;
931   CURLcode result;
932 
933   /* Poll or wait for end of SSL asynchronous handshake. */
934 
935   for(;;) {
936     long timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
937     if(timeout_ms < 0)
938       timeout_ms = 0;
939     stmv.tv_sec = timeout_ms / 1000;
940     stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
941     switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat, &stmv)) {
942     case 1:             /* Operation complete. */
943       break;
944     case -1:            /* An error occurred: handshake still in progress. */
945       if(errno == EINTR) {
946         if(nonblocking)
947           return CURLE_OK;
948         continue;       /* Retry. */
949       }
950       if(errno != ETIME) {
951         failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
952         cancel_async_handshake(conn, sockindex);
953         close_async_handshake(connssl);
954         return CURLE_SSL_CONNECT_ERROR;
955       }
956       /* FALL INTO... */
957     case 0:             /* Handshake in progress, timeout occurred. */
958       if(nonblocking)
959         return CURLE_OK;
960       cancel_async_handshake(conn, sockindex);
961       close_async_handshake(connssl);
962       return CURLE_OPERATION_TIMEDOUT;
963     }
964     break;
965   }
966   result = gskit_status(data, cstat.returnValue, "SSL handshake",
967                         CURLE_SSL_CONNECT_ERROR);
968   if(!result)
969     connssl->connecting_state = ssl_connect_3;
970   close_async_handshake(connssl);
971   return result;
972 }
973 
974 
gskit_connect_step3(struct connectdata * conn,int sockindex)975 static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
976 {
977   struct Curl_easy *data = conn->data;
978   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
979   const gsk_cert_data_elem *cdev;
980   int cdec;
981   const gsk_cert_data_elem *p;
982   const char *cert = (const char *) NULL;
983   const char *certend;
984   const char *ptr;
985   CURLcode result;
986 
987   /* SSL handshake done: gather certificate info and verify host. */
988 
989   if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle,
990                                                     GSK_PARTNER_CERT_INFO,
991                                                     &cdev, &cdec),
992                   "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
993      CURLE_OK) {
994     int i;
995 
996     infof(data, "Server certificate:\n");
997     p = cdev;
998     for(i = 0; i++ < cdec; p++)
999       switch(p->cert_data_id) {
1000       case CERT_BODY_DER:
1001         cert = p->cert_data_p;
1002         certend = cert + cdev->cert_data_l;
1003         break;
1004       case CERT_DN_PRINTABLE:
1005         infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
1006         break;
1007       case CERT_ISSUER_DN_PRINTABLE:
1008         infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
1009         break;
1010       case CERT_VALID_FROM:
1011         infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
1012         break;
1013       case CERT_VALID_TO:
1014         infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
1015         break;
1016     }
1017   }
1018 
1019   /* Verify host. */
1020   result = Curl_verifyhost(conn, cert, certend);
1021   if(result)
1022     return result;
1023 
1024   /* The only place GSKit can get the whole CA chain is a validation
1025      callback where no user data pointer is available. Therefore it's not
1026      possible to copy this chain into our structures for CAINFO.
1027      However the server certificate may be available, thus we can return
1028      info about it. */
1029   if(data->set.ssl.certinfo) {
1030     result = Curl_ssl_init_certinfo(data, 1);
1031     if(result)
1032       return result;
1033 
1034     if(cert) {
1035       result = Curl_extract_certinfo(conn, 0, cert, certend);
1036       if(result)
1037         return result;
1038     }
1039   }
1040 
1041   /* Check pinned public key. */
1042   ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1043                          data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
1044   if(!result && ptr) {
1045     curl_X509certificate x509;
1046     curl_asn1Element *p;
1047 
1048     if(Curl_parseX509(&x509, cert, certend))
1049       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1050     p = &x509.subjectPublicKeyInfo;
1051     result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
1052     if(result) {
1053       failf(data, "SSL: public key does not match pinned public key!");
1054       return result;
1055     }
1056   }
1057 
1058   connssl->connecting_state = ssl_connect_done;
1059   return CURLE_OK;
1060 }
1061 
1062 
gskit_connect_common(struct connectdata * conn,int sockindex,bool nonblocking,bool * done)1063 static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
1064                                      bool nonblocking, bool *done)
1065 {
1066   struct Curl_easy *data = conn->data;
1067   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1068   timediff_t timeout_ms;
1069   CURLcode result = CURLE_OK;
1070 
1071   *done = connssl->state == ssl_connection_complete;
1072   if(*done)
1073     return CURLE_OK;
1074 
1075   /* Step 1: create session, start handshake. */
1076   if(connssl->connecting_state == ssl_connect_1) {
1077     /* check allowed time left */
1078     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1079 
1080     if(timeout_ms < 0) {
1081       /* no need to continue if time already is up */
1082       failf(data, "SSL connection timeout");
1083       result = CURLE_OPERATION_TIMEDOUT;
1084     }
1085     else
1086       result = gskit_connect_step1(conn, sockindex);
1087   }
1088 
1089   /* Handle handshake pipelining. */
1090   if(!result)
1091     if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1092       result = CURLE_SSL_CONNECT_ERROR;
1093 
1094   /* Step 2: check if handshake is over. */
1095   if(!result && connssl->connecting_state == ssl_connect_2) {
1096     /* check allowed time left */
1097     timeout_ms = Curl_timeleft(data, NULL, TRUE);
1098 
1099     if(timeout_ms < 0) {
1100       /* no need to continue if time already is up */
1101       failf(data, "SSL connection timeout");
1102       result = CURLE_OPERATION_TIMEDOUT;
1103     }
1104     else
1105       result = gskit_connect_step2(conn, sockindex, nonblocking);
1106   }
1107 
1108   /* Handle handshake pipelining. */
1109   if(!result)
1110     if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1111       result = CURLE_SSL_CONNECT_ERROR;
1112 
1113   /* Step 3: gather certificate info, verify host. */
1114   if(!result && connssl->connecting_state == ssl_connect_3)
1115     result = gskit_connect_step3(conn, sockindex);
1116 
1117   if(result)
1118     close_one(connssl, conn, sockindex);
1119   else if(connssl->connecting_state == ssl_connect_done) {
1120     connssl->state = ssl_connection_complete;
1121     connssl->connecting_state = ssl_connect_1;
1122     conn->recv[sockindex] = gskit_recv;
1123     conn->send[sockindex] = gskit_send;
1124     *done = TRUE;
1125   }
1126 
1127   return result;
1128 }
1129 
1130 
Curl_gskit_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)1131 static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
1132                                                int sockindex, bool *done)
1133 {
1134   CURLcode result;
1135 
1136   result = gskit_connect_common(conn, sockindex, TRUE, done);
1137   if(*done || result)
1138     conn->ssl[sockindex].connecting_state = ssl_connect_1;
1139   return result;
1140 }
1141 
1142 
Curl_gskit_connect(struct connectdata * conn,int sockindex)1143 static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
1144 {
1145   CURLcode result;
1146   bool done;
1147 
1148   conn->ssl[sockindex].connecting_state = ssl_connect_1;
1149   result = gskit_connect_common(conn, sockindex, FALSE, &done);
1150   if(result)
1151     return result;
1152 
1153   DEBUGASSERT(done);
1154 
1155   return CURLE_OK;
1156 }
1157 
1158 
Curl_gskit_close(struct connectdata * conn,int sockindex)1159 static void Curl_gskit_close(struct connectdata *conn, int sockindex)
1160 {
1161   close_one(&conn->ssl[sockindex], conn, sockindex);
1162   close_one(&conn->proxy_ssl[sockindex], conn, sockindex);
1163 }
1164 
1165 
Curl_gskit_shutdown(struct connectdata * conn,int sockindex)1166 static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
1167 {
1168   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1169   struct Curl_easy *data = conn->data;
1170   int what;
1171   int rc;
1172   char buf[120];
1173 
1174   if(!BACKEND->handle)
1175     return 0;
1176 
1177 #ifndef CURL_DISABLE_FTP
1178   if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
1179     return 0;
1180 #endif
1181 
1182   close_one(connssl, conn, sockindex);
1183   rc = 0;
1184   what = SOCKET_READABLE(conn->sock[sockindex],
1185                          SSL_SHUTDOWN_TIMEOUT);
1186 
1187   for(;;) {
1188     ssize_t nread;
1189 
1190     if(what < 0) {
1191       /* anything that gets here is fatally bad */
1192       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1193       rc = -1;
1194       break;
1195     }
1196 
1197     if(!what) {                                /* timeout */
1198       failf(data, "SSL shutdown timeout");
1199       break;
1200     }
1201 
1202     /* Something to read, let's do it and hope that it is the close
1203        notify alert from the server. No way to gsk_secure_soc_read() now, so
1204        use read(). */
1205 
1206     nread = read(conn->sock[sockindex], buf, sizeof(buf));
1207 
1208     if(nread < 0) {
1209       failf(data, "read: %s", strerror(errno));
1210       rc = -1;
1211     }
1212 
1213     if(nread <= 0)
1214       break;
1215 
1216     what = SOCKET_READABLE(conn->sock[sockindex], 0);
1217   }
1218 
1219   return rc;
1220 }
1221 
1222 
Curl_gskit_version(char * buffer,size_t size)1223 static size_t Curl_gskit_version(char *buffer, size_t size)
1224 {
1225   return msnprintf(buffer, size, "GSKit");
1226 }
1227 
1228 
Curl_gskit_check_cxn(struct connectdata * cxn)1229 static int Curl_gskit_check_cxn(struct connectdata *cxn)
1230 {
1231   struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET];
1232   int err;
1233   int errlen;
1234 
1235   /* The only thing that can be tested here is at the socket level. */
1236 
1237   if(!BACKEND->handle)
1238     return 0; /* connection has been closed */
1239 
1240   err = 0;
1241   errlen = sizeof(err);
1242 
1243   if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
1244                  (unsigned char *) &err, &errlen) ||
1245      errlen != sizeof(err) || err)
1246     return 0; /* connection has been closed */
1247 
1248   return -1;  /* connection status unknown */
1249 }
1250 
Curl_gskit_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)1251 static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl,
1252                                       CURLINFO info UNUSED_PARAM)
1253 {
1254   (void)info;
1255   return BACKEND->handle;
1256 }
1257 
1258 const struct Curl_ssl Curl_ssl_gskit = {
1259   { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */
1260 
1261   SSLSUPP_CERTINFO |
1262   SSLSUPP_PINNEDPUBKEY,
1263 
1264   sizeof(struct ssl_backend_data),
1265 
1266   Curl_gskit_init,                /* init */
1267   Curl_gskit_cleanup,             /* cleanup */
1268   Curl_gskit_version,             /* version */
1269   Curl_gskit_check_cxn,           /* check_cxn */
1270   Curl_gskit_shutdown,            /* shutdown */
1271   Curl_none_data_pending,         /* data_pending */
1272   Curl_none_random,               /* random */
1273   Curl_none_cert_status_request,  /* cert_status_request */
1274   Curl_gskit_connect,             /* connect */
1275   Curl_gskit_connect_nonblocking, /* connect_nonblocking */
1276   Curl_gskit_get_internals,       /* get_internals */
1277   Curl_gskit_close,               /* close_one */
1278   Curl_none_close_all,            /* close_all */
1279   /* No session handling for GSKit */
1280   Curl_none_session_free,         /* session_free */
1281   Curl_none_set_engine,           /* set_engine */
1282   Curl_none_set_engine_default,   /* set_engine_default */
1283   Curl_none_engines_list,         /* engines_list */
1284   Curl_none_false_start,          /* false_start */
1285   Curl_none_md5sum,               /* md5sum */
1286   NULL                            /* sha256sum */
1287 };
1288 
1289 #endif /* USE_GSKIT */
1290