VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/vtls/gskit.c@ 86643

Last change on this file since 86643 was 85671, checked in by vboxsync, 4 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette