Coverage Report

Created: 2026-07-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmcurl/lib/vtls/vtls_config.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 "setopt.h"
49
#include "strcase.h"
50
#include "vtls/vtls.h"
51
#include "vtls/vtls_config.h"
52
53
54
#define CLONE_STRING(var)                    \
55
0
  do {                                       \
56
0
    if(source->var) {                        \
57
0
      dest->var = curlx_strdup(source->var); \
58
0
      if(!dest->var)                         \
59
0
        return FALSE;                        \
60
0
    }                                        \
61
0
    else                                     \
62
0
      dest->var = NULL;                      \
63
0
  } while(0)
64
65
#define CLONE_BLOB(var)                  \
66
0
  do {                                   \
67
0
    if(blobdup(&dest->var, source->var)) \
68
0
      return FALSE;                      \
69
0
  } while(0)
70
71
static CURLcode blobdup(struct curl_blob **dest, struct curl_blob *src)
72
0
{
73
0
  DEBUGASSERT(dest);
74
0
  DEBUGASSERT(!*dest);
75
0
  if(src) {
76
    /* only if there is data to dupe! */
77
0
    struct curl_blob *d;
78
0
    d = curlx_malloc(sizeof(struct curl_blob) + src->len);
79
0
    if(!d)
80
0
      return CURLE_OUT_OF_MEMORY;
81
0
    d->len = src->len;
82
    /* Always duplicate because the connection may survive longer than the
83
       handle that passed in the blob. */
84
0
    d->flags = CURL_BLOB_COPY;
85
0
    d->data = (void *)((char *)d + sizeof(struct curl_blob));
86
0
    memcpy(d->data, src->data, src->len);
87
0
    *dest = d;
88
0
  }
89
0
  return CURLE_OK;
90
0
}
91
92
/* returns TRUE if the blobs are identical */
93
static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
94
0
{
95
0
  if(!first && !second) /* both are NULL */
96
0
    return TRUE;
97
0
  if(!first || !second) /* one is NULL */
98
0
    return FALSE;
99
0
  if(first->len != second->len) /* different sizes */
100
0
    return FALSE;
101
0
  return !memcmp(first->data, second->data, first->len); /* same data */
102
0
}
103
104
void Curl_ssl_config_init(struct ssl_primary_config *sslc)
105
0
{
106
  /*
107
   * libcurl 7.10 introduced SSL verification *by default*! This needs to be
108
   * switched off unless wanted.
109
   */
110
0
  sslc->verifypeer = TRUE;
111
0
  sslc->verifyhost = TRUE;
112
0
  sslc->cache_session = TRUE; /* caching by default */
113
0
}
114
115
void Curl_ssl_config_cleanup(struct ssl_primary_config *sslc)
116
0
{
117
0
  if(sslc->deep_copy) {
118
0
    curlx_safefree(sslc->CApath);
119
0
    curlx_safefree(sslc->CAfile);
120
0
    curlx_safefree(sslc->issuercert);
121
0
    curlx_safefree(sslc->clientcert);
122
0
    curlx_safefree(sslc->cipher_list);
123
0
    curlx_safefree(sslc->cipher_list13);
124
0
    curlx_safefree(sslc->pinned_key);
125
0
    curlx_safefree(sslc->cert_blob);
126
0
    curlx_safefree(sslc->ca_info_blob);
127
0
    curlx_safefree(sslc->issuercert_blob);
128
0
    curlx_safefree(sslc->key_blob);
129
0
    curlx_safefree(sslc->curves);
130
0
    curlx_safefree(sslc->signature_algorithms);
131
0
    curlx_safefree(sslc->CRLfile);
132
0
    curlx_safefree(sslc->cert_type);
133
0
    curlx_safefree(sslc->key);
134
0
    curlx_safefree(sslc->key_type);
135
0
    curlx_safefree(sslc->key_passwd);
136
#ifdef USE_TLS_SRP
137
    curlx_safefree(sslc->username);
138
    curlx_safefree(sslc->password);
139
#endif
140
0
    sslc->deep_copy = FALSE;
141
0
  }
142
0
}
143
144
static bool match_ssl_primary_config(struct Curl_easy *data,
145
                                     struct ssl_primary_config *c1,
146
                                     struct ssl_primary_config *c2)
147
0
{
148
0
  (void)data;
149
0
  if((c1->version == c2->version) &&
150
0
     (c1->version_max == c2->version_max) &&
151
0
     (c1->ssl_options == c2->ssl_options) &&
152
0
     (c1->verifypeer == c2->verifypeer) &&
153
0
     (c1->verifyhost == c2->verifyhost) &&
154
0
     (c1->verifystatus == c2->verifystatus) &&
155
0
     blobcmp(c1->cert_blob, c2->cert_blob) &&
156
0
     blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
157
0
     blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
158
0
     blobcmp(c1->key_blob, c2->key_blob) &&
159
0
     Curl_safecmp(c1->CApath, c2->CApath) &&
160
0
     Curl_safecmp(c1->CAfile, c2->CAfile) &&
161
0
     Curl_safecmp(c1->issuercert, c2->issuercert) &&
162
0
     Curl_safecmp(c1->clientcert, c2->clientcert) &&
163
#ifdef USE_TLS_SRP
164
     !Curl_timestrcmp(c1->username, c2->username) &&
165
     !Curl_timestrcmp(c1->password, c2->password) &&
166
#endif
167
0
     curl_strequal(c1->cipher_list, c2->cipher_list) &&
168
0
     curl_strequal(c1->cipher_list13, c2->cipher_list13) &&
169
0
     curl_strequal(c1->curves, c2->curves) &&
170
0
     curl_strequal(c1->signature_algorithms, c2->signature_algorithms) &&
171
0
     Curl_safecmp(c1->CRLfile, c2->CRLfile) &&
172
0
     Curl_safecmp(c1->pinned_key, c2->pinned_key) &&
173
0
     curl_strequal(c1->cert_type, c2->cert_type) &&
174
0
     Curl_safecmp(c1->key, c2->key) &&
175
0
     curl_strequal(c1->key_type, c2->key_type) &&
176
0
     !Curl_timestrcmp(c1->key_passwd, c2->key_passwd))
177
0
    return TRUE;
178
179
0
  return FALSE;
180
0
}
181
182
bool Curl_ssl_conn_config_match(struct Curl_easy *data,
183
                                struct connectdata *candidate,
184
                                bool proxy)
185
0
{
186
0
#ifndef CURL_DISABLE_PROXY
187
0
  if(proxy)
188
0
    return match_ssl_primary_config(data, &data->set.proxy_ssl.primary,
189
0
                                    &candidate->proxy_ssl_config);
190
#else
191
  (void)proxy;
192
#endif
193
0
  return match_ssl_primary_config(data, &data->set.ssl.primary,
194
0
                                  &candidate->ssl_config);
195
0
}
196
197
static bool clone_ssl_primary_config(struct ssl_primary_config *source,
198
                                     struct ssl_primary_config *dest)
199
0
{
200
0
  DEBUGASSERT(!dest->deep_copy);
201
0
  dest->deep_copy = TRUE;
202
0
  dest->version = source->version;
203
0
  dest->version_max = source->version_max;
204
0
  dest->verifypeer = source->verifypeer;
205
0
  dest->verifyhost = source->verifyhost;
206
0
  dest->verifystatus = source->verifystatus;
207
0
  dest->cache_session = source->cache_session;
208
0
  dest->ssl_options = source->ssl_options;
209
210
0
  CLONE_BLOB(cert_blob);
211
0
  CLONE_BLOB(ca_info_blob);
212
0
  CLONE_BLOB(issuercert_blob);
213
0
  CLONE_STRING(CApath);
214
0
  CLONE_STRING(CAfile);
215
0
  CLONE_STRING(issuercert);
216
0
  CLONE_STRING(cipher_list);
217
0
  CLONE_STRING(cipher_list13);
218
0
  CLONE_STRING(pinned_key);
219
0
  CLONE_STRING(curves);
220
0
  CLONE_STRING(signature_algorithms);
221
0
  CLONE_STRING(CRLfile);
222
  /* SSL credentials: client certificate, SRP auth */
223
0
  CLONE_STRING(clientcert);
224
0
  CLONE_STRING(cert_type);
225
0
  CLONE_STRING(key);
226
0
  CLONE_STRING(key_type);
227
0
  CLONE_STRING(key_passwd);
228
0
  CLONE_BLOB(key_blob);
229
#ifdef USE_TLS_SRP
230
  CLONE_STRING(username);
231
  CLONE_STRING(password);
232
#endif
233
234
0
  return TRUE;
235
0
}
236
237
static void ssl_easy_config_compl_options(struct Curl_peer *origin,
238
                                          struct Curl_peer *initial_origin,
239
                                          struct ssl_config_data *sslc)
240
0
{
241
0
  uint8_t options = sslc->primary.ssl_options;
242
  /* If set via CURLOPT_(PROXY_)SSL_OPTIONS, we definitely use it.
243
   * If not, we switch it on for supported backends if no custom
244
   * CA settings exist. */
245
0
  sslc->native_ca_store = !!(options & CURLSSLOPT_NATIVE_CA);
246
0
  sslc->enable_beast = !!(options & CURLSSLOPT_ALLOW_BEAST);
247
0
  sslc->no_partialchain = !!(options & CURLSSLOPT_NO_PARTIALCHAIN);
248
0
  sslc->no_revoke = !!(options & CURLSSLOPT_NO_REVOKE);
249
0
  sslc->revoke_best_effort = !!(options & CURLSSLOPT_REVOKE_BEST_EFFORT);
250
0
  sslc->earlydata = !!(options & CURLSSLOPT_EARLYDATA);
251
252
0
  sslc->auto_client_cert = Curl_peer_equal(origin, initial_origin) &&
253
0
                           !!(options & CURLSSLOPT_AUTO_CLIENT_CERT);
254
0
}
255
256
CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data,
257
                                       struct Curl_peer *origin)
258
0
{
259
0
  struct ssl_config_data *sslc = &data->set.ssl;
260
#if defined(CURL_CA_PATH) || defined(CURL_CA_BUNDLE)
261
  struct UserDefined *set = &data->set;
262
  CURLcode result;
263
#endif
264
265
0
  ssl_easy_config_compl_options(origin, data->state.initial_origin, sslc);
266
267
0
  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
268
#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
269
    if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
270
      sslc->native_ca_store = TRUE;
271
#endif
272
#ifdef CURL_CA_PATH
273
    if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH]) {
274
      result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
275
      if(result)
276
        return result;
277
    }
278
#endif
279
#ifdef CURL_CA_BUNDLE
280
    if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE]) {
281
      result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
282
      if(result)
283
        return result;
284
    }
285
#endif
286
0
  }
287
0
  sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE];
288
0
  sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
289
0
  sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH];
290
0
  sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
291
0
  sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST];
292
0
  sslc->primary.signature_algorithms =
293
0
    data->set.str[STRING_SSL_SIGNATURE_ALGORITHMS];
294
0
  sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
295
0
  sslc->primary.curves = data->set.str[STRING_SSL_EC_CURVES];
296
  /* Maybe these should not be used for another origin. But for
297
   * backwards compatibility, keep them in. */
298
0
  sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
299
0
  sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
300
301
0
  if(Curl_peer_equal(data->state.initial_origin, origin)) {
302
0
    sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
303
0
    sslc->primary.cert_blob = data->set.blobs[BLOB_CERT];
304
0
    sslc->primary.cert_type = data->set.str[STRING_CERT_TYPE];
305
0
    sslc->primary.key = data->set.str[STRING_KEY];
306
0
    sslc->primary.key_type = data->set.str[STRING_KEY_TYPE];
307
0
    sslc->primary.key_passwd = data->set.str[STRING_KEY_PASSWD];
308
0
    sslc->primary.clientcert = data->set.str[STRING_CERT];
309
0
    sslc->primary.key_blob = data->set.blobs[BLOB_KEY];
310
#ifdef USE_TLS_SRP
311
    sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
312
    sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
313
#endif
314
0
  }
315
0
  else {
316
0
    sslc->primary.pinned_key = NULL;
317
0
    sslc->primary.cert_blob = NULL;
318
0
    sslc->primary.cert_type = NULL;
319
0
    sslc->primary.key = NULL;
320
0
    sslc->primary.key_type = NULL;
321
0
    sslc->primary.key_passwd = NULL;
322
0
    sslc->primary.clientcert = NULL;
323
0
    sslc->primary.key_blob = NULL;
324
#ifdef USE_TLS_SRP
325
    sslc->primary.username = NULL;
326
    sslc->primary.password = NULL;
327
#endif
328
0
  }
329
330
0
#ifndef CURL_DISABLE_PROXY
331
0
  sslc = &data->set.proxy_ssl;
332
  /* no initial origin for proxy, it is not changed for redirects */
333
0
  ssl_easy_config_compl_options(NULL, NULL, sslc);
334
335
0
  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
336
#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
337
    if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
338
      sslc->native_ca_store = TRUE;
339
#endif
340
#ifdef CURL_CA_PATH
341
    if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH_PROXY]) {
342
      result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY],
343
                              CURL_CA_PATH);
344
      if(result)
345
        return result;
346
    }
347
#endif
348
#ifdef CURL_CA_BUNDLE
349
    if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE_PROXY]) {
350
      result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
351
                              CURL_CA_BUNDLE);
352
      if(result)
353
        return result;
354
    }
355
#endif
356
0
  }
357
0
  sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
358
0
  sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
359
0
  sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
360
0
  sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
361
0
  sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
362
0
  sslc->primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
363
0
  sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO_PROXY];
364
0
  sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
365
0
  sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
366
0
  sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
367
0
  sslc->primary.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
368
0
  sslc->primary.key = data->set.str[STRING_KEY_PROXY];
369
0
  sslc->primary.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
370
0
  sslc->primary.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
371
0
  sslc->primary.clientcert = data->set.str[STRING_CERT_PROXY];
372
0
  sslc->primary.key_blob = data->set.blobs[BLOB_KEY_PROXY];
373
#ifdef USE_TLS_SRP
374
  sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
375
  sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
376
#endif
377
0
#endif /* CURL_DISABLE_PROXY */
378
379
0
  return CURLE_OK;
380
0
}
381
382
CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
383
                                   struct connectdata *conn)
384
0
{
385
  /* Clone "primary" SSL configurations from the easy handle to
386
   * the connection. They are used for connection cache matching and
387
   * probably outlive the easy handle */
388
0
  if(!clone_ssl_primary_config(&data->set.ssl.primary, &conn->ssl_config))
389
0
    return CURLE_OUT_OF_MEMORY;
390
0
#ifndef CURL_DISABLE_PROXY
391
0
  if(!clone_ssl_primary_config(&data->set.proxy_ssl.primary,
392
0
                               &conn->proxy_ssl_config))
393
0
    return CURLE_OUT_OF_MEMORY;
394
0
#endif
395
0
  return CURLE_OK;
396
0
}
397
398
void Curl_ssl_conn_config_cleanup(struct connectdata *conn)
399
0
{
400
0
  Curl_ssl_config_cleanup(&conn->ssl_config);
401
0
#ifndef CURL_DISABLE_PROXY
402
0
  Curl_ssl_config_cleanup(&conn->proxy_ssl_config);
403
0
#endif
404
0
}
405
406
void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy)
407
0
{
408
  /* May be called on an easy that has no connection yet */
409
0
  if(data->conn) {
410
0
    struct ssl_primary_config *src, *dest;
411
0
#ifndef CURL_DISABLE_PROXY
412
0
    src = for_proxy ? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
413
0
    dest = for_proxy ? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
414
#else
415
    (void)for_proxy;
416
    src = &data->set.ssl.primary;
417
    dest = &data->conn->ssl_config;
418
#endif
419
0
    dest->verifyhost = src->verifyhost;
420
0
    dest->verifypeer = src->verifypeer;
421
0
    dest->verifystatus = src->verifystatus;
422
0
  }
423
0
}