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