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