Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/vtls/gskit.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*************************************************************************** | |
| 2 * _ _ ____ _ | |
| 3 * Project ___| | | | _ \| | | |
| 4 * / __| | | | |_) | | | |
| 5 * | (__| |_| | _ <| |___ | |
| 6 * \___|\___/|_| \_\_____| | |
| 7 * | |
| 8 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. | |
| 9 * | |
| 10 * This software is licensed as described in the file COPYING, which | |
| 11 * you should have received as part of this distribution. The terms | |
| 12 * are also available at https://curl.haxx.se/docs/copyright.html. | |
| 13 * | |
| 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell | |
| 15 * copies of the Software, and permit persons to whom the Software is | |
| 16 * furnished to do so, under the terms of the COPYING file. | |
| 17 * | |
| 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | |
| 19 * KIND, either express or implied. | |
| 20 * | |
| 21 ***************************************************************************/ | |
| 22 | |
| 23 #include "curl_setup.h" | |
| 24 | |
| 25 #ifdef USE_GSKIT | |
| 26 | |
| 27 #include <gskssl.h> | |
| 28 #include <qsoasync.h> | |
| 29 | |
| 30 /* Some symbols are undefined/unsupported on OS400 versions < V7R1. */ | |
| 31 #ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST | |
| 32 #define GSK_SSL_EXTN_SERVERNAME_REQUEST 230 | |
| 33 #endif | |
| 34 | |
| 35 #ifndef GSK_TLSV10_CIPHER_SPECS | |
| 36 #define GSK_TLSV10_CIPHER_SPECS 236 | |
| 37 #endif | |
| 38 | |
| 39 #ifndef GSK_TLSV11_CIPHER_SPECS | |
| 40 #define GSK_TLSV11_CIPHER_SPECS 237 | |
| 41 #endif | |
| 42 | |
| 43 #ifndef GSK_TLSV12_CIPHER_SPECS | |
| 44 #define GSK_TLSV12_CIPHER_SPECS 238 | |
| 45 #endif | |
| 46 | |
| 47 #ifndef GSK_PROTOCOL_TLSV11 | |
| 48 #define GSK_PROTOCOL_TLSV11 437 | |
| 49 #endif | |
| 50 | |
| 51 #ifndef GSK_PROTOCOL_TLSV12 | |
| 52 #define GSK_PROTOCOL_TLSV12 438 | |
| 53 #endif | |
| 54 | |
| 55 #ifndef GSK_FALSE | |
| 56 #define GSK_FALSE 0 | |
| 57 #endif | |
| 58 | |
| 59 #ifndef GSK_TRUE | |
| 60 #define GSK_TRUE 1 | |
| 61 #endif | |
| 62 | |
| 63 | |
| 64 #include <limits.h> | |
| 65 | |
| 66 #include <curl/curl.h> | |
| 67 #include "urldata.h" | |
| 68 #include "sendf.h" | |
| 69 #include "gskit.h" | |
| 70 #include "vtls.h" | |
| 71 #include "connect.h" /* for the connect timeout */ | |
| 72 #include "select.h" | |
| 73 #include "strcase.h" | |
| 74 #include "x509asn1.h" | |
| 75 #include "curl_printf.h" | |
| 76 | |
| 77 #include "curl_memory.h" | |
| 78 /* The last #include file should be: */ | |
| 79 #include "memdebug.h" | |
| 80 | |
| 81 | |
| 82 /* Directions. */ | |
| 83 #define SOS_READ 0x01 | |
| 84 #define SOS_WRITE 0x02 | |
| 85 | |
| 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 | |
| 98 | |
| 99 struct ssl_backend_data { | |
| 100 gsk_handle handle; | |
| 101 int iocport; | |
| 102 int localfd; | |
| 103 int remotefd; | |
| 104 }; | |
| 105 | |
| 106 #define BACKEND connssl->backend | |
| 107 | |
| 108 /* Supported ciphers. */ | |
| 109 typedef struct { | |
| 110 const char *name; /* Cipher name. */ | |
| 111 const char *gsktoken; /* Corresponding token for GSKit String. */ | |
| 112 unsigned int versions; /* SSL version flags. */ | |
| 113 } gskit_cipher; | |
| 114 | |
| 115 static const gskit_cipher ciphertable[] = { | |
| 116 { "null-md5", "01", | |
| 117 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | | |
| 118 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, | |
| 119 { "null-sha", "02", | |
| 120 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | | |
| 121 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, | |
| 122 { "exp-rc4-md5", "03", | |
| 123 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK }, | |
| 124 { "rc4-md5", "04", | |
| 125 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | | |
| 126 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, | |
| 127 { "rc4-sha", "05", | |
| 128 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | | |
| 129 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, | |
| 130 { "exp-rc2-cbc-md5", "06", | |
| 131 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK }, | |
| 132 { "exp-des-cbc-sha", "09", | |
| 133 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | | |
| 134 CURL_GSKPROTO_TLSV11_MASK }, | |
| 135 { "des-cbc3-sha", "0A", | |
| 136 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | | |
| 137 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, | |
| 138 { "aes128-sha", "2F", | |
| 139 CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | | |
| 140 CURL_GSKPROTO_TLSV12_MASK }, | |
| 141 { "aes256-sha", "35", | |
| 142 CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | | |
| 143 CURL_GSKPROTO_TLSV12_MASK }, | |
| 144 { "null-sha256", "3B", CURL_GSKPROTO_TLSV12_MASK }, | |
| 145 { "aes128-sha256", "3C", CURL_GSKPROTO_TLSV12_MASK }, | |
| 146 { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK }, | |
| 147 { "aes128-gcm-sha256", | |
| 148 "9C", CURL_GSKPROTO_TLSV12_MASK }, | |
| 149 { "aes256-gcm-sha384", | |
| 150 "9D", CURL_GSKPROTO_TLSV12_MASK }, | |
| 151 { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK }, | |
| 152 { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK }, | |
| 153 { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK }, | |
| 154 { "exp-rc2-md5", "4", CURL_GSKPROTO_SSLV2_MASK }, | |
| 155 { "des-cbc-md5", "6", CURL_GSKPROTO_SSLV2_MASK }, | |
| 156 { "des-cbc3-md5", "7", CURL_GSKPROTO_SSLV2_MASK }, | |
| 157 { (const char *) NULL, (const char *) NULL, 0 } | |
| 158 }; | |
| 159 | |
| 160 | |
| 161 static bool is_separator(char c) | |
| 162 { | |
| 163 /* Return whether character is a cipher list separator. */ | |
| 164 switch(c) { | |
| 165 case ' ': | |
| 166 case '\t': | |
| 167 case ':': | |
| 168 case ',': | |
| 169 case ';': | |
| 170 return true; | |
| 171 } | |
| 172 return false; | |
| 173 } | |
| 174 | |
| 175 | |
| 176 static CURLcode gskit_status(struct Curl_easy *data, int rc, | |
| 177 const char *procname, CURLcode defcode) | |
| 178 { | |
| 179 /* Process GSKit status and map it to a CURLcode. */ | |
| 180 switch(rc) { | |
| 181 case GSK_OK: | |
| 182 case GSK_OS400_ASYNCHRONOUS_SOC_INIT: | |
| 183 return CURLE_OK; | |
| 184 case GSK_KEYRING_OPEN_ERROR: | |
| 185 case GSK_OS400_ERROR_NO_ACCESS: | |
| 186 return CURLE_SSL_CACERT_BADFILE; | |
| 187 case GSK_INSUFFICIENT_STORAGE: | |
| 188 return CURLE_OUT_OF_MEMORY; | |
| 189 case GSK_ERROR_BAD_V2_CIPHER: | |
| 190 case GSK_ERROR_BAD_V3_CIPHER: | |
| 191 case GSK_ERROR_NO_CIPHERS: | |
| 192 return CURLE_SSL_CIPHER; | |
| 193 case GSK_OS400_ERROR_NOT_TRUSTED_ROOT: | |
| 194 case GSK_ERROR_CERT_VALIDATION: | |
| 195 return CURLE_PEER_FAILED_VERIFICATION; | |
| 196 case GSK_OS400_ERROR_TIMED_OUT: | |
| 197 return CURLE_OPERATION_TIMEDOUT; | |
| 198 case GSK_WOULD_BLOCK: | |
| 199 return CURLE_AGAIN; | |
| 200 case GSK_OS400_ERROR_NOT_REGISTERED: | |
| 201 break; | |
| 202 case GSK_ERROR_IO: | |
| 203 switch(errno) { | |
| 204 case ENOMEM: | |
| 205 return CURLE_OUT_OF_MEMORY; | |
| 206 default: | |
| 207 failf(data, "%s I/O error: %s", procname, strerror(errno)); | |
| 208 break; | |
| 209 } | |
| 210 break; | |
| 211 default: | |
| 212 failf(data, "%s: %s", procname, gsk_strerror(rc)); | |
| 213 break; | |
| 214 } | |
| 215 return defcode; | |
| 216 } | |
| 217 | |
| 218 | |
| 219 static CURLcode set_enum(struct Curl_easy *data, gsk_handle h, | |
| 220 GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok) | |
| 221 { | |
| 222 int rc = gsk_attribute_set_enum(h, id, value); | |
| 223 | |
| 224 switch(rc) { | |
| 225 case GSK_OK: | |
| 226 return CURLE_OK; | |
| 227 case GSK_ERROR_IO: | |
| 228 failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno)); | |
| 229 break; | |
| 230 case GSK_ATTRIBUTE_INVALID_ID: | |
| 231 if(unsupported_ok) | |
| 232 return CURLE_UNSUPPORTED_PROTOCOL; | |
| 233 default: | |
| 234 failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc)); | |
| 235 break; | |
| 236 } | |
| 237 return CURLE_SSL_CONNECT_ERROR; | |
| 238 } | |
| 239 | |
| 240 | |
| 241 static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h, | |
| 242 GSK_BUF_ID id, const char *buffer, bool unsupported_ok) | |
| 243 { | |
| 244 int rc = gsk_attribute_set_buffer(h, id, buffer, 0); | |
| 245 | |
| 246 switch(rc) { | |
| 247 case GSK_OK: | |
| 248 return CURLE_OK; | |
| 249 case GSK_ERROR_IO: | |
| 250 failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno)); | |
| 251 break; | |
| 252 case GSK_ATTRIBUTE_INVALID_ID: | |
| 253 if(unsupported_ok) | |
| 254 return CURLE_UNSUPPORTED_PROTOCOL; | |
| 255 default: | |
| 256 failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc)); | |
| 257 break; | |
| 258 } | |
| 259 return CURLE_SSL_CONNECT_ERROR; | |
| 260 } | |
| 261 | |
| 262 | |
| 263 static CURLcode set_numeric(struct Curl_easy *data, | |
| 264 gsk_handle h, GSK_NUM_ID id, int value) | |
| 265 { | |
| 266 int rc = gsk_attribute_set_numeric_value(h, id, value); | |
| 267 | |
| 268 switch(rc) { | |
| 269 case GSK_OK: | |
| 270 return CURLE_OK; | |
| 271 case GSK_ERROR_IO: | |
| 272 failf(data, "gsk_attribute_set_numeric_value() I/O error: %s", | |
| 273 strerror(errno)); | |
| 274 break; | |
| 275 default: | |
| 276 failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc)); | |
| 277 break; | |
| 278 } | |
| 279 return CURLE_SSL_CONNECT_ERROR; | |
| 280 } | |
| 281 | |
| 282 | |
| 283 static CURLcode set_callback(struct Curl_easy *data, | |
| 284 gsk_handle h, GSK_CALLBACK_ID id, void *info) | |
| 285 { | |
| 286 int rc = gsk_attribute_set_callback(h, id, info); | |
| 287 | |
| 288 switch(rc) { | |
| 289 case GSK_OK: | |
| 290 return CURLE_OK; | |
| 291 case GSK_ERROR_IO: | |
| 292 failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno)); | |
| 293 break; | |
| 294 default: | |
| 295 failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc)); | |
| 296 break; | |
| 297 } | |
| 298 return CURLE_SSL_CONNECT_ERROR; | |
| 299 } | |
| 300 | |
| 301 | |
| 302 static CURLcode set_ciphers(struct connectdata *conn, | |
| 303 gsk_handle h, unsigned int *protoflags) | |
| 304 { | |
| 305 struct Curl_easy *data = conn->data; | |
| 306 const char *cipherlist = SSL_CONN_CONFIG(cipher_list); | |
| 307 const char *clp; | |
| 308 const gskit_cipher *ctp; | |
| 309 int i; | |
| 310 int l; | |
| 311 bool unsupported; | |
| 312 CURLcode result; | |
| 313 struct { | |
| 314 char *buf; | |
| 315 char *ptr; | |
| 316 } ciphers[CURL_GSKPROTO_LAST]; | |
| 317 | |
| 318 /* Compile cipher list into GSKit-compatible cipher lists. */ | |
| 319 | |
| 320 if(!cipherlist) | |
| 321 return CURLE_OK; | |
| 322 while(is_separator(*cipherlist)) /* Skip initial separators. */ | |
| 323 cipherlist++; | |
| 324 if(!*cipherlist) | |
| 325 return CURLE_OK; | |
| 326 | |
| 327 /* We allocate GSKit buffers of the same size as the input string: since | |
| 328 GSKit tokens are always shorter than their cipher names, allocated buffers | |
| 329 will always be large enough to accommodate the result. */ | |
| 330 l = strlen(cipherlist) + 1; | |
| 331 memset((char *) ciphers, 0, sizeof(ciphers)); | |
| 332 for(i = 0; i < CURL_GSKPROTO_LAST; i++) { | |
| 333 ciphers[i].buf = malloc(l); | |
| 334 if(!ciphers[i].buf) { | |
| 335 while(i--) | |
| 336 free(ciphers[i].buf); | |
| 337 return CURLE_OUT_OF_MEMORY; | |
| 338 } | |
| 339 ciphers[i].ptr = ciphers[i].buf; | |
| 340 *ciphers[i].ptr = '\0'; | |
| 341 } | |
| 342 | |
| 343 /* Process each cipher in input string. */ | |
| 344 unsupported = FALSE; | |
| 345 result = CURLE_OK; | |
| 346 for(;;) { | |
| 347 for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);) | |
| 348 cipherlist++; | |
| 349 l = cipherlist - clp; | |
| 350 if(!l) | |
| 351 break; | |
| 352 /* Search the cipher in our table. */ | |
| 353 for(ctp = ciphertable; ctp->name; ctp++) | |
| 354 if(strncasecompare(ctp->name, clp, l) && !ctp->name[l]) | |
| 355 break; | |
| 356 if(!ctp->name) { | |
| 357 failf(data, "Unknown cipher %.*s", l, clp); | |
| 358 result = CURLE_SSL_CIPHER; | |
| 359 } | |
| 360 else { | |
| 361 unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK | | |
| 362 CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK)); | |
| 363 for(i = 0; i < CURL_GSKPROTO_LAST; i++) { | |
| 364 if(ctp->versions & (1 << i)) { | |
| 365 strcpy(ciphers[i].ptr, ctp->gsktoken); | |
| 366 ciphers[i].ptr += strlen(ctp->gsktoken); | |
| 367 } | |
| 368 } | |
| 369 } | |
| 370 | |
| 371 /* Advance to next cipher name or end of string. */ | |
| 372 while(is_separator(*cipherlist)) | |
| 373 cipherlist++; | |
| 374 } | |
| 375 | |
| 376 /* Disable protocols with empty cipher lists. */ | |
| 377 for(i = 0; i < CURL_GSKPROTO_LAST; i++) { | |
| 378 if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) { | |
| 379 *protoflags &= ~(1 << i); | |
| 380 ciphers[i].buf[0] = '\0'; | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */ | |
| 385 if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) { | |
| 386 result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS, | |
| 387 ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE); | |
| 388 if(result == CURLE_UNSUPPORTED_PROTOCOL) { | |
| 389 result = CURLE_OK; | |
| 390 if(unsupported) { | |
| 391 failf(data, "TLSv1.1-only ciphers are not yet supported"); | |
| 392 result = CURLE_SSL_CIPHER; | |
| 393 } | |
| 394 } | |
| 395 } | |
| 396 if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) { | |
| 397 result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS, | |
| 398 ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE); | |
| 399 if(result == CURLE_UNSUPPORTED_PROTOCOL) { | |
| 400 result = CURLE_OK; | |
| 401 if(unsupported) { | |
| 402 failf(data, "TLSv1.2-only ciphers are not yet supported"); | |
| 403 result = CURLE_SSL_CIPHER; | |
| 404 } | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to | |
| 409 the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */ | |
| 410 if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) { | |
| 411 result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS, | |
| 412 ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE); | |
| 413 if(result == CURLE_UNSUPPORTED_PROTOCOL) { | |
| 414 result = CURLE_OK; | |
| 415 strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr, | |
| 416 ciphers[CURL_GSKPROTO_TLSV10].ptr); | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 /* Set-up other ciphers. */ | |
| 421 if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK)) | |
| 422 result = set_buffer(data, h, GSK_V3_CIPHER_SPECS, | |
| 423 ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE); | |
| 424 if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK)) | |
| 425 result = set_buffer(data, h, GSK_V2_CIPHER_SPECS, | |
| 426 ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE); | |
| 427 | |
| 428 /* Clean-up. */ | |
| 429 for(i = 0; i < CURL_GSKPROTO_LAST; i++) | |
| 430 free(ciphers[i].buf); | |
| 431 | |
| 432 return result; | |
| 433 } | |
| 434 | |
| 435 | |
| 436 static int Curl_gskit_init(void) | |
| 437 { | |
| 438 /* No initialisation needed. */ | |
| 439 | |
| 440 return 1; | |
| 441 } | |
| 442 | |
| 443 | |
| 444 static void Curl_gskit_cleanup(void) | |
| 445 { | |
| 446 /* Nothing to do. */ | |
| 447 } | |
| 448 | |
| 449 | |
| 450 static CURLcode init_environment(struct Curl_easy *data, | |
| 451 gsk_handle *envir, const char *appid, | |
| 452 const char *file, const char *label, | |
| 453 const char *password) | |
| 454 { | |
| 455 int rc; | |
| 456 CURLcode result; | |
| 457 gsk_handle h; | |
| 458 | |
| 459 /* Creates the GSKit environment. */ | |
| 460 | |
| 461 rc = gsk_environment_open(&h); | |
| 462 switch(rc) { | |
| 463 case GSK_OK: | |
| 464 break; | |
| 465 case GSK_INSUFFICIENT_STORAGE: | |
| 466 return CURLE_OUT_OF_MEMORY; | |
| 467 default: | |
| 468 failf(data, "gsk_environment_open(): %s", gsk_strerror(rc)); | |
| 469 return CURLE_SSL_CONNECT_ERROR; | |
| 470 } | |
| 471 | |
| 472 result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE); | |
| 473 if(!result && appid) | |
| 474 result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE); | |
| 475 if(!result && file) | |
| 476 result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE); | |
| 477 if(!result && label) | |
| 478 result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE); | |
| 479 if(!result && password) | |
| 480 result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE); | |
| 481 | |
| 482 if(!result) { | |
| 483 /* Locate CAs, Client certificate and key according to our settings. | |
| 484 Note: this call may be blocking for some tenths of seconds. */ | |
| 485 result = gskit_status(data, gsk_environment_init(h), | |
| 486 "gsk_environment_init()", CURLE_SSL_CERTPROBLEM); | |
| 487 if(!result) { | |
| 488 *envir = h; | |
| 489 return result; | |
| 490 } | |
| 491 } | |
| 492 /* Error: rollback. */ | |
| 493 gsk_environment_close(&h); | |
| 494 return result; | |
| 495 } | |
| 496 | |
| 497 | |
| 498 static void cancel_async_handshake(struct connectdata *conn, int sockindex) | |
| 499 { | |
| 500 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 501 Qso_OverlappedIO_t cstat; | |
| 502 | |
| 503 if(QsoCancelOperation(conn->sock[sockindex], 0) > 0) | |
| 504 QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL); | |
| 505 } | |
| 506 | |
| 507 | |
| 508 static void close_async_handshake(struct ssl_connect_data *connssl) | |
| 509 { | |
| 510 QsoDestroyIOCompletionPort(BACKEND->iocport); | |
| 511 BACKEND->iocport = -1; | |
| 512 } | |
| 513 | |
| 514 /* SSL over SSL | |
| 515 * Problems: | |
| 516 * 1) GSKit can only perform SSL on an AF_INET or AF_INET6 stream socket. To | |
| 517 * pipe an SSL stream into another, it is therefore needed to have a pair | |
| 518 * of such communicating sockets and handle the pipelining explicitly. | |
| 519 * 2) OS/400 socketpair() is only implemented for domain AF_UNIX, thus cannot | |
| 520 * be used to produce the pipeline. | |
| 521 * The solution is to simulate socketpair() for AF_INET with low-level API | |
| 522 * listen(), bind() and connect(). | |
| 523 */ | |
| 524 | |
| 525 static int | |
| 526 inetsocketpair(int sv[2]) | |
| 527 { | |
| 528 int lfd; /* Listening socket. */ | |
| 529 int sfd; /* Server socket. */ | |
| 530 int cfd; /* Client socket. */ | |
| 531 int len; | |
| 532 struct sockaddr_in addr1; | |
| 533 struct sockaddr_in addr2; | |
| 534 | |
| 535 /* Create listening socket on a local dynamic port. */ | |
| 536 lfd = socket(AF_INET, SOCK_STREAM, 0); | |
| 537 if(lfd < 0) | |
| 538 return -1; | |
| 539 memset((char *) &addr1, 0, sizeof(addr1)); | |
| 540 addr1.sin_family = AF_INET; | |
| 541 addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
| 542 addr1.sin_port = 0; | |
| 543 if(bind(lfd, (struct sockaddr *) &addr1, sizeof(addr1)) || | |
| 544 listen(lfd, 2) < 0) { | |
| 545 close(lfd); | |
| 546 return -1; | |
| 547 } | |
| 548 | |
| 549 /* Get the allocated port. */ | |
| 550 len = sizeof(addr1); | |
| 551 if(getsockname(lfd, (struct sockaddr *) &addr1, &len) < 0) { | |
| 552 close(lfd); | |
| 553 return -1; | |
| 554 } | |
| 555 | |
| 556 /* Create the client socket. */ | |
| 557 cfd = socket(AF_INET, SOCK_STREAM, 0); | |
| 558 if(cfd < 0) { | |
| 559 close(lfd); | |
| 560 return -1; | |
| 561 } | |
| 562 | |
| 563 /* Request unblocking connection to the listening socket. */ | |
| 564 curlx_nonblock(cfd, TRUE); | |
| 565 if(connect(cfd, (struct sockaddr *) &addr1, sizeof(addr1)) < 0 && | |
| 566 errno != EINPROGRESS) { | |
| 567 close(lfd); | |
| 568 close(cfd); | |
| 569 return -1; | |
| 570 } | |
| 571 | |
| 572 /* Get the client dynamic port for intrusion check below. */ | |
| 573 len = sizeof(addr2); | |
| 574 if(getsockname(cfd, (struct sockaddr *) &addr2, &len) < 0) { | |
| 575 close(lfd); | |
| 576 close(cfd); | |
| 577 return -1; | |
| 578 } | |
| 579 | |
| 580 /* Accept the incoming connection and get the server socket. */ | |
| 581 curlx_nonblock(lfd, TRUE); | |
| 582 for(;;) { | |
| 583 len = sizeof(addr1); | |
| 584 sfd = accept(lfd, (struct sockaddr *) &addr1, &len); | |
| 585 if(sfd < 0) { | |
| 586 close(lfd); | |
| 587 close(cfd); | |
| 588 return -1; | |
| 589 } | |
| 590 | |
| 591 /* Check for possible intrusion from an external process. */ | |
| 592 if(addr1.sin_addr.s_addr == addr2.sin_addr.s_addr && | |
| 593 addr1.sin_port == addr2.sin_port) | |
| 594 break; | |
| 595 | |
| 596 /* Intrusion: reject incoming connection. */ | |
| 597 close(sfd); | |
| 598 } | |
| 599 | |
| 600 /* Done, return sockets and succeed. */ | |
| 601 close(lfd); | |
| 602 curlx_nonblock(cfd, FALSE); | |
| 603 sv[0] = cfd; | |
| 604 sv[1] = sfd; | |
| 605 return 0; | |
| 606 } | |
| 607 | |
| 608 static int pipe_ssloverssl(struct connectdata *conn, int sockindex, | |
| 609 int directions) | |
| 610 { | |
| 611 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 612 struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex]; | |
| 613 fd_set fds_read; | |
| 614 fd_set fds_write; | |
| 615 int n; | |
| 616 int m; | |
| 617 int i; | |
| 618 int ret = 0; | |
| 619 struct timeval tv = {0, 0}; | |
| 620 char buf[CURL_MAX_WRITE_SIZE]; | |
| 621 | |
| 622 if(!connssl->use || !connproxyssl->use) | |
| 623 return 0; /* No SSL over SSL: OK. */ | |
| 624 | |
| 625 FD_ZERO(&fds_read); | |
| 626 FD_ZERO(&fds_write); | |
| 627 n = -1; | |
| 628 if(directions & SOS_READ) { | |
| 629 FD_SET(BACKEND->remotefd, &fds_write); | |
| 630 n = BACKEND->remotefd; | |
| 631 } | |
| 632 if(directions & SOS_WRITE) { | |
| 633 FD_SET(BACKEND->remotefd, &fds_read); | |
| 634 n = BACKEND->remotefd; | |
| 635 FD_SET(conn->sock[sockindex], &fds_write); | |
| 636 if(n < conn->sock[sockindex]) | |
| 637 n = conn->sock[sockindex]; | |
| 638 } | |
| 639 i = select(n + 1, &fds_read, &fds_write, NULL, &tv); | |
| 640 if(i < 0) | |
| 641 return -1; /* Select error. */ | |
| 642 | |
| 643 if(FD_ISSET(BACKEND->remotefd, &fds_write)) { | |
| 644 /* Try getting data from HTTPS proxy and pipe it upstream. */ | |
| 645 n = 0; | |
| 646 i = gsk_secure_soc_read(connproxyssl->backend->handle, | |
| 647 buf, sizeof(buf), &n); | |
| 648 switch(i) { | |
| 649 case GSK_OK: | |
| 650 if(n) { | |
| 651 i = write(BACKEND->remotefd, buf, n); | |
| 652 if(i < 0) | |
| 653 return -1; | |
| 654 ret = 1; | |
| 655 } | |
| 656 break; | |
| 657 case GSK_OS400_ERROR_TIMED_OUT: | |
| 658 case GSK_WOULD_BLOCK: | |
| 659 break; | |
| 660 default: | |
| 661 return -1; | |
| 662 } | |
| 663 } | |
| 664 | |
| 665 if(FD_ISSET(BACKEND->remotefd, &fds_read) && | |
| 666 FD_ISSET(conn->sock[sockindex], &fds_write)) { | |
| 667 /* Pipe data to HTTPS proxy. */ | |
| 668 n = read(BACKEND->remotefd, buf, sizeof(buf)); | |
| 669 if(n < 0) | |
| 670 return -1; | |
| 671 if(n) { | |
| 672 i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m); | |
| 673 if(i != GSK_OK || n != m) | |
| 674 return -1; | |
| 675 ret = 1; | |
| 676 } | |
| 677 } | |
| 678 | |
| 679 return ret; /* OK */ | |
| 680 } | |
| 681 | |
| 682 | |
| 683 static void close_one(struct ssl_connect_data *connssl, | |
| 684 struct connectdata *conn, int sockindex) | |
| 685 { | |
| 686 if(BACKEND->handle) { | |
| 687 gskit_status(conn->data, gsk_secure_soc_close(&BACKEND->handle), | |
| 688 "gsk_secure_soc_close()", 0); | |
| 689 /* Last chance to drain output. */ | |
| 690 while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0) | |
| 691 ; | |
| 692 BACKEND->handle = (gsk_handle) NULL; | |
| 693 if(BACKEND->localfd >= 0) { | |
| 694 close(BACKEND->localfd); | |
| 695 BACKEND->localfd = -1; | |
| 696 } | |
| 697 if(BACKEND->remotefd >= 0) { | |
| 698 close(BACKEND->remotefd); | |
| 699 BACKEND->remotefd = -1; | |
| 700 } | |
| 701 } | |
| 702 if(BACKEND->iocport >= 0) | |
| 703 close_async_handshake(connssl); | |
| 704 } | |
| 705 | |
| 706 | |
| 707 static ssize_t gskit_send(struct connectdata *conn, int sockindex, | |
| 708 const void *mem, size_t len, CURLcode *curlcode) | |
| 709 { | |
| 710 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 711 struct Curl_easy *data = conn->data; | |
| 712 CURLcode cc = CURLE_SEND_ERROR; | |
| 713 int written; | |
| 714 | |
| 715 if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) { | |
| 716 cc = gskit_status(data, | |
| 717 gsk_secure_soc_write(BACKEND->handle, | |
| 718 (char *) mem, (int) len, &written), | |
| 719 "gsk_secure_soc_write()", CURLE_SEND_ERROR); | |
| 720 if(cc == CURLE_OK) | |
| 721 if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0) | |
| 722 cc = CURLE_SEND_ERROR; | |
| 723 } | |
| 724 if(cc != CURLE_OK) { | |
| 725 *curlcode = cc; | |
| 726 written = -1; | |
| 727 } | |
| 728 return (ssize_t) written; /* number of bytes */ | |
| 729 } | |
| 730 | |
| 731 | |
| 732 static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, | |
| 733 size_t buffersize, CURLcode *curlcode) | |
| 734 { | |
| 735 struct ssl_connect_data *connssl = &conn->ssl[num]; | |
| 736 struct Curl_easy *data = conn->data; | |
| 737 int nread; | |
| 738 CURLcode cc = CURLE_RECV_ERROR; | |
| 739 | |
| 740 if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) { | |
| 741 int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; | |
| 742 cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle, | |
| 743 buf, buffsize, &nread), | |
| 744 "gsk_secure_soc_read()", CURLE_RECV_ERROR); | |
| 745 } | |
| 746 switch(cc) { | |
| 747 case CURLE_OK: | |
| 748 break; | |
| 749 case CURLE_OPERATION_TIMEDOUT: | |
| 750 cc = CURLE_AGAIN; | |
| 751 default: | |
| 752 *curlcode = cc; | |
| 753 nread = -1; | |
| 754 break; | |
| 755 } | |
| 756 return (ssize_t) nread; | |
| 757 } | |
| 758 | |
| 759 static CURLcode | |
| 760 set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn) | |
| 761 { | |
| 762 struct Curl_easy *data = conn->data; | |
| 763 long ssl_version = SSL_CONN_CONFIG(version); | |
| 764 long ssl_version_max = SSL_CONN_CONFIG(version_max); | |
| 765 long i = ssl_version; | |
| 766 switch(ssl_version_max) { | |
| 767 case CURL_SSLVERSION_MAX_NONE: | |
| 768 case CURL_SSLVERSION_MAX_DEFAULT: | |
| 769 ssl_version_max = CURL_SSLVERSION_TLSv1_2; | |
| 770 break; | |
| 771 } | |
| 772 for(; i <= (ssl_version_max >> 16); ++i) { | |
| 773 switch(i) { | |
| 774 case CURL_SSLVERSION_TLSv1_0: | |
| 775 *protoflags |= CURL_GSKPROTO_TLSV10_MASK; | |
| 776 break; | |
| 777 case CURL_SSLVERSION_TLSv1_1: | |
| 778 *protoflags |= CURL_GSKPROTO_TLSV11_MASK; | |
| 779 break; | |
| 780 case CURL_SSLVERSION_TLSv1_2: | |
| 781 *protoflags |= CURL_GSKPROTO_TLSV11_MASK; | |
| 782 break; | |
| 783 case CURL_SSLVERSION_TLSv1_3: | |
| 784 failf(data, "GSKit: TLS 1.3 is not yet supported"); | |
| 785 return CURLE_SSL_CONNECT_ERROR; | |
| 786 } | |
| 787 } | |
| 788 | |
| 789 return CURLE_OK; | |
| 790 } | |
| 791 | |
| 792 static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) | |
| 793 { | |
| 794 struct Curl_easy *data = conn->data; | |
| 795 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 796 gsk_handle envir; | |
| 797 CURLcode result; | |
| 798 int rc; | |
| 799 const char * const keyringfile = SSL_CONN_CONFIG(CAfile); | |
| 800 const char * const keyringpwd = SSL_SET_OPTION(key_passwd); | |
| 801 const char * const keyringlabel = SSL_SET_OPTION(cert); | |
| 802 const long int ssl_version = SSL_CONN_CONFIG(version); | |
| 803 const bool verifypeer = SSL_CONN_CONFIG(verifypeer); | |
| 804 const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: | |
| 805 conn->host.name; | |
| 806 const char *sni; | |
| 807 unsigned int protoflags = 0; | |
| 808 Qso_OverlappedIO_t commarea; | |
| 809 int sockpair[2]; | |
| 810 static const int sobufsize = CURL_MAX_WRITE_SIZE; | |
| 811 | |
| 812 /* Create SSL environment, start (preferably asynchronous) handshake. */ | |
| 813 | |
| 814 BACKEND->handle = (gsk_handle) NULL; | |
| 815 BACKEND->iocport = -1; | |
| 816 BACKEND->localfd = -1; | |
| 817 BACKEND->remotefd = -1; | |
| 818 | |
| 819 /* GSKit supports two ways of specifying an SSL context: either by | |
| 820 * application identifier (that should have been defined at the system | |
| 821 * level) or by keyring file, password and certificate label. | |
| 822 * Local certificate name (CURLOPT_SSLCERT) is used to hold either the | |
| 823 * application identifier of the certificate label. | |
| 824 * Key password (CURLOPT_KEYPASSWD) holds the keyring password. | |
| 825 * It is not possible to have different keyrings for the CAs and the | |
| 826 * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify | |
| 827 * the keyring file. | |
| 828 * If no key password is given and the keyring is the system keyring, | |
| 829 * application identifier mode is tried first, as recommended in IBM doc. | |
| 830 */ | |
| 831 | |
| 832 envir = (gsk_handle) NULL; | |
| 833 | |
| 834 if(keyringlabel && *keyringlabel && !keyringpwd && | |
| 835 !strcmp(keyringfile, CURL_CA_BUNDLE)) { | |
| 836 /* Try application identifier mode. */ | |
| 837 init_environment(data, &envir, keyringlabel, (const char *) NULL, | |
| 838 (const char *) NULL, (const char *) NULL); | |
| 839 } | |
| 840 | |
| 841 if(!envir) { | |
| 842 /* Use keyring mode. */ | |
| 843 result = init_environment(data, &envir, (const char *) NULL, | |
| 844 keyringfile, keyringlabel, keyringpwd); | |
| 845 if(result) | |
| 846 return result; | |
| 847 } | |
| 848 | |
| 849 /* Create secure session. */ | |
| 850 result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle), | |
| 851 "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR); | |
| 852 gsk_environment_close(&envir); | |
| 853 if(result) | |
| 854 return result; | |
| 855 | |
| 856 /* Establish a pipelining socket pair for SSL over SSL. */ | |
| 857 if(conn->proxy_ssl[sockindex].use) { | |
| 858 if(inetsocketpair(sockpair)) | |
| 859 return CURLE_SSL_CONNECT_ERROR; | |
| 860 BACKEND->localfd = sockpair[0]; | |
| 861 BACKEND->remotefd = sockpair[1]; | |
| 862 setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF, | |
| 863 (void *) sobufsize, sizeof(sobufsize)); | |
| 864 setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF, | |
| 865 (void *) sobufsize, sizeof(sobufsize)); | |
| 866 setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF, | |
| 867 (void *) sobufsize, sizeof(sobufsize)); | |
| 868 setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF, | |
| 869 (void *) sobufsize, sizeof(sobufsize)); | |
| 870 curlx_nonblock(BACKEND->localfd, TRUE); | |
| 871 curlx_nonblock(BACKEND->remotefd, TRUE); | |
| 872 } | |
| 873 | |
| 874 /* Determine which SSL/TLS version should be enabled. */ | |
| 875 sni = hostname; | |
| 876 switch(ssl_version) { | |
| 877 case CURL_SSLVERSION_SSLv2: | |
| 878 protoflags = CURL_GSKPROTO_SSLV2_MASK; | |
| 879 sni = NULL; | |
| 880 break; | |
| 881 case CURL_SSLVERSION_SSLv3: | |
| 882 protoflags = CURL_GSKPROTO_SSLV3_MASK; | |
| 883 sni = NULL; | |
| 884 break; | |
| 885 case CURL_SSLVERSION_DEFAULT: | |
| 886 case CURL_SSLVERSION_TLSv1: | |
| 887 protoflags = CURL_GSKPROTO_TLSV10_MASK | | |
| 888 CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK; | |
| 889 break; | |
| 890 case CURL_SSLVERSION_TLSv1_0: | |
| 891 case CURL_SSLVERSION_TLSv1_1: | |
| 892 case CURL_SSLVERSION_TLSv1_2: | |
| 893 case CURL_SSLVERSION_TLSv1_3: | |
| 894 result = set_ssl_version_min_max(&protoflags, conn); | |
| 895 if(result != CURLE_OK) | |
| 896 return result; | |
| 897 break; | |
| 898 default: | |
| 899 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); | |
| 900 return CURLE_SSL_CONNECT_ERROR; | |
| 901 } | |
| 902 | |
| 903 /* Process SNI. Ignore if not supported (on OS400 < V7R1). */ | |
| 904 if(sni) { | |
| 905 result = set_buffer(data, BACKEND->handle, | |
| 906 GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE); | |
| 907 if(result == CURLE_UNSUPPORTED_PROTOCOL) | |
| 908 result = CURLE_OK; | |
| 909 } | |
| 910 | |
| 911 /* Set session parameters. */ | |
| 912 if(!result) { | |
| 913 /* Compute the handshake timeout. Since GSKit granularity is 1 second, | |
| 914 we round up the required value. */ | |
| 915 long timeout = Curl_timeleft(data, NULL, TRUE); | |
| 916 if(timeout < 0) | |
| 917 result = CURLE_OPERATION_TIMEDOUT; | |
| 918 else | |
| 919 result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT, | |
| 920 (timeout + 999) / 1000); | |
| 921 } | |
| 922 if(!result) | |
| 923 result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1); | |
| 924 if(!result) | |
| 925 result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0? | |
| 926 BACKEND->localfd: conn->sock[sockindex]); | |
| 927 if(!result) | |
| 928 result = set_ciphers(conn, BACKEND->handle, &protoflags); | |
| 929 if(!protoflags) { | |
| 930 failf(data, "No SSL protocol/cipher combination enabled"); | |
| 931 result = CURLE_SSL_CIPHER; | |
| 932 } | |
| 933 if(!result) | |
| 934 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2, | |
| 935 (protoflags & CURL_GSKPROTO_SSLV2_MASK)? | |
| 936 GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE); | |
| 937 if(!result) | |
| 938 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3, | |
| 939 (protoflags & CURL_GSKPROTO_SSLV3_MASK)? | |
| 940 GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE); | |
| 941 if(!result) | |
| 942 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1, | |
| 943 (protoflags & CURL_GSKPROTO_TLSV10_MASK)? | |
| 944 GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE); | |
| 945 if(!result) { | |
| 946 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11, | |
| 947 (protoflags & CURL_GSKPROTO_TLSV11_MASK)? | |
| 948 GSK_TRUE: GSK_FALSE, TRUE); | |
| 949 if(result == CURLE_UNSUPPORTED_PROTOCOL) { | |
| 950 result = CURLE_OK; | |
| 951 if(protoflags == CURL_GSKPROTO_TLSV11_MASK) { | |
| 952 failf(data, "TLS 1.1 not yet supported"); | |
| 953 result = CURLE_SSL_CIPHER; | |
| 954 } | |
| 955 } | |
| 956 } | |
| 957 if(!result) { | |
| 958 result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12, | |
| 959 (protoflags & CURL_GSKPROTO_TLSV12_MASK)? | |
| 960 GSK_TRUE: GSK_FALSE, TRUE); | |
| 961 if(result == CURLE_UNSUPPORTED_PROTOCOL) { | |
| 962 result = CURLE_OK; | |
| 963 if(protoflags == CURL_GSKPROTO_TLSV12_MASK) { | |
| 964 failf(data, "TLS 1.2 not yet supported"); | |
| 965 result = CURLE_SSL_CIPHER; | |
| 966 } | |
| 967 } | |
| 968 } | |
| 969 if(!result) | |
| 970 result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE, | |
| 971 verifypeer? GSK_SERVER_AUTH_FULL: | |
| 972 GSK_SERVER_AUTH_PASSTHRU, FALSE); | |
| 973 | |
| 974 if(!result) { | |
| 975 /* Start handshake. Try asynchronous first. */ | |
| 976 memset(&commarea, 0, sizeof(commarea)); | |
| 977 BACKEND->iocport = QsoCreateIOCompletionPort(); | |
| 978 if(BACKEND->iocport != -1) { | |
| 979 result = gskit_status(data, | |
| 980 gsk_secure_soc_startInit(BACKEND->handle, | |
| 981 BACKEND->iocport, | |
| 982 &commarea), | |
| 983 "gsk_secure_soc_startInit()", | |
| 984 CURLE_SSL_CONNECT_ERROR); | |
| 985 if(!result) { | |
| 986 connssl->connecting_state = ssl_connect_2; | |
| 987 return CURLE_OK; | |
| 988 } | |
| 989 else | |
| 990 close_async_handshake(connssl); | |
| 991 } | |
| 992 else if(errno != ENOBUFS) | |
| 993 result = gskit_status(data, GSK_ERROR_IO, | |
| 994 "QsoCreateIOCompletionPort()", 0); | |
| 995 else if(conn->proxy_ssl[sockindex].use) { | |
| 996 /* Cannot pipeline while handshaking synchronously. */ | |
| 997 result = CURLE_SSL_CONNECT_ERROR; | |
| 998 } | |
| 999 else { | |
| 1000 /* No more completion port available. Use synchronous IO. */ | |
| 1001 result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle), | |
| 1002 "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR); | |
| 1003 if(!result) { | |
| 1004 connssl->connecting_state = ssl_connect_3; | |
| 1005 return CURLE_OK; | |
| 1006 } | |
| 1007 } | |
| 1008 } | |
| 1009 | |
| 1010 /* Error: rollback. */ | |
| 1011 close_one(connssl, conn, sockindex); | |
| 1012 return result; | |
| 1013 } | |
| 1014 | |
| 1015 | |
| 1016 static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, | |
| 1017 bool nonblocking) | |
| 1018 { | |
| 1019 struct Curl_easy *data = conn->data; | |
| 1020 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 1021 Qso_OverlappedIO_t cstat; | |
| 1022 struct timeval stmv; | |
| 1023 CURLcode result; | |
| 1024 | |
| 1025 /* Poll or wait for end of SSL asynchronous handshake. */ | |
| 1026 | |
| 1027 for(;;) { | |
| 1028 long timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE); | |
| 1029 if(timeout_ms < 0) | |
| 1030 timeout_ms = 0; | |
| 1031 stmv.tv_sec = timeout_ms / 1000; | |
| 1032 stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000; | |
| 1033 switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat, &stmv)) { | |
| 1034 case 1: /* Operation complete. */ | |
| 1035 break; | |
| 1036 case -1: /* An error occurred: handshake still in progress. */ | |
| 1037 if(errno == EINTR) { | |
| 1038 if(nonblocking) | |
| 1039 return CURLE_OK; | |
| 1040 continue; /* Retry. */ | |
| 1041 } | |
| 1042 if(errno != ETIME) { | |
| 1043 failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno)); | |
| 1044 cancel_async_handshake(conn, sockindex); | |
| 1045 close_async_handshake(connssl); | |
| 1046 return CURLE_SSL_CONNECT_ERROR; | |
| 1047 } | |
| 1048 /* FALL INTO... */ | |
| 1049 case 0: /* Handshake in progress, timeout occurred. */ | |
| 1050 if(nonblocking) | |
| 1051 return CURLE_OK; | |
| 1052 cancel_async_handshake(conn, sockindex); | |
| 1053 close_async_handshake(connssl); | |
| 1054 return CURLE_OPERATION_TIMEDOUT; | |
| 1055 } | |
| 1056 break; | |
| 1057 } | |
| 1058 result = gskit_status(data, cstat.returnValue, "SSL handshake", | |
| 1059 CURLE_SSL_CONNECT_ERROR); | |
| 1060 if(!result) | |
| 1061 connssl->connecting_state = ssl_connect_3; | |
| 1062 close_async_handshake(connssl); | |
| 1063 return result; | |
| 1064 } | |
| 1065 | |
| 1066 | |
| 1067 static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) | |
| 1068 { | |
| 1069 struct Curl_easy *data = conn->data; | |
| 1070 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 1071 const gsk_cert_data_elem *cdev; | |
| 1072 int cdec; | |
| 1073 const gsk_cert_data_elem *p; | |
| 1074 const char *cert = (const char *) NULL; | |
| 1075 const char *certend; | |
| 1076 const char *ptr; | |
| 1077 CURLcode result; | |
| 1078 | |
| 1079 /* SSL handshake done: gather certificate info and verify host. */ | |
| 1080 | |
| 1081 if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle, | |
| 1082 GSK_PARTNER_CERT_INFO, | |
| 1083 &cdev, &cdec), | |
| 1084 "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) == | |
| 1085 CURLE_OK) { | |
| 1086 int i; | |
| 1087 | |
| 1088 infof(data, "Server certificate:\n"); | |
| 1089 p = cdev; | |
| 1090 for(i = 0; i++ < cdec; p++) | |
| 1091 switch(p->cert_data_id) { | |
| 1092 case CERT_BODY_DER: | |
| 1093 cert = p->cert_data_p; | |
| 1094 certend = cert + cdev->cert_data_l; | |
| 1095 break; | |
| 1096 case CERT_DN_PRINTABLE: | |
| 1097 infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p); | |
| 1098 break; | |
| 1099 case CERT_ISSUER_DN_PRINTABLE: | |
| 1100 infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p); | |
| 1101 break; | |
| 1102 case CERT_VALID_FROM: | |
| 1103 infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p); | |
| 1104 break; | |
| 1105 case CERT_VALID_TO: | |
| 1106 infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p); | |
| 1107 break; | |
| 1108 } | |
| 1109 } | |
| 1110 | |
| 1111 /* Verify host. */ | |
| 1112 result = Curl_verifyhost(conn, cert, certend); | |
| 1113 if(result) | |
| 1114 return result; | |
| 1115 | |
| 1116 /* The only place GSKit can get the whole CA chain is a validation | |
| 1117 callback where no user data pointer is available. Therefore it's not | |
| 1118 possible to copy this chain into our structures for CAINFO. | |
| 1119 However the server certificate may be available, thus we can return | |
| 1120 info about it. */ | |
| 1121 if(data->set.ssl.certinfo) { | |
| 1122 result = Curl_ssl_init_certinfo(data, 1); | |
| 1123 if(result) | |
| 1124 return result; | |
| 1125 | |
| 1126 if(cert) { | |
| 1127 result = Curl_extract_certinfo(conn, 0, cert, certend); | |
| 1128 if(result) | |
| 1129 return result; | |
| 1130 } | |
| 1131 } | |
| 1132 | |
| 1133 /* Check pinned public key. */ | |
| 1134 ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : | |
| 1135 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; | |
| 1136 if(!result && ptr) { | |
| 1137 curl_X509certificate x509; | |
| 1138 curl_asn1Element *p; | |
| 1139 | |
| 1140 if(Curl_parseX509(&x509, cert, certend)) | |
| 1141 return CURLE_SSL_PINNEDPUBKEYNOTMATCH; | |
| 1142 p = &x509.subjectPublicKeyInfo; | |
| 1143 result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header); | |
| 1144 if(result) { | |
| 1145 failf(data, "SSL: public key does not match pinned public key!"); | |
| 1146 return result; | |
| 1147 } | |
| 1148 } | |
| 1149 | |
| 1150 connssl->connecting_state = ssl_connect_done; | |
| 1151 return CURLE_OK; | |
| 1152 } | |
| 1153 | |
| 1154 | |
| 1155 static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, | |
| 1156 bool nonblocking, bool *done) | |
| 1157 { | |
| 1158 struct Curl_easy *data = conn->data; | |
| 1159 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 1160 long timeout_ms; | |
| 1161 CURLcode result = CURLE_OK; | |
| 1162 | |
| 1163 *done = connssl->state == ssl_connection_complete; | |
| 1164 if(*done) | |
| 1165 return CURLE_OK; | |
| 1166 | |
| 1167 /* Step 1: create session, start handshake. */ | |
| 1168 if(connssl->connecting_state == ssl_connect_1) { | |
| 1169 /* check allowed time left */ | |
| 1170 timeout_ms = Curl_timeleft(data, NULL, TRUE); | |
| 1171 | |
| 1172 if(timeout_ms < 0) { | |
| 1173 /* no need to continue if time already is up */ | |
| 1174 failf(data, "SSL connection timeout"); | |
| 1175 result = CURLE_OPERATION_TIMEDOUT; | |
| 1176 } | |
| 1177 else | |
| 1178 result = gskit_connect_step1(conn, sockindex); | |
| 1179 } | |
| 1180 | |
| 1181 /* Handle handshake pipelining. */ | |
| 1182 if(!result) | |
| 1183 if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) | |
| 1184 result = CURLE_SSL_CONNECT_ERROR; | |
| 1185 | |
| 1186 /* Step 2: check if handshake is over. */ | |
| 1187 if(!result && connssl->connecting_state == ssl_connect_2) { | |
| 1188 /* check allowed time left */ | |
| 1189 timeout_ms = Curl_timeleft(data, NULL, TRUE); | |
| 1190 | |
| 1191 if(timeout_ms < 0) { | |
| 1192 /* no need to continue if time already is up */ | |
| 1193 failf(data, "SSL connection timeout"); | |
| 1194 result = CURLE_OPERATION_TIMEDOUT; | |
| 1195 } | |
| 1196 else | |
| 1197 result = gskit_connect_step2(conn, sockindex, nonblocking); | |
| 1198 } | |
| 1199 | |
| 1200 /* Handle handshake pipelining. */ | |
| 1201 if(!result) | |
| 1202 if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) | |
| 1203 result = CURLE_SSL_CONNECT_ERROR; | |
| 1204 | |
| 1205 /* Step 3: gather certificate info, verify host. */ | |
| 1206 if(!result && connssl->connecting_state == ssl_connect_3) | |
| 1207 result = gskit_connect_step3(conn, sockindex); | |
| 1208 | |
| 1209 if(result) | |
| 1210 close_one(connssl, conn, sockindex); | |
| 1211 else if(connssl->connecting_state == ssl_connect_done) { | |
| 1212 connssl->state = ssl_connection_complete; | |
| 1213 connssl->connecting_state = ssl_connect_1; | |
| 1214 conn->recv[sockindex] = gskit_recv; | |
| 1215 conn->send[sockindex] = gskit_send; | |
| 1216 *done = TRUE; | |
| 1217 } | |
| 1218 | |
| 1219 return result; | |
| 1220 } | |
| 1221 | |
| 1222 | |
| 1223 static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, | |
| 1224 int sockindex, bool *done) | |
| 1225 { | |
| 1226 CURLcode result; | |
| 1227 | |
| 1228 result = gskit_connect_common(conn, sockindex, TRUE, done); | |
| 1229 if(*done || result) | |
| 1230 conn->ssl[sockindex].connecting_state = ssl_connect_1; | |
| 1231 return result; | |
| 1232 } | |
| 1233 | |
| 1234 | |
| 1235 static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) | |
| 1236 { | |
| 1237 CURLcode result; | |
| 1238 bool done; | |
| 1239 | |
| 1240 conn->ssl[sockindex].connecting_state = ssl_connect_1; | |
| 1241 result = gskit_connect_common(conn, sockindex, FALSE, &done); | |
| 1242 if(result) | |
| 1243 return result; | |
| 1244 | |
| 1245 DEBUGASSERT(done); | |
| 1246 | |
| 1247 return CURLE_OK; | |
| 1248 } | |
| 1249 | |
| 1250 | |
| 1251 static void Curl_gskit_close(struct connectdata *conn, int sockindex) | |
| 1252 { | |
| 1253 close_one(&conn->ssl[sockindex], conn, sockindex); | |
| 1254 close_one(&conn->proxy_ssl[sockindex], conn, sockindex); | |
| 1255 } | |
| 1256 | |
| 1257 | |
| 1258 static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) | |
| 1259 { | |
| 1260 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 1261 struct Curl_easy *data = conn->data; | |
| 1262 int what; | |
| 1263 int rc; | |
| 1264 char buf[120]; | |
| 1265 | |
| 1266 if(!BACKEND->handle) | |
| 1267 return 0; | |
| 1268 | |
| 1269 #ifndef CURL_DISABLE_FTP | |
| 1270 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) | |
| 1271 return 0; | |
| 1272 #endif | |
| 1273 | |
| 1274 close_one(connssl, conn, sockindex); | |
| 1275 rc = 0; | |
| 1276 what = SOCKET_READABLE(conn->sock[sockindex], | |
| 1277 SSL_SHUTDOWN_TIMEOUT); | |
| 1278 | |
| 1279 for(;;) { | |
| 1280 ssize_t nread; | |
| 1281 | |
| 1282 if(what < 0) { | |
| 1283 /* anything that gets here is fatally bad */ | |
| 1284 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); | |
| 1285 rc = -1; | |
| 1286 break; | |
| 1287 } | |
| 1288 | |
| 1289 if(!what) { /* timeout */ | |
| 1290 failf(data, "SSL shutdown timeout"); | |
| 1291 break; | |
| 1292 } | |
| 1293 | |
| 1294 /* Something to read, let's do it and hope that it is the close | |
| 1295 notify alert from the server. No way to gsk_secure_soc_read() now, so | |
| 1296 use read(). */ | |
| 1297 | |
| 1298 nread = read(conn->sock[sockindex], buf, sizeof(buf)); | |
| 1299 | |
| 1300 if(nread < 0) { | |
| 1301 failf(data, "read: %s", strerror(errno)); | |
| 1302 rc = -1; | |
| 1303 } | |
| 1304 | |
| 1305 if(nread <= 0) | |
| 1306 break; | |
| 1307 | |
| 1308 what = SOCKET_READABLE(conn->sock[sockindex], 0); | |
| 1309 } | |
| 1310 | |
| 1311 return rc; | |
| 1312 } | |
| 1313 | |
| 1314 | |
| 1315 static size_t Curl_gskit_version(char *buffer, size_t size) | |
| 1316 { | |
| 1317 return msnprintf(buffer, size, "GSKit"); | |
| 1318 } | |
| 1319 | |
| 1320 | |
| 1321 static int Curl_gskit_check_cxn(struct connectdata *cxn) | |
| 1322 { | |
| 1323 struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET]; | |
| 1324 int err; | |
| 1325 int errlen; | |
| 1326 | |
| 1327 /* The only thing that can be tested here is at the socket level. */ | |
| 1328 | |
| 1329 if(!BACKEND->handle) | |
| 1330 return 0; /* connection has been closed */ | |
| 1331 | |
| 1332 err = 0; | |
| 1333 errlen = sizeof(err); | |
| 1334 | |
| 1335 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, | |
| 1336 (unsigned char *) &err, &errlen) || | |
| 1337 errlen != sizeof(err) || err) | |
| 1338 return 0; /* connection has been closed */ | |
| 1339 | |
| 1340 return -1; /* connection status unknown */ | |
| 1341 } | |
| 1342 | |
| 1343 static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl, | |
| 1344 CURLINFO info UNUSED_PARAM) | |
| 1345 { | |
| 1346 (void)info; | |
| 1347 return BACKEND->handle; | |
| 1348 } | |
| 1349 | |
| 1350 const struct Curl_ssl Curl_ssl_gskit = { | |
| 1351 { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */ | |
| 1352 | |
| 1353 SSLSUPP_CERTINFO | | |
| 1354 SSLSUPP_PINNEDPUBKEY, | |
| 1355 | |
| 1356 sizeof(struct ssl_backend_data), | |
| 1357 | |
| 1358 Curl_gskit_init, /* init */ | |
| 1359 Curl_gskit_cleanup, /* cleanup */ | |
| 1360 Curl_gskit_version, /* version */ | |
| 1361 Curl_gskit_check_cxn, /* check_cxn */ | |
| 1362 Curl_gskit_shutdown, /* shutdown */ | |
| 1363 Curl_none_data_pending, /* data_pending */ | |
| 1364 Curl_none_random, /* random */ | |
| 1365 Curl_none_cert_status_request, /* cert_status_request */ | |
| 1366 Curl_gskit_connect, /* connect */ | |
| 1367 Curl_gskit_connect_nonblocking, /* connect_nonblocking */ | |
| 1368 Curl_gskit_get_internals, /* get_internals */ | |
| 1369 Curl_gskit_close, /* close_one */ | |
| 1370 Curl_none_close_all, /* close_all */ | |
| 1371 /* No session handling for GSKit */ | |
| 1372 Curl_none_session_free, /* session_free */ | |
| 1373 Curl_none_set_engine, /* set_engine */ | |
| 1374 Curl_none_set_engine_default, /* set_engine_default */ | |
| 1375 Curl_none_engines_list, /* engines_list */ | |
| 1376 Curl_none_false_start, /* false_start */ | |
| 1377 Curl_none_md5sum, /* md5sum */ | |
| 1378 NULL /* sha256sum */ | |
| 1379 }; | |
| 1380 | |
| 1381 #endif /* USE_GSKIT */ |
