Annotation of embedaddon/curl/lib/vtls/gskit.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>