source: azure_iot_hub/trunk/curl-7.57.0/lib/vtls/gskit.c@ 389

Last change on this file since 389 was 389, checked in by coas-nagasima, 5 years ago

ビルドが通るよう更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 41.3 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2017, 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#ifdef HAVE_LIMITS_H
65# include <limits.h>
66#endif
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
516/* SSL over SSL
517 * Problems:
518 * 1) GSKit can only perform SSL on an AF_INET or AF_INET6 stream socket. To
519 * pipe an SSL stream into another, it is therefore needed to have a pair
520 * of such communicating sockets and handle the pipelining explicitly.
521 * 2) OS/400 socketpair() is only implemented for domain AF_UNIX, thus cannot
522 * be used to produce the pipeline.
523 * The solution is to simulate socketpair() for AF_INET with low-level API
524 * listen(), bind() and connect().
525 */
526
527static int
528inetsocketpair(int sv[2])
529{
530 int lfd; /* Listening socket. */
531 int sfd; /* Server socket. */
532 int cfd; /* Client socket. */
533 int len;
534 struct sockaddr_in addr1;
535 struct sockaddr_in addr2;
536
537 /* Create listening socket on a local dynamic port. */
538 lfd = socket(AF_INET, SOCK_STREAM, 0);
539 if(lfd < 0)
540 return -1;
541 memset((char *) &addr1, 0, sizeof addr1);
542 addr1.sin_family = AF_INET;
543 addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
544 addr1.sin_port = 0;
545 if(bind(lfd, (struct sockaddr *) &addr1, sizeof addr1) ||
546 listen(lfd, 2) < 0) {
547 close(lfd);
548 return -1;
549 }
550
551 /* Get the allocated port. */
552 len = sizeof addr1;
553 if(getsockname(lfd, (struct sockaddr *) &addr1, &len) < 0) {
554 close(lfd);
555 return -1;
556 }
557
558 /* Create the client socket. */
559 cfd = socket(AF_INET, SOCK_STREAM, 0);
560 if(cfd < 0) {
561 close(lfd);
562 return -1;
563 }
564
565 /* Request unblocking connection to the listening socket. */
566 curlx_nonblock(cfd, TRUE);
567 if(connect(cfd, (struct sockaddr *) &addr1, sizeof addr1) < 0 &&
568 errno != EINPROGRESS) {
569 close(lfd);
570 close(cfd);
571 return -1;
572 }
573
574 /* Get the client dynamic port for intrusion check below. */
575 len = sizeof addr2;
576 if(getsockname(cfd, (struct sockaddr *) &addr2, &len) < 0) {
577 close(lfd);
578 close(cfd);
579 return -1;
580 }
581
582 /* Accept the incoming connection and get the server socket. */
583 curlx_nonblock(lfd, TRUE);
584 for(;;) {
585 len = sizeof addr1;
586 sfd = accept(lfd, (struct sockaddr *) &addr1, &len);
587 if(sfd < 0) {
588 close(lfd);
589 close(cfd);
590 return -1;
591 }
592
593 /* Check for possible intrusion from an external process. */
594 if(addr1.sin_addr.s_addr == addr2.sin_addr.s_addr &&
595 addr1.sin_port == addr2.sin_port)
596 break;
597
598 /* Intrusion: reject incoming connection. */
599 close(sfd);
600 }
601
602 /* Done, return sockets and succeed. */
603 close(lfd);
604 curlx_nonblock(cfd, FALSE);
605 sv[0] = cfd;
606 sv[1] = sfd;
607 return 0;
608}
609
610static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
611 int directions)
612{
613 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
614 struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex];
615 fd_set fds_read;
616 fd_set fds_write;
617 int n;
618 int m;
619 int i;
620 int ret = 0;
621 struct timeval tv = {0, 0};
622 char buf[CURL_MAX_WRITE_SIZE];
623
624 if(!connssl->use || !connproxyssl->use)
625 return 0; /* No SSL over SSL: OK. */
626
627 FD_ZERO(&fds_read);
628 FD_ZERO(&fds_write);
629 n = -1;
630 if(directions & SOS_READ) {
631 FD_SET(BACKEND->remotefd, &fds_write);
632 n = BACKEND->remotefd;
633 }
634 if(directions & SOS_WRITE) {
635 FD_SET(BACKEND->remotefd, &fds_read);
636 n = BACKEND->remotefd;
637 FD_SET(conn->sock[sockindex], &fds_write);
638 if(n < conn->sock[sockindex])
639 n = conn->sock[sockindex];
640 }
641 i = select(n + 1, &fds_read, &fds_write, NULL, &tv);
642 if(i < 0)
643 return -1; /* Select error. */
644
645 if(FD_ISSET(BACKEND->remotefd, &fds_write)) {
646 /* Try getting data from HTTPS proxy and pipe it upstream. */
647 n = 0;
648 i = gsk_secure_soc_read(connproxyssl->backend->handle,
649 buf, sizeof buf, &n);
650 switch(i) {
651 case GSK_OK:
652 if(n) {
653 i = write(BACKEND->remotefd, buf, n);
654 if(i < 0)
655 return -1;
656 ret = 1;
657 }
658 break;
659 case GSK_OS400_ERROR_TIMED_OUT:
660 case GSK_WOULD_BLOCK:
661 break;
662 default:
663 return -1;
664 }
665 }
666
667 if(FD_ISSET(BACKEND->remotefd, &fds_read) &&
668 FD_ISSET(conn->sock[sockindex], &fds_write)) {
669 /* Pipe data to HTTPS proxy. */
670 n = read(BACKEND->remotefd, buf, sizeof buf);
671 if(n < 0)
672 return -1;
673 if(n) {
674 i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m);
675 if(i != GSK_OK || n != m)
676 return -1;
677 ret = 1;
678 }
679 }
680
681 return ret; /* OK */
682}
683
684
685static void close_one(struct ssl_connect_data *connssl,
686 struct connectdata *conn, int sockindex)
687{
688 if(BACKEND->handle) {
689 gskit_status(conn->data, gsk_secure_soc_close(&BACKEND->handle),
690 "gsk_secure_soc_close()", 0);
691 /* Last chance to drain output. */
692 while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
693 ;
694 BACKEND->handle = (gsk_handle) NULL;
695 if(BACKEND->localfd >= 0) {
696 close(BACKEND->localfd);
697 BACKEND->localfd = -1;
698 }
699 if(BACKEND->remotefd >= 0) {
700 close(BACKEND->remotefd);
701 BACKEND->remotefd = -1;
702 }
703 }
704 if(BACKEND->iocport >= 0)
705 close_async_handshake(connssl);
706}
707
708
709static ssize_t gskit_send(struct connectdata *conn, int sockindex,
710 const void *mem, size_t len, CURLcode *curlcode)
711{
712 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
713 struct Curl_easy *data = conn->data;
714 CURLcode cc = CURLE_SEND_ERROR;
715 int written;
716
717 if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
718 cc = gskit_status(data,
719 gsk_secure_soc_write(BACKEND->handle,
720 (char *) mem, (int) len, &written),
721 "gsk_secure_soc_write()", CURLE_SEND_ERROR);
722 if(cc == CURLE_OK)
723 if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0)
724 cc = CURLE_SEND_ERROR;
725 }
726 if(cc != CURLE_OK) {
727 *curlcode = cc;
728 written = -1;
729 }
730 return (ssize_t) written; /* number of bytes */
731}
732
733
734static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
735 size_t buffersize, CURLcode *curlcode)
736{
737 struct ssl_connect_data *connssl = &conn->ssl[num];
738 struct Curl_easy *data = conn->data;
739 int buffsize;
740 int nread;
741 CURLcode cc = CURLE_RECV_ERROR;
742
743 if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
744 buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
745 cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
746 buf, buffsize, &nread),
747 "gsk_secure_soc_read()", CURLE_RECV_ERROR);
748 }
749 switch(cc) {
750 case CURLE_OK:
751 break;
752 case CURLE_OPERATION_TIMEDOUT:
753 cc = CURLE_AGAIN;
754 default:
755 *curlcode = cc;
756 nread = -1;
757 break;
758 }
759 return (ssize_t) nread;
760}
761
762static CURLcode
763set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn)
764{
765 struct Curl_easy *data = conn->data;
766 long ssl_version = SSL_CONN_CONFIG(version);
767 long ssl_version_max = SSL_CONN_CONFIG(version_max);
768 long i = ssl_version;
769 switch(ssl_version_max) {
770 case CURL_SSLVERSION_MAX_NONE:
771 ssl_version_max = ssl_version;
772 break;
773 case CURL_SSLVERSION_MAX_DEFAULT:
774 ssl_version_max = CURL_SSLVERSION_TLSv1_2;
775 break;
776 }
777 for(; i <= (ssl_version_max >> 16); ++i) {
778 switch(i) {
779 case CURL_SSLVERSION_TLSv1_0:
780 *protoflags |= CURL_GSKPROTO_TLSV10_MASK;
781 break;
782 case CURL_SSLVERSION_TLSv1_1:
783 *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
784 break;
785 case CURL_SSLVERSION_TLSv1_2:
786 *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
787 break;
788 case CURL_SSLVERSION_TLSv1_3:
789 failf(data, "GSKit: TLS 1.3 is not yet supported");
790 return CURLE_SSL_CONNECT_ERROR;
791 }
792 }
793
794 return CURLE_OK;
795}
796
797static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
798{
799 struct Curl_easy *data = conn->data;
800 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
801 gsk_handle envir;
802 CURLcode result;
803 int rc;
804 const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
805 const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
806 const char * const keyringlabel = SSL_SET_OPTION(cert);
807 const long int ssl_version = SSL_CONN_CONFIG(version);
808 const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
809 const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
810 conn->host.name;
811 const char *sni;
812 unsigned int protoflags = 0;
813 long timeout;
814 Qso_OverlappedIO_t commarea;
815 int sockpair[2];
816 static const int sobufsize = CURL_MAX_WRITE_SIZE;
817
818 /* Create SSL environment, start (preferably asynchronous) handshake. */
819
820 BACKEND->handle = (gsk_handle) NULL;
821 BACKEND->iocport = -1;
822 BACKEND->localfd = -1;
823 BACKEND->remotefd = -1;
824
825 /* GSKit supports two ways of specifying an SSL context: either by
826 * application identifier (that should have been defined at the system
827 * level) or by keyring file, password and certificate label.
828 * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
829 * application identifier of the certificate label.
830 * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
831 * It is not possible to have different keyrings for the CAs and the
832 * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
833 * the keyring file.
834 * If no key password is given and the keyring is the system keyring,
835 * application identifier mode is tried first, as recommended in IBM doc.
836 */
837
838 envir = (gsk_handle) NULL;
839
840 if(keyringlabel && *keyringlabel && !keyringpwd &&
841 !strcmp(keyringfile, CURL_CA_BUNDLE)) {
842 /* Try application identifier mode. */
843 init_environment(data, &envir, keyringlabel, (const char *) NULL,
844 (const char *) NULL, (const char *) NULL);
845 }
846
847 if(!envir) {
848 /* Use keyring mode. */
849 result = init_environment(data, &envir, (const char *) NULL,
850 keyringfile, keyringlabel, keyringpwd);
851 if(result)
852 return result;
853 }
854
855 /* Create secure session. */
856 result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle),
857 "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
858 gsk_environment_close(&envir);
859 if(result)
860 return result;
861
862 /* Establish a pipelining socket pair for SSL over SSL. */
863 if(conn->proxy_ssl[sockindex].use) {
864 if(inetsocketpair(sockpair))
865 return CURLE_SSL_CONNECT_ERROR;
866 BACKEND->localfd = sockpair[0];
867 BACKEND->remotefd = sockpair[1];
868 setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF,
869 (void *) sobufsize, sizeof sobufsize);
870 setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF,
871 (void *) sobufsize, sizeof sobufsize);
872 setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF,
873 (void *) sobufsize, sizeof sobufsize);
874 setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF,
875 (void *) sobufsize, sizeof sobufsize);
876 curlx_nonblock(BACKEND->localfd, TRUE);
877 curlx_nonblock(BACKEND->remotefd, TRUE);
878 }
879
880 /* Determine which SSL/TLS version should be enabled. */
881 sni = hostname;
882 switch(ssl_version) {
883 case CURL_SSLVERSION_SSLv2:
884 protoflags = CURL_GSKPROTO_SSLV2_MASK;
885 sni = NULL;
886 break;
887 case CURL_SSLVERSION_SSLv3:
888 protoflags = CURL_GSKPROTO_SSLV3_MASK;
889 sni = NULL;
890 break;
891 case CURL_SSLVERSION_DEFAULT:
892 case CURL_SSLVERSION_TLSv1:
893 protoflags = CURL_GSKPROTO_TLSV10_MASK |
894 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
895 break;
896 case CURL_SSLVERSION_TLSv1_0:
897 case CURL_SSLVERSION_TLSv1_1:
898 case CURL_SSLVERSION_TLSv1_2:
899 case CURL_SSLVERSION_TLSv1_3:
900 result = set_ssl_version_min_max(&protoflags, conn);
901 if(result != CURLE_OK)
902 return result;
903 break;
904 default:
905 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
906 return CURLE_SSL_CONNECT_ERROR;
907 }
908
909 /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
910 if(sni) {
911 result = set_buffer(data, BACKEND->handle,
912 GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
913 if(result == CURLE_UNSUPPORTED_PROTOCOL)
914 result = CURLE_OK;
915 }
916
917 /* Set session parameters. */
918 if(!result) {
919 /* Compute the handshake timeout. Since GSKit granularity is 1 second,
920 we round up the required value. */
921 timeout = Curl_timeleft(data, NULL, TRUE);
922 if(timeout < 0)
923 result = CURLE_OPERATION_TIMEDOUT;
924 else
925 result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT,
926 (timeout + 999) / 1000);
927 }
928 if(!result)
929 result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
930 if(!result)
931 result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
932 BACKEND->localfd: conn->sock[sockindex]);
933 if(!result)
934 result = set_ciphers(conn, BACKEND->handle, &protoflags);
935 if(!protoflags) {
936 failf(data, "No SSL protocol/cipher combination enabled");
937 result = CURLE_SSL_CIPHER;
938 }
939 if(!result)
940 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2,
941 (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
942 GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
943 if(!result)
944 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3,
945 (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
946 GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
947 if(!result)
948 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1,
949 (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
950 GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
951 if(!result) {
952 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11,
953 (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
954 GSK_TRUE: GSK_FALSE, TRUE);
955 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
956 result = CURLE_OK;
957 if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
958 failf(data, "TLS 1.1 not yet supported");
959 result = CURLE_SSL_CIPHER;
960 }
961 }
962 }
963 if(!result) {
964 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12,
965 (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
966 GSK_TRUE: GSK_FALSE, TRUE);
967 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
968 result = CURLE_OK;
969 if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
970 failf(data, "TLS 1.2 not yet supported");
971 result = CURLE_SSL_CIPHER;
972 }
973 }
974 }
975 if(!result)
976 result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE,
977 verifypeer? GSK_SERVER_AUTH_FULL:
978 GSK_SERVER_AUTH_PASSTHRU, FALSE);
979
980 if(!result) {
981 /* Start handshake. Try asynchronous first. */
982 memset(&commarea, 0, sizeof commarea);
983 BACKEND->iocport = QsoCreateIOCompletionPort();
984 if(BACKEND->iocport != -1) {
985 result = gskit_status(data,
986 gsk_secure_soc_startInit(BACKEND->handle,
987 BACKEND->iocport,
988 &commarea),
989 "gsk_secure_soc_startInit()",
990 CURLE_SSL_CONNECT_ERROR);
991 if(!result) {
992 connssl->connecting_state = ssl_connect_2;
993 return CURLE_OK;
994 }
995 else
996 close_async_handshake(connssl);
997 }
998 else if(errno != ENOBUFS)
999 result = gskit_status(data, GSK_ERROR_IO,
1000 "QsoCreateIOCompletionPort()", 0);
1001 else if(conn->proxy_ssl[sockindex].use) {
1002 /* Cannot pipeline while handshaking synchronously. */
1003 result = CURLE_SSL_CONNECT_ERROR;
1004 }
1005 else {
1006 /* No more completion port available. Use synchronous IO. */
1007 result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
1008 "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
1009 if(!result) {
1010 connssl->connecting_state = ssl_connect_3;
1011 return CURLE_OK;
1012 }
1013 }
1014 }
1015
1016 /* Error: rollback. */
1017 close_one(connssl, conn, sockindex);
1018 return result;
1019}
1020
1021
1022static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
1023 bool nonblocking)
1024{
1025 struct Curl_easy *data = conn->data;
1026 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1027 Qso_OverlappedIO_t cstat;
1028 long timeout_ms;
1029 struct timeval stmv;
1030 CURLcode result;
1031
1032 /* Poll or wait for end of SSL asynchronous handshake. */
1033
1034 for(;;) {
1035 timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
1036 if(timeout_ms < 0)
1037 timeout_ms = 0;
1038 stmv.tv_sec = timeout_ms / 1000;
1039 stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
1040 switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat, &stmv)) {
1041 case 1: /* Operation complete. */
1042 break;
1043 case -1: /* An error occurred: handshake still in progress. */
1044 if(errno == EINTR) {
1045 if(nonblocking)
1046 return CURLE_OK;
1047 continue; /* Retry. */
1048 }
1049 if(errno != ETIME) {
1050 failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
1051 cancel_async_handshake(conn, sockindex);
1052 close_async_handshake(connssl);
1053 return CURLE_SSL_CONNECT_ERROR;
1054 }
1055 /* FALL INTO... */
1056 case 0: /* Handshake in progress, timeout occurred. */
1057 if(nonblocking)
1058 return CURLE_OK;
1059 cancel_async_handshake(conn, sockindex);
1060 close_async_handshake(connssl);
1061 return CURLE_OPERATION_TIMEDOUT;
1062 }
1063 break;
1064 }
1065 result = gskit_status(data, cstat.returnValue, "SSL handshake",
1066 CURLE_SSL_CONNECT_ERROR);
1067 if(!result)
1068 connssl->connecting_state = ssl_connect_3;
1069 close_async_handshake(connssl);
1070 return result;
1071}
1072
1073
1074static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
1075{
1076 struct Curl_easy *data = conn->data;
1077 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1078 const gsk_cert_data_elem *cdev;
1079 int cdec;
1080 const gsk_cert_data_elem *p;
1081 const char *cert = (const char *) NULL;
1082 const char *certend;
1083 const char *ptr;
1084 int i;
1085 CURLcode result;
1086
1087 /* SSL handshake done: gather certificate info and verify host. */
1088
1089 if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle,
1090 GSK_PARTNER_CERT_INFO,
1091 &cdev, &cdec),
1092 "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
1093 CURLE_OK) {
1094 infof(data, "Server certificate:\n");
1095 p = cdev;
1096 for(i = 0; i++ < cdec; p++)
1097 switch(p->cert_data_id) {
1098 case CERT_BODY_DER:
1099 cert = p->cert_data_p;
1100 certend = cert + cdev->cert_data_l;
1101 break;
1102 case CERT_DN_PRINTABLE:
1103 infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
1104 break;
1105 case CERT_ISSUER_DN_PRINTABLE:
1106 infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
1107 break;
1108 case CERT_VALID_FROM:
1109 infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
1110 break;
1111 case CERT_VALID_TO:
1112 infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
1113 break;
1114 }
1115 }
1116
1117 /* Verify host. */
1118 result = Curl_verifyhost(conn, cert, certend);
1119 if(result)
1120 return result;
1121
1122 /* The only place GSKit can get the whole CA chain is a validation
1123 callback where no user data pointer is available. Therefore it's not
1124 possible to copy this chain into our structures for CAINFO.
1125 However the server certificate may be available, thus we can return
1126 info about it. */
1127 if(data->set.ssl.certinfo) {
1128 result = Curl_ssl_init_certinfo(data, 1);
1129 if(result)
1130 return result;
1131
1132 if(cert) {
1133 result = Curl_extract_certinfo(conn, 0, cert, certend);
1134 if(result)
1135 return result;
1136 }
1137 }
1138
1139 /* Check pinned public key. */
1140 ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1141 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
1142 if(!result && ptr) {
1143 curl_X509certificate x509;
1144 curl_asn1Element *p;
1145
1146 if(Curl_parseX509(&x509, cert, certend))
1147 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1148 p = &x509.subjectPublicKeyInfo;
1149 result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
1150 if(result) {
1151 failf(data, "SSL: public key does not match pinned public key!");
1152 return result;
1153 }
1154 }
1155
1156 connssl->connecting_state = ssl_connect_done;
1157 return CURLE_OK;
1158}
1159
1160
1161static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
1162 bool nonblocking, bool *done)
1163{
1164 struct Curl_easy *data = conn->data;
1165 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1166 long timeout_ms;
1167 Qso_OverlappedIO_t cstat;
1168 CURLcode result = CURLE_OK;
1169
1170 *done = connssl->state == ssl_connection_complete;
1171 if(*done)
1172 return CURLE_OK;
1173
1174 /* Step 1: create session, start handshake. */
1175 if(connssl->connecting_state == ssl_connect_1) {
1176 /* check allowed time left */
1177 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1178
1179 if(timeout_ms < 0) {
1180 /* no need to continue if time already is up */
1181 failf(data, "SSL connection timeout");
1182 result = CURLE_OPERATION_TIMEDOUT;
1183 }
1184 else
1185 result = gskit_connect_step1(conn, sockindex);
1186 }
1187
1188 /* Handle handshake pipelining. */
1189 if(!result)
1190 if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1191 result = CURLE_SSL_CONNECT_ERROR;
1192
1193 /* Step 2: check if handshake is over. */
1194 if(!result && connssl->connecting_state == ssl_connect_2) {
1195 /* check allowed time left */
1196 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1197
1198 if(timeout_ms < 0) {
1199 /* no need to continue if time already is up */
1200 failf(data, "SSL connection timeout");
1201 result = CURLE_OPERATION_TIMEDOUT;
1202 }
1203 else
1204 result = gskit_connect_step2(conn, sockindex, nonblocking);
1205 }
1206
1207 /* Handle handshake pipelining. */
1208 if(!result)
1209 if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
1210 result = CURLE_SSL_CONNECT_ERROR;
1211
1212 /* Step 3: gather certificate info, verify host. */
1213 if(!result && connssl->connecting_state == ssl_connect_3)
1214 result = gskit_connect_step3(conn, sockindex);
1215
1216 if(result)
1217 close_one(connssl, conn, sockindex);
1218 else if(connssl->connecting_state == ssl_connect_done) {
1219 connssl->state = ssl_connection_complete;
1220 connssl->connecting_state = ssl_connect_1;
1221 conn->recv[sockindex] = gskit_recv;
1222 conn->send[sockindex] = gskit_send;
1223 *done = TRUE;
1224 }
1225
1226 return result;
1227}
1228
1229
1230static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
1231 int sockindex, bool *done)
1232{
1233 CURLcode result;
1234
1235 result = gskit_connect_common(conn, sockindex, TRUE, done);
1236 if(*done || result)
1237 conn->ssl[sockindex].connecting_state = ssl_connect_1;
1238 return result;
1239}
1240
1241
1242static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
1243{
1244 CURLcode result;
1245 bool done;
1246
1247 conn->ssl[sockindex].connecting_state = ssl_connect_1;
1248 result = gskit_connect_common(conn, sockindex, FALSE, &done);
1249 if(result)
1250 return result;
1251
1252 DEBUGASSERT(done);
1253
1254 return CURLE_OK;
1255}
1256
1257
1258static void Curl_gskit_close(struct connectdata *conn, int sockindex)
1259{
1260 close_one(&conn->ssl[sockindex], conn, sockindex);
1261 close_one(&conn->proxy_ssl[sockindex], conn, sockindex);
1262}
1263
1264
1265static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
1266{
1267 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1268 struct Curl_easy *data = conn->data;
1269 ssize_t nread;
1270 int what;
1271 int rc;
1272 char buf[120];
1273
1274 if(!BACKEND->handle)
1275 return 0;
1276
1277 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
1278 return 0;
1279
1280 close_one(connssl, conn, sockindex);
1281 rc = 0;
1282 what = SOCKET_READABLE(conn->sock[sockindex],
1283 SSL_SHUTDOWN_TIMEOUT);
1284
1285 for(;;) {
1286 if(what < 0) {
1287 /* anything that gets here is fatally bad */
1288 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1289 rc = -1;
1290 break;
1291 }
1292
1293 if(!what) { /* timeout */
1294 failf(data, "SSL shutdown timeout");
1295 break;
1296 }
1297
1298 /* Something to read, let's do it and hope that it is the close
1299 notify alert from the server. No way to gsk_secure_soc_read() now, so
1300 use read(). */
1301
1302 nread = read(conn->sock[sockindex], buf, sizeof(buf));
1303
1304 if(nread < 0) {
1305 failf(data, "read: %s", strerror(errno));
1306 rc = -1;
1307 }
1308
1309 if(nread <= 0)
1310 break;
1311
1312 what = SOCKET_READABLE(conn->sock[sockindex], 0);
1313 }
1314
1315 return rc;
1316}
1317
1318
1319static size_t Curl_gskit_version(char *buffer, size_t size)
1320{
1321 strncpy(buffer, "GSKit", size);
1322 return strlen(buffer);
1323}
1324
1325
1326static int Curl_gskit_check_cxn(struct connectdata *cxn)
1327{
1328 struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET];
1329 int err;
1330 int errlen;
1331
1332 /* The only thing that can be tested here is at the socket level. */
1333
1334 if(!BACKEND->handle)
1335 return 0; /* connection has been closed */
1336
1337 err = 0;
1338 errlen = sizeof err;
1339
1340 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
1341 (unsigned char *) &err, &errlen) ||
1342 errlen != sizeof err || err)
1343 return 0; /* connection has been closed */
1344
1345 return -1; /* connection status unknown */
1346}
1347
1348static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl,
1349 CURLINFO info UNUSED_PARAM)
1350{
1351 (void)info;
1352 return BACKEND->handle;
1353}
1354
1355const struct Curl_ssl Curl_ssl_gskit = {
1356 { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */
1357
1358 0, /* have_ca_path */
1359 1, /* have_certinfo */
1360 0, /* have_pinnedpubkey */
1361 0, /* have_ssl_ctx */
1362 /* TODO: convert to 1 and fix test #1014 (if need) */
1363 0, /* support_https_proxy */
1364
1365 sizeof(struct ssl_backend_data),
1366
1367 Curl_gskit_init, /* init */
1368 Curl_gskit_cleanup, /* cleanup */
1369 Curl_gskit_version, /* version */
1370 Curl_gskit_check_cxn, /* check_cxn */
1371 Curl_gskit_shutdown, /* shutdown */
1372 Curl_none_data_pending, /* data_pending */
1373 Curl_none_random, /* random */
1374 Curl_none_cert_status_request, /* cert_status_request */
1375 Curl_gskit_connect, /* connect */
1376 Curl_gskit_connect_nonblocking, /* connect_nonblocking */
1377 Curl_gskit_get_internals, /* get_internals */
1378 Curl_gskit_close, /* close_one */
1379 Curl_none_close_all, /* close_all */
1380 /* No session handling for GSKit */
1381 Curl_none_session_free, /* session_free */
1382 Curl_none_set_engine, /* set_engine */
1383 Curl_none_set_engine_default, /* set_engine_default */
1384 Curl_none_engines_list, /* engines_list */
1385 Curl_none_false_start, /* false_start */
1386 Curl_none_md5sum, /* md5sum */
1387 NULL /* sha256sum */
1388};
1389
1390#endif /* USE_GSKIT */
Note: See TracBrowser for help on using the repository browser.