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

1.1     ! misho       1: /***************************************************************************
        !             2:  *                                  _   _ ____  _
        !             3:  *  Project                     ___| | | |  _ \| |
        !             4:  *                             / __| | | | |_) | |
        !             5:  *                            | (__| |_| |  _ <| |___
        !             6:  *                             \___|\___/|_| \_\_____|
        !             7:  *
        !             8:  * Copyright (C) 2019 - 2020, Michael Forney, <mforney@mforney.org>
        !             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: #include "curl_setup.h"
        !            23: 
        !            24: #ifdef USE_BEARSSL
        !            25: 
        !            26: #include <bearssl.h>
        !            27: 
        !            28: #include "bearssl.h"
        !            29: #include "urldata.h"
        !            30: #include "sendf.h"
        !            31: #include "inet_pton.h"
        !            32: #include "vtls.h"
        !            33: #include "connect.h"
        !            34: #include "select.h"
        !            35: #include "multiif.h"
        !            36: #include "curl_printf.h"
        !            37: #include "curl_memory.h"
        !            38: 
        !            39: struct x509_context {
        !            40:   const br_x509_class *vtable;
        !            41:   br_x509_minimal_context minimal;
        !            42:   bool verifyhost;
        !            43:   bool verifypeer;
        !            44: };
        !            45: 
        !            46: struct ssl_backend_data {
        !            47:   br_ssl_client_context ctx;
        !            48:   struct x509_context x509;
        !            49:   unsigned char buf[BR_SSL_BUFSIZE_BIDI];
        !            50:   br_x509_trust_anchor *anchors;
        !            51:   size_t anchors_len;
        !            52:   const char *protocols[2];
        !            53:   /* SSL client context is active */
        !            54:   bool active;
        !            55:   /* size of pending write, yet to be flushed */
        !            56:   size_t pending_write;
        !            57: };
        !            58: 
        !            59: struct cafile_parser {
        !            60:   CURLcode err;
        !            61:   bool in_cert;
        !            62:   br_x509_decoder_context xc;
        !            63:   /* array of trust anchors loaded from CAfile */
        !            64:   br_x509_trust_anchor *anchors;
        !            65:   size_t anchors_len;
        !            66:   /* buffer for DN data */
        !            67:   unsigned char dn[1024];
        !            68:   size_t dn_len;
        !            69: };
        !            70: 
        !            71: static void append_dn(void *ctx, const void *buf, size_t len)
        !            72: {
        !            73:   struct cafile_parser *ca = ctx;
        !            74: 
        !            75:   if(ca->err != CURLE_OK || !ca->in_cert)
        !            76:     return;
        !            77:   if(sizeof(ca->dn) - ca->dn_len < len) {
        !            78:     ca->err = CURLE_FAILED_INIT;
        !            79:     return;
        !            80:   }
        !            81:   memcpy(ca->dn + ca->dn_len, buf, len);
        !            82:   ca->dn_len += len;
        !            83: }
        !            84: 
        !            85: static void x509_push(void *ctx, const void *buf, size_t len)
        !            86: {
        !            87:   struct cafile_parser *ca = ctx;
        !            88: 
        !            89:   if(ca->in_cert)
        !            90:     br_x509_decoder_push(&ca->xc, buf, len);
        !            91: }
        !            92: 
        !            93: static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
        !            94:                             size_t *anchors_len)
        !            95: {
        !            96:   struct cafile_parser ca;
        !            97:   br_pem_decoder_context pc;
        !            98:   br_x509_trust_anchor *ta;
        !            99:   size_t ta_size;
        !           100:   br_x509_trust_anchor *new_anchors;
        !           101:   size_t new_anchors_len;
        !           102:   br_x509_pkey *pkey;
        !           103:   FILE *fp;
        !           104:   unsigned char buf[BUFSIZ], *p;
        !           105:   const char *name;
        !           106:   size_t n, i, pushed;
        !           107: 
        !           108:   fp = fopen(path, "rb");
        !           109:   if(!fp)
        !           110:     return CURLE_SSL_CACERT_BADFILE;
        !           111: 
        !           112:   ca.err = CURLE_OK;
        !           113:   ca.in_cert = FALSE;
        !           114:   ca.anchors = NULL;
        !           115:   ca.anchors_len = 0;
        !           116:   br_pem_decoder_init(&pc);
        !           117:   br_pem_decoder_setdest(&pc, x509_push, &ca);
        !           118:   for(;;) {
        !           119:     n = fread(buf, 1, sizeof(buf), fp);
        !           120:     if(n == 0)
        !           121:       break;
        !           122:     p = buf;
        !           123:     while(n) {
        !           124:       pushed = br_pem_decoder_push(&pc, p, n);
        !           125:       if(ca.err)
        !           126:         goto fail;
        !           127:       p += pushed;
        !           128:       n -= pushed;
        !           129: 
        !           130:       switch(br_pem_decoder_event(&pc)) {
        !           131:       case 0:
        !           132:         break;
        !           133:       case BR_PEM_BEGIN_OBJ:
        !           134:         name = br_pem_decoder_name(&pc);
        !           135:         if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE"))
        !           136:           break;
        !           137:         br_x509_decoder_init(&ca.xc, append_dn, &ca);
        !           138:         if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) {
        !           139:           ca.err = CURLE_OUT_OF_MEMORY;
        !           140:           goto fail;
        !           141:         }
        !           142:         new_anchors_len = ca.anchors_len + 1;
        !           143:         new_anchors = realloc(ca.anchors,
        !           144:                               new_anchors_len * sizeof(ca.anchors[0]));
        !           145:         if(!new_anchors) {
        !           146:           ca.err = CURLE_OUT_OF_MEMORY;
        !           147:           goto fail;
        !           148:         }
        !           149:         ca.anchors = new_anchors;
        !           150:         ca.anchors_len = new_anchors_len;
        !           151:         ca.in_cert = TRUE;
        !           152:         ca.dn_len = 0;
        !           153:         ta = &ca.anchors[ca.anchors_len - 1];
        !           154:         ta->dn.data = NULL;
        !           155:         break;
        !           156:       case BR_PEM_END_OBJ:
        !           157:         if(!ca.in_cert)
        !           158:           break;
        !           159:         ca.in_cert = FALSE;
        !           160:         if(br_x509_decoder_last_error(&ca.xc)) {
        !           161:           ca.err = CURLE_SSL_CACERT_BADFILE;
        !           162:           goto fail;
        !           163:         }
        !           164:         ta->flags = 0;
        !           165:         if(br_x509_decoder_isCA(&ca.xc))
        !           166:           ta->flags |= BR_X509_TA_CA;
        !           167:         pkey = br_x509_decoder_get_pkey(&ca.xc);
        !           168:         if(!pkey) {
        !           169:           ca.err = CURLE_SSL_CACERT_BADFILE;
        !           170:           goto fail;
        !           171:         }
        !           172:         ta->pkey = *pkey;
        !           173: 
        !           174:         /* calculate space needed for trust anchor data */
        !           175:         ta_size = ca.dn_len;
        !           176:         switch(pkey->key_type) {
        !           177:         case BR_KEYTYPE_RSA:
        !           178:           ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen;
        !           179:           break;
        !           180:         case BR_KEYTYPE_EC:
        !           181:           ta_size += pkey->key.ec.qlen;
        !           182:           break;
        !           183:         default:
        !           184:           ca.err = CURLE_FAILED_INIT;
        !           185:           goto fail;
        !           186:         }
        !           187: 
        !           188:         /* fill in trust anchor DN and public key data */
        !           189:         ta->dn.data = malloc(ta_size);
        !           190:         if(!ta->dn.data) {
        !           191:           ca.err = CURLE_OUT_OF_MEMORY;
        !           192:           goto fail;
        !           193:         }
        !           194:         memcpy(ta->dn.data, ca.dn, ca.dn_len);
        !           195:         ta->dn.len = ca.dn_len;
        !           196:         switch(pkey->key_type) {
        !           197:         case BR_KEYTYPE_RSA:
        !           198:           ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len;
        !           199:           memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen);
        !           200:           ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen;
        !           201:           memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen);
        !           202:           break;
        !           203:         case BR_KEYTYPE_EC:
        !           204:           ta->pkey.key.ec.q = ta->dn.data + ta->dn.len;
        !           205:           memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen);
        !           206:           break;
        !           207:         }
        !           208:         break;
        !           209:       default:
        !           210:         ca.err = CURLE_SSL_CACERT_BADFILE;
        !           211:         goto fail;
        !           212:       }
        !           213:     }
        !           214:   }
        !           215:   if(ferror(fp))
        !           216:     ca.err = CURLE_READ_ERROR;
        !           217: 
        !           218: fail:
        !           219:   fclose(fp);
        !           220:   if(ca.err == CURLE_OK) {
        !           221:     *anchors = ca.anchors;
        !           222:     *anchors_len = ca.anchors_len;
        !           223:   }
        !           224:   else {
        !           225:     for(i = 0; i < ca.anchors_len; ++i)
        !           226:       free(ca.anchors[i].dn.data);
        !           227:     free(ca.anchors);
        !           228:   }
        !           229: 
        !           230:   return ca.err;
        !           231: }
        !           232: 
        !           233: static void x509_start_chain(const br_x509_class **ctx,
        !           234:                              const char *server_name)
        !           235: {
        !           236:   struct x509_context *x509 = (struct x509_context *)ctx;
        !           237: 
        !           238:   if(!x509->verifyhost)
        !           239:     server_name = NULL;
        !           240:   x509->minimal.vtable->start_chain(&x509->minimal.vtable, server_name);
        !           241: }
        !           242: 
        !           243: static void x509_start_cert(const br_x509_class **ctx, uint32_t length)
        !           244: {
        !           245:   struct x509_context *x509 = (struct x509_context *)ctx;
        !           246: 
        !           247:   x509->minimal.vtable->start_cert(&x509->minimal.vtable, length);
        !           248: }
        !           249: 
        !           250: static void x509_append(const br_x509_class **ctx, const unsigned char *buf,
        !           251:                         size_t len)
        !           252: {
        !           253:   struct x509_context *x509 = (struct x509_context *)ctx;
        !           254: 
        !           255:   x509->minimal.vtable->append(&x509->minimal.vtable, buf, len);
        !           256: }
        !           257: 
        !           258: static void x509_end_cert(const br_x509_class **ctx)
        !           259: {
        !           260:   struct x509_context *x509 = (struct x509_context *)ctx;
        !           261: 
        !           262:   x509->minimal.vtable->end_cert(&x509->minimal.vtable);
        !           263: }
        !           264: 
        !           265: static unsigned x509_end_chain(const br_x509_class **ctx)
        !           266: {
        !           267:   struct x509_context *x509 = (struct x509_context *)ctx;
        !           268:   unsigned err;
        !           269: 
        !           270:   err = x509->minimal.vtable->end_chain(&x509->minimal.vtable);
        !           271:   if(err && !x509->verifypeer) {
        !           272:     /* ignore any X.509 errors */
        !           273:     err = BR_ERR_OK;
        !           274:   }
        !           275: 
        !           276:   return err;
        !           277: }
        !           278: 
        !           279: static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx,
        !           280:                                          unsigned *usages)
        !           281: {
        !           282:   struct x509_context *x509 = (struct x509_context *)ctx;
        !           283: 
        !           284:   return x509->minimal.vtable->get_pkey(&x509->minimal.vtable, usages);
        !           285: }
        !           286: 
        !           287: static const br_x509_class x509_vtable = {
        !           288:   sizeof(struct x509_context),
        !           289:   x509_start_chain,
        !           290:   x509_start_cert,
        !           291:   x509_append,
        !           292:   x509_end_cert,
        !           293:   x509_end_chain,
        !           294:   x509_get_pkey
        !           295: };
        !           296: 
        !           297: static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
        !           298: {
        !           299:   struct Curl_easy *data = conn->data;
        !           300:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !           301:   struct ssl_backend_data *backend = connssl->backend;
        !           302:   const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
        !           303:   const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
        !           304:     conn->host.name;
        !           305:   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
        !           306:   const bool verifyhost = SSL_CONN_CONFIG(verifyhost);
        !           307:   CURLcode ret;
        !           308:   unsigned version_min, version_max;
        !           309: #ifdef ENABLE_IPV6
        !           310:   struct in6_addr addr;
        !           311: #else
        !           312:   struct in_addr addr;
        !           313: #endif
        !           314: 
        !           315:   switch(SSL_CONN_CONFIG(version)) {
        !           316:   case CURL_SSLVERSION_SSLv2:
        !           317:     failf(data, "BearSSL does not support SSLv2");
        !           318:     return CURLE_SSL_CONNECT_ERROR;
        !           319:   case CURL_SSLVERSION_SSLv3:
        !           320:     failf(data, "BearSSL does not support SSLv3");
        !           321:     return CURLE_SSL_CONNECT_ERROR;
        !           322:   case CURL_SSLVERSION_TLSv1_0:
        !           323:     version_min = BR_TLS10;
        !           324:     version_max = BR_TLS10;
        !           325:     break;
        !           326:   case CURL_SSLVERSION_TLSv1_1:
        !           327:     version_min = BR_TLS11;
        !           328:     version_max = BR_TLS11;
        !           329:     break;
        !           330:   case CURL_SSLVERSION_TLSv1_2:
        !           331:     version_min = BR_TLS12;
        !           332:     version_max = BR_TLS12;
        !           333:     break;
        !           334:   case CURL_SSLVERSION_DEFAULT:
        !           335:   case CURL_SSLVERSION_TLSv1:
        !           336:     version_min = BR_TLS10;
        !           337:     version_max = BR_TLS12;
        !           338:     break;
        !           339:   default:
        !           340:     failf(data, "BearSSL: unknown CURLOPT_SSLVERSION");
        !           341:     return CURLE_SSL_CONNECT_ERROR;
        !           342:   }
        !           343: 
        !           344:   if(ssl_cafile) {
        !           345:     ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len);
        !           346:     if(ret != CURLE_OK) {
        !           347:       if(verifypeer) {
        !           348:         failf(data, "error setting certificate verify locations:\n"
        !           349:               "  CAfile: %s\n", ssl_cafile);
        !           350:         return ret;
        !           351:       }
        !           352:       infof(data, "error setting certificate verify locations,"
        !           353:             " continuing anyway:\n");
        !           354:     }
        !           355:   }
        !           356: 
        !           357:   /* initialize SSL context */
        !           358:   br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal,
        !           359:                           backend->anchors, backend->anchors_len);
        !           360:   br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max);
        !           361:   br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf,
        !           362:                            sizeof(backend->buf), 1);
        !           363: 
        !           364:   /* initialize X.509 context */
        !           365:   backend->x509.vtable = &x509_vtable;
        !           366:   backend->x509.verifypeer = verifypeer;
        !           367:   backend->x509.verifyhost = verifyhost;
        !           368:   br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
        !           369: 
        !           370:   if(SSL_SET_OPTION(primary.sessionid)) {
        !           371:     void *session;
        !           372: 
        !           373:     Curl_ssl_sessionid_lock(conn);
        !           374:     if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) {
        !           375:       br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
        !           376:       infof(data, "BearSSL: re-using session ID\n");
        !           377:     }
        !           378:     Curl_ssl_sessionid_unlock(conn);
        !           379:   }
        !           380: 
        !           381:   if(conn->bits.tls_enable_alpn) {
        !           382:     int cur = 0;
        !           383: 
        !           384:     /* NOTE: when adding more protocols here, increase the size of the
        !           385:      * protocols array in `struct ssl_backend_data`.
        !           386:      */
        !           387: 
        !           388: #ifdef USE_NGHTTP2
        !           389:     if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
        !           390:        (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
        !           391:       backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID;
        !           392:       infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
        !           393:     }
        !           394: #endif
        !           395: 
        !           396:     backend->protocols[cur++] = ALPN_HTTP_1_1;
        !           397:     infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
        !           398: 
        !           399:     br_ssl_engine_set_protocol_names(&backend->ctx.eng,
        !           400:                                      backend->protocols, cur);
        !           401:   }
        !           402: 
        !           403:   if((1 == Curl_inet_pton(AF_INET, hostname, &addr))
        !           404: #ifdef ENABLE_IPV6
        !           405:       || (1 == Curl_inet_pton(AF_INET6, hostname, &addr))
        !           406: #endif
        !           407:      ) {
        !           408:     if(verifyhost) {
        !           409:       failf(data, "BearSSL: "
        !           410:             "host verification of IP address is not supported");
        !           411:       return CURLE_PEER_FAILED_VERIFICATION;
        !           412:     }
        !           413:     hostname = NULL;
        !           414:   }
        !           415: 
        !           416:   if(!br_ssl_client_reset(&backend->ctx, hostname, 0))
        !           417:     return CURLE_FAILED_INIT;
        !           418:   backend->active = TRUE;
        !           419: 
        !           420:   connssl->connecting_state = ssl_connect_2;
        !           421: 
        !           422:   return CURLE_OK;
        !           423: }
        !           424: 
        !           425: static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex,
        !           426:                                   unsigned target)
        !           427: {
        !           428:   struct Curl_easy *data = conn->data;
        !           429:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !           430:   struct ssl_backend_data *backend = connssl->backend;
        !           431:   curl_socket_t sockfd = conn->sock[sockindex];
        !           432:   unsigned state;
        !           433:   unsigned char *buf;
        !           434:   size_t len;
        !           435:   ssize_t ret;
        !           436:   int err;
        !           437: 
        !           438:   for(;;) {
        !           439:     state = br_ssl_engine_current_state(&backend->ctx.eng);
        !           440:     if(state & BR_SSL_CLOSED) {
        !           441:       err = br_ssl_engine_last_error(&backend->ctx.eng);
        !           442:       switch(err) {
        !           443:       case BR_ERR_OK:
        !           444:         /* TLS close notify */
        !           445:         if(connssl->state != ssl_connection_complete) {
        !           446:           failf(data, "SSL: connection closed during handshake");
        !           447:           return CURLE_SSL_CONNECT_ERROR;
        !           448:         }
        !           449:         return CURLE_OK;
        !           450:       case BR_ERR_X509_EXPIRED:
        !           451:         failf(data, "SSL: X.509 verification: "
        !           452:               "certificate is expired or not yet valid");
        !           453:         return CURLE_PEER_FAILED_VERIFICATION;
        !           454:       case BR_ERR_X509_BAD_SERVER_NAME:
        !           455:         failf(data, "SSL: X.509 verification: "
        !           456:               "expected server name was not found in the chain");
        !           457:         return CURLE_PEER_FAILED_VERIFICATION;
        !           458:       case BR_ERR_X509_NOT_TRUSTED:
        !           459:         failf(data, "SSL: X.509 verification: "
        !           460:               "chain could not be linked to a trust anchor");
        !           461:         return CURLE_PEER_FAILED_VERIFICATION;
        !           462:       }
        !           463:       /* X.509 errors are documented to have the range 32..63 */
        !           464:       if(err >= 32 && err < 64)
        !           465:         return CURLE_PEER_FAILED_VERIFICATION;
        !           466:       return CURLE_SSL_CONNECT_ERROR;
        !           467:     }
        !           468:     if(state & target)
        !           469:       return CURLE_OK;
        !           470:     if(state & BR_SSL_SENDREC) {
        !           471:       buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
        !           472:       ret = swrite(sockfd, buf, len);
        !           473:       if(ret == -1) {
        !           474:         if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
        !           475:           if(connssl->state != ssl_connection_complete)
        !           476:             connssl->connecting_state = ssl_connect_2_writing;
        !           477:           return CURLE_AGAIN;
        !           478:         }
        !           479:         return CURLE_WRITE_ERROR;
        !           480:       }
        !           481:       br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
        !           482:     }
        !           483:     else if(state & BR_SSL_RECVREC) {
        !           484:       buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
        !           485:       ret = sread(sockfd, buf, len);
        !           486:       if(ret == 0) {
        !           487:         failf(data, "SSL: EOF without close notify");
        !           488:         return CURLE_READ_ERROR;
        !           489:       }
        !           490:       if(ret == -1) {
        !           491:         if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
        !           492:           if(connssl->state != ssl_connection_complete)
        !           493:             connssl->connecting_state = ssl_connect_2_reading;
        !           494:           return CURLE_AGAIN;
        !           495:         }
        !           496:         return CURLE_READ_ERROR;
        !           497:       }
        !           498:       br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
        !           499:     }
        !           500:   }
        !           501: }
        !           502: 
        !           503: static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex)
        !           504: {
        !           505:   struct Curl_easy *data = conn->data;
        !           506:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !           507:   struct ssl_backend_data *backend = connssl->backend;
        !           508:   CURLcode ret;
        !           509: 
        !           510:   ret = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
        !           511:   if(ret == CURLE_AGAIN)
        !           512:     return CURLE_OK;
        !           513:   if(ret == CURLE_OK) {
        !           514:     if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
        !           515:       failf(data, "SSL: connection closed during handshake");
        !           516:       return CURLE_SSL_CONNECT_ERROR;
        !           517:     }
        !           518:     connssl->connecting_state = ssl_connect_3;
        !           519:   }
        !           520:   return ret;
        !           521: }
        !           522: 
        !           523: static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex)
        !           524: {
        !           525:   struct Curl_easy *data = conn->data;
        !           526:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !           527:   struct ssl_backend_data *backend = connssl->backend;
        !           528:   CURLcode ret;
        !           529: 
        !           530:   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
        !           531: 
        !           532:   if(conn->bits.tls_enable_alpn) {
        !           533:     const char *protocol;
        !           534: 
        !           535:     protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
        !           536:     if(protocol) {
        !           537:       infof(data, "ALPN, server accepted to use %s\n", protocol);
        !           538: 
        !           539: #ifdef USE_NGHTTP2
        !           540:       if(!strcmp(protocol, NGHTTP2_PROTO_VERSION_ID))
        !           541:         conn->negnpn = CURL_HTTP_VERSION_2;
        !           542:       else
        !           543: #endif
        !           544:       if(!strcmp(protocol, ALPN_HTTP_1_1))
        !           545:         conn->negnpn = CURL_HTTP_VERSION_1_1;
        !           546:       else
        !           547:         infof(data, "ALPN, unrecognized protocol %s\n", protocol);
        !           548:       Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
        !           549:                           BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
        !           550:     }
        !           551:     else
        !           552:       infof(data, "ALPN, server did not agree to a protocol\n");
        !           553:   }
        !           554: 
        !           555:   if(SSL_SET_OPTION(primary.sessionid)) {
        !           556:     bool incache;
        !           557:     void *oldsession;
        !           558:     br_ssl_session_parameters *session;
        !           559: 
        !           560:     session = malloc(sizeof(*session));
        !           561:     if(!session)
        !           562:       return CURLE_OUT_OF_MEMORY;
        !           563:     br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
        !           564:     Curl_ssl_sessionid_lock(conn);
        !           565:     incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex));
        !           566:     if(incache)
        !           567:       Curl_ssl_delsessionid(conn, oldsession);
        !           568:     ret = Curl_ssl_addsessionid(conn, session, 0, sockindex);
        !           569:     Curl_ssl_sessionid_unlock(conn);
        !           570:     if(ret) {
        !           571:       free(session);
        !           572:       return CURLE_OUT_OF_MEMORY;
        !           573:     }
        !           574:   }
        !           575: 
        !           576:   connssl->connecting_state = ssl_connect_done;
        !           577: 
        !           578:   return CURLE_OK;
        !           579: }
        !           580: 
        !           581: static ssize_t bearssl_send(struct connectdata *conn, int sockindex,
        !           582:                             const void *buf, size_t len, CURLcode *err)
        !           583: {
        !           584:   struct Curl_easy *data = conn->data;
        !           585:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !           586:   struct ssl_backend_data *backend = connssl->backend;
        !           587:   unsigned char *app;
        !           588:   size_t applen;
        !           589: 
        !           590:   for(;;) {
        !           591:     *err = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP);
        !           592:     if (*err != CURLE_OK)
        !           593:       return -1;
        !           594:     app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen);
        !           595:     if(!app) {
        !           596:       failf(data, "SSL: connection closed during write");
        !           597:       *err = CURLE_SEND_ERROR;
        !           598:       return -1;
        !           599:     }
        !           600:     if(backend->pending_write) {
        !           601:       applen = backend->pending_write;
        !           602:       backend->pending_write = 0;
        !           603:       return applen;
        !           604:     }
        !           605:     if(applen > len)
        !           606:       applen = len;
        !           607:     memcpy(app, buf, applen);
        !           608:     br_ssl_engine_sendapp_ack(&backend->ctx.eng, applen);
        !           609:     br_ssl_engine_flush(&backend->ctx.eng, 0);
        !           610:     backend->pending_write = applen;
        !           611:   }
        !           612: }
        !           613: 
        !           614: static ssize_t bearssl_recv(struct connectdata *conn, int sockindex,
        !           615:                             char *buf, size_t len, CURLcode *err)
        !           616: {
        !           617:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !           618:   struct ssl_backend_data *backend = connssl->backend;
        !           619:   unsigned char *app;
        !           620:   size_t applen;
        !           621: 
        !           622:   *err = bearssl_run_until(conn, sockindex, BR_SSL_RECVAPP);
        !           623:   if(*err != CURLE_OK)
        !           624:     return -1;
        !           625:   app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen);
        !           626:   if(!app)
        !           627:     return 0;
        !           628:   if(applen > len)
        !           629:     applen = len;
        !           630:   memcpy(buf, app, applen);
        !           631:   br_ssl_engine_recvapp_ack(&backend->ctx.eng, applen);
        !           632: 
        !           633:   return applen;
        !           634: }
        !           635: 
        !           636: static CURLcode bearssl_connect_common(struct connectdata *conn,
        !           637:                                        int sockindex,
        !           638:                                        bool nonblocking,
        !           639:                                        bool *done)
        !           640: {
        !           641:   CURLcode ret;
        !           642:   struct Curl_easy *data = conn->data;
        !           643:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !           644:   curl_socket_t sockfd = conn->sock[sockindex];
        !           645:   time_t timeout_ms;
        !           646:   int what;
        !           647: 
        !           648:   /* check if the connection has already been established */
        !           649:   if(ssl_connection_complete == connssl->state) {
        !           650:     *done = TRUE;
        !           651:     return CURLE_OK;
        !           652:   }
        !           653: 
        !           654:   if(ssl_connect_1 == connssl->connecting_state) {
        !           655:     ret = bearssl_connect_step1(conn, sockindex);
        !           656:     if(ret)
        !           657:       return ret;
        !           658:   }
        !           659: 
        !           660:   while(ssl_connect_2 == connssl->connecting_state ||
        !           661:         ssl_connect_2_reading == connssl->connecting_state ||
        !           662:         ssl_connect_2_writing == connssl->connecting_state) {
        !           663:     /* check allowed time left */
        !           664:     timeout_ms = Curl_timeleft(data, NULL, TRUE);
        !           665: 
        !           666:     if(timeout_ms < 0) {
        !           667:       /* no need to continue if time already is up */
        !           668:       failf(data, "SSL connection timeout");
        !           669:       return CURLE_OPERATION_TIMEDOUT;
        !           670:     }
        !           671: 
        !           672:     /* if ssl is expecting something, check if it's available. */
        !           673:     if(ssl_connect_2_reading == connssl->connecting_state ||
        !           674:        ssl_connect_2_writing == connssl->connecting_state) {
        !           675: 
        !           676:       curl_socket_t writefd = ssl_connect_2_writing ==
        !           677:         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
        !           678:       curl_socket_t readfd = ssl_connect_2_reading ==
        !           679:         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
        !           680: 
        !           681:       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
        !           682:                                nonblocking?0:timeout_ms);
        !           683:       if(what < 0) {
        !           684:         /* fatal error */
        !           685:         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        !           686:         return CURLE_SSL_CONNECT_ERROR;
        !           687:       }
        !           688:       else if(0 == what) {
        !           689:         if(nonblocking) {
        !           690:           *done = FALSE;
        !           691:           return CURLE_OK;
        !           692:         }
        !           693:         else {
        !           694:           /* timeout */
        !           695:           failf(data, "SSL connection timeout");
        !           696:           return CURLE_OPERATION_TIMEDOUT;
        !           697:         }
        !           698:       }
        !           699:       /* socket is readable or writable */
        !           700:     }
        !           701: 
        !           702:     /* Run transaction, and return to the caller if it failed or if this
        !           703:      * connection is done nonblocking and this loop would execute again. This
        !           704:      * permits the owner of a multi handle to abort a connection attempt
        !           705:      * before step2 has completed while ensuring that a client using select()
        !           706:      * or epoll() will always have a valid fdset to wait on.
        !           707:      */
        !           708:     ret = bearssl_connect_step2(conn, sockindex);
        !           709:     if(ret || (nonblocking &&
        !           710:                (ssl_connect_2 == connssl->connecting_state ||
        !           711:                 ssl_connect_2_reading == connssl->connecting_state ||
        !           712:                 ssl_connect_2_writing == connssl->connecting_state)))
        !           713:       return ret;
        !           714:   }
        !           715: 
        !           716:   if(ssl_connect_3 == connssl->connecting_state) {
        !           717:     ret = bearssl_connect_step3(conn, sockindex);
        !           718:     if(ret)
        !           719:       return ret;
        !           720:   }
        !           721: 
        !           722:   if(ssl_connect_done == connssl->connecting_state) {
        !           723:     connssl->state = ssl_connection_complete;
        !           724:     conn->recv[sockindex] = bearssl_recv;
        !           725:     conn->send[sockindex] = bearssl_send;
        !           726:     *done = TRUE;
        !           727:   }
        !           728:   else
        !           729:     *done = FALSE;
        !           730: 
        !           731:   /* Reset our connect state machine */
        !           732:   connssl->connecting_state = ssl_connect_1;
        !           733: 
        !           734:   return CURLE_OK;
        !           735: }
        !           736: 
        !           737: static size_t Curl_bearssl_version(char *buffer, size_t size)
        !           738: {
        !           739:   return msnprintf(buffer, size, "BearSSL");
        !           740: }
        !           741: 
        !           742: static bool Curl_bearssl_data_pending(const struct connectdata *conn,
        !           743:                                       int connindex)
        !           744: {
        !           745:   const struct ssl_connect_data *connssl = &conn->ssl[connindex];
        !           746:   struct ssl_backend_data *backend = connssl->backend;
        !           747:   return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP;
        !           748: }
        !           749: 
        !           750: static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM,
        !           751:                                     unsigned char *entropy, size_t length)
        !           752: {
        !           753:   static br_hmac_drbg_context ctx;
        !           754:   static bool seeded = FALSE;
        !           755: 
        !           756:   if(!seeded) {
        !           757:     br_prng_seeder seeder;
        !           758: 
        !           759:     br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0);
        !           760:     seeder = br_prng_seeder_system(NULL);
        !           761:     if(!seeder || !seeder(&ctx.vtable))
        !           762:       return CURLE_FAILED_INIT;
        !           763:     seeded = TRUE;
        !           764:   }
        !           765:   br_hmac_drbg_generate(&ctx, entropy, length);
        !           766: 
        !           767:   return CURLE_OK;
        !           768: }
        !           769: 
        !           770: static CURLcode Curl_bearssl_connect(struct connectdata *conn, int sockindex)
        !           771: {
        !           772:   CURLcode ret;
        !           773:   bool done = FALSE;
        !           774: 
        !           775:   ret = bearssl_connect_common(conn, sockindex, FALSE, &done);
        !           776:   if(ret)
        !           777:     return ret;
        !           778: 
        !           779:   DEBUGASSERT(done);
        !           780: 
        !           781:   return CURLE_OK;
        !           782: }
        !           783: 
        !           784: static CURLcode Curl_bearssl_connect_nonblocking(struct connectdata *conn,
        !           785:                                                  int sockindex, bool *done)
        !           786: {
        !           787:   return bearssl_connect_common(conn, sockindex, TRUE, done);
        !           788: }
        !           789: 
        !           790: static void *Curl_bearssl_get_internals(struct ssl_connect_data *connssl,
        !           791:                                         CURLINFO info UNUSED_PARAM)
        !           792: {
        !           793:   struct ssl_backend_data *backend = connssl->backend;
        !           794:   return &backend->ctx;
        !           795: }
        !           796: 
        !           797: static void Curl_bearssl_close(struct connectdata *conn, int sockindex)
        !           798: {
        !           799:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !           800:   struct ssl_backend_data *backend = connssl->backend;
        !           801:   size_t i;
        !           802: 
        !           803:   if(backend->active) {
        !           804:     br_ssl_engine_close(&backend->ctx.eng);
        !           805:     (void)bearssl_run_until(conn, sockindex, BR_SSL_CLOSED);
        !           806:   }
        !           807:   for(i = 0; i < backend->anchors_len; ++i)
        !           808:     free(backend->anchors[i].dn.data);
        !           809:   free(backend->anchors);
        !           810: }
        !           811: 
        !           812: static void Curl_bearssl_session_free(void *ptr)
        !           813: {
        !           814:   free(ptr);
        !           815: }
        !           816: 
        !           817: static CURLcode Curl_bearssl_md5sum(unsigned char *input,
        !           818:                                     size_t inputlen,
        !           819:                                     unsigned char *md5sum,
        !           820:                                     size_t md5len UNUSED_PARAM)
        !           821: {
        !           822:   br_md5_context ctx;
        !           823: 
        !           824:   br_md5_init(&ctx);
        !           825:   br_md5_update(&ctx, input, inputlen);
        !           826:   br_md5_out(&ctx, md5sum);
        !           827:   return CURLE_OK;
        !           828: }
        !           829: 
        !           830: static CURLcode Curl_bearssl_sha256sum(const unsigned char *input,
        !           831:                                        size_t inputlen,
        !           832:                                        unsigned char *sha256sum,
        !           833:                                        size_t sha256len UNUSED_PARAM)
        !           834: {
        !           835:   br_sha256_context ctx;
        !           836: 
        !           837:   br_sha256_init(&ctx);
        !           838:   br_sha256_update(&ctx, input, inputlen);
        !           839:   br_sha256_out(&ctx, sha256sum);
        !           840:   return CURLE_OK;
        !           841: }
        !           842: 
        !           843: const struct Curl_ssl Curl_ssl_bearssl = {
        !           844:   { CURLSSLBACKEND_BEARSSL, "bearssl" },
        !           845:   0,
        !           846:   sizeof(struct ssl_backend_data),
        !           847: 
        !           848:   Curl_none_init,
        !           849:   Curl_none_cleanup,
        !           850:   Curl_bearssl_version,
        !           851:   Curl_none_check_cxn,
        !           852:   Curl_none_shutdown,
        !           853:   Curl_bearssl_data_pending,
        !           854:   Curl_bearssl_random,
        !           855:   Curl_none_cert_status_request,
        !           856:   Curl_bearssl_connect,
        !           857:   Curl_bearssl_connect_nonblocking,
        !           858:   Curl_bearssl_get_internals,
        !           859:   Curl_bearssl_close,
        !           860:   Curl_none_close_all,
        !           861:   Curl_bearssl_session_free,
        !           862:   Curl_none_set_engine,
        !           863:   Curl_none_set_engine_default,
        !           864:   Curl_none_engines_list,
        !           865:   Curl_none_false_start,
        !           866:   Curl_bearssl_md5sum,
        !           867:   Curl_bearssl_sha256sum
        !           868: };
        !           869: 
        !           870: #endif /* USE_BEARSSL */

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