comparison mupdf-source/thirdparty/curl/lib/vtls/gskit.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2018, 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
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
99 struct 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. */
109 typedef 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
115 static 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
161 static 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
176 static 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
219 static 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
241 static 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
263 static 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
283 static 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
302 static 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
436 static int Curl_gskit_init(void)
437 {
438 /* No initialisation needed. */
439
440 return 1;
441 }
442
443
444 static void Curl_gskit_cleanup(void)
445 {
446 /* Nothing to do. */
447 }
448
449
450 static 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
498 static 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
508 static 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
525 static int
526 inetsocketpair(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
608 static 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
683 static 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
707 static 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
732 static 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 nread;
738 CURLcode cc = CURLE_RECV_ERROR;
739
740 if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
741 int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
742 cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
743 buf, buffsize, &nread),
744 "gsk_secure_soc_read()", CURLE_RECV_ERROR);
745 }
746 switch(cc) {
747 case CURLE_OK:
748 break;
749 case CURLE_OPERATION_TIMEDOUT:
750 cc = CURLE_AGAIN;
751 default:
752 *curlcode = cc;
753 nread = -1;
754 break;
755 }
756 return (ssize_t) nread;
757 }
758
759 static CURLcode
760 set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn)
761 {
762 struct Curl_easy *data = conn->data;
763 long ssl_version = SSL_CONN_CONFIG(version);
764 long ssl_version_max = SSL_CONN_CONFIG(version_max);
765 long i = ssl_version;
766 switch(ssl_version_max) {
767 case CURL_SSLVERSION_MAX_NONE:
768 case CURL_SSLVERSION_MAX_DEFAULT:
769 ssl_version_max = CURL_SSLVERSION_TLSv1_2;
770 break;
771 }
772 for(; i <= (ssl_version_max >> 16); ++i) {
773 switch(i) {
774 case CURL_SSLVERSION_TLSv1_0:
775 *protoflags |= CURL_GSKPROTO_TLSV10_MASK;
776 break;
777 case CURL_SSLVERSION_TLSv1_1:
778 *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
779 break;
780 case CURL_SSLVERSION_TLSv1_2:
781 *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
782 break;
783 case CURL_SSLVERSION_TLSv1_3:
784 failf(data, "GSKit: TLS 1.3 is not yet supported");
785 return CURLE_SSL_CONNECT_ERROR;
786 }
787 }
788
789 return CURLE_OK;
790 }
791
792 static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
793 {
794 struct Curl_easy *data = conn->data;
795 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
796 gsk_handle envir;
797 CURLcode result;
798 int rc;
799 const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
800 const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
801 const char * const keyringlabel = SSL_SET_OPTION(cert);
802 const long int ssl_version = SSL_CONN_CONFIG(version);
803 const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
804 const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
805 conn->host.name;
806 const char *sni;
807 unsigned int protoflags = 0;
808 Qso_OverlappedIO_t commarea;
809 int sockpair[2];
810 static const int sobufsize = CURL_MAX_WRITE_SIZE;
811
812 /* Create SSL environment, start (preferably asynchronous) handshake. */
813
814 BACKEND->handle = (gsk_handle) NULL;
815 BACKEND->iocport = -1;
816 BACKEND->localfd = -1;
817 BACKEND->remotefd = -1;
818
819 /* GSKit supports two ways of specifying an SSL context: either by
820 * application identifier (that should have been defined at the system
821 * level) or by keyring file, password and certificate label.
822 * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
823 * application identifier of the certificate label.
824 * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
825 * It is not possible to have different keyrings for the CAs and the
826 * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
827 * the keyring file.
828 * If no key password is given and the keyring is the system keyring,
829 * application identifier mode is tried first, as recommended in IBM doc.
830 */
831
832 envir = (gsk_handle) NULL;
833
834 if(keyringlabel && *keyringlabel && !keyringpwd &&
835 !strcmp(keyringfile, CURL_CA_BUNDLE)) {
836 /* Try application identifier mode. */
837 init_environment(data, &envir, keyringlabel, (const char *) NULL,
838 (const char *) NULL, (const char *) NULL);
839 }
840
841 if(!envir) {
842 /* Use keyring mode. */
843 result = init_environment(data, &envir, (const char *) NULL,
844 keyringfile, keyringlabel, keyringpwd);
845 if(result)
846 return result;
847 }
848
849 /* Create secure session. */
850 result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle),
851 "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
852 gsk_environment_close(&envir);
853 if(result)
854 return result;
855
856 /* Establish a pipelining socket pair for SSL over SSL. */
857 if(conn->proxy_ssl[sockindex].use) {
858 if(inetsocketpair(sockpair))
859 return CURLE_SSL_CONNECT_ERROR;
860 BACKEND->localfd = sockpair[0];
861 BACKEND->remotefd = sockpair[1];
862 setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF,
863 (void *) sobufsize, sizeof(sobufsize));
864 setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF,
865 (void *) sobufsize, sizeof(sobufsize));
866 setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF,
867 (void *) sobufsize, sizeof(sobufsize));
868 setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF,
869 (void *) sobufsize, sizeof(sobufsize));
870 curlx_nonblock(BACKEND->localfd, TRUE);
871 curlx_nonblock(BACKEND->remotefd, TRUE);
872 }
873
874 /* Determine which SSL/TLS version should be enabled. */
875 sni = hostname;
876 switch(ssl_version) {
877 case CURL_SSLVERSION_SSLv2:
878 protoflags = CURL_GSKPROTO_SSLV2_MASK;
879 sni = NULL;
880 break;
881 case CURL_SSLVERSION_SSLv3:
882 protoflags = CURL_GSKPROTO_SSLV3_MASK;
883 sni = NULL;
884 break;
885 case CURL_SSLVERSION_DEFAULT:
886 case CURL_SSLVERSION_TLSv1:
887 protoflags = CURL_GSKPROTO_TLSV10_MASK |
888 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
889 break;
890 case CURL_SSLVERSION_TLSv1_0:
891 case CURL_SSLVERSION_TLSv1_1:
892 case CURL_SSLVERSION_TLSv1_2:
893 case CURL_SSLVERSION_TLSv1_3:
894 result = set_ssl_version_min_max(&protoflags, conn);
895 if(result != CURLE_OK)
896 return result;
897 break;
898 default:
899 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
900 return CURLE_SSL_CONNECT_ERROR;
901 }
902
903 /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
904 if(sni) {
905 result = set_buffer(data, BACKEND->handle,
906 GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
907 if(result == CURLE_UNSUPPORTED_PROTOCOL)
908 result = CURLE_OK;
909 }
910
911 /* Set session parameters. */
912 if(!result) {
913 /* Compute the handshake timeout. Since GSKit granularity is 1 second,
914 we round up the required value. */
915 long timeout = Curl_timeleft(data, NULL, TRUE);
916 if(timeout < 0)
917 result = CURLE_OPERATION_TIMEDOUT;
918 else
919 result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT,
920 (timeout + 999) / 1000);
921 }
922 if(!result)
923 result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
924 if(!result)
925 result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
926 BACKEND->localfd: conn->sock[sockindex]);
927 if(!result)
928 result = set_ciphers(conn, BACKEND->handle, &protoflags);
929 if(!protoflags) {
930 failf(data, "No SSL protocol/cipher combination enabled");
931 result = CURLE_SSL_CIPHER;
932 }
933 if(!result)
934 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2,
935 (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
936 GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
937 if(!result)
938 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3,
939 (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
940 GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
941 if(!result)
942 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1,
943 (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
944 GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
945 if(!result) {
946 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11,
947 (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
948 GSK_TRUE: GSK_FALSE, TRUE);
949 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
950 result = CURLE_OK;
951 if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
952 failf(data, "TLS 1.1 not yet supported");
953 result = CURLE_SSL_CIPHER;
954 }
955 }
956 }
957 if(!result) {
958 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12,
959 (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
960 GSK_TRUE: GSK_FALSE, TRUE);
961 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
962 result = CURLE_OK;
963 if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
964 failf(data, "TLS 1.2 not yet supported");
965 result = CURLE_SSL_CIPHER;
966 }
967 }
968 }
969 if(!result)
970 result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE,
971 verifypeer? GSK_SERVER_AUTH_FULL:
972 GSK_SERVER_AUTH_PASSTHRU, FALSE);
973
974 if(!result) {
975 /* Start handshake. Try asynchronous first. */
976 memset(&commarea, 0, sizeof(commarea));
977 BACKEND->iocport = QsoCreateIOCompletionPort();
978 if(BACKEND->iocport != -1) {
979 result = gskit_status(data,
980 gsk_secure_soc_startInit(BACKEND->handle,
981 BACKEND->iocport,
982 &commarea),
983 "gsk_secure_soc_startInit()",
984 CURLE_SSL_CONNECT_ERROR);
985 if(!result) {
986 connssl->connecting_state = ssl_connect_2;
987 return CURLE_OK;
988 }
989 else
990 close_async_handshake(connssl);
991 }
992 else if(errno != ENOBUFS)
993 result = gskit_status(data, GSK_ERROR_IO,
994 "QsoCreateIOCompletionPort()", 0);
995 else if(conn->proxy_ssl[sockindex].use) {
996 /* Cannot pipeline while handshaking synchronously. */
997 result = CURLE_SSL_CONNECT_ERROR;
998 }
999 else {
1000 /* No more completion port available. Use synchronous IO. */
1001 result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
1002 "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
1003 if(!result) {
1004 connssl->connecting_state = ssl_connect_3;
1005 return CURLE_OK;
1006 }
1007 }
1008 }
1009
1010 /* Error: rollback. */
1011 close_one(connssl, conn, sockindex);
1012 return result;
1013 }
1014
1015
1016 static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
1017 bool nonblocking)
1018 {
1019 struct Curl_easy *data = conn->data;
1020 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1021 Qso_OverlappedIO_t cstat;
1022 struct timeval stmv;
1023 CURLcode result;
1024
1025 /* Poll or wait for end of SSL asynchronous handshake. */
1026
1027 for(;;) {
1028 long timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
1029 if(timeout_ms < 0)
1030 timeout_ms = 0;
1031 stmv.tv_sec = timeout_ms / 1000;
1032 stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
1033 switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat, &stmv)) {
1034 case 1: /* Operation complete. */
1035 break;
1036 case -1: /* An error occurred: handshake still in progress. */
1037 if(errno == EINTR) {
1038 if(nonblocking)
1039 return CURLE_OK;
1040 continue; /* Retry. */
1041 }
1042 if(errno != ETIME) {
1043 failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
1044 cancel_async_handshake(conn, sockindex);
1045 close_async_handshake(connssl);
1046 return CURLE_SSL_CONNECT_ERROR;
1047 }
1048 /* FALL INTO... */
1049 case 0: /* Handshake in progress, timeout occurred. */
1050 if(nonblocking)
1051 return CURLE_OK;
1052 cancel_async_handshake(conn, sockindex);
1053 close_async_handshake(connssl);
1054 return CURLE_OPERATION_TIMEDOUT;
1055 }
1056 break;
1057 }
1058 result = gskit_status(data, cstat.returnValue, "SSL handshake",
1059 CURLE_SSL_CONNECT_ERROR);
1060 if(!result)
1061 connssl->connecting_state = ssl_connect_3;
1062 close_async_handshake(connssl);
1063 return result;
1064 }
1065
1066
1067 static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
1068 {
1069 struct Curl_easy *data = conn->data;
1070 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1071 const gsk_cert_data_elem *cdev;
1072 int cdec;
1073 const gsk_cert_data_elem *p;
1074 const char *cert = (const char *) NULL;
1075 const char *certend;
1076 const char *ptr;
1077 CURLcode result;
1078
1079 /* SSL handshake done: gather certificate info and verify host. */
1080
1081 if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle,
1082 GSK_PARTNER_CERT_INFO,
1083 &cdev, &cdec),
1084 "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
1085 CURLE_OK) {
1086 int i;
1087
1088 infof(data, "Server certificate:\n");
1089 p = cdev;
1090 for(i = 0; i++ < cdec; p++)
1091 switch(p->cert_data_id) {
1092 case CERT_BODY_DER:
1093 cert = p->cert_data_p;
1094 certend = cert + cdev->cert_data_l;
1095 break;
1096 case CERT_DN_PRINTABLE:
1097 infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
1098 break;
1099 case CERT_ISSUER_DN_PRINTABLE:
1100 infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
1101 break;
1102 case CERT_VALID_FROM:
1103 infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
1104 break;
1105 case CERT_VALID_TO:
1106 infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
1107 break;
1108 }
1109 }
1110
1111 /* Verify host. */
1112 result = Curl_verifyhost(conn, cert, certend);
1113 if(result)
1114 return result;
1115
1116 /* The only place GSKit can get the whole CA chain is a validation
1117 callback where no user data pointer is available. Therefore it's not
1118 possible to copy this chain into our structures for CAINFO.
1119 However the server certificate may be available, thus we can return
1120 info about it. */
1121 if(data->set.ssl.certinfo) {
1122 result = Curl_ssl_init_certinfo(data, 1);
1123 if(result)
1124 return result;
1125
1126 if(cert) {
1127 result = Curl_extract_certinfo(conn, 0, cert, certend);
1128 if(result)
1129 return result;
1130 }
1131 }
1132
1133 /* Check pinned public key. */
1134 ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1135 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
1136 if(!result && ptr) {
1137 curl_X509certificate x509;
1138 curl_asn1Element *p;
1139
1140 if(Curl_parseX509(&x509, cert, certend))
1141 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1142 p = &x509.subjectPublicKeyInfo;
1143 result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
1144 if(result) {
1145 failf(data, "SSL: public key does not match pinned public key!");
1146 return result;
1147 }
1148 }
1149
1150 connssl->connecting_state = ssl_connect_done;
1151 return CURLE_OK;
1152 }
1153
1154
1155 static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
1156 bool nonblocking, bool *done)
1157 {
1158 struct Curl_easy *data = conn->data;
1159 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1160 long timeout_ms;
1161 CURLcode result = CURLE_OK;
1162
1163 *done = connssl->state == ssl_connection_complete;
1164 if(*done)
1165 return CURLE_OK;
1166
1167 /* Step 1: create session, start handshake. */
1168 if(connssl->connecting_state == ssl_connect_1) {
1169 /* check allowed time left */
1170 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1171
1172 if(timeout_ms < 0) {
1173 /* no need to continue if time already is up */
1174 failf(data, "SSL connection timeout");
1175 result = CURLE_OPERATION_TIMEDOUT;
1176 }
1177 else
1178 result = gskit_connect_step1(conn, sockindex);
1179 }
1180
1181 /* Handle handshake pipelining. */
1182 if(!result)
1183 if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1184 result = CURLE_SSL_CONNECT_ERROR;
1185
1186 /* Step 2: check if handshake is over. */
1187 if(!result && connssl->connecting_state == ssl_connect_2) {
1188 /* check allowed time left */
1189 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1190
1191 if(timeout_ms < 0) {
1192 /* no need to continue if time already is up */
1193 failf(data, "SSL connection timeout");
1194 result = CURLE_OPERATION_TIMEDOUT;
1195 }
1196 else
1197 result = gskit_connect_step2(conn, sockindex, nonblocking);
1198 }
1199
1200 /* Handle handshake pipelining. */
1201 if(!result)
1202 if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1203 result = CURLE_SSL_CONNECT_ERROR;
1204
1205 /* Step 3: gather certificate info, verify host. */
1206 if(!result && connssl->connecting_state == ssl_connect_3)
1207 result = gskit_connect_step3(conn, sockindex);
1208
1209 if(result)
1210 close_one(connssl, conn, sockindex);
1211 else if(connssl->connecting_state == ssl_connect_done) {
1212 connssl->state = ssl_connection_complete;
1213 connssl->connecting_state = ssl_connect_1;
1214 conn->recv[sockindex] = gskit_recv;
1215 conn->send[sockindex] = gskit_send;
1216 *done = TRUE;
1217 }
1218
1219 return result;
1220 }
1221
1222
1223 static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
1224 int sockindex, bool *done)
1225 {
1226 CURLcode result;
1227
1228 result = gskit_connect_common(conn, sockindex, TRUE, done);
1229 if(*done || result)
1230 conn->ssl[sockindex].connecting_state = ssl_connect_1;
1231 return result;
1232 }
1233
1234
1235 static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
1236 {
1237 CURLcode result;
1238 bool done;
1239
1240 conn->ssl[sockindex].connecting_state = ssl_connect_1;
1241 result = gskit_connect_common(conn, sockindex, FALSE, &done);
1242 if(result)
1243 return result;
1244
1245 DEBUGASSERT(done);
1246
1247 return CURLE_OK;
1248 }
1249
1250
1251 static void Curl_gskit_close(struct connectdata *conn, int sockindex)
1252 {
1253 close_one(&conn->ssl[sockindex], conn, sockindex);
1254 close_one(&conn->proxy_ssl[sockindex], conn, sockindex);
1255 }
1256
1257
1258 static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
1259 {
1260 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1261 struct Curl_easy *data = conn->data;
1262 int what;
1263 int rc;
1264 char buf[120];
1265
1266 if(!BACKEND->handle)
1267 return 0;
1268
1269 #ifndef CURL_DISABLE_FTP
1270 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
1271 return 0;
1272 #endif
1273
1274 close_one(connssl, conn, sockindex);
1275 rc = 0;
1276 what = SOCKET_READABLE(conn->sock[sockindex],
1277 SSL_SHUTDOWN_TIMEOUT);
1278
1279 for(;;) {
1280 ssize_t nread;
1281
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
1315 static size_t Curl_gskit_version(char *buffer, size_t size)
1316 {
1317 return msnprintf(buffer, size, "GSKit");
1318 }
1319
1320
1321 static 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
1343 static 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
1350 const 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 */