Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmcurl/lib/vtls/vtls.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) 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.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
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
/* This file is for implementing all "generic" SSL functions that all libcurl
26
   internals should use. It is then responsible for calling the proper
27
   "backend" function.
28
29
   SSL-functions in libcurl should call functions in this source file, and not
30
   to any specific SSL-layer.
31
32
   Curl_ssl_ - prefix for generic ones
33
34
   Note that this source code uses the functions of the configured SSL
35
   backend via the global Curl_ssl instance.
36
37
   "SSL/TLS Strong Encryption: An Introduction"
38
   https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
39
*/
40
41
#include "../curl_setup.h"
42
43
#ifdef HAVE_SYS_TYPES_H
44
#include <sys/types.h>
45
#endif
46
47
#include "../urldata.h"
48
#include "../cfilters.h"
49
50
#include "vtls.h" /* generic SSL protos etc */
51
#include "vtls_int.h"
52
#include "vtls_scache.h"
53
54
#include "openssl.h"        /* OpenSSL versions */
55
#include "gtls.h"           /* GnuTLS versions */
56
#include "wolfssl.h"        /* wolfSSL versions */
57
#include "schannel.h"       /* Schannel SSPI version */
58
#include "mbedtls.h"        /* mbedTLS versions */
59
#include "rustls.h"         /* Rustls versions */
60
61
#include "../slist.h"
62
#include "../curl_trc.h"
63
#include "../strcase.h"
64
#include "../url.h"
65
#include "../progress.h"
66
#include "../curlx/fopen.h"
67
#include "../curl_sha256.h"
68
#include "../curlx/base64.h"
69
#include "../curlx/inet_pton.h"
70
#include "../connect.h"
71
#include "../select.h"
72
#include "../setopt.h"
73
#include "../strdup.h"
74
#include "../curlx/strcopy.h"
75
76
#ifdef USE_APPLE_SECTRUST
77
#include <Security/Security.h>
78
#endif
79
80
81
#define CLONE_STRING(var)                    \
82
0
  do {                                       \
83
0
    if(source->var) {                        \
84
0
      dest->var = curlx_strdup(source->var); \
85
0
      if(!dest->var)                         \
86
0
        return FALSE;                        \
87
0
    }                                        \
88
0
    else                                     \
89
0
      dest->var = NULL;                      \
90
0
  } while(0)
91
92
#define CLONE_BLOB(var)                  \
93
0
  do {                                   \
94
0
    if(blobdup(&dest->var, source->var)) \
95
0
      return FALSE;                      \
96
0
  } while(0)
97
98
static CURLcode blobdup(struct curl_blob **dest, struct curl_blob *src)
99
0
{
100
0
  DEBUGASSERT(dest);
101
0
  DEBUGASSERT(!*dest);
102
0
  if(src) {
103
    /* only if there is data to dupe! */
104
0
    struct curl_blob *d;
105
0
    d = curlx_malloc(sizeof(struct curl_blob) + src->len);
106
0
    if(!d)
107
0
      return CURLE_OUT_OF_MEMORY;
108
0
    d->len = src->len;
109
    /* Always duplicate because the connection may survive longer than the
110
       handle that passed in the blob. */
111
0
    d->flags = CURL_BLOB_COPY;
112
0
    d->data = (void *)((char *)d + sizeof(struct curl_blob));
113
0
    memcpy(d->data, src->data, src->len);
114
0
    *dest = d;
115
0
  }
116
0
  return CURLE_OK;
117
0
}
118
119
/* returns TRUE if the blobs are identical */
120
static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
121
0
{
122
0
  if(!first && !second) /* both are NULL */
123
0
    return TRUE;
124
0
  if(!first || !second) /* one is NULL */
125
0
    return FALSE;
126
0
  if(first->len != second->len) /* different sizes */
127
0
    return FALSE;
128
0
  return !memcmp(first->data, second->data, first->len); /* same data */
129
0
}
130
131
#ifdef USE_SSL
132
#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_PROXY)
133
static const struct alpn_spec ALPN_SPEC_H11 = {
134
  { ALPN_HTTP_1_1 }, 1
135
};
136
#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_PROXY */
137
#ifdef USE_HTTP2
138
static const struct alpn_spec ALPN_SPEC_H2 = {
139
  { ALPN_H2 }, 1
140
};
141
static const struct alpn_spec ALPN_SPEC_H2_H11 = {
142
  { ALPN_H2, ALPN_HTTP_1_1 }, 2
143
};
144
static const struct alpn_spec ALPN_SPEC_H11_H2 = {
145
  { ALPN_HTTP_1_1, ALPN_H2 }, 2
146
};
147
#endif
148
149
#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_PROXY)
150
static const struct alpn_spec *alpn_get_spec(http_majors wanted,
151
                                             http_majors preferred,
152
                                             bool use_alpn)
153
{
154
  if(!use_alpn)
155
    return NULL;
156
#ifdef USE_HTTP2
157
  if(wanted & CURL_HTTP_V2x) {
158
    if(wanted & CURL_HTTP_V1x)
159
      return (preferred == CURL_HTTP_V1x) ?
160
        &ALPN_SPEC_H11_H2 : &ALPN_SPEC_H2_H11;
161
    return &ALPN_SPEC_H2;
162
  }
163
#else
164
  (void)wanted;
165
  (void)preferred;
166
#endif
167
  /* Use the ALPN protocol "http/1.1" for HTTP/1.x.
168
     Avoid "http/1.0" because some servers do not support it. */
169
  return &ALPN_SPEC_H11;
170
}
171
#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_PROXY */
172
#endif /* USE_SSL */
173
174
void Curl_ssl_easy_config_init(struct Curl_easy *data)
175
0
{
176
  /*
177
   * libcurl 7.10 introduced SSL verification *by default*! This needs to be
178
   * switched off unless wanted.
179
   */
180
0
  data->set.ssl.primary.verifypeer = TRUE;
181
0
  data->set.ssl.primary.verifyhost = TRUE;
182
0
  data->set.ssl.primary.cache_session = TRUE; /* caching by default */
183
0
#ifndef CURL_DISABLE_PROXY
184
0
  data->set.proxy_ssl = data->set.ssl;
185
0
#endif
186
0
}
187
188
static bool match_ssl_primary_config(struct Curl_easy *data,
189
                                     struct ssl_primary_config *c1,
190
                                     struct ssl_primary_config *c2)
191
0
{
192
0
  (void)data;
193
0
  if((c1->version == c2->version) &&
194
0
     (c1->version_max == c2->version_max) &&
195
0
     (c1->ssl_options == c2->ssl_options) &&
196
0
     (c1->verifypeer == c2->verifypeer) &&
197
0
     (c1->verifyhost == c2->verifyhost) &&
198
0
     (c1->verifystatus == c2->verifystatus) &&
199
0
     blobcmp(c1->cert_blob, c2->cert_blob) &&
200
0
     blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
201
0
     blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
202
0
     Curl_safecmp(c1->CApath, c2->CApath) &&
203
0
     Curl_safecmp(c1->CAfile, c2->CAfile) &&
204
0
     Curl_safecmp(c1->issuercert, c2->issuercert) &&
205
0
     Curl_safecmp(c1->clientcert, c2->clientcert) &&
206
#ifdef USE_TLS_SRP
207
     !Curl_timestrcmp(c1->username, c2->username) &&
208
     !Curl_timestrcmp(c1->password, c2->password) &&
209
#endif
210
0
     curl_strequal(c1->cipher_list, c2->cipher_list) &&
211
0
     curl_strequal(c1->cipher_list13, c2->cipher_list13) &&
212
0
     curl_strequal(c1->curves, c2->curves) &&
213
0
     curl_strequal(c1->signature_algorithms, c2->signature_algorithms) &&
214
0
     curl_strequal(c1->CRLfile, c2->CRLfile) &&
215
0
     curl_strequal(c1->pinned_key, c2->pinned_key))
216
0
    return TRUE;
217
218
0
  return FALSE;
219
0
}
220
221
bool Curl_ssl_conn_config_match(struct Curl_easy *data,
222
                                struct connectdata *candidate,
223
                                bool proxy)
224
0
{
225
0
#ifndef CURL_DISABLE_PROXY
226
0
  if(proxy)
227
0
    return match_ssl_primary_config(data, &data->set.proxy_ssl.primary,
228
0
                                    &candidate->proxy_ssl_config);
229
#else
230
  (void)proxy;
231
#endif
232
0
  return match_ssl_primary_config(data, &data->set.ssl.primary,
233
0
                                  &candidate->ssl_config);
234
0
}
235
236
static bool clone_ssl_primary_config(struct ssl_primary_config *source,
237
                                     struct ssl_primary_config *dest)
238
0
{
239
0
  dest->version = source->version;
240
0
  dest->version_max = source->version_max;
241
0
  dest->verifypeer = source->verifypeer;
242
0
  dest->verifyhost = source->verifyhost;
243
0
  dest->verifystatus = source->verifystatus;
244
0
  dest->cache_session = source->cache_session;
245
0
  dest->ssl_options = source->ssl_options;
246
247
0
  CLONE_BLOB(cert_blob);
248
0
  CLONE_BLOB(ca_info_blob);
249
0
  CLONE_BLOB(issuercert_blob);
250
0
  CLONE_STRING(CApath);
251
0
  CLONE_STRING(CAfile);
252
0
  CLONE_STRING(issuercert);
253
0
  CLONE_STRING(clientcert);
254
0
  CLONE_STRING(cipher_list);
255
0
  CLONE_STRING(cipher_list13);
256
0
  CLONE_STRING(pinned_key);
257
0
  CLONE_STRING(curves);
258
0
  CLONE_STRING(signature_algorithms);
259
0
  CLONE_STRING(CRLfile);
260
#ifdef USE_TLS_SRP
261
  CLONE_STRING(username);
262
  CLONE_STRING(password);
263
#endif
264
265
0
  return TRUE;
266
0
}
267
268
static void free_primary_ssl_config(struct ssl_primary_config *sslc)
269
0
{
270
0
  Curl_safefree(sslc->CApath);
271
0
  Curl_safefree(sslc->CAfile);
272
0
  Curl_safefree(sslc->issuercert);
273
0
  Curl_safefree(sslc->clientcert);
274
0
  Curl_safefree(sslc->cipher_list);
275
0
  Curl_safefree(sslc->cipher_list13);
276
0
  Curl_safefree(sslc->pinned_key);
277
0
  Curl_safefree(sslc->cert_blob);
278
0
  Curl_safefree(sslc->ca_info_blob);
279
0
  Curl_safefree(sslc->issuercert_blob);
280
0
  Curl_safefree(sslc->curves);
281
0
  Curl_safefree(sslc->signature_algorithms);
282
0
  Curl_safefree(sslc->CRLfile);
283
#ifdef USE_TLS_SRP
284
  Curl_safefree(sslc->username);
285
  Curl_safefree(sslc->password);
286
#endif
287
0
}
288
289
CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
290
0
{
291
0
  struct ssl_config_data *sslc = &data->set.ssl;
292
#if defined(CURL_CA_PATH) || defined(CURL_CA_BUNDLE)
293
  struct UserDefined *set = &data->set;
294
  CURLcode result;
295
#endif
296
297
0
  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
298
#ifdef USE_APPLE_SECTRUST
299
    if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
300
      sslc->native_ca_store = TRUE;
301
#endif
302
#ifdef CURL_CA_PATH
303
    if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH]) {
304
      result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
305
      if(result)
306
        return result;
307
    }
308
#endif
309
#ifdef CURL_CA_BUNDLE
310
    if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE]) {
311
      result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
312
      if(result)
313
        return result;
314
    }
315
#endif
316
0
  }
317
0
  sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE];
318
0
  sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
319
0
  sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH];
320
0
  sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
321
0
  sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
322
0
  sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
323
0
  sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST];
324
0
  sslc->primary.signature_algorithms =
325
0
    data->set.str[STRING_SSL_SIGNATURE_ALGORITHMS];
326
0
  sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
327
0
  sslc->primary.cert_blob = data->set.blobs[BLOB_CERT];
328
0
  sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
329
0
  sslc->primary.curves = data->set.str[STRING_SSL_EC_CURVES];
330
#ifdef USE_TLS_SRP
331
  sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
332
  sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
333
#endif
334
0
  sslc->cert_type = data->set.str[STRING_CERT_TYPE];
335
0
  sslc->key = data->set.str[STRING_KEY];
336
0
  sslc->key_type = data->set.str[STRING_KEY_TYPE];
337
0
  sslc->key_passwd = data->set.str[STRING_KEY_PASSWD];
338
0
  sslc->primary.clientcert = data->set.str[STRING_CERT];
339
0
  sslc->key_blob = data->set.blobs[BLOB_KEY];
340
341
0
#ifndef CURL_DISABLE_PROXY
342
0
  sslc = &data->set.proxy_ssl;
343
0
  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
344
#ifdef USE_APPLE_SECTRUST
345
    if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
346
      sslc->native_ca_store = TRUE;
347
#endif
348
#ifdef CURL_CA_PATH
349
    if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH_PROXY]) {
350
      result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY],
351
                              CURL_CA_PATH);
352
      if(result)
353
        return result;
354
    }
355
#endif
356
#ifdef CURL_CA_BUNDLE
357
    if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE_PROXY]) {
358
      result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
359
                              CURL_CA_BUNDLE);
360
      if(result)
361
        return result;
362
    }
363
#endif
364
0
  }
365
0
  sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
366
0
  sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
367
0
  sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
368
0
  sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
369
0
  sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
370
0
  sslc->primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
371
0
  sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO_PROXY];
372
0
  sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
373
0
  sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
374
0
  sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
375
0
  sslc->cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
376
0
  sslc->key = data->set.str[STRING_KEY_PROXY];
377
0
  sslc->key_type = data->set.str[STRING_KEY_TYPE_PROXY];
378
0
  sslc->key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
379
0
  sslc->primary.clientcert = data->set.str[STRING_CERT_PROXY];
380
0
  sslc->key_blob = data->set.blobs[BLOB_KEY_PROXY];
381
#ifdef USE_TLS_SRP
382
  sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
383
  sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
384
#endif
385
0
#endif /* CURL_DISABLE_PROXY */
386
387
0
  return CURLE_OK;
388
0
}
389
390
CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
391
                                   struct connectdata *conn)
392
0
{
393
  /* Clone "primary" SSL configurations from the esay handle to
394
   * the connection. They are used for connection cache matching and
395
   * probably outlive the easy handle */
396
0
  if(!clone_ssl_primary_config(&data->set.ssl.primary, &conn->ssl_config))
397
0
    return CURLE_OUT_OF_MEMORY;
398
0
#ifndef CURL_DISABLE_PROXY
399
0
  if(!clone_ssl_primary_config(&data->set.proxy_ssl.primary,
400
0
                               &conn->proxy_ssl_config))
401
0
    return CURLE_OUT_OF_MEMORY;
402
0
#endif
403
0
  return CURLE_OK;
404
0
}
405
406
void Curl_ssl_conn_config_cleanup(struct connectdata *conn)
407
0
{
408
0
  free_primary_ssl_config(&conn->ssl_config);
409
0
#ifndef CURL_DISABLE_PROXY
410
0
  free_primary_ssl_config(&conn->proxy_ssl_config);
411
0
#endif
412
0
}
413
414
void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy)
415
0
{
416
  /* May be called on an easy that has no connection yet */
417
0
  if(data->conn) {
418
0
    struct ssl_primary_config *src, *dest;
419
0
#ifndef CURL_DISABLE_PROXY
420
0
    src = for_proxy ? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
421
0
    dest = for_proxy ? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
422
#else
423
    (void)for_proxy;
424
    src = &data->set.ssl.primary;
425
    dest = &data->conn->ssl_config;
426
#endif
427
0
    dest->verifyhost = src->verifyhost;
428
0
    dest->verifypeer = src->verifypeer;
429
0
    dest->verifystatus = src->verifystatus;
430
0
  }
431
0
}
432
433
#ifdef USE_SSL
434
static int multissl_setup(const struct Curl_ssl *backend);
435
#endif
436
437
curl_sslbackend Curl_ssl_backend(void)
438
0
{
439
#ifdef USE_SSL
440
  multissl_setup(NULL);
441
  return Curl_ssl->info.id;
442
#else
443
0
  return CURLSSLBACKEND_NONE;
444
0
#endif
445
0
}
446
447
#ifdef USE_SSL
448
449
/* "global" init done? */
450
static bool init_ssl = FALSE;
451
452
/**
453
 * Global SSL init
454
 *
455
 * @retval 0 error initializing SSL
456
 * @retval 1 SSL initialized successfully
457
 */
458
int Curl_ssl_init(void)
459
{
460
  /* make sure this is only done once */
461
  if(init_ssl)
462
    return 1;
463
  init_ssl = TRUE; /* never again */
464
465
  if(Curl_ssl->init)
466
    return Curl_ssl->init();
467
  return 1;
468
}
469
470
static bool ssl_prefs_check(struct Curl_easy *data)
471
{
472
  /* check for CURLOPT_SSLVERSION invalid parameter value */
473
  const unsigned char sslver = data->set.ssl.primary.version;
474
  if(sslver >= CURL_SSLVERSION_LAST) {
475
    failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
476
    return FALSE;
477
  }
478
479
  switch(data->set.ssl.primary.version_max) {
480
  case CURL_SSLVERSION_MAX_NONE:
481
  case CURL_SSLVERSION_MAX_DEFAULT:
482
    break;
483
484
  default:
485
    if((data->set.ssl.primary.version_max >> 16) < sslver) {
486
      failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION");
487
      return FALSE;
488
    }
489
  }
490
491
  return TRUE;
492
}
493
494
static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
495
                                           const struct alpn_spec *alpn)
496
{
497
  struct ssl_connect_data *ctx;
498
499
  (void)data;
500
  ctx = curlx_calloc(1, sizeof(*ctx));
501
  if(!ctx)
502
    return NULL;
503
504
  ctx->ssl_impl = Curl_ssl;
505
  ctx->alpn = alpn;
506
  Curl_bufq_init2(&ctx->earlydata, CURL_SSL_EARLY_MAX, 1, BUFQ_OPT_NO_SPARES);
507
  ctx->backend = curlx_calloc(1, ctx->ssl_impl->sizeof_ssl_backend_data);
508
  if(!ctx->backend) {
509
    curlx_free(ctx);
510
    return NULL;
511
  }
512
  return ctx;
513
}
514
515
static void cf_ctx_free(struct ssl_connect_data *ctx)
516
{
517
  if(ctx) {
518
    Curl_safefree(ctx->negotiated.alpn);
519
    Curl_bufq_free(&ctx->earlydata);
520
    curlx_free(ctx->backend);
521
    curlx_free(ctx);
522
  }
523
}
524
525
CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex,
526
                                      struct dynbuf *binding)
527
{
528
  if(Curl_ssl->get_channel_binding)
529
    return Curl_ssl->get_channel_binding(data, sockindex, binding);
530
  return CURLE_OK;
531
}
532
533
void Curl_ssl_close_all(struct Curl_easy *data)
534
{
535
  if(Curl_ssl->close_all)
536
    Curl_ssl->close_all(data);
537
}
538
539
CURLcode Curl_ssl_adjust_pollset(struct Curl_cfilter *cf,
540
                                 struct Curl_easy *data,
541
                                 struct easy_pollset *ps)
542
{
543
  struct ssl_connect_data *connssl = cf->ctx;
544
545
  if(connssl->io_need) {
546
    curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
547
    CURLcode result = CURLE_OK;
548
    if(sock != CURL_SOCKET_BAD) {
549
      if(connssl->io_need & CURL_SSL_IO_NEED_SEND) {
550
        result = Curl_pollset_set_out_only(data, ps, sock);
551
        CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%" FMT_SOCKET_T,
552
                    sock);
553
      }
554
      else {
555
        result = Curl_pollset_set_in_only(data, ps, sock);
556
        CURL_TRC_CF(data, cf, "adjust_pollset, POLLIN fd=%" FMT_SOCKET_T,
557
                    sock);
558
      }
559
    }
560
    return result;
561
  }
562
  return CURLE_OK;
563
}
564
565
/* Selects an SSL crypto engine
566
 */
567
CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
568
{
569
  if(Curl_ssl->set_engine)
570
    return Curl_ssl->set_engine(data, engine);
571
  return CURLE_NOT_BUILT_IN;
572
}
573
574
/* Selects the default SSL crypto engine
575
 */
576
CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
577
{
578
  if(Curl_ssl->set_engine_default)
579
    return Curl_ssl->set_engine_default(data);
580
  return CURLE_NOT_BUILT_IN;
581
}
582
583
/* Return list of OpenSSL crypto engine names. */
584
struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
585
{
586
  if(Curl_ssl->engines_list)
587
    return Curl_ssl->engines_list(data);
588
  return NULL;
589
}
590
591
static size_t multissl_version(char *buffer, size_t size);
592
593
void Curl_ssl_version(char *buffer, size_t size)
594
{
595
#ifdef CURL_WITH_MULTI_SSL
596
  (void)multissl_version(buffer, size);
597
#else
598
  (void)Curl_ssl->version(buffer, size);
599
#endif
600
}
601
602
void Curl_ssl_free_certinfo(struct Curl_easy *data)
603
{
604
  struct curl_certinfo *ci = &data->info.certs;
605
606
  if(ci->num_of_certs) {
607
    /* free all individual lists used */
608
    int i;
609
    for(i = 0; i < ci->num_of_certs; i++) {
610
      curl_slist_free_all(ci->certinfo[i]);
611
      ci->certinfo[i] = NULL;
612
    }
613
614
    curlx_free(ci->certinfo); /* free the actual array too */
615
    ci->certinfo = NULL;
616
    ci->num_of_certs = 0;
617
  }
618
}
619
620
CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
621
{
622
  struct curl_certinfo *ci = &data->info.certs;
623
  struct curl_slist **table;
624
625
  /* Free any previous certificate information structures */
626
  Curl_ssl_free_certinfo(data);
627
628
  /* Allocate the required certificate information structures */
629
  table = curlx_calloc((size_t)num, sizeof(struct curl_slist *));
630
  if(!table)
631
    return CURLE_OUT_OF_MEMORY;
632
633
  ci->num_of_certs = num;
634
  ci->certinfo = table;
635
636
  return CURLE_OK;
637
}
638
639
/*
640
 * 'value' is NOT a null-terminated string
641
 */
642
CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
643
                                    int certnum,
644
                                    const char *label,
645
                                    const char *value,
646
                                    size_t valuelen)
647
{
648
  struct curl_certinfo *ci = &data->info.certs;
649
  struct curl_slist *nl;
650
  CURLcode result = CURLE_OK;
651
  struct dynbuf build;
652
653
  DEBUGASSERT(certnum < ci->num_of_certs);
654
655
  curlx_dyn_init(&build, CURL_X509_STR_MAX);
656
657
  if(curlx_dyn_add(&build, label) ||
658
     curlx_dyn_addn(&build, ":", 1) ||
659
     curlx_dyn_addn(&build, value, valuelen))
660
    return CURLE_OUT_OF_MEMORY;
661
662
  nl = Curl_slist_append_nodup(ci->certinfo[certnum], curlx_dyn_ptr(&build));
663
  if(!nl) {
664
    curlx_dyn_free(&build);
665
    curl_slist_free_all(ci->certinfo[certnum]);
666
    result = CURLE_OUT_OF_MEMORY;
667
  }
668
669
  ci->certinfo[certnum] = nl;
670
  return result;
671
}
672
673
/* get length bytes of randomness */
674
CURLcode Curl_ssl_random(struct Curl_easy *data,
675
                         unsigned char *entropy,
676
                         size_t length)
677
{
678
  DEBUGASSERT(length == sizeof(int));
679
  if(Curl_ssl->random)
680
    return Curl_ssl->random(data, entropy, length);
681
  else
682
    return CURLE_NOT_BUILT_IN;
683
}
684
685
/*
686
 * Public key pem to der conversion
687
 */
688
689
static CURLcode pubkey_pem_to_der(const char *pem,
690
                                  unsigned char **der, size_t *der_len)
691
{
692
  char *begin_pos, *end_pos;
693
  size_t pem_count, pem_len;
694
  CURLcode result;
695
  struct dynbuf pbuf;
696
697
  /* if no pem, exit. */
698
  if(!pem)
699
    return CURLE_BAD_CONTENT_ENCODING;
700
701
  curlx_dyn_init(&pbuf, MAX_PINNED_PUBKEY_SIZE);
702
703
  begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
704
  if(!begin_pos)
705
    return CURLE_BAD_CONTENT_ENCODING;
706
707
  pem_count = begin_pos - pem;
708
  /* Invalid if not at beginning AND not directly following \n */
709
  if(pem_count && '\n' != pem[pem_count - 1])
710
    return CURLE_BAD_CONTENT_ENCODING;
711
712
  /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
713
  pem_count += 26;
714
715
  /* Invalid if not directly following \n */
716
  end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
717
  if(!end_pos)
718
    return CURLE_BAD_CONTENT_ENCODING;
719
720
  pem_len = end_pos - pem;
721
722
  /*
723
   * Here we loop through the pem array one character at a time between the
724
   * correct indices, and place each character that is not '\n' or '\r'
725
   * into the stripped_pem array, which should represent the raw base64 string
726
   */
727
  while(pem_count < pem_len) {
728
    if('\n' != pem[pem_count] && '\r' != pem[pem_count]) {
729
      result = curlx_dyn_addn(&pbuf, &pem[pem_count], 1);
730
      if(result)
731
        return result;
732
    }
733
    ++pem_count;
734
  }
735
736
  if(curlx_dyn_len(&pbuf)) {
737
    result = curlx_base64_decode(curlx_dyn_ptr(&pbuf), der, der_len);
738
    curlx_dyn_free(&pbuf);
739
  }
740
  else
741
    result = CURLE_BAD_CONTENT_ENCODING;
742
743
  return result;
744
}
745
746
/*
747
 * Generic pinned public key check.
748
 */
749
750
CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
751
                              const char *pinnedpubkey,
752
                              const unsigned char *pubkey, size_t pubkeylen)
753
{
754
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
755
#ifdef CURL_DISABLE_VERBOSE_STRINGS
756
  (void)data;
757
#endif
758
759
  /* if a path was not specified, do not pin */
760
  if(!pinnedpubkey)
761
    return CURLE_OK;
762
  if(!pubkey || !pubkeylen)
763
    return result;
764
765
  /* only do this if pinnedpubkey starts with "sha256//", length 8 */
766
  if(!strncmp(pinnedpubkey, "sha256//", 8)) {
767
    CURLcode encode;
768
    char *cert_hash = NULL;
769
    const char *pinned_hash, *end_pos;
770
    size_t cert_hash_len = 0, pinned_hash_len;
771
    unsigned char *sha256sumdigest;
772
773
    if(!Curl_ssl->sha256sum) {
774
      /* without sha256 support, this cannot match */
775
      return result;
776
    }
777
778
    /* compute sha256sum of public key */
779
    sha256sumdigest = curlx_malloc(CURL_SHA256_DIGEST_LENGTH);
780
    if(!sha256sumdigest)
781
      return CURLE_OUT_OF_MEMORY;
782
    encode = Curl_ssl->sha256sum(pubkey, pubkeylen,
783
                                 sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
784
785
    if(!encode)
786
      encode = curlx_base64_encode(sha256sumdigest,
787
                                   CURL_SHA256_DIGEST_LENGTH,
788
                                   &cert_hash, &cert_hash_len);
789
    Curl_safefree(sha256sumdigest);
790
791
    if(encode)
792
      return encode;
793
794
    infof(data, " public key hash: sha256//%s", cert_hash);
795
796
    pinned_hash = pinnedpubkey;
797
    while(pinned_hash &&
798
          !strncmp(pinned_hash, "sha256//", (sizeof("sha256//") - 1))) {
799
      pinned_hash = pinned_hash + (sizeof("sha256//") - 1);
800
      end_pos = strchr(pinned_hash, ';');
801
      pinned_hash_len = end_pos ?
802
                        (size_t)(end_pos - pinned_hash) : strlen(pinned_hash);
803
804
      /* compare base64 sha256 digests" */
805
      if(cert_hash_len == pinned_hash_len &&
806
         !memcmp(cert_hash, pinned_hash, cert_hash_len)) {
807
        DEBUGF(infof(data, "public key hash matches pinned value"));
808
        result = CURLE_OK;
809
        break;
810
      }
811
812
      DEBUGF(infof(data, "public key hash does not match 'sha256//%.*s'",
813
                   (int)pinned_hash_len, pinned_hash));
814
      /* next one or we are at the end */
815
      pinned_hash = end_pos ? (end_pos + 1) : NULL;
816
    }
817
    Curl_safefree(cert_hash);
818
  }
819
  else {
820
    long filesize;
821
    size_t size, pem_len;
822
    CURLcode pem_read;
823
    struct dynbuf buf;
824
    char unsigned *pem_ptr = NULL;
825
    size_t left;
826
    FILE *fp = curlx_fopen(pinnedpubkey, "rb");
827
    if(!fp)
828
      return result;
829
830
    curlx_dyn_init(&buf, MAX_PINNED_PUBKEY_SIZE);
831
832
    /* Determine the file's size */
833
    if(fseek(fp, 0, SEEK_END))
834
      goto end;
835
    filesize = ftell(fp);
836
    if(fseek(fp, 0, SEEK_SET))
837
      goto end;
838
    if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
839
      goto end;
840
841
    /*
842
     * if the size of our certificate is bigger than the file
843
     * size then it cannot match
844
     */
845
    size = curlx_sotouz((curl_off_t)filesize);
846
    if(pubkeylen > size)
847
      goto end;
848
849
    /*
850
     * Read the file into the dynbuf
851
     */
852
    left = size;
853
    do {
854
      char buffer[1024];
855
      size_t want = left > sizeof(buffer) ? sizeof(buffer) : left;
856
      if(want != fread(buffer, 1, want, fp))
857
        goto end;
858
      if(curlx_dyn_addn(&buf, buffer, want))
859
        goto end;
860
      left -= want;
861
    } while(left);
862
863
    /* If the sizes are the same, it cannot be base64 encoded, must be der */
864
    if(pubkeylen == size) {
865
      if(!memcmp(pubkey, curlx_dyn_ptr(&buf), pubkeylen))
866
        result = CURLE_OK;
867
      goto end;
868
    }
869
870
    /*
871
     * Otherwise we will assume it is PEM and try to decode it after placing
872
     * null-terminator
873
     */
874
    pem_read = pubkey_pem_to_der(curlx_dyn_ptr(&buf), &pem_ptr, &pem_len);
875
    /* if it was not read successfully, exit */
876
    if(pem_read)
877
      goto end;
878
879
    /*
880
     * if the size of our certificate does not match the size of
881
     * the decoded file, they cannot be the same, otherwise compare
882
     */
883
    if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
884
      result = CURLE_OK;
885
end:
886
    curlx_dyn_free(&buf);
887
    Curl_safefree(pem_ptr);
888
    curlx_fclose(fp);
889
  }
890
891
  return result;
892
}
893
894
/*
895
 * Check whether the SSL backend supports the status_request extension.
896
 */
897
bool Curl_ssl_cert_status_request(void)
898
{
899
  if(Curl_ssl->cert_status_request)
900
    return Curl_ssl->cert_status_request();
901
  return FALSE;
902
}
903
904
static int multissl_init(void)
905
{
906
  if(multissl_setup(NULL))
907
    return 1;
908
  if(Curl_ssl->init)
909
    return Curl_ssl->init();
910
  return 1;
911
}
912
913
static CURLcode multissl_random(struct Curl_easy *data,
914
                                unsigned char *entropy, size_t length)
915
{
916
  if(multissl_setup(NULL))
917
    return CURLE_FAILED_INIT;
918
  return Curl_ssl->random(data, entropy, length);
919
}
920
921
static CURLcode multissl_connect(struct Curl_cfilter *cf,
922
                                 struct Curl_easy *data, bool *done)
923
{
924
  if(multissl_setup(NULL))
925
    return CURLE_FAILED_INIT;
926
  return Curl_ssl->do_connect(cf, data, done);
927
}
928
929
static CURLcode multissl_adjust_pollset(struct Curl_cfilter *cf,
930
                                        struct Curl_easy *data,
931
                                        struct easy_pollset *ps)
932
{
933
  if(multissl_setup(NULL))
934
    return CURLE_OK;
935
  return Curl_ssl->adjust_pollset(cf, data, ps);
936
}
937
938
static void *multissl_get_internals(struct ssl_connect_data *connssl,
939
                                    CURLINFO info)
940
{
941
  if(multissl_setup(NULL))
942
    return NULL;
943
  return Curl_ssl->get_internals(connssl, info);
944
}
945
946
static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
947
{
948
  if(multissl_setup(NULL))
949
    return;
950
  Curl_ssl->close(cf, data);
951
}
952
953
static CURLcode multissl_recv_plain(struct Curl_cfilter *cf,
954
                                    struct Curl_easy *data,
955
                                    char *buf, size_t len, size_t *pnread)
956
{
957
  if(multissl_setup(NULL))
958
    return CURLE_FAILED_INIT;
959
  return Curl_ssl->recv_plain(cf, data, buf, len, pnread);
960
}
961
962
static CURLcode multissl_send_plain(struct Curl_cfilter *cf,
963
                                    struct Curl_easy *data,
964
                                    const void *mem, size_t len,
965
                                    size_t *pnwritten)
966
{
967
  if(multissl_setup(NULL))
968
    return CURLE_FAILED_INIT;
969
  return Curl_ssl->send_plain(cf, data, mem, len, pnwritten);
970
}
971
972
static const struct Curl_ssl Curl_ssl_multi = {
973
  { CURLSSLBACKEND_NONE, "multi" },  /* info */
974
  0, /* supports nothing */
975
  (size_t)-1, /* something insanely large to be on the safe side */
976
977
  multissl_init,                     /* init */
978
  NULL,                              /* cleanup */
979
  multissl_version,                  /* version */
980
  NULL,                              /* shutdown */
981
  NULL,                              /* data_pending */
982
  multissl_random,                   /* random */
983
  NULL,                              /* cert_status_request */
984
  multissl_connect,                  /* connect */
985
  multissl_adjust_pollset,           /* adjust_pollset */
986
  multissl_get_internals,            /* get_internals */
987
  multissl_close,                    /* close_one */
988
  NULL,                              /* close_all */
989
  NULL,                              /* set_engine */
990
  NULL,                              /* set_engine_default */
991
  NULL,                              /* engines_list */
992
  NULL,                              /* sha256sum */
993
  multissl_recv_plain,               /* recv decrypted data */
994
  multissl_send_plain,               /* send data to encrypt */
995
  NULL,                              /* get_channel_binding */
996
};
997
998
const struct Curl_ssl *Curl_ssl =
999
#ifdef CURL_WITH_MULTI_SSL
1000
  &Curl_ssl_multi;
1001
#elif defined(USE_WOLFSSL)
1002
  &Curl_ssl_wolfssl;
1003
#elif defined(USE_GNUTLS)
1004
  &Curl_ssl_gnutls;
1005
#elif defined(USE_MBEDTLS)
1006
  &Curl_ssl_mbedtls;
1007
#elif defined(USE_RUSTLS)
1008
  &Curl_ssl_rustls;
1009
#elif defined(USE_OPENSSL)
1010
  &Curl_ssl_openssl;
1011
#elif defined(USE_SCHANNEL)
1012
  &Curl_ssl_schannel;
1013
#else
1014
#error "Missing struct Curl_ssl for selected SSL backend"
1015
#endif
1016
1017
static const struct Curl_ssl *available_backends[] = {
1018
#ifdef USE_WOLFSSL
1019
  &Curl_ssl_wolfssl,
1020
#endif
1021
#ifdef USE_GNUTLS
1022
  &Curl_ssl_gnutls,
1023
#endif
1024
#ifdef USE_MBEDTLS
1025
  &Curl_ssl_mbedtls,
1026
#endif
1027
#ifdef USE_OPENSSL
1028
  &Curl_ssl_openssl,
1029
#endif
1030
#ifdef USE_SCHANNEL
1031
  &Curl_ssl_schannel,
1032
#endif
1033
#ifdef USE_RUSTLS
1034
  &Curl_ssl_rustls,
1035
#endif
1036
  NULL
1037
};
1038
1039
/* Global cleanup */
1040
void Curl_ssl_cleanup(void)
1041
{
1042
  if(init_ssl) {
1043
    /* only cleanup if we did a previous init */
1044
    if(Curl_ssl->cleanup)
1045
      Curl_ssl->cleanup();
1046
#ifdef CURL_WITH_MULTI_SSL
1047
    Curl_ssl = &Curl_ssl_multi;
1048
#endif
1049
    init_ssl = FALSE;
1050
  }
1051
}
1052
1053
static size_t multissl_version(char *buffer, size_t size)
1054
{
1055
  static const struct Curl_ssl *selected;
1056
  static char backends[200];
1057
  static size_t backends_len;
1058
  const struct Curl_ssl *current;
1059
1060
  current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl;
1061
1062
  if(current != selected) {
1063
    char *p = backends;
1064
    char *end = backends + sizeof(backends);
1065
    int i;
1066
1067
    selected = current;
1068
1069
    backends[0] = '\0';
1070
1071
    for(i = 0; available_backends[i]; ++i) {
1072
      char vb[200];
1073
      bool paren = (selected != available_backends[i]);
1074
1075
      if(available_backends[i]->version(vb, sizeof(vb))) {
1076
        p += curl_msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""),
1077
                            (paren ? "(" : ""), vb, (paren ? ")" : ""));
1078
      }
1079
    }
1080
1081
    backends_len = p - backends;
1082
  }
1083
1084
  if(size) {
1085
    curlx_strcopy(buffer, size, backends, backends_len);
1086
  }
1087
  return 0;
1088
}
1089
1090
static int multissl_setup(const struct Curl_ssl *backend)
1091
{
1092
  int i;
1093
  char *env;
1094
1095
  if(Curl_ssl != &Curl_ssl_multi)
1096
    return 1;
1097
1098
  if(backend) {
1099
    Curl_ssl = backend;
1100
    return 0;
1101
  }
1102
1103
  if(!available_backends[0])
1104
    return 1;
1105
1106
  env = curl_getenv("CURL_SSL_BACKEND");
1107
  if(env) {
1108
    for(i = 0; available_backends[i]; i++) {
1109
      if(curl_strequal(env, available_backends[i]->info.name)) {
1110
        Curl_ssl = available_backends[i];
1111
        curlx_free(env);
1112
        return 0;
1113
      }
1114
    }
1115
  }
1116
1117
#ifdef CURL_DEFAULT_SSL_BACKEND
1118
  for(i = 0; available_backends[i]; i++) {
1119
    if(curl_strequal(CURL_DEFAULT_SSL_BACKEND,
1120
                     available_backends[i]->info.name)) {
1121
      Curl_ssl = available_backends[i];
1122
      curlx_free(env);
1123
      return 0;
1124
    }
1125
  }
1126
#endif
1127
1128
  /* Fall back to first available backend */
1129
  Curl_ssl = available_backends[0];
1130
  curlx_free(env);
1131
  return 0;
1132
}
1133
1134
/* This function is used to select the SSL backend to use. It is called by
1135
   curl_global_sslset (easy.c) which uses the global init lock. */
1136
CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
1137
                                   const curl_ssl_backend ***avail)
1138
{
1139
  int i;
1140
1141
  if(avail)
1142
    *avail = (const curl_ssl_backend **)&available_backends;
1143
1144
  if(Curl_ssl != &Curl_ssl_multi)
1145
    return id == Curl_ssl->info.id ||
1146
           (name && curl_strequal(name, Curl_ssl->info.name)) ?
1147
           CURLSSLSET_OK :
1148
#ifdef CURL_WITH_MULTI_SSL
1149
           CURLSSLSET_TOO_LATE;
1150
#else
1151
           CURLSSLSET_UNKNOWN_BACKEND;
1152
#endif
1153
1154
  for(i = 0; available_backends[i]; i++) {
1155
    if(available_backends[i]->info.id == id ||
1156
       (name && curl_strequal(available_backends[i]->info.name, name))) {
1157
      multissl_setup(available_backends[i]);
1158
      return CURLSSLSET_OK;
1159
    }
1160
  }
1161
1162
  return CURLSSLSET_UNKNOWN_BACKEND;
1163
}
1164
1165
#else /* USE_SSL */
1166
CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
1167
                                   const curl_ssl_backend ***avail)
1168
0
{
1169
0
  (void)id;
1170
0
  (void)name;
1171
0
  (void)avail;
1172
0
  return CURLSSLSET_NO_BACKENDS;
1173
0
}
1174
1175
#endif /* !USE_SSL */
1176
1177
#ifdef USE_SSL
1178
1179
void Curl_ssl_peer_cleanup(struct ssl_peer *peer)
1180
{
1181
  Curl_safefree(peer->sni);
1182
  if(peer->dispname != peer->hostname)
1183
    curlx_free(peer->dispname);
1184
  peer->dispname = NULL;
1185
  Curl_safefree(peer->hostname);
1186
  Curl_safefree(peer->scache_key);
1187
  peer->type = CURL_SSL_PEER_DNS;
1188
}
1189
1190
static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1191
{
1192
  struct ssl_connect_data *connssl = cf->ctx;
1193
  if(connssl) {
1194
    connssl->ssl_impl->close(cf, data);
1195
    connssl->state = ssl_connection_none;
1196
    Curl_ssl_peer_cleanup(&connssl->peer);
1197
  }
1198
  cf->connected = FALSE;
1199
}
1200
1201
static ssl_peer_type get_peer_type(const char *hostname)
1202
{
1203
  if(hostname && hostname[0]) {
1204
#ifdef USE_IPV6
1205
    struct in6_addr addr;
1206
#else
1207
    struct in_addr addr;
1208
#endif
1209
    if(curlx_inet_pton(AF_INET, hostname, &addr))
1210
      return CURL_SSL_PEER_IPV4;
1211
#ifdef USE_IPV6
1212
    else if(curlx_inet_pton(AF_INET6, hostname, &addr)) {
1213
      return CURL_SSL_PEER_IPV6;
1214
    }
1215
#endif
1216
  }
1217
  return CURL_SSL_PEER_DNS;
1218
}
1219
1220
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer,
1221
                            struct Curl_cfilter *cf,
1222
                            const char *tls_id,
1223
                            int transport)
1224
{
1225
  const char *ehostname, *edispname;
1226
  CURLcode result = CURLE_OUT_OF_MEMORY;
1227
1228
  /* We expect a clean struct, e.g. called only ONCE */
1229
  DEBUGASSERT(peer);
1230
  DEBUGASSERT(!peer->hostname);
1231
  DEBUGASSERT(!peer->dispname);
1232
  DEBUGASSERT(!peer->sni);
1233
  /* We need the hostname for SNI negotiation. Once handshaked, this remains
1234
   * the SNI hostname for the TLS connection. When the connection is reused,
1235
   * the settings in cf->conn might change. We keep a copy of the hostname we
1236
   * use for SNI.
1237
   */
1238
  peer->transport = transport;
1239
#ifndef CURL_DISABLE_PROXY
1240
  if(Curl_ssl_cf_is_proxy(cf)) {
1241
    ehostname = cf->conn->http_proxy.host.name;
1242
    edispname = cf->conn->http_proxy.host.dispname;
1243
    peer->port = cf->conn->http_proxy.port;
1244
  }
1245
  else
1246
#endif
1247
  {
1248
    ehostname = cf->conn->host.name;
1249
    edispname = cf->conn->host.dispname;
1250
    peer->port = cf->conn->remote_port;
1251
  }
1252
1253
  /* hostname MUST exist and not be empty */
1254
  if(!ehostname || !ehostname[0]) {
1255
    result = CURLE_FAILED_INIT;
1256
    goto out;
1257
  }
1258
1259
  peer->hostname = curlx_strdup(ehostname);
1260
  if(!peer->hostname)
1261
    goto out;
1262
  if(!edispname || !strcmp(ehostname, edispname))
1263
    peer->dispname = peer->hostname;
1264
  else {
1265
    peer->dispname = curlx_strdup(edispname);
1266
    if(!peer->dispname)
1267
      goto out;
1268
  }
1269
  peer->type = get_peer_type(peer->hostname);
1270
  if(peer->type == CURL_SSL_PEER_DNS) {
1271
    /* not an IP address, normalize according to RCC 6066 ch. 3,
1272
     * max len of SNI is 2^16-1, no trailing dot */
1273
    size_t len = strlen(peer->hostname);
1274
    if(len && (peer->hostname[len - 1] == '.'))
1275
      len--;
1276
    if(len < USHRT_MAX) {
1277
      peer->sni = curlx_calloc(1, len + 1);
1278
      if(!peer->sni)
1279
        goto out;
1280
      Curl_strntolower(peer->sni, peer->hostname, len);
1281
      peer->sni[len] = 0;
1282
    }
1283
  }
1284
1285
  result = Curl_ssl_peer_key_make(cf, peer, tls_id, &peer->scache_key);
1286
1287
out:
1288
  if(result)
1289
    Curl_ssl_peer_cleanup(peer);
1290
  return result;
1291
}
1292
1293
static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
1294
{
1295
  struct cf_call_data save;
1296
1297
  CF_DATA_SAVE(save, cf, data);
1298
  cf_close(cf, data);
1299
  CF_DATA_RESTORE(cf, save);
1300
  cf_ctx_free(cf->ctx);
1301
  cf->ctx = NULL;
1302
}
1303
1304
static void ssl_cf_close(struct Curl_cfilter *cf,
1305
                         struct Curl_easy *data)
1306
{
1307
  struct cf_call_data save;
1308
1309
  CF_DATA_SAVE(save, cf, data);
1310
  cf_close(cf, data);
1311
  if(cf->next)
1312
    cf->next->cft->do_close(cf->next, data);
1313
  CF_DATA_RESTORE(cf, save);
1314
}
1315
1316
static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
1317
                               struct Curl_easy *data,
1318
                               bool *done)
1319
{
1320
  struct ssl_connect_data *connssl = cf->ctx;
1321
  struct cf_call_data save;
1322
  CURLcode result;
1323
1324
  if(cf->connected && (connssl->state != ssl_connection_deferred)) {
1325
    *done = TRUE;
1326
    return CURLE_OK;
1327
  }
1328
1329
  if(!cf->next) {
1330
    *done = FALSE;
1331
    return CURLE_FAILED_INIT;
1332
  }
1333
1334
  if(!cf->next->connected) {
1335
    result = cf->next->cft->do_connect(cf->next, data, done);
1336
    if(result || !*done)
1337
      return result;
1338
  }
1339
1340
  CF_DATA_SAVE(save, cf, data);
1341
  CURL_TRC_CF(data, cf, "cf_connect()");
1342
  DEBUGASSERT(connssl);
1343
1344
  *done = FALSE;
1345
1346
  if(!connssl->prefs_checked) {
1347
    if(!ssl_prefs_check(data)) {
1348
      result = CURLE_SSL_CONNECT_ERROR;
1349
      goto out;
1350
    }
1351
    connssl->prefs_checked = TRUE;
1352
  }
1353
1354
  if(!connssl->peer.hostname) {
1355
    char tls_id[80];
1356
    connssl->ssl_impl->version(tls_id, sizeof(tls_id) - 1);
1357
    result = Curl_ssl_peer_init(&connssl->peer, cf, tls_id, TRNSPRT_TCP);
1358
    if(result)
1359
      goto out;
1360
  }
1361
1362
  result = connssl->ssl_impl->do_connect(cf, data, done);
1363
1364
  if(!result && *done) {
1365
    cf->connected = TRUE;
1366
    if(connssl->state == ssl_connection_complete) {
1367
      connssl->handshake_done = *Curl_pgrs_now(data);
1368
    }
1369
    /* Connection can be deferred when sending early data */
1370
    DEBUGASSERT(connssl->state == ssl_connection_complete ||
1371
                connssl->state == ssl_connection_deferred);
1372
    DEBUGASSERT(connssl->state != ssl_connection_deferred ||
1373
                connssl->earlydata_state > ssl_earlydata_none);
1374
  }
1375
out:
1376
  CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
1377
  CF_DATA_RESTORE(cf, save);
1378
  return result;
1379
}
1380
1381
static CURLcode ssl_cf_set_earlydata(struct Curl_cfilter *cf,
1382
                                     struct Curl_easy *data,
1383
                                     const void *buf, size_t blen)
1384
{
1385
  struct ssl_connect_data *connssl = cf->ctx;
1386
  size_t nwritten = 0;
1387
  CURLcode result = CURLE_OK;
1388
1389
  DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_await);
1390
  DEBUGASSERT(Curl_bufq_is_empty(&connssl->earlydata));
1391
  if(blen) {
1392
    if(blen > connssl->earlydata_max)
1393
      blen = connssl->earlydata_max;
1394
    result = Curl_bufq_write(&connssl->earlydata, buf, blen, &nwritten);
1395
    CURL_TRC_CF(data, cf, "ssl_cf_set_earlydata(len=%zu) -> %zd",
1396
                blen, nwritten);
1397
    if(result)
1398
      return result;
1399
  }
1400
  return CURLE_OK;
1401
}
1402
1403
static CURLcode ssl_cf_connect_deferred(struct Curl_cfilter *cf,
1404
                                        struct Curl_easy *data,
1405
                                        const void *buf, size_t blen,
1406
                                        bool *done)
1407
{
1408
  struct ssl_connect_data *connssl = cf->ctx;
1409
  CURLcode result = CURLE_OK;
1410
1411
  DEBUGASSERT(connssl->state == ssl_connection_deferred);
1412
  *done = FALSE;
1413
  if(connssl->earlydata_state == ssl_earlydata_await) {
1414
    result = ssl_cf_set_earlydata(cf, data, buf, blen);
1415
    if(result)
1416
      return result;
1417
    /* we buffered any early data we would like to send. Actually
1418
     * do the connect now which sends it and performs the handshake. */
1419
    connssl->earlydata_state = ssl_earlydata_sending;
1420
    connssl->earlydata_skip = Curl_bufq_len(&connssl->earlydata);
1421
  }
1422
1423
  result = ssl_cf_connect(cf, data, done);
1424
1425
  if(!result && *done) {
1426
    Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done);
1427
    switch(connssl->earlydata_state) {
1428
    case ssl_earlydata_none:
1429
      break;
1430
    case ssl_earlydata_accepted:
1431
      if(!Curl_ssl_cf_is_proxy(cf))
1432
        Curl_pgrsEarlyData(data, (curl_off_t)connssl->earlydata_skip);
1433
      infof(data, "Server accepted %zu bytes of TLS early data.",
1434
            connssl->earlydata_skip);
1435
      break;
1436
    case ssl_earlydata_rejected:
1437
      if(!Curl_ssl_cf_is_proxy(cf))
1438
        Curl_pgrsEarlyData(data, -(curl_off_t)connssl->earlydata_skip);
1439
      infof(data, "Server rejected TLS early data.");
1440
      connssl->earlydata_skip = 0;
1441
      break;
1442
    default:
1443
      /* This should not happen. Either we do not use early data or we
1444
       * should know if it was accepted or not. */
1445
      DEBUGASSERT(NULL);
1446
      break;
1447
    }
1448
  }
1449
  return result;
1450
}
1451
1452
static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
1453
                                const struct Curl_easy *data)
1454
{
1455
  struct ssl_connect_data *connssl = cf->ctx;
1456
  struct cf_call_data save;
1457
  bool result;
1458
1459
  CF_DATA_SAVE(save, cf, data);
1460
  if(connssl->ssl_impl->data_pending &&
1461
     connssl->ssl_impl->data_pending(cf, data))
1462
    result = TRUE;
1463
  else
1464
    result = cf->next->cft->has_data_pending(cf->next, data);
1465
  CF_DATA_RESTORE(cf, save);
1466
  return result;
1467
}
1468
1469
static CURLcode ssl_cf_send(struct Curl_cfilter *cf,
1470
                            struct Curl_easy *data,
1471
                            const uint8_t *buf, size_t blen,
1472
                            bool eos, size_t *pnwritten)
1473
{
1474
  struct ssl_connect_data *connssl = cf->ctx;
1475
  struct cf_call_data save;
1476
  CURLcode result = CURLE_OK;
1477
1478
  (void)eos;
1479
  *pnwritten = 0;
1480
  CF_DATA_SAVE(save, cf, data);
1481
1482
  if(connssl->state == ssl_connection_deferred) {
1483
    bool done = FALSE;
1484
    result = ssl_cf_connect_deferred(cf, data, buf, blen, &done);
1485
    if(result)
1486
      goto out;
1487
    else if(!done) {
1488
      result = CURLE_AGAIN;
1489
      goto out;
1490
    }
1491
    DEBUGASSERT(connssl->state == ssl_connection_complete);
1492
  }
1493
1494
  if(connssl->earlydata_skip) {
1495
    if(connssl->earlydata_skip >= blen) {
1496
      connssl->earlydata_skip -= blen;
1497
      result = CURLE_OK;
1498
      *pnwritten = blen;
1499
      goto out;
1500
    }
1501
    else {
1502
      *pnwritten = connssl->earlydata_skip;
1503
      buf = buf + connssl->earlydata_skip;
1504
      blen -= connssl->earlydata_skip;
1505
      connssl->earlydata_skip = 0;
1506
    }
1507
  }
1508
1509
  /* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */
1510
  if(blen > 0) {
1511
    size_t nwritten;
1512
    result = connssl->ssl_impl->send_plain(cf, data, buf, blen, &nwritten);
1513
    if(!result)
1514
      *pnwritten += nwritten;
1515
  }
1516
1517
out:
1518
  CF_DATA_RESTORE(cf, save);
1519
  return result;
1520
}
1521
1522
static CURLcode ssl_cf_recv(struct Curl_cfilter *cf,
1523
                            struct Curl_easy *data, char *buf, size_t len,
1524
                            size_t *pnread)
1525
{
1526
  struct ssl_connect_data *connssl = cf->ctx;
1527
  struct cf_call_data save;
1528
  CURLcode result = CURLE_OK;
1529
1530
  CF_DATA_SAVE(save, cf, data);
1531
  *pnread = 0;
1532
  if(connssl->state == ssl_connection_deferred) {
1533
    bool done = FALSE;
1534
    result = ssl_cf_connect_deferred(cf, data, NULL, 0, &done);
1535
    if(result)
1536
      goto out;
1537
    else if(!done) {
1538
      result = CURLE_AGAIN;
1539
      goto out;
1540
    }
1541
    DEBUGASSERT(connssl->state == ssl_connection_complete);
1542
  }
1543
1544
  result = connssl->ssl_impl->recv_plain(cf, data, buf, len, pnread);
1545
1546
out:
1547
  CF_DATA_RESTORE(cf, save);
1548
  return result;
1549
}
1550
1551
static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf,
1552
                                struct Curl_easy *data,
1553
                                bool *done)
1554
{
1555
  struct ssl_connect_data *connssl = cf->ctx;
1556
  CURLcode result = CURLE_OK;
1557
1558
  *done = TRUE;
1559
  /* If we have done the SSL handshake, shut down the connection cleanly */
1560
  if(cf->connected && (connssl->state == ssl_connection_complete) &&
1561
     !cf->shutdown && Curl_ssl->shut_down) {
1562
    struct cf_call_data save;
1563
1564
    CF_DATA_SAVE(save, cf, data);
1565
    result = connssl->ssl_impl->shut_down(cf, data, TRUE, done);
1566
    CURL_TRC_CF(data, cf, "cf_shutdown -> %d, done=%d", result, *done);
1567
    CF_DATA_RESTORE(cf, save);
1568
    cf->shutdown = (result || *done);
1569
  }
1570
  return result;
1571
}
1572
1573
static CURLcode ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
1574
                                      struct Curl_easy *data,
1575
                                      struct easy_pollset *ps)
1576
{
1577
  struct ssl_connect_data *connssl = cf->ctx;
1578
  struct cf_call_data save;
1579
  CURLcode result;
1580
1581
  CF_DATA_SAVE(save, cf, data);
1582
  result = connssl->ssl_impl->adjust_pollset(cf, data, ps);
1583
  CF_DATA_RESTORE(cf, save);
1584
  return result;
1585
}
1586
1587
static CURLcode ssl_cf_query(struct Curl_cfilter *cf,
1588
                             struct Curl_easy *data,
1589
                             int query, int *pres1, void *pres2)
1590
{
1591
  struct ssl_connect_data *connssl = cf->ctx;
1592
1593
  switch(query) {
1594
  case CF_QUERY_TIMER_APPCONNECT: {
1595
    struct curltime *when = pres2;
1596
    if(cf->connected && !Curl_ssl_cf_is_proxy(cf))
1597
      *when = connssl->handshake_done;
1598
    return CURLE_OK;
1599
  }
1600
  case CF_QUERY_SSL_INFO:
1601
  case CF_QUERY_SSL_CTX_INFO:
1602
    if(!Curl_ssl_cf_is_proxy(cf)) {
1603
      struct curl_tlssessioninfo *info = pres2;
1604
      struct cf_call_data save;
1605
      CF_DATA_SAVE(save, cf, data);
1606
      info->backend = Curl_ssl_backend();
1607
      info->internals = connssl->ssl_impl->get_internals(
1608
        cf->ctx, (query == CF_QUERY_SSL_INFO) ?
1609
        CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION);
1610
      CF_DATA_RESTORE(cf, save);
1611
      return CURLE_OK;
1612
    }
1613
    break;
1614
  case CF_QUERY_ALPN_NEGOTIATED: {
1615
    const char **palpn = pres2;
1616
    DEBUGASSERT(palpn);
1617
    *palpn = connssl->negotiated.alpn;
1618
    CURL_TRC_CF(data, cf, "query ALPN: returning '%s'", *palpn);
1619
    return CURLE_OK;
1620
  }
1621
  default:
1622
    break;
1623
  }
1624
  return cf->next ?
1625
    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1626
    CURLE_UNKNOWN_OPTION;
1627
}
1628
1629
static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
1630
                             struct Curl_easy *data,
1631
                             int event, int arg1, void *arg2)
1632
{
1633
  struct ssl_connect_data *connssl = cf->ctx;
1634
1635
  (void)arg1;
1636
  (void)arg2;
1637
  (void)data;
1638
  switch(event) {
1639
  case CF_CTRL_CONN_INFO_UPDATE:
1640
    if(connssl->negotiated.alpn && !cf->sockindex) {
1641
      if(!strcmp("http/1.1", connssl->negotiated.alpn))
1642
        cf->conn->httpversion_seen = 11;
1643
      else if(!strcmp("h2", connssl->negotiated.alpn))
1644
        cf->conn->httpversion_seen = 20;
1645
      else if(!strcmp("h3", connssl->negotiated.alpn))
1646
        cf->conn->httpversion_seen = 30;
1647
    }
1648
    break;
1649
  }
1650
  return CURLE_OK;
1651
}
1652
1653
static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data,
1654
                            bool *input_pending)
1655
{
1656
  /*
1657
   * This function tries to determine connection status.
1658
   */
1659
  return cf->next ?
1660
    cf->next->cft->is_alive(cf->next, data, input_pending) :
1661
    FALSE; /* pessimistic in absence of data */
1662
}
1663
1664
struct Curl_cftype Curl_cft_ssl = {
1665
  "SSL",
1666
  CF_TYPE_SSL,
1667
  CURL_LOG_LVL_NONE,
1668
  ssl_cf_destroy,
1669
  ssl_cf_connect,
1670
  ssl_cf_close,
1671
  ssl_cf_shutdown,
1672
  ssl_cf_adjust_pollset,
1673
  ssl_cf_data_pending,
1674
  ssl_cf_send,
1675
  ssl_cf_recv,
1676
  ssl_cf_cntrl,
1677
  cf_ssl_is_alive,
1678
  Curl_cf_def_conn_keep_alive,
1679
  ssl_cf_query,
1680
};
1681
1682
#ifndef CURL_DISABLE_PROXY
1683
1684
struct Curl_cftype Curl_cft_ssl_proxy = {
1685
  "SSL-PROXY",
1686
  CF_TYPE_SSL|CF_TYPE_PROXY,
1687
  CURL_LOG_LVL_NONE,
1688
  ssl_cf_destroy,
1689
  ssl_cf_connect,
1690
  ssl_cf_close,
1691
  ssl_cf_shutdown,
1692
  ssl_cf_adjust_pollset,
1693
  ssl_cf_data_pending,
1694
  ssl_cf_send,
1695
  ssl_cf_recv,
1696
  Curl_cf_def_cntrl,
1697
  cf_ssl_is_alive,
1698
  Curl_cf_def_conn_keep_alive,
1699
  ssl_cf_query,
1700
};
1701
1702
#endif /* !CURL_DISABLE_PROXY */
1703
1704
static CURLcode cf_ssl_create(struct Curl_cfilter **pcf,
1705
                              struct Curl_easy *data,
1706
                              struct connectdata *conn)
1707
{
1708
  struct Curl_cfilter *cf = NULL;
1709
  struct ssl_connect_data *ctx;
1710
  CURLcode result;
1711
1712
  DEBUGASSERT(data->conn);
1713
1714
#ifdef CURL_DISABLE_HTTP
1715
  (void)conn;
1716
  /* We only support ALPN for HTTP so far. */
1717
  DEBUGASSERT(!conn->bits.tls_enable_alpn);
1718
  ctx = cf_ctx_new(data, NULL);
1719
#else
1720
  ctx = cf_ctx_new(data, alpn_get_spec(data->state.http_neg.wanted,
1721
                                       data->state.http_neg.preferred,
1722
                                       conn->bits.tls_enable_alpn));
1723
#endif
1724
  if(!ctx) {
1725
    result = CURLE_OUT_OF_MEMORY;
1726
    goto out;
1727
  }
1728
1729
  result = Curl_cf_create(&cf, &Curl_cft_ssl, ctx);
1730
1731
out:
1732
  if(result)
1733
    cf_ctx_free(ctx);
1734
  *pcf = result ? NULL : cf;
1735
  return result;
1736
}
1737
1738
CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
1739
                              struct connectdata *conn,
1740
                              int sockindex)
1741
{
1742
  struct Curl_cfilter *cf;
1743
  CURLcode result;
1744
1745
  result = cf_ssl_create(&cf, data, conn);
1746
  if(!result)
1747
    Curl_conn_cf_add(data, conn, sockindex, cf);
1748
  return result;
1749
}
1750
1751
CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
1752
                                  struct Curl_easy *data)
1753
{
1754
  struct Curl_cfilter *cf;
1755
  CURLcode result;
1756
1757
  result = cf_ssl_create(&cf, data, cf_at->conn);
1758
  if(!result)
1759
    Curl_conn_cf_insert_after(cf_at, cf);
1760
  return result;
1761
}
1762
1763
#ifndef CURL_DISABLE_PROXY
1764
1765
static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf,
1766
                                    struct Curl_easy *data,
1767
                                    struct connectdata *conn)
1768
{
1769
  struct Curl_cfilter *cf = NULL;
1770
  struct ssl_connect_data *ctx;
1771
  CURLcode result;
1772
  /* ALPN is default, but if user explicitly disables it, obey */
1773
  bool use_alpn = data->set.ssl_enable_alpn;
1774
  http_majors wanted = CURL_HTTP_V1x;
1775
1776
  (void)conn;
1777
#ifdef USE_HTTP2
1778
  if(conn->http_proxy.proxytype == CURLPROXY_HTTPS2) {
1779
    use_alpn = TRUE;
1780
    wanted = (CURL_HTTP_V1x | CURL_HTTP_V2x);
1781
  }
1782
#endif
1783
1784
  ctx = cf_ctx_new(data, alpn_get_spec(wanted, 0, use_alpn));
1785
  if(!ctx) {
1786
    result = CURLE_OUT_OF_MEMORY;
1787
    goto out;
1788
  }
1789
  result = Curl_cf_create(&cf, &Curl_cft_ssl_proxy, ctx);
1790
1791
out:
1792
  if(result)
1793
    cf_ctx_free(ctx);
1794
  *pcf = result ? NULL : cf;
1795
  return result;
1796
}
1797
1798
CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
1799
                                        struct Curl_easy *data)
1800
{
1801
  struct Curl_cfilter *cf;
1802
  CURLcode result;
1803
1804
  result = cf_ssl_proxy_create(&cf, data, cf_at->conn);
1805
  if(!result)
1806
    Curl_conn_cf_insert_after(cf_at, cf);
1807
  return result;
1808
}
1809
1810
#endif /* !CURL_DISABLE_PROXY */
1811
1812
bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option)
1813
{
1814
  (void)data;
1815
  return (Curl_ssl->supports & ssl_option);
1816
}
1817
1818
static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf,
1819
                                       struct Curl_easy *data,
1820
                                       bool send_shutdown, bool *done)
1821
{
1822
  struct ssl_connect_data *connssl = cf->ctx;
1823
  struct cf_call_data save;
1824
  CURLcode result = CURLE_OK;
1825
  timediff_t timeout_ms;
1826
  int what, loop = 10;
1827
1828
  if(cf->shutdown) {
1829
    *done = TRUE;
1830
    return CURLE_OK;
1831
  }
1832
  CF_DATA_SAVE(save, cf, data);
1833
1834
  *done = FALSE;
1835
  while(!result && !*done && loop--) {
1836
    timeout_ms = Curl_shutdown_timeleft(data, cf->conn, cf->sockindex);
1837
1838
    if(timeout_ms < 0) {
1839
      /* no need to continue if time is already up */
1840
      failf(data, "SSL shutdown timeout");
1841
      result = CURLE_OPERATION_TIMEDOUT;
1842
      goto out;
1843
    }
1844
1845
    result = connssl->ssl_impl->shut_down(cf, data, send_shutdown, done);
1846
    if(result || *done)
1847
      goto out;
1848
1849
    if(connssl->io_need) {
1850
      what = Curl_conn_cf_poll(cf, data, timeout_ms);
1851
      if(what < 0) {
1852
        /* fatal error */
1853
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1854
        result = CURLE_RECV_ERROR;
1855
        goto out;
1856
      }
1857
      else if(what == 0) {
1858
        /* timeout */
1859
        failf(data, "SSL shutdown timeout");
1860
        result = CURLE_OPERATION_TIMEDOUT;
1861
        goto out;
1862
      }
1863
      /* socket is readable or writable */
1864
    }
1865
  }
1866
out:
1867
  CF_DATA_RESTORE(cf, save);
1868
  cf->shutdown = (result || *done);
1869
  return result;
1870
}
1871
1872
CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
1873
                                 int sockindex, bool send_shutdown)
1874
{
1875
  struct Curl_cfilter *cf, *head;
1876
  CURLcode result = CURLE_OK;
1877
1878
  head = data->conn ? data->conn->cfilter[sockindex] : NULL;
1879
  for(cf = head; cf; cf = cf->next) {
1880
    if(cf->cft == &Curl_cft_ssl) {
1881
      bool done;
1882
      CURL_TRC_CF(data, cf, "shutdown and remove SSL, start");
1883
      Curl_shutdown_start(data, sockindex, 0);
1884
      result = vtls_shutdown_blocking(cf, data, send_shutdown, &done);
1885
      Curl_shutdown_clear(data, sockindex);
1886
      if(!result && !done) /* blocking failed? */
1887
        result = CURLE_SSL_SHUTDOWN_FAILED;
1888
      Curl_conn_cf_discard(&cf, data);
1889
      CURL_TRC_CF(data, cf, "shutdown and remove SSL, done -> %d", result);
1890
      break;
1891
    }
1892
  }
1893
  return result;
1894
}
1895
1896
bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
1897
{
1898
  return (cf->cft->flags & CF_TYPE_SSL) && (cf->cft->flags & CF_TYPE_PROXY);
1899
}
1900
1901
struct ssl_config_data *
1902
Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data)
1903
{
1904
#ifdef CURL_DISABLE_PROXY
1905
  (void)cf;
1906
  return &data->set.ssl;
1907
#else
1908
  return Curl_ssl_cf_is_proxy(cf) ? &data->set.proxy_ssl : &data->set.ssl;
1909
#endif
1910
}
1911
1912
struct ssl_primary_config *
1913
Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf)
1914
{
1915
#ifdef CURL_DISABLE_PROXY
1916
  return &cf->conn->ssl_config;
1917
#else
1918
  return Curl_ssl_cf_is_proxy(cf) ?
1919
    &cf->conn->proxy_ssl_config : &cf->conn->ssl_config;
1920
#endif
1921
}
1922
1923
CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf,
1924
                                const struct alpn_spec *spec)
1925
{
1926
  size_t i, len;
1927
  int off = 0;
1928
  unsigned char blen;
1929
1930
  memset(buf, 0, sizeof(*buf));
1931
  for(i = 0; spec && i < spec->count; ++i) {
1932
    len = strlen(spec->entries[i]);
1933
    if(len >= ALPN_NAME_MAX)
1934
      return CURLE_FAILED_INIT;
1935
    blen = (unsigned char)len;
1936
    if(off + blen + 1 >= (int)sizeof(buf->data))
1937
      return CURLE_FAILED_INIT;
1938
    buf->data[off++] = blen;
1939
    memcpy(buf->data + off, spec->entries[i], blen);
1940
    off += blen;
1941
  }
1942
  buf->len = off;
1943
  return CURLE_OK;
1944
}
1945
1946
CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
1947
                                const struct alpn_spec *spec)
1948
{
1949
  size_t i, len;
1950
  size_t off = 0;
1951
1952
  memset(buf, 0, sizeof(*buf));
1953
  for(i = 0; spec && i < spec->count; ++i) {
1954
    len = strlen(spec->entries[i]);
1955
    if(len >= ALPN_NAME_MAX)
1956
      return CURLE_FAILED_INIT;
1957
    if(off + len + 2 >= sizeof(buf->data))
1958
      return CURLE_FAILED_INIT;
1959
    if(off)
1960
      buf->data[off++] = ',';
1961
    memcpy(buf->data + off, spec->entries[i], len);
1962
    off += len;
1963
  }
1964
  buf->data[off] = '\0';
1965
  buf->len = (int)off;
1966
  return CURLE_OK;
1967
}
1968
1969
bool Curl_alpn_contains_proto(const struct alpn_spec *spec,
1970
                              const char *proto)
1971
{
1972
  size_t i, plen = proto ? strlen(proto) : 0;
1973
  for(i = 0; spec && plen && i < spec->count; ++i) {
1974
    size_t slen = strlen(spec->entries[i]);
1975
    if((slen == plen) && !memcmp(proto, spec->entries[i], plen))
1976
      return TRUE;
1977
  }
1978
  return FALSE;
1979
}
1980
1981
void Curl_alpn_restrict_to(struct alpn_spec *spec, const char *proto)
1982
{
1983
  size_t plen = strlen(proto);
1984
  DEBUGASSERT(plen < sizeof(spec->entries[0]));
1985
  if(plen < sizeof(spec->entries[0])) {
1986
    memcpy(spec->entries[0], proto, plen + 1);
1987
    spec->count = 1;
1988
  }
1989
}
1990
1991
void Curl_alpn_copy(struct alpn_spec *dest, const struct alpn_spec *src)
1992
{
1993
  if(src)
1994
    memcpy(dest, src, sizeof(*dest));
1995
  else
1996
    memset(dest, 0, sizeof(*dest));
1997
}
1998
1999
CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
2000
                                  struct Curl_easy *data,
2001
                                  struct ssl_connect_data *connssl,
2002
                                  const unsigned char *proto,
2003
                                  size_t proto_len)
2004
{
2005
  CURLcode result = CURLE_OK;
2006
  (void)cf;
2007
2008
  if(connssl->negotiated.alpn) {
2009
    /* When we ask for a specific ALPN protocol, we need the confirmation
2010
     * of it by the server, as we have installed protocol handler and
2011
     * connection filter chain for exactly this protocol. */
2012
    if(!proto_len) {
2013
      failf(data, "ALPN: asked for '%s' from previous session, "
2014
            "but server did not confirm it. Refusing to continue.",
2015
            connssl->negotiated.alpn);
2016
      result = CURLE_SSL_CONNECT_ERROR;
2017
      goto out;
2018
    }
2019
    else if(!proto) {
2020
      DEBUGASSERT(0); /* with length, we need a pointer */
2021
      result = CURLE_SSL_CONNECT_ERROR;
2022
      goto out;
2023
    }
2024
    else if((strlen(connssl->negotiated.alpn) != proto_len) ||
2025
            memcmp(connssl->negotiated.alpn, proto, proto_len)) {
2026
      failf(data, "ALPN: asked for '%s' from previous session, but server "
2027
            "selected '%.*s'. Refusing to continue.",
2028
            connssl->negotiated.alpn, (int)proto_len, proto);
2029
      result = CURLE_SSL_CONNECT_ERROR;
2030
      goto out;
2031
    }
2032
    /* ALPN is exactly what we asked for, done. */
2033
    infof(data, "ALPN: server confirmed to use '%s'",
2034
          connssl->negotiated.alpn);
2035
    goto out;
2036
  }
2037
2038
  if(proto && proto_len) {
2039
    if(memchr(proto, '\0', proto_len)) {
2040
      failf(data, "ALPN: server selected protocol contains NUL. "
2041
                  "Refusing to continue.");
2042
      result = CURLE_SSL_CONNECT_ERROR;
2043
      goto out;
2044
    }
2045
    connssl->negotiated.alpn = Curl_memdup0((const char *)proto, proto_len);
2046
    if(!connssl->negotiated.alpn)
2047
      return CURLE_OUT_OF_MEMORY;
2048
  }
2049
2050
  if(proto && proto_len) {
2051
    if(connssl->state == ssl_connection_deferred)
2052
      infof(data, VTLS_INFOF_ALPN_DEFERRED, (int)proto_len, proto);
2053
    else
2054
      infof(data, VTLS_INFOF_ALPN_ACCEPTED, (int)proto_len, proto);
2055
  }
2056
  else {
2057
    if(connssl->state == ssl_connection_deferred)
2058
      infof(data, VTLS_INFOF_NO_ALPN_DEFERRED);
2059
    else
2060
      infof(data, VTLS_INFOF_NO_ALPN);
2061
  }
2062
2063
out:
2064
  return result;
2065
}
2066
2067
#endif /* USE_SSL */