Coverage Report

Created: 2025-06-11 06:41

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