Coverage Report

Created: 2026-08-28 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/x509/x509_vpm.cc
Line
Count
Source
1
// Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <string.h>
16
17
#include <type_traits>
18
19
#include <openssl/mem.h>
20
#include <openssl/obj.h>
21
#include <openssl/stack.h>
22
#include <openssl/x509.h>
23
24
#include "../internal.h"
25
#include "../mem_internal.h"
26
#include "internal.h"
27
28
29
using namespace bssl;
30
31
// X509_VERIFY_PARAM functions
32
33
0
#define SET_HOST 0
34
0
#define ADD_HOST 1
35
36
0
static void str_free(char *s) { OPENSSL_free(s); }
37
38
static int int_x509_param_set_hosts(X509_VERIFY_PARAM *param, int mode,
39
0
                                    const char *name, size_t namelen) {
40
0
  char *copy;
41
42
0
  if (name == nullptr || namelen == 0) {
43
    // Unlike OpenSSL, we reject trying to set or add an empty name.
44
0
    return 0;
45
0
  }
46
47
  // Refuse names with embedded NUL bytes.
48
  // XXX: Do we need to push an error onto the error stack?
49
0
  if (name && OPENSSL_memchr(name, '\0', namelen)) {
50
0
    return 0;
51
0
  }
52
53
0
  if (mode == SET_HOST && param->hosts) {
54
0
    sk_OPENSSL_STRING_pop_free(param->hosts, str_free);
55
0
    param->hosts = nullptr;
56
0
  }
57
58
0
  copy = OPENSSL_strndup(name, namelen);
59
0
  if (copy == nullptr) {
60
0
    return 0;
61
0
  }
62
63
0
  if (param->hosts == nullptr &&
64
0
      (param->hosts = sk_OPENSSL_STRING_new_null()) == nullptr) {
65
0
    OPENSSL_free(copy);
66
0
    return 0;
67
0
  }
68
69
0
  if (!sk_OPENSSL_STRING_push(param->hosts, copy)) {
70
0
    OPENSSL_free(copy);
71
0
    if (sk_OPENSSL_STRING_num(param->hosts) == 0) {
72
0
      sk_OPENSSL_STRING_free(param->hosts);
73
0
      param->hosts = nullptr;
74
0
    }
75
0
    return 0;
76
0
  }
77
78
0
  return 1;
79
0
}
80
81
76.5k
X509_VERIFY_PARAM *X509_VERIFY_PARAM_new() {
82
76.5k
  X509_VERIFY_PARAM *param = New<X509_VERIFY_PARAM>();
83
76.5k
  if (!param) {
84
0
    return nullptr;
85
0
  }
86
76.5k
  param->depth = -1;
87
76.5k
  return param;
88
76.5k
}
89
90
84.5k
void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) {
91
84.5k
  if (param == nullptr) {
92
8.02k
    return;
93
8.02k
  }
94
76.5k
  sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
95
76.5k
  sk_OPENSSL_STRING_pop_free(param->hosts, str_free);
96
76.5k
  OPENSSL_free(param->email);
97
76.5k
  OPENSSL_free(param->ip);
98
76.5k
  Delete(param);
99
76.5k
}
100
101
724k
static bool should_copy(bool dest_is_set, bool src_is_set, bool prefer_src) {
102
724k
  if (prefer_src) {
103
    // We prefer the source, so as long as there is a value to copy, copy it.
104
64.1k
    return src_is_set;
105
64.1k
  }
106
107
  // We prefer the destination, so only copy if the destination is unset.
108
660k
  return src_is_set && !dest_is_set;
109
724k
}
110
111
template <typename T>
112
static void copy_int_param(T *dest, const T *src, T default_val,
113
362k
                           bool prefer_src) {
114
362k
  static_assert(std::is_integral_v<T>);
115
362k
  if (should_copy(*dest != default_val, *src != default_val, prefer_src)) {
116
24.0k
    *dest = *src;
117
24.0k
  }
118
362k
}
x509_vpm.cc:void copy_int_param<int>(int*, int const*, int, bool)
Line
Count
Source
113
271k
                           bool prefer_src) {
114
271k
  static_assert(std::is_integral_v<T>);
115
271k
  if (should_copy(*dest != default_val, *src != default_val, prefer_src)) {
116
24.0k
    *dest = *src;
117
24.0k
  }
118
271k
}
x509_vpm.cc:void copy_int_param<unsigned int>(unsigned int*, unsigned int const*, unsigned int, bool)
Line
Count
Source
113
90.5k
                           bool prefer_src) {
114
90.5k
  static_assert(std::is_integral_v<T>);
115
90.5k
  if (should_copy(*dest != default_val, *src != default_val, prefer_src)) {
116
0
    *dest = *src;
117
0
  }
118
90.5k
}
119
120
// x509_verify_param_merge merges fields from `src` to `dest`. If both `src` and
121
// `dest` have some field set, `prefer_src` determines whether `src` or `dest`'s
122
// version is used.
123
static int x509_verify_param_merge(X509_VERIFY_PARAM *dest,
124
                                   const X509_VERIFY_PARAM *src,
125
90.5k
                                   bool prefer_src) {
126
90.5k
  if (src == nullptr) {
127
0
    return 1;
128
0
  }
129
130
90.5k
  if (src->poison || dest->poison) {
131
0
    OPENSSL_PUT_ERROR(X509, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
132
0
    return 0;
133
0
  }
134
135
90.5k
  copy_int_param(&dest->purpose, &src->purpose, /*default_val=*/0, prefer_src);
136
90.5k
  copy_int_param(&dest->trust, &src->trust, /*default_val=*/0, prefer_src);
137
90.5k
  copy_int_param(&dest->depth, &src->depth, /*default_val=*/-1, prefer_src);
138
139
  // `check_time`, unlike all other parameters, does not honor `prefer_src`.
140
  // This means `X509_VERIFY_PARAM_set1` will not overwrite it. This behavior
141
  // comes from OpenSSL but may have been a bug.
142
90.5k
  if (!(dest->flags & X509_V_FLAG_USE_CHECK_TIME)) {
143
90.5k
    dest->check_time = src->check_time;
144
    // The source `X509_V_FLAG_USE_CHECK_TIME` flag, if set, is copied below.
145
90.5k
  }
146
147
90.5k
  dest->flags |= src->flags;
148
149
90.5k
  if (should_copy(dest->policies != nullptr, src->policies != nullptr,
150
90.5k
                  prefer_src)) {
151
0
    if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies)) {
152
0
      return 0;
153
0
    }
154
0
  }
155
156
90.5k
  if (should_copy(dest->hosts != nullptr, src->hosts != nullptr, prefer_src)) {
157
0
    sk_OPENSSL_STRING_pop_free(dest->hosts, str_free);
158
0
    dest->hosts = nullptr;
159
0
    if (src->hosts) {
160
0
      dest->hosts =
161
0
          sk_OPENSSL_STRING_deep_copy(src->hosts, OPENSSL_strdup, str_free);
162
0
      if (dest->hosts == nullptr) {
163
0
        return 0;
164
0
      }
165
0
    }
166
0
  }
167
168
90.5k
  copy_int_param(&dest->hostflags, &src->hostflags, /*default_val=*/unsigned{0},
169
90.5k
                 prefer_src);
170
171
90.5k
  if (should_copy(dest->email != nullptr, src->email != nullptr, prefer_src)) {
172
0
    if (!X509_VERIFY_PARAM_set1_email(dest, src->email, src->emaillen)) {
173
0
      return 0;
174
0
    }
175
0
  }
176
177
90.5k
  if (should_copy(dest->ip != nullptr, src->ip != nullptr, prefer_src)) {
178
0
    if (!X509_VERIFY_PARAM_set1_ip(dest, src->ip, src->iplen)) {
179
0
      return 0;
180
0
    }
181
0
  }
182
183
90.5k
  return 1;
184
90.5k
}
185
186
int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
187
82.5k
                              const X509_VERIFY_PARAM *src) {
188
  // Prefer the destination. That is, this function only changes unset
189
  // parameters in `dest`.
190
82.5k
  return x509_verify_param_merge(dest, src, /*prefer_src=*/false);
191
82.5k
}
192
193
int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
194
8.02k
                           const X509_VERIFY_PARAM *from) {
195
  // Prefer the source. That is, values in `to` are only preserved if they were
196
  // unset in `from`.
197
8.02k
  return x509_verify_param_merge(to, from, /*prefer_src=*/true);
198
8.02k
}
199
200
static int int_x509_param_set1(char **pdest, size_t *pdestlen, const char *src,
201
0
                               size_t srclen) {
202
0
  void *tmp;
203
0
  if (src == nullptr || srclen == 0) {
204
    // Unlike OpenSSL, we do not allow an empty string to disable previously
205
    // configured checks.
206
0
    return 0;
207
0
  }
208
209
0
  tmp = OPENSSL_memdup(src, srclen);
210
0
  if (!tmp) {
211
0
    return 0;
212
0
  }
213
214
0
  if (*pdest) {
215
0
    OPENSSL_free(*pdest);
216
0
  }
217
0
  *pdest = reinterpret_cast<char *>(tmp);
218
0
  if (pdestlen) {
219
0
    *pdestlen = srclen;
220
0
  }
221
0
  return 1;
222
0
}
223
224
0
int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags) {
225
0
  param->flags |= flags;
226
0
  return 1;
227
0
}
228
229
int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param,
230
0
                                  unsigned long flags) {
231
0
  param->flags &= ~flags;
232
0
  return 1;
233
0
}
234
235
0
unsigned long X509_VERIFY_PARAM_get_flags(const X509_VERIFY_PARAM *param) {
236
0
  return param->flags;
237
0
}
238
239
0
int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose) {
240
0
  if (X509_PURPOSE_get0(purpose) == nullptr) {
241
0
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_PURPOSE);
242
0
    return 0;
243
0
  }
244
0
  param->purpose = purpose;
245
0
  return 1;
246
0
}
247
248
0
int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust) {
249
0
  if (!X509_is_valid_trust_id(trust)) {
250
0
    OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_TRUST_ID);
251
0
    return 0;
252
0
  }
253
254
0
  param->trust = trust;
255
0
  return 1;
256
0
}
257
258
0
void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth) {
259
0
  param->depth = depth;
260
0
}
261
262
0
void X509_VERIFY_PARAM_set_time_posix(X509_VERIFY_PARAM *param, int64_t t) {
263
0
  param->check_time = t;
264
0
  param->flags |= X509_V_FLAG_USE_CHECK_TIME;
265
0
}
266
267
0
void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t) {
268
0
  X509_VERIFY_PARAM_set_time_posix(param, t);
269
0
}
270
271
int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
272
0
                                  ASN1_OBJECT *policy) {
273
0
  if (!param->policies) {
274
0
    param->policies = sk_ASN1_OBJECT_new_null();
275
0
    if (!param->policies) {
276
0
      return 0;
277
0
    }
278
0
  }
279
0
  if (!sk_ASN1_OBJECT_push(param->policies, policy)) {
280
0
    return 0;
281
0
  }
282
0
  return 1;
283
0
}
284
285
int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
286
0
                                    const STACK_OF(ASN1_OBJECT) *policies) {
287
0
  if (!param) {
288
0
    return 0;
289
0
  }
290
291
0
  sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
292
0
  if (!policies) {
293
0
    param->policies = nullptr;
294
0
    return 1;
295
0
  }
296
297
0
  param->policies =
298
0
      sk_ASN1_OBJECT_deep_copy(policies, OBJ_dup, ASN1_OBJECT_free);
299
0
  if (!param->policies) {
300
0
    return 0;
301
0
  }
302
303
0
  return 1;
304
0
}
305
306
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, const char *name,
307
0
                                size_t namelen) {
308
0
  if (!int_x509_param_set_hosts(param, SET_HOST, name, namelen)) {
309
0
    param->poison = 1;
310
0
    return 0;
311
0
  }
312
0
  return 1;
313
0
}
314
315
int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, const char *name,
316
0
                                size_t namelen) {
317
0
  if (!int_x509_param_set_hosts(param, ADD_HOST, name, namelen)) {
318
0
    param->poison = 1;
319
0
    return 0;
320
0
  }
321
0
  return 1;
322
0
}
323
324
void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
325
0
                                     unsigned int flags) {
326
0
  param->hostflags = flags;
327
0
}
328
329
int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, const char *email,
330
0
                                 size_t emaillen) {
331
0
  if (OPENSSL_memchr(email, '\0', emaillen) != nullptr ||
332
0
      !int_x509_param_set1(&param->email, &param->emaillen, email, emaillen)) {
333
0
    param->poison = 1;
334
0
    return 0;
335
0
  }
336
337
0
  return 1;
338
0
}
339
340
int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, const unsigned char *ip,
341
0
                              size_t iplen) {
342
0
  if ((iplen != 4 && iplen != 16) ||
343
0
      !int_x509_param_set1((char **)&param->ip, &param->iplen, (char *)ip,
344
0
                           iplen)) {
345
0
    param->poison = 1;
346
0
    return 0;
347
0
  }
348
349
0
  return 1;
350
0
}
351
352
0
int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc) {
353
0
  unsigned char ipout[16];
354
0
  size_t iplen;
355
356
0
  iplen = (size_t)x509v3_a2i_ipadd(ipout, ipasc);
357
0
  if (iplen == 0) {
358
0
    return 0;
359
0
  }
360
0
  return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen);
361
0
}
362
363
0
int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param) {
364
0
  return param->depth;
365
0
}
366
367
static const X509_VERIFY_PARAM kDefaultParam = {
368
    /*check_time=*/0,
369
    /*flags=*/0,
370
    /*purpose=*/0,
371
    /*trust=*/0,
372
    /*depth=*/100,
373
    /*policies=*/nullptr,
374
    /*hosts=*/nullptr,
375
    /*hostflags=*/0,
376
    /*email=*/nullptr,
377
    /*emaillen=*/0,
378
    /*ip=*/nullptr,
379
    /*iplen=*/0,
380
    /*poison=*/0,
381
};
382
383
static const X509_VERIFY_PARAM kSMIMESignParam = {
384
    /*check_time=*/0,
385
    /*flags=*/0,
386
    /*purpose=*/X509_PURPOSE_SMIME_SIGN,
387
    /*trust=*/X509_TRUST_EMAIL,
388
    /*depth=*/-1,
389
    /*policies=*/nullptr,
390
    /*hosts=*/nullptr,
391
    /*hostflags=*/0,
392
    /*email=*/nullptr,
393
    /*emaillen=*/0,
394
    /*ip=*/nullptr,
395
    /*iplen=*/0,
396
    /*poison=*/0,
397
};
398
399
static const X509_VERIFY_PARAM kSSLClientParam = {
400
    /*check_time=*/0,
401
    /*flags=*/0,
402
    /*purpose=*/X509_PURPOSE_SSL_CLIENT,
403
    /*trust=*/X509_TRUST_SSL_CLIENT,
404
    /*depth=*/-1,
405
    /*policies=*/nullptr,
406
    /*hosts=*/nullptr,
407
    /*hostflags=*/0,
408
    /*email=*/nullptr,
409
    /*emaillen=*/0,
410
    /*ip=*/nullptr,
411
    /*iplen=*/0,
412
    /*poison=*/0,
413
};
414
415
static const X509_VERIFY_PARAM kSSLServerParam = {
416
    /*check_time=*/0,
417
    /*flags=*/0,
418
    /*purpose=*/X509_PURPOSE_SSL_SERVER,
419
    /*trust=*/X509_TRUST_SSL_SERVER,
420
    /*depth=*/-1,
421
    /*policies=*/nullptr,
422
    /*hosts=*/nullptr,
423
    /*hostflags=*/0,
424
    /*email=*/nullptr,
425
    /*emaillen=*/0,
426
    /*ip=*/nullptr,
427
    /*iplen=*/0,
428
    /*poison=*/0,
429
};
430
431
16.0k
const X509_VERIFY_PARAM *bssl::X509_VERIFY_PARAM_lookup(const char *name) {
432
16.0k
  if (strcmp(name, "default") == 0) {
433
8.02k
    return &kDefaultParam;
434
8.02k
  }
435
8.02k
  if (strcmp(name, "pkcs7") == 0) {
436
    // PKCS#7 and S/MIME signing use the same defaults.
437
0
    return &kSMIMESignParam;
438
0
  }
439
8.02k
  if (strcmp(name, "smime_sign") == 0) {
440
0
    return &kSMIMESignParam;
441
0
  }
442
8.02k
  if (strcmp(name, "ssl_client") == 0) {
443
2.21k
    return &kSSLClientParam;
444
2.21k
  }
445
5.81k
  if (strcmp(name, "ssl_server") == 0) {
446
5.81k
    return &kSSLServerParam;
447
5.81k
  }
448
0
  return nullptr;
449
5.81k
}