1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
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
35 #ifndef GSK_TLSV10_CIPHER_SPECS
36 #define GSK_TLSV10_CIPHER_SPECS 236
39 #ifndef GSK_TLSV11_CIPHER_SPECS
40 #define GSK_TLSV11_CIPHER_SPECS 237
43 #ifndef GSK_TLSV12_CIPHER_SPECS
44 #define GSK_TLSV12_CIPHER_SPECS 238
47 #ifndef GSK_PROTOCOL_TLSV11
48 #define GSK_PROTOCOL_TLSV11 437
51 #ifndef GSK_PROTOCOL_TLSV12
52 #define GSK_PROTOCOL_TLSV12 438
68 #include <curl/curl.h>
73 #include "connect.h" /* for the connect timeout */
78 #define _MPRINTF_REPLACE /* use our functions only */
79 #include <curl/mprintf.h>
81 #include "curl_memory.h"
82 /* The last #include file should be: */
86 /* SSL version flags. */
87 #define CURL_GSKPROTO_SSLV2 0
88 #define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2)
89 #define CURL_GSKPROTO_SSLV3 1
90 #define CURL_GSKPROTO_SSLV3_MASK (1 << CURL_GSKPROTO_SSLV3)
91 #define CURL_GSKPROTO_TLSV10 2
92 #define CURL_GSKPROTO_TLSV10_MASK (1 << CURL_GSKPROTO_TLSV10)
93 #define CURL_GSKPROTO_TLSV11 3
94 #define CURL_GSKPROTO_TLSV11_MASK (1 << CURL_GSKPROTO_TLSV11)
95 #define CURL_GSKPROTO_TLSV12 4
96 #define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12)
97 #define CURL_GSKPROTO_LAST 5
100 /* Supported ciphers. */
102 const char *name; /* Cipher name. */
103 const char *gsktoken; /* Corresponding token for GSKit String. */
104 unsigned int versions; /* SSL version flags. */
107 static const gskit_cipher ciphertable[] = {
109 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
110 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
112 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
113 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
114 { "exp-rc4-md5", "03",
115 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
117 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
118 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
120 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
121 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
122 { "exp-rc2-cbc-md5", "06",
123 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
124 { "exp-des-cbc-sha", "09",
125 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
126 CURL_GSKPROTO_TLSV11_MASK },
127 { "des-cbc3-sha", "0A",
128 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
129 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
130 { "aes128-sha", "2F",
131 CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
132 CURL_GSKPROTO_TLSV12_MASK },
133 { "aes256-sha", "35",
134 CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
135 CURL_GSKPROTO_TLSV12_MASK },
136 { "null-sha256", "3B", CURL_GSKPROTO_TLSV12_MASK },
137 { "aes128-sha256", "3C", CURL_GSKPROTO_TLSV12_MASK },
138 { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK },
139 { "aes128-gcm-sha256",
140 "9C", CURL_GSKPROTO_TLSV12_MASK },
141 { "aes256-gcm-sha384",
142 "9D", CURL_GSKPROTO_TLSV12_MASK },
143 { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK },
144 { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK },
145 { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK },
146 { "exp-rc2-md5", "4", CURL_GSKPROTO_SSLV2_MASK },
147 { "des-cbc-md5", "6", CURL_GSKPROTO_SSLV2_MASK },
148 { "des-cbc3-md5", "7", CURL_GSKPROTO_SSLV2_MASK },
149 { (const char *) NULL, (const char *) NULL, 0 }
153 static bool is_separator(char c)
155 /* Return whether character is a cipher list separator. */
168 static CURLcode gskit_status(struct SessionHandle *data, int rc,
169 const char *procname, CURLcode defcode)
171 /* Process GSKit status and map it to a CURLcode. */
174 case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
176 case GSK_KEYRING_OPEN_ERROR:
177 case GSK_OS400_ERROR_NO_ACCESS:
178 return CURLE_SSL_CACERT_BADFILE;
179 case GSK_INSUFFICIENT_STORAGE:
180 return CURLE_OUT_OF_MEMORY;
181 case GSK_ERROR_BAD_V2_CIPHER:
182 case GSK_ERROR_BAD_V3_CIPHER:
183 case GSK_ERROR_NO_CIPHERS:
184 return CURLE_SSL_CIPHER;
185 case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
186 case GSK_ERROR_CERT_VALIDATION:
187 return CURLE_PEER_FAILED_VERIFICATION;
188 case GSK_OS400_ERROR_TIMED_OUT:
189 return CURLE_OPERATION_TIMEDOUT;
190 case GSK_WOULD_BLOCK:
192 case GSK_OS400_ERROR_NOT_REGISTERED:
197 return CURLE_OUT_OF_MEMORY;
199 failf(data, "%s I/O error: %s", procname, strerror(errno));
204 failf(data, "%s: %s", procname, gsk_strerror(rc));
211 static CURLcode set_enum(struct SessionHandle *data, gsk_handle h,
212 GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
214 int rc = gsk_attribute_set_enum(h, id, value);
220 failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
222 case GSK_ATTRIBUTE_INVALID_ID:
224 return CURLE_UNSUPPORTED_PROTOCOL;
226 failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
229 return CURLE_SSL_CONNECT_ERROR;
233 static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h,
234 GSK_BUF_ID id, const char *buffer, bool unsupported_ok)
236 int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
242 failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
244 case GSK_ATTRIBUTE_INVALID_ID:
246 return CURLE_UNSUPPORTED_PROTOCOL;
248 failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
251 return CURLE_SSL_CONNECT_ERROR;
255 static CURLcode set_numeric(struct SessionHandle *data,
256 gsk_handle h, GSK_NUM_ID id, int value)
258 int rc = gsk_attribute_set_numeric_value(h, id, value);
264 failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
268 failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
271 return CURLE_SSL_CONNECT_ERROR;
275 static CURLcode set_callback(struct SessionHandle *data,
276 gsk_handle h, GSK_CALLBACK_ID id, void *info)
278 int rc = gsk_attribute_set_callback(h, id, info);
284 failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
287 failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
290 return CURLE_SSL_CONNECT_ERROR;
294 static CURLcode set_ciphers(struct SessionHandle *data,
295 gsk_handle h, unsigned int *protoflags)
297 const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
299 const gskit_cipher *ctp;
307 } ciphers[CURL_GSKPROTO_LAST];
309 /* Compile cipher list into GSKit-compatible cipher lists. */
313 while(is_separator(*cipherlist)) /* Skip initial separators. */
318 /* We allocate GSKit buffers of the same size as the input string: since
319 GSKit tokens are always shorter than their cipher names, allocated buffers
320 will always be large enough to accomodate the result. */
321 l = strlen(cipherlist) + 1;
322 memset((char *) ciphers, 0, sizeof ciphers);
323 for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
324 ciphers[i].buf = malloc(l);
325 if(!ciphers[i].buf) {
327 free(ciphers[i].buf);
328 return CURLE_OUT_OF_MEMORY;
330 ciphers[i].ptr = ciphers[i].buf;
331 *ciphers[i].ptr = '\0';
334 /* Process each cipher in input string. */
338 for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
340 l = cipherlist - clp;
343 /* Search the cipher in our table. */
344 for(ctp = ciphertable; ctp->name; ctp++)
345 if(strnequal(ctp->name, clp, l) && !ctp->name[l])
348 failf(data, "Unknown cipher %.*s", l, clp);
349 result = CURLE_SSL_CIPHER;
352 unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK |
353 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK));
354 for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
355 if(ctp->versions & (1 << i)) {
356 strcpy(ciphers[i].ptr, ctp->gsktoken);
357 ciphers[i].ptr += strlen(ctp->gsktoken);
362 /* Advance to next cipher name or end of string. */
363 while(is_separator(*cipherlist))
367 /* Disable protocols with empty cipher lists. */
368 for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
369 if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) {
370 *protoflags &= ~(1 << i);
371 ciphers[i].buf[0] = '\0';
375 /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */
376 if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) {
377 result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS,
378 ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE);
379 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
382 failf(data, "TLSv1.1-only ciphers are not yet supported");
383 result = CURLE_SSL_CIPHER;
387 if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) {
388 result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS,
389 ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE);
390 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
393 failf(data, "TLSv1.2-only ciphers are not yet supported");
394 result = CURLE_SSL_CIPHER;
399 /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to
400 the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */
401 if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) {
402 result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS,
403 ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE);
404 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
406 strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr,
407 ciphers[CURL_GSKPROTO_TLSV10].ptr);
411 /* Set-up other ciphers. */
412 if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK))
413 result = set_buffer(data, h, GSK_V3_CIPHER_SPECS,
414 ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE);
415 if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK))
416 result = set_buffer(data, h, GSK_V2_CIPHER_SPECS,
417 ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE);
420 for(i = 0; i < CURL_GSKPROTO_LAST; i++)
421 free(ciphers[i].buf);
427 int Curl_gskit_init(void)
429 /* No initialisation needed. */
435 void Curl_gskit_cleanup(void)
441 static CURLcode init_environment(struct SessionHandle *data,
442 gsk_handle *envir, const char *appid,
443 const char *file, const char *label,
444 const char *password)
450 /* Creates the GSKit environment. */
452 rc = gsk_environment_open(&h);
456 case GSK_INSUFFICIENT_STORAGE:
457 return CURLE_OUT_OF_MEMORY;
459 failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
460 return CURLE_SSL_CONNECT_ERROR;
463 result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE);
465 result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE);
467 result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE);
469 result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE);
470 if(!result && password)
471 result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE);
474 /* Locate CAs, Client certificate and key according to our settings.
475 Note: this call may be blocking for some tenths of seconds. */
476 result = gskit_status(data, gsk_environment_init(h),
477 "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
483 /* Error: rollback. */
484 gsk_environment_close(&h);
489 static void cancel_async_handshake(struct connectdata *conn, int sockindex)
491 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
492 Qso_OverlappedIO_t cstat;
494 if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
495 QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
499 static void close_async_handshake(struct ssl_connect_data *connssl)
501 QsoDestroyIOCompletionPort(connssl->iocport);
502 connssl->iocport = -1;
506 static void close_one(struct ssl_connect_data *conn,
507 struct SessionHandle *data)
510 gskit_status(data, gsk_secure_soc_close(&conn->handle),
511 "gsk_secure_soc_close()", 0);
512 conn->handle = (gsk_handle) NULL;
514 if(conn->iocport >= 0)
515 close_async_handshake(conn);
519 static ssize_t gskit_send(struct connectdata *conn, int sockindex,
520 const void *mem, size_t len, CURLcode *curlcode)
522 struct SessionHandle *data = conn->data;
526 cc = gskit_status(data,
527 gsk_secure_soc_write(conn->ssl[sockindex].handle,
528 (char *) mem, (int) len, &written),
529 "gsk_secure_soc_write()", CURLE_SEND_ERROR);
534 return (ssize_t) written; /* number of bytes */
538 static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
539 size_t buffersize, CURLcode *curlcode)
541 struct SessionHandle *data = conn->data;
546 buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
547 cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
548 buf, buffsize, &nread),
549 "gsk_secure_soc_read()", CURLE_RECV_ERROR);
554 return (ssize_t) nread;
558 static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
560 struct SessionHandle *data = conn->data;
561 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
569 unsigned int protoflags;
571 Qso_OverlappedIO_t commarea;
573 /* Create SSL environment, start (preferably asynchronous) handshake. */
575 connssl->handle = (gsk_handle) NULL;
576 connssl->iocport = -1;
578 /* GSKit supports two ways of specifying an SSL context: either by
579 * application identifier (that should have been defined at the system
580 * level) or by keyring file, password and certificate label.
581 * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
582 * application identifier of the certificate label.
583 * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
584 * It is not possible to have different keyrings for the CAs and the
585 * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
587 * If no key password is given and the keyring is the system keyring,
588 * application identifier mode is tried first, as recommended in IBM doc.
591 keyringfile = data->set.str[STRING_SSL_CAFILE];
592 keyringpwd = data->set.str[STRING_KEY_PASSWD];
593 keyringlabel = data->set.str[STRING_CERT];
594 envir = (gsk_handle) NULL;
596 if(keyringlabel && *keyringlabel && !keyringpwd &&
597 !strcmp(keyringfile, CURL_CA_BUNDLE)) {
598 /* Try application identifier mode. */
599 init_environment(data, &envir, keyringlabel, (const char *) NULL,
600 (const char *) NULL, (const char *) NULL);
604 /* Use keyring mode. */
605 result = init_environment(data, &envir, (const char *) NULL,
606 keyringfile, keyringlabel, keyringpwd);
611 /* Create secure session. */
612 result = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
613 "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
614 gsk_environment_close(&envir);
618 /* Determine which SSL/TLS version should be enabled. */
619 protoflags = CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
620 CURL_GSKPROTO_TLSV12_MASK;
621 sni = conn->host.name;
622 switch (data->set.ssl.version) {
623 case CURL_SSLVERSION_SSLv2:
624 protoflags = CURL_GSKPROTO_SSLV2_MASK;
627 case CURL_SSLVERSION_SSLv3:
628 protoflags = CURL_GSKPROTO_SSLV2_MASK;
631 case CURL_SSLVERSION_TLSv1:
632 protoflags = CURL_GSKPROTO_TLSV10_MASK |
633 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
635 case CURL_SSLVERSION_TLSv1_0:
636 protoflags = CURL_GSKPROTO_TLSV10_MASK;
638 case CURL_SSLVERSION_TLSv1_1:
639 protoflags = CURL_GSKPROTO_TLSV11_MASK;
641 case CURL_SSLVERSION_TLSv1_2:
642 protoflags = CURL_GSKPROTO_TLSV12_MASK;
646 /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
648 result = set_buffer(data, connssl->handle,
649 GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
650 if(result == CURLE_UNSUPPORTED_PROTOCOL)
654 /* Set session parameters. */
656 /* Compute the handshake timeout. Since GSKit granularity is 1 second,
657 we round up the required value. */
658 timeout = Curl_timeleft(data, NULL, TRUE);
660 result = CURLE_OPERATION_TIMEDOUT;
662 result = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
663 (timeout + 999) / 1000);
666 result = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]);
668 result = set_ciphers(data, connssl->handle, &protoflags);
670 failf(data, "No SSL protocol/cipher combination enabled");
671 result = CURLE_SSL_CIPHER;
674 result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
675 (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
676 GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
678 result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
679 (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
680 GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
682 result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
683 (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
684 GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
686 result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11,
687 (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
688 GSK_TRUE: GSK_FALSE, TRUE);
689 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
691 if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
692 failf(data, "TLS 1.1 not yet supported");
693 result = CURLE_SSL_CIPHER;
698 result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12,
699 (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
700 GSK_TRUE: GSK_FALSE, TRUE);
701 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
703 if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
704 failf(data, "TLS 1.2 not yet supported");
705 result = CURLE_SSL_CIPHER;
710 result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
711 data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL:
712 GSK_SERVER_AUTH_PASSTHRU, FALSE);
715 /* Start handshake. Try asynchronous first. */
716 memset(&commarea, 0, sizeof commarea);
717 connssl->iocport = QsoCreateIOCompletionPort();
718 if(connssl->iocport != -1) {
719 result = gskit_status(data,
720 gsk_secure_soc_startInit(connssl->handle,
723 "gsk_secure_soc_startInit()",
724 CURLE_SSL_CONNECT_ERROR);
726 connssl->connecting_state = ssl_connect_2;
730 close_async_handshake(connssl);
732 else if(errno != ENOBUFS)
733 result = gskit_status(data, GSK_ERROR_IO,
734 "QsoCreateIOCompletionPort()", 0);
736 /* No more completion port available. Use synchronous IO. */
737 result = gskit_status(data, gsk_secure_soc_init(connssl->handle),
738 "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
740 connssl->connecting_state = ssl_connect_3;
746 /* Error: rollback. */
747 close_one(connssl, data);
752 static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
755 struct SessionHandle *data = conn->data;
756 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
757 Qso_OverlappedIO_t cstat;
762 /* Poll or wait for end of SSL asynchronous handshake. */
765 timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
768 stmv.tv_sec = timeout_ms / 1000;
769 stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
770 switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
771 case 1: /* Operation complete. */
773 case -1: /* An error occurred: handshake still in progress. */
777 continue; /* Retry. */
780 failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
781 cancel_async_handshake(conn, sockindex);
782 close_async_handshake(connssl);
783 return CURLE_SSL_CONNECT_ERROR;
786 case 0: /* Handshake in progress, timeout occurred. */
789 cancel_async_handshake(conn, sockindex);
790 close_async_handshake(connssl);
791 return CURLE_OPERATION_TIMEDOUT;
795 result = gskit_status(data, cstat.returnValue, "SSL handshake",
796 CURLE_SSL_CONNECT_ERROR);
798 connssl->connecting_state = ssl_connect_3;
799 close_async_handshake(connssl);
804 static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
806 struct SessionHandle *data = conn->data;
807 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
808 const gsk_cert_data_elem *cdev;
810 const gsk_cert_data_elem *p;
811 const char *cert = (const char *) NULL;
817 /* SSL handshake done: gather certificate info and verify host. */
819 if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
820 GSK_PARTNER_CERT_INFO,
822 "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
824 infof(data, "Server certificate:\n");
826 for(i = 0; i++ < cdec; p++)
827 switch (p->cert_data_id) {
829 cert = p->cert_data_p;
830 certend = cert + cdev->cert_data_l;
832 case CERT_DN_PRINTABLE:
833 infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
835 case CERT_ISSUER_DN_PRINTABLE:
836 infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
838 case CERT_VALID_FROM:
839 infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
842 infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
848 result = Curl_verifyhost(conn, cert, certend);
852 /* The only place GSKit can get the whole CA chain is a validation
853 callback where no user data pointer is available. Therefore it's not
854 possible to copy this chain into our structures for CAINFO.
855 However the server certificate may be available, thus we can return
857 if(data->set.ssl.certinfo) {
858 result = Curl_ssl_init_certinfo(data, 1);
863 result = Curl_extract_certinfo(conn, 0, cert, certend);
869 /* Check pinned public key. */
870 ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
872 curl_X509certificate x509;
876 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
877 Curl_parseX509(&x509, cert, certend);
878 p = &x509.subjectPublicKeyInfo;
879 result = Curl_pin_peer_pubkey(ptr, p->header, p->end - p->header);
881 failf(data, "SSL: public key does not match pinned public key!");
886 connssl->connecting_state = ssl_connect_done;
891 static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
892 bool nonblocking, bool *done)
894 struct SessionHandle *data = conn->data;
895 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
897 Qso_OverlappedIO_t cstat;
898 CURLcode result = CURLE_OK;
900 *done = connssl->state == ssl_connection_complete;
904 /* Step 1: create session, start handshake. */
905 if(connssl->connecting_state == ssl_connect_1) {
906 /* check allowed time left */
907 timeout_ms = Curl_timeleft(data, NULL, TRUE);
910 /* no need to continue if time already is up */
911 failf(data, "SSL connection timeout");
912 result = CURLE_OPERATION_TIMEDOUT;
915 result = gskit_connect_step1(conn, sockindex);
918 /* Step 2: check if handshake is over. */
919 if(!result && connssl->connecting_state == ssl_connect_2) {
920 /* check allowed time left */
921 timeout_ms = Curl_timeleft(data, NULL, TRUE);
924 /* no need to continue if time already is up */
925 failf(data, "SSL connection timeout");
926 result = CURLE_OPERATION_TIMEDOUT;
929 result = gskit_connect_step2(conn, sockindex, nonblocking);
932 /* Step 3: gather certificate info, verify host. */
933 if(!result && connssl->connecting_state == ssl_connect_3)
934 result = gskit_connect_step3(conn, sockindex);
937 close_one(connssl, data);
938 else if(connssl->connecting_state == ssl_connect_done) {
939 connssl->state = ssl_connection_complete;
940 connssl->connecting_state = ssl_connect_1;
941 conn->recv[sockindex] = gskit_recv;
942 conn->send[sockindex] = gskit_send;
950 CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
956 result = gskit_connect_common(conn, sockindex, TRUE, done);
958 conn->ssl[sockindex].connecting_state = ssl_connect_1;
963 CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
968 conn->ssl[sockindex].connecting_state = ssl_connect_1;
969 result = gskit_connect_common(conn, sockindex, FALSE, &done);
979 void Curl_gskit_close(struct connectdata *conn, int sockindex)
981 struct SessionHandle *data = conn->data;
982 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
985 close_one(connssl, data);
989 void Curl_gskit_close_all(struct SessionHandle *data)
996 int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
998 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
999 struct SessionHandle *data = conn->data;
1005 if(!connssl->handle)
1008 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
1011 close_one(connssl, data);
1013 what = Curl_socket_ready(conn->sock[sockindex],
1014 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
1018 /* anything that gets here is fatally bad */
1019 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1024 if(!what) { /* timeout */
1025 failf(data, "SSL shutdown timeout");
1029 /* Something to read, let's do it and hope that it is the close
1030 notify alert from the server. No way to gsk_secure_soc_read() now, so
1033 nread = read(conn->sock[sockindex], buf, sizeof(buf));
1036 failf(data, "read: %s", strerror(errno));
1043 what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
1050 size_t Curl_gskit_version(char *buffer, size_t size)
1052 strncpy(buffer, "GSKit", size);
1053 return strlen(buffer);
1057 int Curl_gskit_check_cxn(struct connectdata *cxn)
1062 /* The only thing that can be tested here is at the socket level. */
1064 if(!cxn->ssl[FIRSTSOCKET].handle)
1065 return 0; /* connection has been closed */
1068 errlen = sizeof err;
1070 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
1071 (unsigned char *) &err, &errlen) ||
1072 errlen != sizeof err || err)
1073 return 0; /* connection has been closed */
1075 return -1; /* connection status unknown */
1078 #endif /* USE_GSKIT */