Coverage Report

Created: 2023-06-07 07:02

/src/curl/lib/vtls/vtls.c
Line
Count
Source (jump to first uncovered line)
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
#ifdef HAVE_SYS_STAT_H
47
#include <sys/stat.h>
48
#endif
49
#ifdef HAVE_FCNTL_H
50
#include <fcntl.h>
51
#endif
52
53
#include "urldata.h"
54
#include "cfilters.h"
55
56
#include "vtls.h" /* generic SSL protos etc */
57
#include "vtls_int.h"
58
#include "slist.h"
59
#include "sendf.h"
60
#include "strcase.h"
61
#include "url.h"
62
#include "progress.h"
63
#include "share.h"
64
#include "multiif.h"
65
#include "timeval.h"
66
#include "curl_md5.h"
67
#include "warnless.h"
68
#include "curl_base64.h"
69
#include "curl_printf.h"
70
#include "strdup.h"
71
72
/* The last #include files should be: */
73
#include "curl_memory.h"
74
#include "memdebug.h"
75
76
77
/* convenience macro to check if this handle is using a shared SSL session */
78
#define SSLSESSION_SHARED(data) (data->share &&                        \
79
                                 (data->share->specifier &             \
80
                                  (1<<CURL_LOCK_DATA_SSL_SESSION)))
81
82
#define CLONE_STRING(var)                    \
83
0
  do {                                       \
84
0
    if(source->var) {                        \
85
0
      dest->var = strdup(source->var);       \
86
0
      if(!dest->var)                         \
87
0
        return FALSE;                        \
88
0
    }                                        \
89
0
    else                                     \
90
0
      dest->var = NULL;                      \
91
0
  } while(0)
92
93
#define CLONE_BLOB(var)                        \
94
0
  do {                                         \
95
0
    if(blobdup(&dest->var, source->var))       \
96
0
      return FALSE;                            \
97
0
  } while(0)
98
99
static CURLcode blobdup(struct curl_blob **dest,
100
                        struct curl_blob *src)
101
0
{
102
0
  DEBUGASSERT(dest);
103
0
  DEBUGASSERT(!*dest);
104
0
  if(src) {
105
    /* only if there's data to dupe! */
106
0
    struct curl_blob *d;
107
0
    d = malloc(sizeof(struct curl_blob) + src->len);
108
0
    if(!d)
109
0
      return CURLE_OUT_OF_MEMORY;
110
0
    d->len = src->len;
111
    /* Always duplicate because the connection may survive longer than the
112
       handle that passed in the blob. */
113
0
    d->flags = CURL_BLOB_COPY;
114
0
    d->data = (void *)((char *)d + sizeof(struct curl_blob));
115
0
    memcpy(d->data, src->data, src->len);
116
0
    *dest = d;
117
0
  }
118
0
  return CURLE_OK;
119
0
}
120
121
/* returns TRUE if the blobs are identical */
122
static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
123
0
{
124
0
  if(!first && !second) /* both are NULL */
125
0
    return TRUE;
126
0
  if(!first || !second) /* one is NULL */
127
0
    return FALSE;
128
0
  if(first->len != second->len) /* different sizes */
129
0
    return FALSE;
130
0
  return !memcmp(first->data, second->data, first->len); /* same data */
131
0
}
132
133
#ifdef USE_SSL
134
static const struct alpn_spec ALPN_SPEC_H10 = {
135
  { ALPN_HTTP_1_0 }, 1
136
};
137
static const struct alpn_spec ALPN_SPEC_H11 = {
138
  { ALPN_HTTP_1_1 }, 1
139
};
140
#ifdef USE_HTTP2
141
static const struct alpn_spec ALPN_SPEC_H2_H11 = {
142
  { ALPN_H2, ALPN_HTTP_1_1 }, 2
143
};
144
#endif
145
146
static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn)
147
{
148
  if(!use_alpn)
149
    return NULL;
150
  if(httpwant == CURL_HTTP_VERSION_1_0)
151
    return &ALPN_SPEC_H10;
152
#ifdef USE_HTTP2
153
  if(httpwant >= CURL_HTTP_VERSION_2)
154
    return &ALPN_SPEC_H2_H11;
155
#endif
156
  return &ALPN_SPEC_H11;
157
}
158
#endif /* USE_SSL */
159
160
161
bool
162
Curl_ssl_config_matches(struct ssl_primary_config *data,
163
                        struct ssl_primary_config *needle)
164
0
{
165
0
  if((data->version == needle->version) &&
166
0
     (data->version_max == needle->version_max) &&
167
0
     (data->ssl_options == needle->ssl_options) &&
168
0
     (data->verifypeer == needle->verifypeer) &&
169
0
     (data->verifyhost == needle->verifyhost) &&
170
0
     (data->verifystatus == needle->verifystatus) &&
171
0
     blobcmp(data->cert_blob, needle->cert_blob) &&
172
0
     blobcmp(data->ca_info_blob, needle->ca_info_blob) &&
173
0
     blobcmp(data->issuercert_blob, needle->issuercert_blob) &&
174
0
     Curl_safecmp(data->CApath, needle->CApath) &&
175
0
     Curl_safecmp(data->CAfile, needle->CAfile) &&
176
0
     Curl_safecmp(data->issuercert, needle->issuercert) &&
177
0
     Curl_safecmp(data->clientcert, needle->clientcert) &&
178
#ifdef USE_TLS_SRP
179
     !Curl_timestrcmp(data->username, needle->username) &&
180
     !Curl_timestrcmp(data->password, needle->password) &&
181
#endif
182
0
     strcasecompare(data->cipher_list, needle->cipher_list) &&
183
0
     strcasecompare(data->cipher_list13, needle->cipher_list13) &&
184
0
     strcasecompare(data->curves, needle->curves) &&
185
0
     strcasecompare(data->CRLfile, needle->CRLfile) &&
186
0
     strcasecompare(data->pinned_key, needle->pinned_key))
187
0
    return TRUE;
188
189
0
  return FALSE;
190
0
}
191
192
bool
193
Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
194
                              struct ssl_primary_config *dest)
195
0
{
196
0
  dest->version = source->version;
197
0
  dest->version_max = source->version_max;
198
0
  dest->verifypeer = source->verifypeer;
199
0
  dest->verifyhost = source->verifyhost;
200
0
  dest->verifystatus = source->verifystatus;
201
0
  dest->sessionid = source->sessionid;
202
0
  dest->ssl_options = source->ssl_options;
203
204
0
  CLONE_BLOB(cert_blob);
205
0
  CLONE_BLOB(ca_info_blob);
206
0
  CLONE_BLOB(issuercert_blob);
207
0
  CLONE_STRING(CApath);
208
0
  CLONE_STRING(CAfile);
209
0
  CLONE_STRING(issuercert);
210
0
  CLONE_STRING(clientcert);
211
0
  CLONE_STRING(cipher_list);
212
0
  CLONE_STRING(cipher_list13);
213
0
  CLONE_STRING(pinned_key);
214
0
  CLONE_STRING(curves);
215
0
  CLONE_STRING(CRLfile);
216
#ifdef USE_TLS_SRP
217
  CLONE_STRING(username);
218
  CLONE_STRING(password);
219
#endif
220
221
0
  return TRUE;
222
0
}
223
224
void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
225
0
{
226
0
  Curl_safefree(sslc->CApath);
227
0
  Curl_safefree(sslc->CAfile);
228
0
  Curl_safefree(sslc->issuercert);
229
0
  Curl_safefree(sslc->clientcert);
230
0
  Curl_safefree(sslc->cipher_list);
231
0
  Curl_safefree(sslc->cipher_list13);
232
0
  Curl_safefree(sslc->pinned_key);
233
0
  Curl_safefree(sslc->cert_blob);
234
0
  Curl_safefree(sslc->ca_info_blob);
235
0
  Curl_safefree(sslc->issuercert_blob);
236
0
  Curl_safefree(sslc->curves);
237
0
  Curl_safefree(sslc->CRLfile);
238
#ifdef USE_TLS_SRP
239
  Curl_safefree(sslc->username);
240
  Curl_safefree(sslc->password);
241
#endif
242
0
}
243
244
#ifdef USE_SSL
245
static int multissl_setup(const struct Curl_ssl *backend);
246
#endif
247
248
curl_sslbackend Curl_ssl_backend(void)
249
1.04k
{
250
#ifdef USE_SSL
251
  multissl_setup(NULL);
252
  return Curl_ssl->info.id;
253
#else
254
1.04k
  return CURLSSLBACKEND_NONE;
255
1.04k
#endif
256
1.04k
}
257
258
#ifdef USE_SSL
259
260
/* "global" init done? */
261
static bool init_ssl = FALSE;
262
263
/**
264
 * Global SSL init
265
 *
266
 * @retval 0 error initializing SSL
267
 * @retval 1 SSL initialized successfully
268
 */
269
int Curl_ssl_init(void)
270
{
271
  /* make sure this is only done once */
272
  if(init_ssl)
273
    return 1;
274
  init_ssl = TRUE; /* never again */
275
276
  return Curl_ssl->init();
277
}
278
279
#if defined(CURL_WITH_MULTI_SSL)
280
static const struct Curl_ssl Curl_ssl_multi;
281
#endif
282
283
/* Global cleanup */
284
void Curl_ssl_cleanup(void)
285
{
286
  if(init_ssl) {
287
    /* only cleanup if we did a previous init */
288
    Curl_ssl->cleanup();
289
#if defined(CURL_WITH_MULTI_SSL)
290
    Curl_ssl = &Curl_ssl_multi;
291
#endif
292
    init_ssl = FALSE;
293
  }
294
}
295
296
static bool ssl_prefs_check(struct Curl_easy *data)
297
{
298
  /* check for CURLOPT_SSLVERSION invalid parameter value */
299
  const unsigned char sslver = data->set.ssl.primary.version;
300
  if(sslver >= CURL_SSLVERSION_LAST) {
301
    failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
302
    return FALSE;
303
  }
304
305
  switch(data->set.ssl.primary.version_max) {
306
  case CURL_SSLVERSION_MAX_NONE:
307
  case CURL_SSLVERSION_MAX_DEFAULT:
308
    break;
309
310
  default:
311
    if((data->set.ssl.primary.version_max >> 16) < sslver) {
312
      failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION");
313
      return FALSE;
314
    }
315
  }
316
317
  return TRUE;
318
}
319
320
static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
321
                                     const struct alpn_spec *alpn)
322
{
323
  struct ssl_connect_data *ctx;
324
325
  (void)data;
326
  ctx = calloc(1, sizeof(*ctx));
327
  if(!ctx)
328
    return NULL;
329
330
  ctx->alpn = alpn;
331
  ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data);
332
  if(!ctx->backend) {
333
    free(ctx);
334
    return NULL;
335
  }
336
  return ctx;
337
}
338
339
static void cf_ctx_free(struct ssl_connect_data *ctx)
340
{
341
  if(ctx) {
342
    free(ctx->backend);
343
    free(ctx);
344
  }
345
}
346
347
static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data)
348
{
349
  struct ssl_connect_data *connssl = cf->ctx;
350
  CURLcode result;
351
352
  if(!ssl_prefs_check(data))
353
    return CURLE_SSL_CONNECT_ERROR;
354
355
  /* mark this is being ssl-enabled from here on. */
356
  connssl->state = ssl_connection_negotiating;
357
358
  result = Curl_ssl->connect_blocking(cf, data);
359
360
  if(!result) {
361
    DEBUGASSERT(connssl->state == ssl_connection_complete);
362
  }
363
364
  return result;
365
}
366
367
static CURLcode
368
ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data,
369
                        bool *done)
370
{
371
  if(!ssl_prefs_check(data))
372
    return CURLE_SSL_CONNECT_ERROR;
373
374
  /* mark this is being ssl requested from here on. */
375
  return Curl_ssl->connect_nonblocking(cf, data, done);
376
}
377
378
/*
379
 * Lock shared SSL session data
380
 */
381
void Curl_ssl_sessionid_lock(struct Curl_easy *data)
382
{
383
  if(SSLSESSION_SHARED(data))
384
    Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
385
}
386
387
/*
388
 * Unlock shared SSL session data
389
 */
390
void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
391
{
392
  if(SSLSESSION_SHARED(data))
393
    Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
394
}
395
396
/*
397
 * Check if there's a session ID for the given connection in the cache, and if
398
 * there's one suitable, it is provided. Returns TRUE when no entry matched.
399
 */
400
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
401
                           struct Curl_easy *data,
402
                           void **ssl_sessionid,
403
                           size_t *idsize) /* set 0 if unknown */
404
{
405
  struct ssl_connect_data *connssl = cf->ctx;
406
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
407
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
408
  struct Curl_ssl_session *check;
409
  size_t i;
410
  long *general_age;
411
  bool no_match = TRUE;
412
413
  *ssl_sessionid = NULL;
414
  if(!ssl_config)
415
    return TRUE;
416
417
  DEBUGASSERT(ssl_config->primary.sessionid);
418
419
  if(!ssl_config->primary.sessionid || !data->state.session)
420
    /* session ID re-use is disabled or the session cache has not been
421
       setup */
422
    return TRUE;
423
424
  /* Lock if shared */
425
  if(SSLSESSION_SHARED(data))
426
    general_age = &data->share->sessionage;
427
  else
428
    general_age = &data->state.sessionage;
429
430
  for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
431
    check = &data->state.session[i];
432
    if(!check->sessionid)
433
      /* not session ID means blank entry */
434
      continue;
435
    if(strcasecompare(connssl->hostname, check->name) &&
436
       ((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
437
        (cf->conn->bits.conn_to_host && check->conn_to_host &&
438
         strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
439
       ((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) ||
440
        (cf->conn->bits.conn_to_port && check->conn_to_port != -1 &&
441
         cf->conn->conn_to_port == check->conn_to_port)) &&
442
       (connssl->port == check->remote_port) &&
443
       strcasecompare(cf->conn->handler->scheme, check->scheme) &&
444
       Curl_ssl_config_matches(conn_config, &check->ssl_config)) {
445
      /* yes, we have a session ID! */
446
      (*general_age)++;          /* increase general age */
447
      check->age = *general_age; /* set this as used in this age */
448
      *ssl_sessionid = check->sessionid;
449
      if(idsize)
450
        *idsize = check->idsize;
451
      no_match = FALSE;
452
      break;
453
    }
454
  }
455
456
  DEBUGF(infof(data, DMSG(data, "%s Session ID in cache for %s %s://%s:%d"),
457
               no_match? "Didn't find": "Found",
458
               Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
459
               cf->conn->handler->scheme, connssl->hostname, connssl->port));
460
  return no_match;
461
}
462
463
/*
464
 * Kill a single session ID entry in the cache.
465
 */
466
void Curl_ssl_kill_session(struct Curl_ssl_session *session)
467
{
468
  if(session->sessionid) {
469
    /* defensive check */
470
471
    /* free the ID the SSL-layer specific way */
472
    Curl_ssl->session_free(session->sessionid);
473
474
    session->sessionid = NULL;
475
    session->age = 0; /* fresh */
476
477
    Curl_free_primary_ssl_config(&session->ssl_config);
478
479
    Curl_safefree(session->name);
480
    Curl_safefree(session->conn_to_host);
481
  }
482
}
483
484
/*
485
 * Delete the given session ID from the cache.
486
 */
487
void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
488
{
489
  size_t i;
490
491
  for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
492
    struct Curl_ssl_session *check = &data->state.session[i];
493
494
    if(check->sessionid == ssl_sessionid) {
495
      Curl_ssl_kill_session(check);
496
      break;
497
    }
498
  }
499
}
500
501
/*
502
 * Store session id in the session cache. The ID passed on to this function
503
 * must already have been extracted and allocated the proper way for the SSL
504
 * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
505
 * later on.
506
 */
507
CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
508
                               struct Curl_easy *data,
509
                               void *ssl_sessionid,
510
                               size_t idsize,
511
                               bool *added)
512
{
513
  struct ssl_connect_data *connssl = cf->ctx;
514
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
515
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
516
  size_t i;
517
  struct Curl_ssl_session *store;
518
  long oldest_age;
519
  char *clone_host;
520
  char *clone_conn_to_host;
521
  int conn_to_port;
522
  long *general_age;
523
524
  if(added)
525
    *added = FALSE;
526
527
  if(!data->state.session)
528
    return CURLE_OK;
529
530
  store = &data->state.session[0];
531
  oldest_age = data->state.session[0].age; /* zero if unused */
532
  (void)ssl_config;
533
  DEBUGASSERT(ssl_config->primary.sessionid);
534
535
  clone_host = strdup(connssl->hostname);
536
  if(!clone_host)
537
    return CURLE_OUT_OF_MEMORY; /* bail out */
538
539
  if(cf->conn->bits.conn_to_host) {
540
    clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
541
    if(!clone_conn_to_host) {
542
      free(clone_host);
543
      return CURLE_OUT_OF_MEMORY; /* bail out */
544
    }
545
  }
546
  else
547
    clone_conn_to_host = NULL;
548
549
  if(cf->conn->bits.conn_to_port)
550
    conn_to_port = cf->conn->conn_to_port;
551
  else
552
    conn_to_port = -1;
553
554
  /* Now we should add the session ID and the host name to the cache, (remove
555
     the oldest if necessary) */
556
557
  /* If using shared SSL session, lock! */
558
  if(SSLSESSION_SHARED(data)) {
559
    general_age = &data->share->sessionage;
560
  }
561
  else {
562
    general_age = &data->state.sessionage;
563
  }
564
565
  /* find an empty slot for us, or find the oldest */
566
  for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) &&
567
        data->state.session[i].sessionid; i++) {
568
    if(data->state.session[i].age < oldest_age) {
569
      oldest_age = data->state.session[i].age;
570
      store = &data->state.session[i];
571
    }
572
  }
573
  if(i == data->set.general_ssl.max_ssl_sessions)
574
    /* cache is full, we must "kill" the oldest entry! */
575
    Curl_ssl_kill_session(store);
576
  else
577
    store = &data->state.session[i]; /* use this slot */
578
579
  /* now init the session struct wisely */
580
  store->sessionid = ssl_sessionid;
581
  store->idsize = idsize;
582
  store->age = *general_age;    /* set current age */
583
  /* free it if there's one already present */
584
  free(store->name);
585
  free(store->conn_to_host);
586
  store->name = clone_host;               /* clone host name */
587
  store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
588
  store->conn_to_port = conn_to_port; /* connect to port number */
589
  /* port number */
590
  store->remote_port = connssl->port;
591
  store->scheme = cf->conn->handler->scheme;
592
593
  if(!Curl_clone_primary_ssl_config(conn_config, &store->ssl_config)) {
594
    Curl_free_primary_ssl_config(&store->ssl_config);
595
    store->sessionid = NULL; /* let caller free sessionid */
596
    free(clone_host);
597
    free(clone_conn_to_host);
598
    return CURLE_OUT_OF_MEMORY;
599
  }
600
601
  if(added)
602
    *added = TRUE;
603
604
  DEBUGF(infof(data, DMSG(data, "Added Session ID to cache for %s://%s:%d"
605
               " [%s]"), store->scheme, store->name, store->remote_port,
606
               Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"));
607
  return CURLE_OK;
608
}
609
610
void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend)
611
{
612
  if(Curl_ssl->free_multi_ssl_backend_data && mbackend)
613
    Curl_ssl->free_multi_ssl_backend_data(mbackend);
614
}
615
616
void Curl_ssl_close_all(struct Curl_easy *data)
617
{
618
  /* kill the session ID cache if not shared */
619
  if(data->state.session && !SSLSESSION_SHARED(data)) {
620
    size_t i;
621
    for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
622
      /* the single-killer function handles empty table slots */
623
      Curl_ssl_kill_session(&data->state.session[i]);
624
625
    /* free the cache data */
626
    Curl_safefree(data->state.session);
627
  }
628
629
  Curl_ssl->close_all(data);
630
}
631
632
int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
633
                              curl_socket_t *socks)
634
{
635
  struct ssl_connect_data *connssl = cf->ctx;
636
  curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
637
638
  if(sock != CURL_SOCKET_BAD) {
639
    if(connssl->connecting_state == ssl_connect_2_writing) {
640
      /* write mode */
641
      socks[0] = sock;
642
      return GETSOCK_WRITESOCK(0);
643
    }
644
    if(connssl->connecting_state == ssl_connect_2_reading) {
645
      /* read mode */
646
      socks[0] = sock;
647
      return GETSOCK_READSOCK(0);
648
    }
649
  }
650
  return GETSOCK_BLANK;
651
}
652
653
/* Selects an SSL crypto engine
654
 */
655
CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
656
{
657
  return Curl_ssl->set_engine(data, engine);
658
}
659
660
/* Selects the default SSL crypto engine
661
 */
662
CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
663
{
664
  return Curl_ssl->set_engine_default(data);
665
}
666
667
/* Return list of OpenSSL crypto engine names. */
668
struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
669
{
670
  return Curl_ssl->engines_list(data);
671
}
672
673
/*
674
 * This sets up a session ID cache to the specified size. Make sure this code
675
 * is agnostic to what underlying SSL technology we use.
676
 */
677
CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
678
{
679
  struct Curl_ssl_session *session;
680
681
  if(data->state.session)
682
    /* this is just a precaution to prevent multiple inits */
683
    return CURLE_OK;
684
685
  session = calloc(amount, sizeof(struct Curl_ssl_session));
686
  if(!session)
687
    return CURLE_OUT_OF_MEMORY;
688
689
  /* store the info in the SSL section */
690
  data->set.general_ssl.max_ssl_sessions = amount;
691
  data->state.session = session;
692
  data->state.sessionage = 1; /* this is brand new */
693
  return CURLE_OK;
694
}
695
696
static size_t multissl_version(char *buffer, size_t size);
697
698
void Curl_ssl_version(char *buffer, size_t size)
699
{
700
#ifdef CURL_WITH_MULTI_SSL
701
  (void)multissl_version(buffer, size);
702
#else
703
  (void)Curl_ssl->version(buffer, size);
704
#endif
705
}
706
707
void Curl_ssl_free_certinfo(struct Curl_easy *data)
708
{
709
  struct curl_certinfo *ci = &data->info.certs;
710
711
  if(ci->num_of_certs) {
712
    /* free all individual lists used */
713
    int i;
714
    for(i = 0; i<ci->num_of_certs; i++) {
715
      curl_slist_free_all(ci->certinfo[i]);
716
      ci->certinfo[i] = NULL;
717
    }
718
719
    free(ci->certinfo); /* free the actual array too */
720
    ci->certinfo = NULL;
721
    ci->num_of_certs = 0;
722
  }
723
}
724
725
CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
726
{
727
  struct curl_certinfo *ci = &data->info.certs;
728
  struct curl_slist **table;
729
730
  /* Free any previous certificate information structures */
731
  Curl_ssl_free_certinfo(data);
732
733
  /* Allocate the required certificate information structures */
734
  table = calloc((size_t) num, sizeof(struct curl_slist *));
735
  if(!table)
736
    return CURLE_OUT_OF_MEMORY;
737
738
  ci->num_of_certs = num;
739
  ci->certinfo = table;
740
741
  return CURLE_OK;
742
}
743
744
/*
745
 * 'value' is NOT a null-terminated string
746
 */
747
CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
748
                                    int certnum,
749
                                    const char *label,
750
                                    const char *value,
751
                                    size_t valuelen)
752
{
753
  struct curl_certinfo *ci = &data->info.certs;
754
  char *output;
755
  struct curl_slist *nl;
756
  CURLcode result = CURLE_OK;
757
  size_t labellen = strlen(label);
758
  size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
759
760
  output = malloc(outlen);
761
  if(!output)
762
    return CURLE_OUT_OF_MEMORY;
763
764
  /* sprintf the label and colon */
765
  msnprintf(output, outlen, "%s:", label);
766
767
  /* memcpy the value (it might not be null-terminated) */
768
  memcpy(&output[labellen + 1], value, valuelen);
769
770
  /* null-terminate the output */
771
  output[labellen + 1 + valuelen] = 0;
772
773
  nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
774
  if(!nl) {
775
    free(output);
776
    curl_slist_free_all(ci->certinfo[certnum]);
777
    result = CURLE_OUT_OF_MEMORY;
778
  }
779
780
  ci->certinfo[certnum] = nl;
781
  return result;
782
}
783
784
CURLcode Curl_ssl_random(struct Curl_easy *data,
785
                         unsigned char *entropy,
786
                         size_t length)
787
{
788
  return Curl_ssl->random(data, entropy, length);
789
}
790
791
/*
792
 * Curl_ssl_snihost() converts the input host name to a suitable SNI name put
793
 * in data->state.buffer. Returns a pointer to the name (or NULL if a problem)
794
 * and stores the new length in 'olen'.
795
 *
796
 * SNI fields must not have any trailing dot and while RFC 6066 section 3 says
797
 * the SNI field is case insensitive, browsers always send the data lowercase
798
 * and subsequently there are numerous servers out there that don't work
799
 * unless the name is lowercased.
800
 */
801
802
char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen)
803
{
804
  size_t len = strlen(host);
805
  if(len && (host[len-1] == '.'))
806
    len--;
807
  if(len >= data->set.buffer_size)
808
    return NULL;
809
810
  Curl_strntolower(data->state.buffer, host, len);
811
  data->state.buffer[len] = 0;
812
  if(olen)
813
    *olen = len;
814
  return data->state.buffer;
815
}
816
817
/*
818
 * Public key pem to der conversion
819
 */
820
821
static CURLcode pubkey_pem_to_der(const char *pem,
822
                                  unsigned char **der, size_t *der_len)
823
{
824
  char *stripped_pem, *begin_pos, *end_pos;
825
  size_t pem_count, stripped_pem_count = 0, pem_len;
826
  CURLcode result;
827
828
  /* if no pem, exit. */
829
  if(!pem)
830
    return CURLE_BAD_CONTENT_ENCODING;
831
832
  begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
833
  if(!begin_pos)
834
    return CURLE_BAD_CONTENT_ENCODING;
835
836
  pem_count = begin_pos - pem;
837
  /* Invalid if not at beginning AND not directly following \n */
838
  if(0 != pem_count && '\n' != pem[pem_count - 1])
839
    return CURLE_BAD_CONTENT_ENCODING;
840
841
  /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
842
  pem_count += 26;
843
844
  /* Invalid if not directly following \n */
845
  end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
846
  if(!end_pos)
847
    return CURLE_BAD_CONTENT_ENCODING;
848
849
  pem_len = end_pos - pem;
850
851
  stripped_pem = malloc(pem_len - pem_count + 1);
852
  if(!stripped_pem)
853
    return CURLE_OUT_OF_MEMORY;
854
855
  /*
856
   * Here we loop through the pem array one character at a time between the
857
   * correct indices, and place each character that is not '\n' or '\r'
858
   * into the stripped_pem array, which should represent the raw base64 string
859
   */
860
  while(pem_count < pem_len) {
861
    if('\n' != pem[pem_count] && '\r' != pem[pem_count])
862
      stripped_pem[stripped_pem_count++] = pem[pem_count];
863
    ++pem_count;
864
  }
865
  /* Place the null terminator in the correct place */
866
  stripped_pem[stripped_pem_count] = '\0';
867
868
  result = Curl_base64_decode(stripped_pem, der, der_len);
869
870
  Curl_safefree(stripped_pem);
871
872
  return result;
873
}
874
875
/*
876
 * Generic pinned public key check.
877
 */
878
879
CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
880
                              const char *pinnedpubkey,
881
                              const unsigned char *pubkey, size_t pubkeylen)
882
{
883
  FILE *fp;
884
  unsigned char *buf = NULL, *pem_ptr = NULL;
885
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
886
887
  /* if a path wasn't specified, don't pin */
888
  if(!pinnedpubkey)
889
    return CURLE_OK;
890
  if(!pubkey || !pubkeylen)
891
    return result;
892
893
  /* only do this if pinnedpubkey starts with "sha256//", length 8 */
894
  if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
895
    CURLcode encode;
896
    size_t encodedlen, pinkeylen;
897
    char *encoded, *pinkeycopy, *begin_pos, *end_pos;
898
    unsigned char *sha256sumdigest;
899
900
    if(!Curl_ssl->sha256sum) {
901
      /* without sha256 support, this cannot match */
902
      return result;
903
    }
904
905
    /* compute sha256sum of public key */
906
    sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH);
907
    if(!sha256sumdigest)
908
      return CURLE_OUT_OF_MEMORY;
909
    encode = Curl_ssl->sha256sum(pubkey, pubkeylen,
910
                        sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
911
912
    if(encode != CURLE_OK)
913
      return encode;
914
915
    encode = Curl_base64_encode((char *)sha256sumdigest,
916
                                CURL_SHA256_DIGEST_LENGTH, &encoded,
917
                                &encodedlen);
918
    Curl_safefree(sha256sumdigest);
919
920
    if(encode)
921
      return encode;
922
923
    infof(data, " public key hash: sha256//%s", encoded);
924
925
    /* it starts with sha256//, copy so we can modify it */
926
    pinkeylen = strlen(pinnedpubkey) + 1;
927
    pinkeycopy = malloc(pinkeylen);
928
    if(!pinkeycopy) {
929
      Curl_safefree(encoded);
930
      return CURLE_OUT_OF_MEMORY;
931
    }
932
    memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
933
    /* point begin_pos to the copy, and start extracting keys */
934
    begin_pos = pinkeycopy;
935
    do {
936
      end_pos = strstr(begin_pos, ";sha256//");
937
      /*
938
       * if there is an end_pos, null terminate,
939
       * otherwise it'll go to the end of the original string
940
       */
941
      if(end_pos)
942
        end_pos[0] = '\0';
943
944
      /* compare base64 sha256 digests, 8 is the length of "sha256//" */
945
      if(encodedlen == strlen(begin_pos + 8) &&
946
         !memcmp(encoded, begin_pos + 8, encodedlen)) {
947
        result = CURLE_OK;
948
        break;
949
      }
950
951
      /*
952
       * change back the null-terminator we changed earlier,
953
       * and look for next begin
954
       */
955
      if(end_pos) {
956
        end_pos[0] = ';';
957
        begin_pos = strstr(end_pos, "sha256//");
958
      }
959
    } while(end_pos && begin_pos);
960
    Curl_safefree(encoded);
961
    Curl_safefree(pinkeycopy);
962
    return result;
963
  }
964
965
  fp = fopen(pinnedpubkey, "rb");
966
  if(!fp)
967
    return result;
968
969
  do {
970
    long filesize;
971
    size_t size, pem_len;
972
    CURLcode pem_read;
973
974
    /* Determine the file's size */
975
    if(fseek(fp, 0, SEEK_END))
976
      break;
977
    filesize = ftell(fp);
978
    if(fseek(fp, 0, SEEK_SET))
979
      break;
980
    if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
981
      break;
982
983
    /*
984
     * if the size of our certificate is bigger than the file
985
     * size then it can't match
986
     */
987
    size = curlx_sotouz((curl_off_t) filesize);
988
    if(pubkeylen > size)
989
      break;
990
991
    /*
992
     * Allocate buffer for the pinned key
993
     * With 1 additional byte for null terminator in case of PEM key
994
     */
995
    buf = malloc(size + 1);
996
    if(!buf)
997
      break;
998
999
    /* Returns number of elements read, which should be 1 */
1000
    if((int) fread(buf, size, 1, fp) != 1)
1001
      break;
1002
1003
    /* If the sizes are the same, it can't be base64 encoded, must be der */
1004
    if(pubkeylen == size) {
1005
      if(!memcmp(pubkey, buf, pubkeylen))
1006
        result = CURLE_OK;
1007
      break;
1008
    }
1009
1010
    /*
1011
     * Otherwise we will assume it's PEM and try to decode it
1012
     * after placing null terminator
1013
     */
1014
    buf[size] = '\0';
1015
    pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
1016
    /* if it wasn't read successfully, exit */
1017
    if(pem_read)
1018
      break;
1019
1020
    /*
1021
     * if the size of our certificate doesn't match the size of
1022
     * the decoded file, they can't be the same, otherwise compare
1023
     */
1024
    if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
1025
      result = CURLE_OK;
1026
  } while(0);
1027
1028
  Curl_safefree(buf);
1029
  Curl_safefree(pem_ptr);
1030
  fclose(fp);
1031
1032
  return result;
1033
}
1034
1035
/*
1036
 * Check whether the SSL backend supports the status_request extension.
1037
 */
1038
bool Curl_ssl_cert_status_request(void)
1039
{
1040
  return Curl_ssl->cert_status_request();
1041
}
1042
1043
/*
1044
 * Check whether the SSL backend supports false start.
1045
 */
1046
bool Curl_ssl_false_start(struct Curl_easy *data)
1047
{
1048
  (void)data;
1049
  return Curl_ssl->false_start();
1050
}
1051
1052
/*
1053
 * Default implementations for unsupported functions.
1054
 */
1055
1056
int Curl_none_init(void)
1057
{
1058
  return 1;
1059
}
1060
1061
void Curl_none_cleanup(void)
1062
{ }
1063
1064
int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
1065
                       struct Curl_easy *data UNUSED_PARAM)
1066
{
1067
  (void)data;
1068
  (void)cf;
1069
  return 0;
1070
}
1071
1072
int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
1073
{
1074
  (void)cf;
1075
  (void)data;
1076
  return -1;
1077
}
1078
1079
CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM,
1080
                          unsigned char *entropy UNUSED_PARAM,
1081
                          size_t length UNUSED_PARAM)
1082
{
1083
  (void)data;
1084
  (void)entropy;
1085
  (void)length;
1086
  return CURLE_NOT_BUILT_IN;
1087
}
1088
1089
void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM)
1090
{
1091
  (void)data;
1092
}
1093
1094
void Curl_none_session_free(void *ptr UNUSED_PARAM)
1095
{
1096
  (void)ptr;
1097
}
1098
1099
bool Curl_none_data_pending(struct Curl_cfilter *cf UNUSED_PARAM,
1100
                            const struct Curl_easy *data UNUSED_PARAM)
1101
{
1102
  (void)cf;
1103
  (void)data;
1104
  return 0;
1105
}
1106
1107
bool Curl_none_cert_status_request(void)
1108
{
1109
  return FALSE;
1110
}
1111
1112
CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM,
1113
                              const char *engine UNUSED_PARAM)
1114
{
1115
  (void)data;
1116
  (void)engine;
1117
  return CURLE_NOT_BUILT_IN;
1118
}
1119
1120
CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM)
1121
{
1122
  (void)data;
1123
  return CURLE_NOT_BUILT_IN;
1124
}
1125
1126
struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM)
1127
{
1128
  (void)data;
1129
  return (struct curl_slist *)NULL;
1130
}
1131
1132
bool Curl_none_false_start(void)
1133
{
1134
  return FALSE;
1135
}
1136
1137
static int multissl_init(void)
1138
{
1139
  if(multissl_setup(NULL))
1140
    return 1;
1141
  return Curl_ssl->init();
1142
}
1143
1144
static CURLcode multissl_connect(struct Curl_cfilter *cf,
1145
                                 struct Curl_easy *data)
1146
{
1147
  if(multissl_setup(NULL))
1148
    return CURLE_FAILED_INIT;
1149
  return Curl_ssl->connect_blocking(cf, data);
1150
}
1151
1152
static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf,
1153
                                             struct Curl_easy *data,
1154
                                             bool *done)
1155
{
1156
  if(multissl_setup(NULL))
1157
    return CURLE_FAILED_INIT;
1158
  return Curl_ssl->connect_nonblocking(cf, data, done);
1159
}
1160
1161
static int multissl_get_select_socks(struct Curl_cfilter *cf,
1162
                                     struct Curl_easy *data,
1163
                                     curl_socket_t *socks)
1164
{
1165
  if(multissl_setup(NULL))
1166
    return 0;
1167
  return Curl_ssl->get_select_socks(cf, data, socks);
1168
}
1169
1170
static void *multissl_get_internals(struct ssl_connect_data *connssl,
1171
                                    CURLINFO info)
1172
{
1173
  if(multissl_setup(NULL))
1174
    return NULL;
1175
  return Curl_ssl->get_internals(connssl, info);
1176
}
1177
1178
static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1179
{
1180
  if(multissl_setup(NULL))
1181
    return;
1182
  Curl_ssl->close(cf, data);
1183
}
1184
1185
static ssize_t multissl_recv_plain(struct Curl_cfilter *cf,
1186
                                   struct Curl_easy *data,
1187
                                   char *buf, size_t len, CURLcode *code)
1188
{
1189
  if(multissl_setup(NULL))
1190
    return CURLE_FAILED_INIT;
1191
  return Curl_ssl->recv_plain(cf, data, buf, len, code);
1192
}
1193
1194
static ssize_t multissl_send_plain(struct Curl_cfilter *cf,
1195
                                   struct Curl_easy *data,
1196
                                   const void *mem, size_t len,
1197
                                   CURLcode *code)
1198
{
1199
  if(multissl_setup(NULL))
1200
    return CURLE_FAILED_INIT;
1201
  return Curl_ssl->send_plain(cf, data, mem, len, code);
1202
}
1203
1204
static const struct Curl_ssl Curl_ssl_multi = {
1205
  { CURLSSLBACKEND_NONE, "multi" },  /* info */
1206
  0, /* supports nothing */
1207
  (size_t)-1, /* something insanely large to be on the safe side */
1208
1209
  multissl_init,                     /* init */
1210
  Curl_none_cleanup,                 /* cleanup */
1211
  multissl_version,                  /* version */
1212
  Curl_none_check_cxn,               /* check_cxn */
1213
  Curl_none_shutdown,                /* shutdown */
1214
  Curl_none_data_pending,            /* data_pending */
1215
  Curl_none_random,                  /* random */
1216
  Curl_none_cert_status_request,     /* cert_status_request */
1217
  multissl_connect,                  /* connect */
1218
  multissl_connect_nonblocking,      /* connect_nonblocking */
1219
  multissl_get_select_socks,         /* getsock */
1220
  multissl_get_internals,            /* get_internals */
1221
  multissl_close,                    /* close_one */
1222
  Curl_none_close_all,               /* close_all */
1223
  Curl_none_session_free,            /* session_free */
1224
  Curl_none_set_engine,              /* set_engine */
1225
  Curl_none_set_engine_default,      /* set_engine_default */
1226
  Curl_none_engines_list,            /* engines_list */
1227
  Curl_none_false_start,             /* false_start */
1228
  NULL,                              /* sha256sum */
1229
  NULL,                              /* associate_connection */
1230
  NULL,                              /* disassociate_connection */
1231
  NULL,                              /* free_multi_ssl_backend_data */
1232
  multissl_recv_plain,               /* recv decrypted data */
1233
  multissl_send_plain,               /* send data to encrypt */
1234
};
1235
1236
const struct Curl_ssl *Curl_ssl =
1237
#if defined(CURL_WITH_MULTI_SSL)
1238
  &Curl_ssl_multi;
1239
#elif defined(USE_WOLFSSL)
1240
  &Curl_ssl_wolfssl;
1241
#elif defined(USE_SECTRANSP)
1242
  &Curl_ssl_sectransp;
1243
#elif defined(USE_GNUTLS)
1244
  &Curl_ssl_gnutls;
1245
#elif defined(USE_GSKIT)
1246
  &Curl_ssl_gskit;
1247
#elif defined(USE_MBEDTLS)
1248
  &Curl_ssl_mbedtls;
1249
#elif defined(USE_NSS)
1250
  &Curl_ssl_nss;
1251
#elif defined(USE_RUSTLS)
1252
  &Curl_ssl_rustls;
1253
#elif defined(USE_OPENSSL)
1254
  &Curl_ssl_openssl;
1255
#elif defined(USE_SCHANNEL)
1256
  &Curl_ssl_schannel;
1257
#elif defined(USE_BEARSSL)
1258
  &Curl_ssl_bearssl;
1259
#else
1260
#error "Missing struct Curl_ssl for selected SSL backend"
1261
#endif
1262
1263
static const struct Curl_ssl *available_backends[] = {
1264
#if defined(USE_WOLFSSL)
1265
  &Curl_ssl_wolfssl,
1266
#endif
1267
#if defined(USE_SECTRANSP)
1268
  &Curl_ssl_sectransp,
1269
#endif
1270
#if defined(USE_GNUTLS)
1271
  &Curl_ssl_gnutls,
1272
#endif
1273
#if defined(USE_GSKIT)
1274
  &Curl_ssl_gskit,
1275
#endif
1276
#if defined(USE_MBEDTLS)
1277
  &Curl_ssl_mbedtls,
1278
#endif
1279
#if defined(USE_NSS)
1280
  &Curl_ssl_nss,
1281
#endif
1282
#if defined(USE_OPENSSL)
1283
  &Curl_ssl_openssl,
1284
#endif
1285
#if defined(USE_SCHANNEL)
1286
  &Curl_ssl_schannel,
1287
#endif
1288
#if defined(USE_BEARSSL)
1289
  &Curl_ssl_bearssl,
1290
#endif
1291
#if defined(USE_RUSTLS)
1292
  &Curl_ssl_rustls,
1293
#endif
1294
  NULL
1295
};
1296
1297
static size_t multissl_version(char *buffer, size_t size)
1298
{
1299
  static const struct Curl_ssl *selected;
1300
  static char backends[200];
1301
  static size_t backends_len;
1302
  const struct Curl_ssl *current;
1303
1304
  current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl;
1305
1306
  if(current != selected) {
1307
    char *p = backends;
1308
    char *end = backends + sizeof(backends);
1309
    int i;
1310
1311
    selected = current;
1312
1313
    backends[0] = '\0';
1314
1315
    for(i = 0; available_backends[i]; ++i) {
1316
      char vb[200];
1317
      bool paren = (selected != available_backends[i]);
1318
1319
      if(available_backends[i]->version(vb, sizeof(vb))) {
1320
        p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""),
1321
                       (paren ? "(" : ""), vb, (paren ? ")" : ""));
1322
      }
1323
    }
1324
1325
    backends_len = p - backends;
1326
  }
1327
1328
  if(!size)
1329
    return 0;
1330
1331
  if(size <= backends_len) {
1332
    strncpy(buffer, backends, size - 1);
1333
    buffer[size - 1] = '\0';
1334
    return size - 1;
1335
  }
1336
1337
  strcpy(buffer, backends);
1338
  return backends_len;
1339
}
1340
1341
static int multissl_setup(const struct Curl_ssl *backend)
1342
{
1343
  const char *env;
1344
  char *env_tmp;
1345
1346
  if(Curl_ssl != &Curl_ssl_multi)
1347
    return 1;
1348
1349
  if(backend) {
1350
    Curl_ssl = backend;
1351
    return 0;
1352
  }
1353
1354
  if(!available_backends[0])
1355
    return 1;
1356
1357
  env = env_tmp = curl_getenv("CURL_SSL_BACKEND");
1358
#ifdef CURL_DEFAULT_SSL_BACKEND
1359
  if(!env)
1360
    env = CURL_DEFAULT_SSL_BACKEND;
1361
#endif
1362
  if(env) {
1363
    int i;
1364
    for(i = 0; available_backends[i]; i++) {
1365
      if(strcasecompare(env, available_backends[i]->info.name)) {
1366
        Curl_ssl = available_backends[i];
1367
        free(env_tmp);
1368
        return 0;
1369
      }
1370
    }
1371
  }
1372
1373
  /* Fall back to first available backend */
1374
  Curl_ssl = available_backends[0];
1375
  free(env_tmp);
1376
  return 0;
1377
}
1378
1379
/* This function is used to select the SSL backend to use. It is called by
1380
   curl_global_sslset (easy.c) which uses the global init lock. */
1381
CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
1382
                                   const curl_ssl_backend ***avail)
1383
{
1384
  int i;
1385
1386
  if(avail)
1387
    *avail = (const curl_ssl_backend **)&available_backends;
1388
1389
  if(Curl_ssl != &Curl_ssl_multi)
1390
    return id == Curl_ssl->info.id ||
1391
           (name && strcasecompare(name, Curl_ssl->info.name)) ?
1392
           CURLSSLSET_OK :
1393
#if defined(CURL_WITH_MULTI_SSL)
1394
           CURLSSLSET_TOO_LATE;
1395
#else
1396
           CURLSSLSET_UNKNOWN_BACKEND;
1397
#endif
1398
1399
  for(i = 0; available_backends[i]; i++) {
1400
    if(available_backends[i]->info.id == id ||
1401
       (name && strcasecompare(available_backends[i]->info.name, name))) {
1402
      multissl_setup(available_backends[i]);
1403
      return CURLSSLSET_OK;
1404
    }
1405
  }
1406
1407
  return CURLSSLSET_UNKNOWN_BACKEND;
1408
}
1409
1410
#else /* USE_SSL */
1411
CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
1412
                                   const curl_ssl_backend ***avail)
1413
0
{
1414
0
  (void)id;
1415
0
  (void)name;
1416
0
  (void)avail;
1417
0
  return CURLSSLSET_NO_BACKENDS;
1418
0
}
1419
1420
#endif /* !USE_SSL */
1421
1422
#ifdef USE_SSL
1423
1424
static void free_hostname(struct ssl_connect_data *connssl)
1425
{
1426
  if(connssl->dispname != connssl->hostname)
1427
    free(connssl->dispname);
1428
  free(connssl->hostname);
1429
  connssl->hostname = connssl->dispname = NULL;
1430
}
1431
1432
static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1433
{
1434
  struct ssl_connect_data *connssl = cf->ctx;
1435
  if(connssl) {
1436
    Curl_ssl->close(cf, data);
1437
    connssl->state = ssl_connection_none;
1438
    free_hostname(connssl);
1439
  }
1440
  cf->connected = FALSE;
1441
}
1442
1443
static CURLcode reinit_hostname(struct Curl_cfilter *cf)
1444
{
1445
  struct ssl_connect_data *connssl = cf->ctx;
1446
  const char *ehostname, *edispname;
1447
  int eport;
1448
1449
  /* We need the hostname for SNI negotiation. Once handshaked, this
1450
   * remains the SNI hostname for the TLS connection. But when the
1451
   * connection is reused, the settings in cf->conn might change.
1452
   * So we keep a copy of the hostname we use for SNI.
1453
   */
1454
#ifndef CURL_DISABLE_PROXY
1455
  if(Curl_ssl_cf_is_proxy(cf)) {
1456
    ehostname = cf->conn->http_proxy.host.name;
1457
    edispname = cf->conn->http_proxy.host.dispname;
1458
    eport = cf->conn->http_proxy.port;
1459
  }
1460
  else
1461
#endif
1462
  {
1463
    ehostname = cf->conn->host.name;
1464
    edispname = cf->conn->host.dispname;
1465
    eport = cf->conn->remote_port;
1466
  }
1467
1468
  /* change if ehostname changed */
1469
  if(ehostname && (!connssl->hostname
1470
                   || strcmp(ehostname, connssl->hostname))) {
1471
    free_hostname(connssl);
1472
    connssl->hostname = strdup(ehostname);
1473
    if(!connssl->hostname) {
1474
      free_hostname(connssl);
1475
      return CURLE_OUT_OF_MEMORY;
1476
    }
1477
    if(!edispname || !strcmp(ehostname, edispname))
1478
      connssl->dispname = connssl->hostname;
1479
    else {
1480
      connssl->dispname = strdup(edispname);
1481
      if(!connssl->dispname) {
1482
        free_hostname(connssl);
1483
        return CURLE_OUT_OF_MEMORY;
1484
      }
1485
    }
1486
  }
1487
  connssl->port = eport;
1488
  return CURLE_OK;
1489
}
1490
1491
static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
1492
{
1493
  struct cf_call_data save;
1494
1495
  CF_DATA_SAVE(save, cf, data);
1496
  cf_close(cf, data);
1497
  CF_DATA_RESTORE(cf, save);
1498
  cf_ctx_free(cf->ctx);
1499
  cf->ctx = NULL;
1500
}
1501
1502
static void ssl_cf_close(struct Curl_cfilter *cf,
1503
                         struct Curl_easy *data)
1504
{
1505
  struct cf_call_data save;
1506
1507
  CF_DATA_SAVE(save, cf, data);
1508
  cf_close(cf, data);
1509
  cf->next->cft->close(cf->next, data);
1510
  CF_DATA_RESTORE(cf, save);
1511
}
1512
1513
static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
1514
                               struct Curl_easy *data,
1515
                               bool blocking, bool *done)
1516
{
1517
  struct ssl_connect_data *connssl = cf->ctx;
1518
  struct cf_call_data save;
1519
  CURLcode result;
1520
1521
  if(cf->connected) {
1522
    *done = TRUE;
1523
    return CURLE_OK;
1524
  }
1525
1526
  CF_DATA_SAVE(save, cf, data);
1527
  (void)connssl;
1528
  DEBUGASSERT(data->conn);
1529
  DEBUGASSERT(data->conn == cf->conn);
1530
  DEBUGASSERT(connssl);
1531
  DEBUGASSERT(cf->conn->host.name);
1532
1533
  result = cf->next->cft->connect(cf->next, data, blocking, done);
1534
  if(result || !*done)
1535
    goto out;
1536
1537
  *done = FALSE;
1538
  result = reinit_hostname(cf);
1539
  if(result)
1540
    goto out;
1541
1542
  if(blocking) {
1543
    result = ssl_connect(cf, data);
1544
    *done = (result == CURLE_OK);
1545
  }
1546
  else {
1547
    result = ssl_connect_nonblocking(cf, data, done);
1548
  }
1549
1550
  if(!result && *done) {
1551
    cf->connected = TRUE;
1552
    connssl->handshake_done = Curl_now();
1553
    DEBUGASSERT(connssl->state == ssl_connection_complete);
1554
  }
1555
out:
1556
  CF_DATA_RESTORE(cf, save);
1557
  return result;
1558
}
1559
1560
static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
1561
                                const struct Curl_easy *data)
1562
{
1563
  struct cf_call_data save;
1564
  bool result;
1565
1566
  CF_DATA_SAVE(save, cf, data);
1567
  if(Curl_ssl->data_pending(cf, data))
1568
    result = TRUE;
1569
  else
1570
    result = cf->next->cft->has_data_pending(cf->next, data);
1571
  CF_DATA_RESTORE(cf, save);
1572
  return result;
1573
}
1574
1575
static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
1576
                           struct Curl_easy *data, const void *buf, size_t len,
1577
                           CURLcode *err)
1578
{
1579
  struct cf_call_data save;
1580
  ssize_t nwritten;
1581
1582
  CF_DATA_SAVE(save, cf, data);
1583
  *err = CURLE_OK;
1584
  nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
1585
  CF_DATA_RESTORE(cf, save);
1586
  return nwritten;
1587
}
1588
1589
static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
1590
                           struct Curl_easy *data, char *buf, size_t len,
1591
                           CURLcode *err)
1592
{
1593
  struct cf_call_data save;
1594
  ssize_t nread;
1595
1596
  CF_DATA_SAVE(save, cf, data);
1597
  nread = Curl_ssl->recv_plain(cf, data, buf, len, err);
1598
  if(nread > 0) {
1599
    DEBUGASSERT((size_t)nread <= len);
1600
  }
1601
  else if(nread == 0) {
1602
    /* eof */
1603
    *err = CURLE_OK;
1604
  }
1605
  DEBUGF(LOG_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len, nread, *err));
1606
  CF_DATA_RESTORE(cf, save);
1607
  return nread;
1608
}
1609
1610
static int ssl_cf_get_select_socks(struct Curl_cfilter *cf,
1611
                                   struct Curl_easy *data,
1612
                                   curl_socket_t *socks)
1613
{
1614
  struct cf_call_data save;
1615
  int result;
1616
1617
  CF_DATA_SAVE(save, cf, data);
1618
  result = Curl_ssl->get_select_socks(cf, data, socks);
1619
  CF_DATA_RESTORE(cf, save);
1620
  return result;
1621
}
1622
1623
static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
1624
                             struct Curl_easy *data,
1625
                             int event, int arg1, void *arg2)
1626
{
1627
  struct cf_call_data save;
1628
1629
  (void)arg1;
1630
  (void)arg2;
1631
  switch(event) {
1632
  case CF_CTRL_DATA_ATTACH:
1633
    if(Curl_ssl->attach_data) {
1634
      CF_DATA_SAVE(save, cf, data);
1635
      Curl_ssl->attach_data(cf, data);
1636
      CF_DATA_RESTORE(cf, save);
1637
    }
1638
    break;
1639
  case CF_CTRL_DATA_DETACH:
1640
    if(Curl_ssl->detach_data) {
1641
      CF_DATA_SAVE(save, cf, data);
1642
      Curl_ssl->detach_data(cf, data);
1643
      CF_DATA_RESTORE(cf, save);
1644
    }
1645
    break;
1646
  default:
1647
    break;
1648
  }
1649
  return CURLE_OK;
1650
}
1651
1652
static CURLcode ssl_cf_query(struct Curl_cfilter *cf,
1653
                             struct Curl_easy *data,
1654
                             int query, int *pres1, void *pres2)
1655
{
1656
  struct ssl_connect_data *connssl = cf->ctx;
1657
1658
  switch(query) {
1659
  case CF_QUERY_TIMER_APPCONNECT: {
1660
    struct curltime *when = pres2;
1661
    if(cf->connected && !Curl_ssl_cf_is_proxy(cf))
1662
      *when = connssl->handshake_done;
1663
    return CURLE_OK;
1664
  }
1665
  default:
1666
    break;
1667
  }
1668
  return cf->next?
1669
    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1670
    CURLE_UNKNOWN_OPTION;
1671
}
1672
1673
static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data,
1674
                            bool *input_pending)
1675
{
1676
  struct cf_call_data save;
1677
  int result;
1678
  /*
1679
   * This function tries to determine connection status.
1680
   *
1681
   * Return codes:
1682
   *     1 means the connection is still in place
1683
   *     0 means the connection has been closed
1684
   *    -1 means the connection status is unknown
1685
   */
1686
  CF_DATA_SAVE(save, cf, data);
1687
  result = Curl_ssl->check_cxn(cf, data);
1688
  CF_DATA_RESTORE(cf, save);
1689
  if(result > 0) {
1690
    *input_pending = TRUE;
1691
    return TRUE;
1692
  }
1693
  if(result == 0) {
1694
    *input_pending = FALSE;
1695
    return FALSE;
1696
  }
1697
  /* ssl backend does not know */
1698
  return cf->next?
1699
    cf->next->cft->is_alive(cf->next, data, input_pending) :
1700
    FALSE; /* pessimistic in absence of data */
1701
}
1702
1703
struct Curl_cftype Curl_cft_ssl = {
1704
  "SSL",
1705
  CF_TYPE_SSL,
1706
  CURL_LOG_DEFAULT,
1707
  ssl_cf_destroy,
1708
  ssl_cf_connect,
1709
  ssl_cf_close,
1710
  Curl_cf_def_get_host,
1711
  ssl_cf_get_select_socks,
1712
  ssl_cf_data_pending,
1713
  ssl_cf_send,
1714
  ssl_cf_recv,
1715
  ssl_cf_cntrl,
1716
  cf_ssl_is_alive,
1717
  Curl_cf_def_conn_keep_alive,
1718
  ssl_cf_query,
1719
};
1720
1721
struct Curl_cftype Curl_cft_ssl_proxy = {
1722
  "SSL-PROXY",
1723
  CF_TYPE_SSL,
1724
  CURL_LOG_DEFAULT,
1725
  ssl_cf_destroy,
1726
  ssl_cf_connect,
1727
  ssl_cf_close,
1728
  Curl_cf_def_get_host,
1729
  ssl_cf_get_select_socks,
1730
  ssl_cf_data_pending,
1731
  ssl_cf_send,
1732
  ssl_cf_recv,
1733
  ssl_cf_cntrl,
1734
  cf_ssl_is_alive,
1735
  Curl_cf_def_conn_keep_alive,
1736
  Curl_cf_def_query,
1737
};
1738
1739
static CURLcode cf_ssl_create(struct Curl_cfilter **pcf,
1740
                              struct Curl_easy *data,
1741
                              struct connectdata *conn)
1742
{
1743
  struct Curl_cfilter *cf = NULL;
1744
  struct ssl_connect_data *ctx;
1745
  CURLcode result;
1746
1747
  DEBUGASSERT(data->conn);
1748
1749
  ctx = cf_ctx_new(data, alpn_get_spec(data->state.httpwant,
1750
                                       conn->bits.tls_enable_alpn));
1751
  if(!ctx) {
1752
    result = CURLE_OUT_OF_MEMORY;
1753
    goto out;
1754
  }
1755
1756
  result = Curl_cf_create(&cf, &Curl_cft_ssl, ctx);
1757
1758
out:
1759
  if(result)
1760
    cf_ctx_free(ctx);
1761
  *pcf = result? NULL : cf;
1762
  return result;
1763
}
1764
1765
CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
1766
                              struct connectdata *conn,
1767
                              int sockindex)
1768
{
1769
  struct Curl_cfilter *cf;
1770
  CURLcode result;
1771
1772
  result = cf_ssl_create(&cf, data, conn);
1773
  if(!result)
1774
    Curl_conn_cf_add(data, conn, sockindex, cf);
1775
  return result;
1776
}
1777
1778
CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
1779
                                  struct Curl_easy *data)
1780
{
1781
  struct Curl_cfilter *cf;
1782
  CURLcode result;
1783
1784
  result = cf_ssl_create(&cf, data, cf_at->conn);
1785
  if(!result)
1786
    Curl_conn_cf_insert_after(cf_at, cf);
1787
  return result;
1788
}
1789
1790
#ifndef CURL_DISABLE_PROXY
1791
1792
static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf,
1793
                                    struct Curl_easy *data,
1794
                                    struct connectdata *conn)
1795
{
1796
  struct Curl_cfilter *cf = NULL;
1797
  struct ssl_connect_data *ctx;
1798
  CURLcode result;
1799
  bool use_alpn = conn->bits.tls_enable_alpn;
1800
  int httpwant = CURL_HTTP_VERSION_1_1;
1801
1802
#ifdef USE_HTTP2
1803
  if(conn->http_proxy.proxytype == CURLPROXY_HTTPS2) {
1804
    use_alpn = TRUE;
1805
    httpwant = CURL_HTTP_VERSION_2;
1806
  }
1807
#endif
1808
1809
  ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn));
1810
  if(!ctx) {
1811
    result = CURLE_OUT_OF_MEMORY;
1812
    goto out;
1813
  }
1814
  result = Curl_cf_create(&cf, &Curl_cft_ssl_proxy, ctx);
1815
1816
out:
1817
  if(result)
1818
    cf_ctx_free(ctx);
1819
  *pcf = result? NULL : cf;
1820
  return result;
1821
}
1822
1823
CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
1824
                                        struct Curl_easy *data)
1825
{
1826
  struct Curl_cfilter *cf;
1827
  CURLcode result;
1828
1829
  result = cf_ssl_proxy_create(&cf, data, cf_at->conn);
1830
  if(!result)
1831
    Curl_conn_cf_insert_after(cf_at, cf);
1832
  return result;
1833
}
1834
1835
#endif /* !CURL_DISABLE_PROXY */
1836
1837
bool Curl_ssl_supports(struct Curl_easy *data, int option)
1838
{
1839
  (void)data;
1840
  return (Curl_ssl->supports & option)? TRUE : FALSE;
1841
}
1842
1843
void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
1844
                             CURLINFO info, int n)
1845
{
1846
  void *result = NULL;
1847
  (void)n;
1848
  if(data->conn) {
1849
    struct Curl_cfilter *cf;
1850
    /* get first filter in chain, if any is present */
1851
    cf = Curl_ssl_cf_get_ssl(data->conn->cfilter[sockindex]);
1852
    if(cf) {
1853
      struct cf_call_data save;
1854
      CF_DATA_SAVE(save, cf, data);
1855
      result = Curl_ssl->get_internals(cf->ctx, info);
1856
      CF_DATA_RESTORE(cf, save);
1857
    }
1858
  }
1859
  return result;
1860
}
1861
1862
CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
1863
                                 int sockindex)
1864
{
1865
  struct Curl_cfilter *cf, *head;
1866
  CURLcode result = CURLE_OK;
1867
1868
  (void)data;
1869
  head = data->conn? data->conn->cfilter[sockindex] : NULL;
1870
  for(cf = head; cf; cf = cf->next) {
1871
    if(cf->cft == &Curl_cft_ssl) {
1872
      if(Curl_ssl->shut_down(cf, data))
1873
        result = CURLE_SSL_SHUTDOWN_FAILED;
1874
      Curl_conn_cf_discard_sub(head, cf, data, FALSE);
1875
      break;
1876
    }
1877
  }
1878
  return result;
1879
}
1880
1881
static struct Curl_cfilter *get_ssl_cf_engaged(struct connectdata *conn,
1882
                                               int sockindex)
1883
{
1884
  struct Curl_cfilter *cf, *lowest_ssl_cf = NULL;
1885
1886
  for(cf = conn->cfilter[sockindex]; cf; cf = cf->next) {
1887
    if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy) {
1888
      lowest_ssl_cf = cf;
1889
      if(cf->connected || (cf->next && cf->next->connected)) {
1890
        /* connected or about to start */
1891
        return cf;
1892
      }
1893
    }
1894
  }
1895
  return lowest_ssl_cf;
1896
}
1897
1898
bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
1899
{
1900
  return (cf->cft == &Curl_cft_ssl_proxy);
1901
}
1902
1903
struct ssl_config_data *
1904
Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data)
1905
{
1906
#ifdef CURL_DISABLE_PROXY
1907
  (void)cf;
1908
  return &data->set.ssl;
1909
#else
1910
  return Curl_ssl_cf_is_proxy(cf)? &data->set.proxy_ssl : &data->set.ssl;
1911
#endif
1912
}
1913
1914
struct ssl_config_data *
1915
Curl_ssl_get_config(struct Curl_easy *data, int sockindex)
1916
{
1917
  struct Curl_cfilter *cf;
1918
1919
  (void)data;
1920
  DEBUGASSERT(data->conn);
1921
  cf = get_ssl_cf_engaged(data->conn, sockindex);
1922
  return cf? Curl_ssl_cf_get_config(cf, data) : &data->set.ssl;
1923
}
1924
1925
struct ssl_primary_config *
1926
Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf)
1927
{
1928
#ifdef CURL_DISABLE_PROXY
1929
  return &cf->conn->ssl_config;
1930
#else
1931
  return Curl_ssl_cf_is_proxy(cf)?
1932
    &cf->conn->proxy_ssl_config : &cf->conn->ssl_config;
1933
#endif
1934
}
1935
1936
struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf)
1937
{
1938
  for(; cf; cf = cf->next) {
1939
    if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy)
1940
      return cf;
1941
  }
1942
  return NULL;
1943
}
1944
1945
CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf,
1946
                                const struct alpn_spec *spec)
1947
{
1948
  size_t i, len;
1949
  int off = 0;
1950
  unsigned char blen;
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
    blen = (unsigned  char)len;
1958
    if(off + blen + 1 >= (int)sizeof(buf->data))
1959
      return CURLE_FAILED_INIT;
1960
    buf->data[off++] = blen;
1961
    memcpy(buf->data + off, spec->entries[i], blen);
1962
    off += blen;
1963
  }
1964
  buf->len = off;
1965
  return CURLE_OK;
1966
}
1967
1968
CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
1969
                                const struct alpn_spec *spec)
1970
{
1971
  size_t i, len;
1972
  size_t off = 0;
1973
1974
  memset(buf, 0, sizeof(*buf));
1975
  for(i = 0; spec && i < spec->count; ++i) {
1976
    len = strlen(spec->entries[i]);
1977
    if(len >= ALPN_NAME_MAX)
1978
      return CURLE_FAILED_INIT;
1979
    if(off + len + 2 >= sizeof(buf->data))
1980
      return CURLE_FAILED_INIT;
1981
    if(off)
1982
      buf->data[off++] = ',';
1983
    memcpy(buf->data + off, spec->entries[i], len);
1984
    off += len;
1985
  }
1986
  buf->data[off] = '\0';
1987
  buf->len = (int)off;
1988
  return CURLE_OK;
1989
}
1990
1991
CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
1992
                                  struct Curl_easy *data,
1993
                                  const unsigned char *proto,
1994
                                  size_t proto_len)
1995
{
1996
  int can_multi = 0;
1997
  unsigned char *palpn =
1998
#ifndef CURL_DISABLE_PROXY
1999
    (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf))?
2000
    &cf->conn->proxy_alpn : &cf->conn->alpn
2001
#else
2002
    &cf->conn->alpn
2003
#endif
2004
    ;
2005
2006
  if(proto && proto_len) {
2007
    if(proto_len == ALPN_HTTP_1_1_LENGTH &&
2008
       !memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) {
2009
      *palpn = CURL_HTTP_VERSION_1_1;
2010
    }
2011
    else if(proto_len == ALPN_HTTP_1_0_LENGTH &&
2012
            !memcmp(ALPN_HTTP_1_0, proto, ALPN_HTTP_1_0_LENGTH)) {
2013
      *palpn = CURL_HTTP_VERSION_1_0;
2014
    }
2015
#ifdef USE_HTTP2
2016
    else if(proto_len == ALPN_H2_LENGTH &&
2017
            !memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) {
2018
      *palpn = CURL_HTTP_VERSION_2;
2019
      can_multi = 1;
2020
    }
2021
#endif
2022
#ifdef USE_HTTP3
2023
    else if(proto_len == ALPN_H3_LENGTH &&
2024
            !memcmp(ALPN_H3, proto, ALPN_H3_LENGTH)) {
2025
      *palpn = CURL_HTTP_VERSION_3;
2026
      can_multi = 1;
2027
    }
2028
#endif
2029
    else {
2030
      *palpn = CURL_HTTP_VERSION_NONE;
2031
      failf(data, "unsupported ALPN protocol: '%.*s'", (int)proto_len, proto);
2032
      /* TODO: do we want to fail this? Previous code just ignored it and
2033
       * some vtls backends even ignore the return code of this function. */
2034
      /* return CURLE_NOT_BUILT_IN; */
2035
      goto out;
2036
    }
2037
    infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, (int)proto_len, proto);
2038
  }
2039
  else {
2040
    *palpn = CURL_HTTP_VERSION_NONE;
2041
    infof(data, VTLS_INFOF_NO_ALPN);
2042
  }
2043
2044
out:
2045
  if(!Curl_ssl_cf_is_proxy(cf))
2046
    Curl_multiuse_state(data, can_multi?
2047
                        BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
2048
  return CURLE_OK;
2049
}
2050
2051
#endif /* USE_SSL */