Coverage Report

Created: 2025-11-03 06:30

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