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