Annotation of embedaddon/curl/lib/vtls/gskit.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
! 9: *
! 10: * This software is licensed as described in the file COPYING, which
! 11: * you should have received as part of this distribution. The terms
! 12: * are also available at https://curl.haxx.se/docs/copyright.html.
! 13: *
! 14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
! 15: * copies of the Software, and permit persons to whom the Software is
! 16: * furnished to do so, under the terms of the COPYING file.
! 17: *
! 18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
! 19: * KIND, either express or implied.
! 20: *
! 21: ***************************************************************************/
! 22:
! 23: #include "curl_setup.h"
! 24:
! 25: #ifdef USE_GSKIT
! 26:
! 27: #include <gskssl.h>
! 28: #include <qsoasync.h>
! 29: #undef HAVE_SOCKETPAIR /* because the native one isn't good enough */
! 30: #include "socketpair.h"
! 31:
! 32: /* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
! 33: #ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
! 34: #define GSK_SSL_EXTN_SERVERNAME_REQUEST 230
! 35: #endif
! 36:
! 37: #ifndef GSK_TLSV10_CIPHER_SPECS
! 38: #define GSK_TLSV10_CIPHER_SPECS 236
! 39: #endif
! 40:
! 41: #ifndef GSK_TLSV11_CIPHER_SPECS
! 42: #define GSK_TLSV11_CIPHER_SPECS 237
! 43: #endif
! 44:
! 45: #ifndef GSK_TLSV12_CIPHER_SPECS
! 46: #define GSK_TLSV12_CIPHER_SPECS 238
! 47: #endif
! 48:
! 49: #ifndef GSK_PROTOCOL_TLSV11
! 50: #define GSK_PROTOCOL_TLSV11 437
! 51: #endif
! 52:
! 53: #ifndef GSK_PROTOCOL_TLSV12
! 54: #define GSK_PROTOCOL_TLSV12 438
! 55: #endif
! 56:
! 57: #ifndef GSK_FALSE
! 58: #define GSK_FALSE 0
! 59: #endif
! 60:
! 61: #ifndef GSK_TRUE
! 62: #define GSK_TRUE 1
! 63: #endif
! 64:
! 65:
! 66: #include <limits.h>
! 67:
! 68: #include <curl/curl.h>
! 69: #include "urldata.h"
! 70: #include "sendf.h"
! 71: #include "gskit.h"
! 72: #include "vtls.h"
! 73: #include "connect.h" /* for the connect timeout */
! 74: #include "select.h"
! 75: #include "strcase.h"
! 76: #include "x509asn1.h"
! 77: #include "curl_printf.h"
! 78:
! 79: #include "curl_memory.h"
! 80: /* The last #include file should be: */
! 81: #include "memdebug.h"
! 82:
! 83:
! 84: /* Directions. */
! 85: #define SOS_READ 0x01
! 86: #define SOS_WRITE 0x02
! 87:
! 88: /* SSL version flags. */
! 89: #define CURL_GSKPROTO_SSLV2 0
! 90: #define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2)
! 91: #define CURL_GSKPROTO_SSLV3 1
! 92: #define CURL_GSKPROTO_SSLV3_MASK (1 << CURL_GSKPROTO_SSLV3)
! 93: #define CURL_GSKPROTO_TLSV10 2
! 94: #define CURL_GSKPROTO_TLSV10_MASK (1 << CURL_GSKPROTO_TLSV10)
! 95: #define CURL_GSKPROTO_TLSV11 3
! 96: #define CURL_GSKPROTO_TLSV11_MASK (1 << CURL_GSKPROTO_TLSV11)
! 97: #define CURL_GSKPROTO_TLSV12 4
! 98: #define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12)
! 99: #define CURL_GSKPROTO_LAST 5
! 100:
! 101: struct 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. */
! 111: typedef 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:
! 117: static 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:
! 163: static 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:
! 178: static 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:
! 221: static 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:
! 243: static 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:
! 265: static 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:
! 285: static 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:
! 304: static 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:
! 438: static int Curl_gskit_init(void)
! 439: {
! 440: /* No initialisation needed. */
! 441:
! 442: return 1;
! 443: }
! 444:
! 445:
! 446: static void Curl_gskit_cleanup(void)
! 447: {
! 448: /* Nothing to do. */
! 449: }
! 450:
! 451:
! 452: static 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:
! 500: static 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:
! 510: static void close_async_handshake(struct ssl_connect_data *connssl)
! 511: {
! 512: QsoDestroyIOCompletionPort(BACKEND->iocport);
! 513: BACKEND->iocport = -1;
! 514: }
! 515:
! 516: static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
! 517: int directions)
! 518: {
! 519: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 520: struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex];
! 521: fd_set fds_read;
! 522: fd_set fds_write;
! 523: int n;
! 524: int m;
! 525: int i;
! 526: int ret = 0;
! 527: char buf[CURL_MAX_WRITE_SIZE];
! 528:
! 529: if(!connssl->use || !connproxyssl->use)
! 530: return 0; /* No SSL over SSL: OK. */
! 531:
! 532: FD_ZERO(&fds_read);
! 533: FD_ZERO(&fds_write);
! 534: n = -1;
! 535: if(directions & SOS_READ) {
! 536: FD_SET(BACKEND->remotefd, &fds_write);
! 537: n = BACKEND->remotefd;
! 538: }
! 539: if(directions & SOS_WRITE) {
! 540: FD_SET(BACKEND->remotefd, &fds_read);
! 541: n = BACKEND->remotefd;
! 542: FD_SET(conn->sock[sockindex], &fds_write);
! 543: if(n < conn->sock[sockindex])
! 544: n = conn->sock[sockindex];
! 545: }
! 546: i = Curl_select(n + 1, &fds_read, &fds_write, NULL, 0);
! 547: if(i < 0)
! 548: return -1; /* Select error. */
! 549:
! 550: if(FD_ISSET(BACKEND->remotefd, &fds_write)) {
! 551: /* Try getting data from HTTPS proxy and pipe it upstream. */
! 552: n = 0;
! 553: i = gsk_secure_soc_read(connproxyssl->backend->handle,
! 554: buf, sizeof(buf), &n);
! 555: switch(i) {
! 556: case GSK_OK:
! 557: if(n) {
! 558: i = write(BACKEND->remotefd, buf, n);
! 559: if(i < 0)
! 560: return -1;
! 561: ret = 1;
! 562: }
! 563: break;
! 564: case GSK_OS400_ERROR_TIMED_OUT:
! 565: case GSK_WOULD_BLOCK:
! 566: break;
! 567: default:
! 568: return -1;
! 569: }
! 570: }
! 571:
! 572: if(FD_ISSET(BACKEND->remotefd, &fds_read) &&
! 573: FD_ISSET(conn->sock[sockindex], &fds_write)) {
! 574: /* Pipe data to HTTPS proxy. */
! 575: n = read(BACKEND->remotefd, buf, sizeof(buf));
! 576: if(n < 0)
! 577: return -1;
! 578: if(n) {
! 579: i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m);
! 580: if(i != GSK_OK || n != m)
! 581: return -1;
! 582: ret = 1;
! 583: }
! 584: }
! 585:
! 586: return ret; /* OK */
! 587: }
! 588:
! 589:
! 590: static void close_one(struct ssl_connect_data *connssl,
! 591: struct connectdata *conn, int sockindex)
! 592: {
! 593: if(BACKEND->handle) {
! 594: gskit_status(conn->data, gsk_secure_soc_close(&BACKEND->handle),
! 595: "gsk_secure_soc_close()", 0);
! 596: /* Last chance to drain output. */
! 597: while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
! 598: ;
! 599: BACKEND->handle = (gsk_handle) NULL;
! 600: if(BACKEND->localfd >= 0) {
! 601: close(BACKEND->localfd);
! 602: BACKEND->localfd = -1;
! 603: }
! 604: if(BACKEND->remotefd >= 0) {
! 605: close(BACKEND->remotefd);
! 606: BACKEND->remotefd = -1;
! 607: }
! 608: }
! 609: if(BACKEND->iocport >= 0)
! 610: close_async_handshake(connssl);
! 611: }
! 612:
! 613:
! 614: static ssize_t gskit_send(struct connectdata *conn, int sockindex,
! 615: const void *mem, size_t len, CURLcode *curlcode)
! 616: {
! 617: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 618: struct Curl_easy *data = conn->data;
! 619: CURLcode cc = CURLE_SEND_ERROR;
! 620: int written;
! 621:
! 622: if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
! 623: cc = gskit_status(data,
! 624: gsk_secure_soc_write(BACKEND->handle,
! 625: (char *) mem, (int) len, &written),
! 626: "gsk_secure_soc_write()", CURLE_SEND_ERROR);
! 627: if(cc == CURLE_OK)
! 628: if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0)
! 629: cc = CURLE_SEND_ERROR;
! 630: }
! 631: if(cc != CURLE_OK) {
! 632: *curlcode = cc;
! 633: written = -1;
! 634: }
! 635: return (ssize_t) written; /* number of bytes */
! 636: }
! 637:
! 638:
! 639: static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
! 640: size_t buffersize, CURLcode *curlcode)
! 641: {
! 642: struct ssl_connect_data *connssl = &conn->ssl[num];
! 643: struct Curl_easy *data = conn->data;
! 644: int nread;
! 645: CURLcode cc = CURLE_RECV_ERROR;
! 646:
! 647: if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
! 648: int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
! 649: cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
! 650: buf, buffsize, &nread),
! 651: "gsk_secure_soc_read()", CURLE_RECV_ERROR);
! 652: }
! 653: switch(cc) {
! 654: case CURLE_OK:
! 655: break;
! 656: case CURLE_OPERATION_TIMEDOUT:
! 657: cc = CURLE_AGAIN;
! 658: default:
! 659: *curlcode = cc;
! 660: nread = -1;
! 661: break;
! 662: }
! 663: return (ssize_t) nread;
! 664: }
! 665:
! 666: static CURLcode
! 667: set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn)
! 668: {
! 669: struct Curl_easy *data = conn->data;
! 670: long ssl_version = SSL_CONN_CONFIG(version);
! 671: long ssl_version_max = SSL_CONN_CONFIG(version_max);
! 672: long i = ssl_version;
! 673: switch(ssl_version_max) {
! 674: case CURL_SSLVERSION_MAX_NONE:
! 675: case CURL_SSLVERSION_MAX_DEFAULT:
! 676: ssl_version_max = CURL_SSLVERSION_TLSv1_2;
! 677: break;
! 678: }
! 679: for(; i <= (ssl_version_max >> 16); ++i) {
! 680: switch(i) {
! 681: case CURL_SSLVERSION_TLSv1_0:
! 682: *protoflags |= CURL_GSKPROTO_TLSV10_MASK;
! 683: break;
! 684: case CURL_SSLVERSION_TLSv1_1:
! 685: *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
! 686: break;
! 687: case CURL_SSLVERSION_TLSv1_2:
! 688: *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
! 689: break;
! 690: case CURL_SSLVERSION_TLSv1_3:
! 691: failf(data, "GSKit: TLS 1.3 is not yet supported");
! 692: return CURLE_SSL_CONNECT_ERROR;
! 693: }
! 694: }
! 695:
! 696: return CURLE_OK;
! 697: }
! 698:
! 699: static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
! 700: {
! 701: struct Curl_easy *data = conn->data;
! 702: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 703: gsk_handle envir;
! 704: CURLcode result;
! 705: int rc;
! 706: const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
! 707: const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
! 708: const char * const keyringlabel = SSL_SET_OPTION(cert);
! 709: const long int ssl_version = SSL_CONN_CONFIG(version);
! 710: const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
! 711: const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
! 712: conn->host.name;
! 713: const char *sni;
! 714: unsigned int protoflags = 0;
! 715: Qso_OverlappedIO_t commarea;
! 716: int sockpair[2];
! 717: static const int sobufsize = CURL_MAX_WRITE_SIZE;
! 718:
! 719: /* Create SSL environment, start (preferably asynchronous) handshake. */
! 720:
! 721: BACKEND->handle = (gsk_handle) NULL;
! 722: BACKEND->iocport = -1;
! 723: BACKEND->localfd = -1;
! 724: BACKEND->remotefd = -1;
! 725:
! 726: /* GSKit supports two ways of specifying an SSL context: either by
! 727: * application identifier (that should have been defined at the system
! 728: * level) or by keyring file, password and certificate label.
! 729: * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
! 730: * application identifier of the certificate label.
! 731: * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
! 732: * It is not possible to have different keyrings for the CAs and the
! 733: * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
! 734: * the keyring file.
! 735: * If no key password is given and the keyring is the system keyring,
! 736: * application identifier mode is tried first, as recommended in IBM doc.
! 737: */
! 738:
! 739: envir = (gsk_handle) NULL;
! 740:
! 741: if(keyringlabel && *keyringlabel && !keyringpwd &&
! 742: !strcmp(keyringfile, CURL_CA_BUNDLE)) {
! 743: /* Try application identifier mode. */
! 744: init_environment(data, &envir, keyringlabel, (const char *) NULL,
! 745: (const char *) NULL, (const char *) NULL);
! 746: }
! 747:
! 748: if(!envir) {
! 749: /* Use keyring mode. */
! 750: result = init_environment(data, &envir, (const char *) NULL,
! 751: keyringfile, keyringlabel, keyringpwd);
! 752: if(result)
! 753: return result;
! 754: }
! 755:
! 756: /* Create secure session. */
! 757: result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle),
! 758: "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
! 759: gsk_environment_close(&envir);
! 760: if(result)
! 761: return result;
! 762:
! 763: /* Establish a pipelining socket pair for SSL over SSL. */
! 764: if(conn->proxy_ssl[sockindex].use) {
! 765: if(Curl_socketpair(0, 0, 0, sockpair))
! 766: return CURLE_SSL_CONNECT_ERROR;
! 767: BACKEND->localfd = sockpair[0];
! 768: BACKEND->remotefd = sockpair[1];
! 769: setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF,
! 770: (void *) sobufsize, sizeof(sobufsize));
! 771: setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF,
! 772: (void *) sobufsize, sizeof(sobufsize));
! 773: setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF,
! 774: (void *) sobufsize, sizeof(sobufsize));
! 775: setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF,
! 776: (void *) sobufsize, sizeof(sobufsize));
! 777: curlx_nonblock(BACKEND->localfd, TRUE);
! 778: curlx_nonblock(BACKEND->remotefd, TRUE);
! 779: }
! 780:
! 781: /* Determine which SSL/TLS version should be enabled. */
! 782: sni = hostname;
! 783: switch(ssl_version) {
! 784: case CURL_SSLVERSION_SSLv2:
! 785: protoflags = CURL_GSKPROTO_SSLV2_MASK;
! 786: sni = NULL;
! 787: break;
! 788: case CURL_SSLVERSION_SSLv3:
! 789: protoflags = CURL_GSKPROTO_SSLV3_MASK;
! 790: sni = NULL;
! 791: break;
! 792: case CURL_SSLVERSION_DEFAULT:
! 793: case CURL_SSLVERSION_TLSv1:
! 794: protoflags = CURL_GSKPROTO_TLSV10_MASK |
! 795: CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
! 796: break;
! 797: case CURL_SSLVERSION_TLSv1_0:
! 798: case CURL_SSLVERSION_TLSv1_1:
! 799: case CURL_SSLVERSION_TLSv1_2:
! 800: case CURL_SSLVERSION_TLSv1_3:
! 801: result = set_ssl_version_min_max(&protoflags, conn);
! 802: if(result != CURLE_OK)
! 803: return result;
! 804: break;
! 805: default:
! 806: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
! 807: return CURLE_SSL_CONNECT_ERROR;
! 808: }
! 809:
! 810: /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
! 811: if(sni) {
! 812: result = set_buffer(data, BACKEND->handle,
! 813: GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
! 814: if(result == CURLE_UNSUPPORTED_PROTOCOL)
! 815: result = CURLE_OK;
! 816: }
! 817:
! 818: /* Set session parameters. */
! 819: if(!result) {
! 820: /* Compute the handshake timeout. Since GSKit granularity is 1 second,
! 821: we round up the required value. */
! 822: long timeout = Curl_timeleft(data, NULL, TRUE);
! 823: if(timeout < 0)
! 824: result = CURLE_OPERATION_TIMEDOUT;
! 825: else
! 826: result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT,
! 827: (timeout + 999) / 1000);
! 828: }
! 829: if(!result)
! 830: result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
! 831: if(!result)
! 832: result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
! 833: BACKEND->localfd: conn->sock[sockindex]);
! 834: if(!result)
! 835: result = set_ciphers(conn, BACKEND->handle, &protoflags);
! 836: if(!protoflags) {
! 837: failf(data, "No SSL protocol/cipher combination enabled");
! 838: result = CURLE_SSL_CIPHER;
! 839: }
! 840: if(!result)
! 841: result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2,
! 842: (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
! 843: GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
! 844: if(!result)
! 845: result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3,
! 846: (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
! 847: GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
! 848: if(!result)
! 849: result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1,
! 850: (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
! 851: GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
! 852: if(!result) {
! 853: result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11,
! 854: (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
! 855: GSK_TRUE: GSK_FALSE, TRUE);
! 856: if(result == CURLE_UNSUPPORTED_PROTOCOL) {
! 857: result = CURLE_OK;
! 858: if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
! 859: failf(data, "TLS 1.1 not yet supported");
! 860: result = CURLE_SSL_CIPHER;
! 861: }
! 862: }
! 863: }
! 864: if(!result) {
! 865: result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12,
! 866: (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
! 867: GSK_TRUE: GSK_FALSE, TRUE);
! 868: if(result == CURLE_UNSUPPORTED_PROTOCOL) {
! 869: result = CURLE_OK;
! 870: if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
! 871: failf(data, "TLS 1.2 not yet supported");
! 872: result = CURLE_SSL_CIPHER;
! 873: }
! 874: }
! 875: }
! 876: if(!result)
! 877: result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE,
! 878: verifypeer? GSK_SERVER_AUTH_FULL:
! 879: GSK_SERVER_AUTH_PASSTHRU, FALSE);
! 880:
! 881: if(!result) {
! 882: /* Start handshake. Try asynchronous first. */
! 883: memset(&commarea, 0, sizeof(commarea));
! 884: BACKEND->iocport = QsoCreateIOCompletionPort();
! 885: if(BACKEND->iocport != -1) {
! 886: result = gskit_status(data,
! 887: gsk_secure_soc_startInit(BACKEND->handle,
! 888: BACKEND->iocport,
! 889: &commarea),
! 890: "gsk_secure_soc_startInit()",
! 891: CURLE_SSL_CONNECT_ERROR);
! 892: if(!result) {
! 893: connssl->connecting_state = ssl_connect_2;
! 894: return CURLE_OK;
! 895: }
! 896: else
! 897: close_async_handshake(connssl);
! 898: }
! 899: else if(errno != ENOBUFS)
! 900: result = gskit_status(data, GSK_ERROR_IO,
! 901: "QsoCreateIOCompletionPort()", 0);
! 902: else if(conn->proxy_ssl[sockindex].use) {
! 903: /* Cannot pipeline while handshaking synchronously. */
! 904: result = CURLE_SSL_CONNECT_ERROR;
! 905: }
! 906: else {
! 907: /* No more completion port available. Use synchronous IO. */
! 908: result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
! 909: "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
! 910: if(!result) {
! 911: connssl->connecting_state = ssl_connect_3;
! 912: return CURLE_OK;
! 913: }
! 914: }
! 915: }
! 916:
! 917: /* Error: rollback. */
! 918: close_one(connssl, conn, sockindex);
! 919: return result;
! 920: }
! 921:
! 922:
! 923: static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
! 924: bool nonblocking)
! 925: {
! 926: struct Curl_easy *data = conn->data;
! 927: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 928: Qso_OverlappedIO_t cstat;
! 929: struct timeval stmv;
! 930: CURLcode result;
! 931:
! 932: /* Poll or wait for end of SSL asynchronous handshake. */
! 933:
! 934: for(;;) {
! 935: long timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
! 936: if(timeout_ms < 0)
! 937: timeout_ms = 0;
! 938: stmv.tv_sec = timeout_ms / 1000;
! 939: stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
! 940: switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat, &stmv)) {
! 941: case 1: /* Operation complete. */
! 942: break;
! 943: case -1: /* An error occurred: handshake still in progress. */
! 944: if(errno == EINTR) {
! 945: if(nonblocking)
! 946: return CURLE_OK;
! 947: continue; /* Retry. */
! 948: }
! 949: if(errno != ETIME) {
! 950: failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
! 951: cancel_async_handshake(conn, sockindex);
! 952: close_async_handshake(connssl);
! 953: return CURLE_SSL_CONNECT_ERROR;
! 954: }
! 955: /* FALL INTO... */
! 956: case 0: /* Handshake in progress, timeout occurred. */
! 957: if(nonblocking)
! 958: return CURLE_OK;
! 959: cancel_async_handshake(conn, sockindex);
! 960: close_async_handshake(connssl);
! 961: return CURLE_OPERATION_TIMEDOUT;
! 962: }
! 963: break;
! 964: }
! 965: result = gskit_status(data, cstat.returnValue, "SSL handshake",
! 966: CURLE_SSL_CONNECT_ERROR);
! 967: if(!result)
! 968: connssl->connecting_state = ssl_connect_3;
! 969: close_async_handshake(connssl);
! 970: return result;
! 971: }
! 972:
! 973:
! 974: static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
! 975: {
! 976: struct Curl_easy *data = conn->data;
! 977: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 978: const gsk_cert_data_elem *cdev;
! 979: int cdec;
! 980: const gsk_cert_data_elem *p;
! 981: const char *cert = (const char *) NULL;
! 982: const char *certend;
! 983: const char *ptr;
! 984: CURLcode result;
! 985:
! 986: /* SSL handshake done: gather certificate info and verify host. */
! 987:
! 988: if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle,
! 989: GSK_PARTNER_CERT_INFO,
! 990: &cdev, &cdec),
! 991: "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
! 992: CURLE_OK) {
! 993: int i;
! 994:
! 995: infof(data, "Server certificate:\n");
! 996: p = cdev;
! 997: for(i = 0; i++ < cdec; p++)
! 998: switch(p->cert_data_id) {
! 999: case CERT_BODY_DER:
! 1000: cert = p->cert_data_p;
! 1001: certend = cert + cdev->cert_data_l;
! 1002: break;
! 1003: case CERT_DN_PRINTABLE:
! 1004: infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
! 1005: break;
! 1006: case CERT_ISSUER_DN_PRINTABLE:
! 1007: infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
! 1008: break;
! 1009: case CERT_VALID_FROM:
! 1010: infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
! 1011: break;
! 1012: case CERT_VALID_TO:
! 1013: infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
! 1014: break;
! 1015: }
! 1016: }
! 1017:
! 1018: /* Verify host. */
! 1019: result = Curl_verifyhost(conn, cert, certend);
! 1020: if(result)
! 1021: return result;
! 1022:
! 1023: /* The only place GSKit can get the whole CA chain is a validation
! 1024: callback where no user data pointer is available. Therefore it's not
! 1025: possible to copy this chain into our structures for CAINFO.
! 1026: However the server certificate may be available, thus we can return
! 1027: info about it. */
! 1028: if(data->set.ssl.certinfo) {
! 1029: result = Curl_ssl_init_certinfo(data, 1);
! 1030: if(result)
! 1031: return result;
! 1032:
! 1033: if(cert) {
! 1034: result = Curl_extract_certinfo(conn, 0, cert, certend);
! 1035: if(result)
! 1036: return result;
! 1037: }
! 1038: }
! 1039:
! 1040: /* Check pinned public key. */
! 1041: ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
! 1042: data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
! 1043: if(!result && ptr) {
! 1044: curl_X509certificate x509;
! 1045: curl_asn1Element *p;
! 1046:
! 1047: if(Curl_parseX509(&x509, cert, certend))
! 1048: return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
! 1049: p = &x509.subjectPublicKeyInfo;
! 1050: result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
! 1051: if(result) {
! 1052: failf(data, "SSL: public key does not match pinned public key!");
! 1053: return result;
! 1054: }
! 1055: }
! 1056:
! 1057: connssl->connecting_state = ssl_connect_done;
! 1058: return CURLE_OK;
! 1059: }
! 1060:
! 1061:
! 1062: static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
! 1063: bool nonblocking, bool *done)
! 1064: {
! 1065: struct Curl_easy *data = conn->data;
! 1066: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 1067: timediff_t timeout_ms;
! 1068: CURLcode result = CURLE_OK;
! 1069:
! 1070: *done = connssl->state == ssl_connection_complete;
! 1071: if(*done)
! 1072: return CURLE_OK;
! 1073:
! 1074: /* Step 1: create session, start handshake. */
! 1075: if(connssl->connecting_state == ssl_connect_1) {
! 1076: /* check allowed time left */
! 1077: timeout_ms = Curl_timeleft(data, NULL, TRUE);
! 1078:
! 1079: if(timeout_ms < 0) {
! 1080: /* no need to continue if time already is up */
! 1081: failf(data, "SSL connection timeout");
! 1082: result = CURLE_OPERATION_TIMEDOUT;
! 1083: }
! 1084: else
! 1085: result = gskit_connect_step1(conn, sockindex);
! 1086: }
! 1087:
! 1088: /* Handle handshake pipelining. */
! 1089: if(!result)
! 1090: if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
! 1091: result = CURLE_SSL_CONNECT_ERROR;
! 1092:
! 1093: /* Step 2: check if handshake is over. */
! 1094: if(!result && connssl->connecting_state == ssl_connect_2) {
! 1095: /* check allowed time left */
! 1096: timeout_ms = Curl_timeleft(data, NULL, TRUE);
! 1097:
! 1098: if(timeout_ms < 0) {
! 1099: /* no need to continue if time already is up */
! 1100: failf(data, "SSL connection timeout");
! 1101: result = CURLE_OPERATION_TIMEDOUT;
! 1102: }
! 1103: else
! 1104: result = gskit_connect_step2(conn, sockindex, nonblocking);
! 1105: }
! 1106:
! 1107: /* Handle handshake pipelining. */
! 1108: if(!result)
! 1109: if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
! 1110: result = CURLE_SSL_CONNECT_ERROR;
! 1111:
! 1112: /* Step 3: gather certificate info, verify host. */
! 1113: if(!result && connssl->connecting_state == ssl_connect_3)
! 1114: result = gskit_connect_step3(conn, sockindex);
! 1115:
! 1116: if(result)
! 1117: close_one(connssl, conn, sockindex);
! 1118: else if(connssl->connecting_state == ssl_connect_done) {
! 1119: connssl->state = ssl_connection_complete;
! 1120: connssl->connecting_state = ssl_connect_1;
! 1121: conn->recv[sockindex] = gskit_recv;
! 1122: conn->send[sockindex] = gskit_send;
! 1123: *done = TRUE;
! 1124: }
! 1125:
! 1126: return result;
! 1127: }
! 1128:
! 1129:
! 1130: static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
! 1131: int sockindex, bool *done)
! 1132: {
! 1133: CURLcode result;
! 1134:
! 1135: result = gskit_connect_common(conn, sockindex, TRUE, done);
! 1136: if(*done || result)
! 1137: conn->ssl[sockindex].connecting_state = ssl_connect_1;
! 1138: return result;
! 1139: }
! 1140:
! 1141:
! 1142: static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
! 1143: {
! 1144: CURLcode result;
! 1145: bool done;
! 1146:
! 1147: conn->ssl[sockindex].connecting_state = ssl_connect_1;
! 1148: result = gskit_connect_common(conn, sockindex, FALSE, &done);
! 1149: if(result)
! 1150: return result;
! 1151:
! 1152: DEBUGASSERT(done);
! 1153:
! 1154: return CURLE_OK;
! 1155: }
! 1156:
! 1157:
! 1158: static void Curl_gskit_close(struct connectdata *conn, int sockindex)
! 1159: {
! 1160: close_one(&conn->ssl[sockindex], conn, sockindex);
! 1161: close_one(&conn->proxy_ssl[sockindex], conn, sockindex);
! 1162: }
! 1163:
! 1164:
! 1165: static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
! 1166: {
! 1167: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 1168: struct Curl_easy *data = conn->data;
! 1169: int what;
! 1170: int rc;
! 1171: char buf[120];
! 1172:
! 1173: if(!BACKEND->handle)
! 1174: return 0;
! 1175:
! 1176: #ifndef CURL_DISABLE_FTP
! 1177: if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
! 1178: return 0;
! 1179: #endif
! 1180:
! 1181: close_one(connssl, conn, sockindex);
! 1182: rc = 0;
! 1183: what = SOCKET_READABLE(conn->sock[sockindex],
! 1184: SSL_SHUTDOWN_TIMEOUT);
! 1185:
! 1186: for(;;) {
! 1187: ssize_t nread;
! 1188:
! 1189: if(what < 0) {
! 1190: /* anything that gets here is fatally bad */
! 1191: failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
! 1192: rc = -1;
! 1193: break;
! 1194: }
! 1195:
! 1196: if(!what) { /* timeout */
! 1197: failf(data, "SSL shutdown timeout");
! 1198: break;
! 1199: }
! 1200:
! 1201: /* Something to read, let's do it and hope that it is the close
! 1202: notify alert from the server. No way to gsk_secure_soc_read() now, so
! 1203: use read(). */
! 1204:
! 1205: nread = read(conn->sock[sockindex], buf, sizeof(buf));
! 1206:
! 1207: if(nread < 0) {
! 1208: failf(data, "read: %s", strerror(errno));
! 1209: rc = -1;
! 1210: }
! 1211:
! 1212: if(nread <= 0)
! 1213: break;
! 1214:
! 1215: what = SOCKET_READABLE(conn->sock[sockindex], 0);
! 1216: }
! 1217:
! 1218: return rc;
! 1219: }
! 1220:
! 1221:
! 1222: static size_t Curl_gskit_version(char *buffer, size_t size)
! 1223: {
! 1224: return msnprintf(buffer, size, "GSKit");
! 1225: }
! 1226:
! 1227:
! 1228: static int Curl_gskit_check_cxn(struct connectdata *cxn)
! 1229: {
! 1230: struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET];
! 1231: int err;
! 1232: int errlen;
! 1233:
! 1234: /* The only thing that can be tested here is at the socket level. */
! 1235:
! 1236: if(!BACKEND->handle)
! 1237: return 0; /* connection has been closed */
! 1238:
! 1239: err = 0;
! 1240: errlen = sizeof(err);
! 1241:
! 1242: if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
! 1243: (unsigned char *) &err, &errlen) ||
! 1244: errlen != sizeof(err) || err)
! 1245: return 0; /* connection has been closed */
! 1246:
! 1247: return -1; /* connection status unknown */
! 1248: }
! 1249:
! 1250: static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl,
! 1251: CURLINFO info UNUSED_PARAM)
! 1252: {
! 1253: (void)info;
! 1254: return BACKEND->handle;
! 1255: }
! 1256:
! 1257: const struct Curl_ssl Curl_ssl_gskit = {
! 1258: { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */
! 1259:
! 1260: SSLSUPP_CERTINFO |
! 1261: SSLSUPP_PINNEDPUBKEY,
! 1262:
! 1263: sizeof(struct ssl_backend_data),
! 1264:
! 1265: Curl_gskit_init, /* init */
! 1266: Curl_gskit_cleanup, /* cleanup */
! 1267: Curl_gskit_version, /* version */
! 1268: Curl_gskit_check_cxn, /* check_cxn */
! 1269: Curl_gskit_shutdown, /* shutdown */
! 1270: Curl_none_data_pending, /* data_pending */
! 1271: Curl_none_random, /* random */
! 1272: Curl_none_cert_status_request, /* cert_status_request */
! 1273: Curl_gskit_connect, /* connect */
! 1274: Curl_gskit_connect_nonblocking, /* connect_nonblocking */
! 1275: Curl_gskit_get_internals, /* get_internals */
! 1276: Curl_gskit_close, /* close_one */
! 1277: Curl_none_close_all, /* close_all */
! 1278: /* No session handling for GSKit */
! 1279: Curl_none_session_free, /* session_free */
! 1280: Curl_none_set_engine, /* set_engine */
! 1281: Curl_none_set_engine_default, /* set_engine_default */
! 1282: Curl_none_engines_list, /* engines_list */
! 1283: Curl_none_false_start, /* false_start */
! 1284: Curl_none_md5sum, /* md5sum */
! 1285: NULL /* sha256sum */
! 1286: };
! 1287:
! 1288: #endif /* USE_GSKIT */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>