Return to gskit.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vtls |
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 */