1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2013, 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", "3D", CURL_GSKPROTO_TLSV12_MASK },
138 { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK },
139 { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK },
140 { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK },
141 { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK },
142 { "exp-rc2-md5", "4", CURL_GSKPROTO_SSLV2_MASK },
143 { "des-cbc-md5", "6", CURL_GSKPROTO_SSLV2_MASK },
144 { "des-cbc3-md5", "7", CURL_GSKPROTO_SSLV2_MASK },
145 { (const char *) NULL, (const char *) NULL, 0 }
149 static bool is_separator(char c)
151 /* Return whether character is a cipher list separator. */
164 static CURLcode gskit_status(struct SessionHandle *data, int rc,
165 const char *procname, CURLcode defcode)
169 /* Process GSKit status and map it to a CURLcode. */
172 case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
174 case GSK_KEYRING_OPEN_ERROR:
175 case GSK_OS400_ERROR_NO_ACCESS:
176 return CURLE_SSL_CACERT_BADFILE;
177 case GSK_INSUFFICIENT_STORAGE:
178 return CURLE_OUT_OF_MEMORY;
179 case GSK_ERROR_BAD_V2_CIPHER:
180 case GSK_ERROR_BAD_V3_CIPHER:
181 case GSK_ERROR_NO_CIPHERS:
182 return CURLE_SSL_CIPHER;
183 case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
184 case GSK_ERROR_CERT_VALIDATION:
185 return CURLE_PEER_FAILED_VERIFICATION;
186 case GSK_OS400_ERROR_TIMED_OUT:
187 return CURLE_OPERATION_TIMEDOUT;
188 case GSK_WOULD_BLOCK:
190 case GSK_OS400_ERROR_NOT_REGISTERED:
195 return CURLE_OUT_OF_MEMORY;
197 failf(data, "%s I/O error: %s", procname, strerror(errno));
202 failf(data, "%s: %s", procname, gsk_strerror(rc));
209 static CURLcode set_enum(struct SessionHandle *data, gsk_handle h,
210 GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
212 int rc = gsk_attribute_set_enum(h, id, value);
218 failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
220 case GSK_ATTRIBUTE_INVALID_ID:
222 return CURLE_UNSUPPORTED_PROTOCOL;
224 failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
227 return CURLE_SSL_CONNECT_ERROR;
231 static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h,
232 GSK_BUF_ID id, const char *buffer, bool unsupported_ok)
234 int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
240 failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
242 case GSK_ATTRIBUTE_INVALID_ID:
244 return CURLE_UNSUPPORTED_PROTOCOL;
246 failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
249 return CURLE_SSL_CONNECT_ERROR;
253 static CURLcode set_numeric(struct SessionHandle *data,
254 gsk_handle h, GSK_NUM_ID id, int value)
256 int rc = gsk_attribute_set_numeric_value(h, id, value);
262 failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
266 failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
269 return CURLE_SSL_CONNECT_ERROR;
273 static CURLcode set_callback(struct SessionHandle *data,
274 gsk_handle h, GSK_CALLBACK_ID id, void *info)
276 int rc = gsk_attribute_set_callback(h, id, info);
282 failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
285 failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
288 return CURLE_SSL_CONNECT_ERROR;
292 static CURLcode set_ciphers(struct SessionHandle *data,
293 gsk_handle h, unsigned int *protoflags)
295 const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
297 const gskit_cipher *ctp;
305 } ciphers[CURL_GSKPROTO_LAST];
307 /* Compile cipher list into GSKit-compatible cipher lists. */
311 while(is_separator(*cipherlist)) /* Skip initial separators. */
316 /* We allocate GSKit buffers of the same size as the input string: since
317 GSKit tokens are always shorter than their cipher names, allocated buffers
318 will always be large enough to accomodate the result. */
319 l = strlen(cipherlist) + 1;
320 memset((char *) ciphers, 0, sizeof ciphers);
321 for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
322 ciphers[i].buf = malloc(l);
323 if(!ciphers[i].buf) {
325 free(ciphers[i].buf);
326 return CURLE_OUT_OF_MEMORY;
328 ciphers[i].ptr = ciphers[i].buf;
329 *ciphers[i].ptr = '\0';
332 /* Process each cipher in input string. */
336 for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
338 l = cipherlist - clp;
341 /* Search the cipher in our table. */
342 for(ctp = ciphertable; ctp->name; ctp++)
343 if(strnequal(ctp->name, clp, l) && !ctp->name[l])
346 failf(data, "Unknown cipher %.*s", l, clp);
347 cc = CURLE_SSL_CIPHER;
350 unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK |
351 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK));
352 for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
353 if(ctp->versions & (1 << i)) {
354 strcpy(ciphers[i].ptr, ctp->gsktoken);
355 ciphers[i].ptr += strlen(ctp->gsktoken);
360 /* Advance to next cipher name or end of string. */
361 while(is_separator(*cipherlist))
365 /* Disable protocols with empty cipher lists. */
366 for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
367 if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) {
368 *protoflags &= ~(1 << i);
369 ciphers[i].buf[0] = '\0';
373 /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */
374 if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) {
375 cc = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS,
376 ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE);
377 if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
380 failf(data, "TLSv1.1-only ciphers are not yet supported");
381 cc = CURLE_SSL_CIPHER;
385 if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) {
386 cc = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS,
387 ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE);
388 if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
391 failf(data, "TLSv1.2-only ciphers are not yet supported");
392 cc = CURLE_SSL_CIPHER;
397 /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to
398 the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */
399 if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) {
400 cc = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS,
401 ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE);
402 if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
404 strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr,
405 ciphers[CURL_GSKPROTO_TLSV10].ptr);
409 /* Set-up other ciphers. */
410 if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_SSLV3_MASK))
411 cc = set_buffer(data, h, GSK_V3_CIPHER_SPECS,
412 ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE);
413 if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_SSLV2_MASK))
414 cc = set_buffer(data, h, GSK_V2_CIPHER_SPECS,
415 ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE);
418 for(i = 0; i < CURL_GSKPROTO_LAST; i++)
419 free(ciphers[i].buf);
425 int Curl_gskit_init(void)
427 /* No initialisation needed. */
433 void Curl_gskit_cleanup(void)
439 static CURLcode init_environment(struct SessionHandle *data,
440 gsk_handle *envir, const char *appid,
441 const char *file, const char *label,
442 const char *password)
448 /* Creates the GSKit environment. */
450 rc = gsk_environment_open(&h);
454 case GSK_INSUFFICIENT_STORAGE:
455 return CURLE_OUT_OF_MEMORY;
457 failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
458 return CURLE_SSL_CONNECT_ERROR;
461 c = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE);
462 if(c == CURLE_OK && appid)
463 c = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE);
464 if(c == CURLE_OK && file)
465 c = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE);
466 if(c == CURLE_OK && label)
467 c = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE);
468 if(c == CURLE_OK && password)
469 c = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE);
472 /* Locate CAs, Client certificate and key according to our settings.
473 Note: this call may be blocking for some tenths of seconds. */
474 c = gskit_status(data, gsk_environment_init(h),
475 "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
481 /* Error: rollback. */
482 gsk_environment_close(&h);
487 static void cancel_async_handshake(struct connectdata *conn, int sockindex)
489 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
490 Qso_OverlappedIO_t cstat;
492 if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
493 QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
497 static void close_async_handshake(struct ssl_connect_data *connssl)
499 QsoDestroyIOCompletionPort(connssl->iocport);
500 connssl->iocport = -1;
504 static void close_one(struct ssl_connect_data *conn,
505 struct SessionHandle *data)
508 gskit_status(data, gsk_secure_soc_close(&conn->handle),
509 "gsk_secure_soc_close()", 0);
510 conn->handle = (gsk_handle) NULL;
512 if(conn->iocport >= 0)
513 close_async_handshake(conn);
517 static ssize_t gskit_send(struct connectdata *conn, int sockindex,
518 const void *mem, size_t len, CURLcode *curlcode)
520 struct SessionHandle *data = conn->data;
524 cc = gskit_status(data,
525 gsk_secure_soc_write(conn->ssl[sockindex].handle,
526 (char *) mem, (int) len, &written),
527 "gsk_secure_soc_write()", CURLE_SEND_ERROR);
532 return (ssize_t) written; /* number of bytes */
536 static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
537 size_t buffersize, CURLcode *curlcode)
539 struct SessionHandle *data = conn->data;
544 buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
545 cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
546 buf, buffsize, &nread),
547 "gsk_secure_soc_read()", CURLE_RECV_ERROR);
552 return (ssize_t) nread;
556 static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
558 struct SessionHandle *data = conn->data;
559 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
567 unsigned int protoflags;
569 Qso_OverlappedIO_t commarea;
571 /* Create SSL environment, start (preferably asynchronous) handshake. */
573 connssl->handle = (gsk_handle) NULL;
574 connssl->iocport = -1;
576 /* GSKit supports two ways of specifying an SSL context: either by
577 * application identifier (that should have been defined at the system
578 * level) or by keyring file, password and certificate label.
579 * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
580 * application identifier of the certificate label.
581 * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
582 * It is not possible to have different keyrings for the CAs and the
583 * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
585 * If no key password is given and the keyring is the system keyring,
586 * application identifier mode is tried first, as recommended in IBM doc.
589 keyringfile = data->set.str[STRING_SSL_CAFILE];
590 keyringpwd = data->set.str[STRING_KEY_PASSWD];
591 keyringlabel = data->set.str[STRING_CERT];
592 envir = (gsk_handle) NULL;
594 if(keyringlabel && *keyringlabel && !keyringpwd &&
595 !strcmp(keyringfile, CURL_CA_BUNDLE)) {
596 /* Try application identifier mode. */
597 init_environment(data, &envir, keyringlabel, (const char *) NULL,
598 (const char *) NULL, (const char *) NULL);
602 /* Use keyring mode. */
603 cc = init_environment(data, &envir, (const char *) NULL,
604 keyringfile, keyringlabel, keyringpwd);
609 /* Create secure session. */
610 cc = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
611 "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
612 gsk_environment_close(&envir);
616 /* Determine which SSL/TLS version should be enabled. */
617 protoflags = CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
618 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
619 sni = conn->host.name;
620 switch (data->set.ssl.version) {
621 case CURL_SSLVERSION_SSLv2:
622 protoflags = CURL_GSKPROTO_SSLV2_MASK;
625 case CURL_SSLVERSION_SSLv3:
626 protoflags = CURL_GSKPROTO_SSLV2_MASK;
629 case CURL_SSLVERSION_TLSv1:
630 protoflags = CURL_GSKPROTO_TLSV10_MASK |
631 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
633 case CURL_SSLVERSION_TLSv1_0:
634 protoflags = CURL_GSKPROTO_TLSV10_MASK;
636 case CURL_SSLVERSION_TLSv1_1:
637 protoflags = CURL_GSKPROTO_TLSV11_MASK;
639 case CURL_SSLVERSION_TLSv1_2:
640 protoflags = CURL_GSKPROTO_TLSV12_MASK;
644 /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
646 cc = set_buffer(data, connssl->handle,
647 GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
648 if(cc == CURLE_UNSUPPORTED_PROTOCOL)
652 /* Set session parameters. */
654 /* Compute the handshake timeout. Since GSKit granularity is 1 second,
655 we round up the required value. */
656 timeout = Curl_timeleft(data, NULL, TRUE);
658 cc = CURLE_OPERATION_TIMEDOUT;
660 cc = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
661 (timeout + 999) / 1000);
664 cc = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]);
666 cc = set_ciphers(data, connssl->handle, &protoflags);
668 failf(data, "No SSL protocol/cipher combination enabled");
669 cc = CURLE_SSL_CIPHER;
672 cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
673 (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
674 GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
676 cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
677 (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
678 GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
680 cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
681 (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
682 GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
684 cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11,
685 (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
686 GSK_TRUE: GSK_FALSE, TRUE);
687 if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
689 if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
690 failf(data, "TLS 1.1 not yet supported");
691 cc = CURLE_SSL_CIPHER;
696 cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12,
697 (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
698 GSK_TRUE: GSK_FALSE, TRUE);
699 if(cc == CURLE_UNSUPPORTED_PROTOCOL) {
701 if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
702 failf(data, "TLS 1.2 not yet supported");
703 cc = CURLE_SSL_CIPHER;
708 cc = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
709 data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL:
710 GSK_SERVER_AUTH_PASSTHRU, FALSE);
713 /* Start handshake. Try asynchronous first. */
714 memset(&commarea, 0, sizeof commarea);
715 connssl->iocport = QsoCreateIOCompletionPort();
716 if(connssl->iocport != -1) {
717 cc = gskit_status(data, gsk_secure_soc_startInit(connssl->handle,
718 connssl->iocport, &commarea),
719 "gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR);
721 connssl->connecting_state = ssl_connect_2;
725 close_async_handshake(connssl);
727 else if(errno != ENOBUFS)
728 cc = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0);
730 /* No more completion port available. Use synchronous IO. */
731 cc = gskit_status(data, gsk_secure_soc_init(connssl->handle),
732 "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
734 connssl->connecting_state = ssl_connect_3;
740 /* Error: rollback. */
741 close_one(connssl, data);
746 static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
749 struct SessionHandle *data = conn->data;
750 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
751 Qso_OverlappedIO_t cstat;
756 /* Poll or wait for end of SSL asynchronous handshake. */
759 timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
762 stmv.tv_sec = timeout_ms / 1000;
763 stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
764 switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
765 case 1: /* Operation complete. */
767 case -1: /* An error occurred: handshake still in progress. */
771 continue; /* Retry. */
774 failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
775 cancel_async_handshake(conn, sockindex);
776 close_async_handshake(connssl);
777 return CURLE_SSL_CONNECT_ERROR;
780 case 0: /* Handshake in progress, timeout occurred. */
783 cancel_async_handshake(conn, sockindex);
784 close_async_handshake(connssl);
785 return CURLE_OPERATION_TIMEDOUT;
789 cc = gskit_status(data, cstat.returnValue, "SSL handshake",
790 CURLE_SSL_CONNECT_ERROR);
792 connssl->connecting_state = ssl_connect_3;
793 close_async_handshake(connssl);
798 static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
800 struct SessionHandle *data = conn->data;
801 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
802 const gsk_cert_data_elem *cdev;
804 const gsk_cert_data_elem *p;
805 const char *cert = (const char *) NULL;
810 /* SSL handshake done: gather certificate info and verify host. */
812 if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
813 GSK_PARTNER_CERT_INFO,
815 "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
817 infof(data, "Server certificate:\n");
819 for(i = 0; i++ < cdec; p++)
820 switch (p->cert_data_id) {
822 cert = p->cert_data_p;
823 certend = cert + cdev->cert_data_l;
825 case CERT_DN_PRINTABLE:
826 infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
828 case CERT_ISSUER_DN_PRINTABLE:
829 infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
831 case CERT_VALID_FROM:
832 infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
835 infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
841 cc = Curl_verifyhost(conn, cert, certend);
845 /* The only place GSKit can get the whole CA chain is a validation
846 callback where no user data pointer is available. Therefore it's not
847 possible to copy this chain into our structures for CAINFO.
848 However the server certificate may be available, thus we can return
850 if(data->set.ssl.certinfo) {
851 if(Curl_ssl_init_certinfo(data, 1))
852 return CURLE_OUT_OF_MEMORY;
854 cc = Curl_extract_certinfo(conn, 0, cert, certend);
860 connssl->connecting_state = ssl_connect_done;
865 static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
866 bool nonblocking, bool *done)
868 struct SessionHandle *data = conn->data;
869 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
871 Qso_OverlappedIO_t cstat;
872 CURLcode cc = CURLE_OK;
874 *done = connssl->state == ssl_connection_complete;
878 /* Step 1: create session, start handshake. */
879 if(connssl->connecting_state == ssl_connect_1) {
880 /* check allowed time left */
881 timeout_ms = Curl_timeleft(data, NULL, TRUE);
884 /* no need to continue if time already is up */
885 failf(data, "SSL connection timeout");
886 cc = CURLE_OPERATION_TIMEDOUT;
889 cc = gskit_connect_step1(conn, sockindex);
892 /* Step 2: check if handshake is over. */
893 if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_2) {
894 /* check allowed time left */
895 timeout_ms = Curl_timeleft(data, NULL, TRUE);
898 /* no need to continue if time already is up */
899 failf(data, "SSL connection timeout");
900 cc = CURLE_OPERATION_TIMEDOUT;
903 cc = gskit_connect_step2(conn, sockindex, nonblocking);
906 /* Step 3: gather certificate info, verify host. */
907 if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_3)
908 cc = gskit_connect_step3(conn, sockindex);
911 close_one(connssl, data);
912 else if(connssl->connecting_state == ssl_connect_done) {
913 connssl->state = ssl_connection_complete;
914 connssl->connecting_state = ssl_connect_1;
915 conn->recv[sockindex] = gskit_recv;
916 conn->send[sockindex] = gskit_send;
924 CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
930 cc = gskit_connect_common(conn, sockindex, TRUE, done);
931 if(*done || cc != CURLE_OK)
932 conn->ssl[sockindex].connecting_state = ssl_connect_1;
937 CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
942 conn->ssl[sockindex].connecting_state = ssl_connect_1;
943 retcode = gskit_connect_common(conn, sockindex, FALSE, &done);
953 void Curl_gskit_close(struct connectdata *conn, int sockindex)
955 struct SessionHandle *data = conn->data;
956 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
959 close_one(connssl, data);
963 int Curl_gskit_close_all(struct SessionHandle *data)
971 int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
973 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
974 struct SessionHandle *data = conn->data;
983 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
986 close_one(connssl, data);
988 what = Curl_socket_ready(conn->sock[sockindex],
989 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
993 /* anything that gets here is fatally bad */
994 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
999 if(!what) { /* timeout */
1000 failf(data, "SSL shutdown timeout");
1004 /* Something to read, let's do it and hope that it is the close
1005 notify alert from the server. No way to gsk_secure_soc_read() now, so
1008 nread = read(conn->sock[sockindex], buf, sizeof(buf));
1011 failf(data, "read: %s", strerror(errno));
1018 what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
1025 size_t Curl_gskit_version(char *buffer, size_t size)
1027 strncpy(buffer, "GSKit", size);
1028 return strlen(buffer);
1032 int Curl_gskit_check_cxn(struct connectdata *cxn)
1037 /* The only thing that can be tested here is at the socket level. */
1039 if(!cxn->ssl[FIRSTSOCKET].handle)
1040 return 0; /* connection has been closed */
1043 errlen = sizeof err;
1045 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
1046 (unsigned char *) &err, &errlen) ||
1047 errlen != sizeof err || err)
1048 return 0; /* connection has been closed */
1050 return -1; /* connection status unknown */
1053 #endif /* USE_GSKIT */