Coverage Report

Created: 2026-04-30 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/x509/x_x509.cc
Line
Count
Source
1
// Copyright 1995-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 <assert.h>
16
#include <limits.h>
17
#include <stdio.h>
18
19
#include <openssl/asn1.h>
20
#include <openssl/asn1t.h>
21
#include <openssl/bytestring.h>
22
#include <openssl/evp.h>
23
#include <openssl/mem.h>
24
#include <openssl/obj.h>
25
#include <openssl/pool.h>
26
#include <openssl/x509.h>
27
28
#include "../asn1/internal.h"
29
#include "../bytestring/internal.h"
30
#include "../evp/internal.h"
31
#include "../internal.h"
32
#include "../mem_internal.h"
33
#include "internal.h"
34
35
36
using namespace bssl;
37
38
static ExDataClass g_ex_data_class;
39
40
static constexpr CBS_ASN1_TAG kVersionTag =
41
    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0;
42
static constexpr CBS_ASN1_TAG kIssuerUIDTag = CBS_ASN1_CONTEXT_SPECIFIC | 1;
43
static constexpr CBS_ASN1_TAG kSubjectUIDTag = CBS_ASN1_CONTEXT_SPECIFIC | 2;
44
static constexpr CBS_ASN1_TAG kExtensionsTag =
45
    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3;
46
47
205k
X509Impl::X509Impl() : RefCounted(CheckSubClass()) {
48
205k
  asn1_string_init(&serialNumber, V_ASN1_INTEGER);
49
205k
  x509_algor_init(&tbs_sig_alg);
50
205k
  x509_name_init(&issuer);
51
205k
  asn1_string_init(&notBefore, -1);
52
205k
  asn1_string_init(&notAfter, -1);
53
205k
  x509_name_init(&subject);
54
205k
  x509_pubkey_init(&key);
55
205k
  x509_algor_init(&sig_alg);
56
205k
  asn1_string_init(&signature, V_ASN1_BIT_STRING);
57
205k
  CRYPTO_new_ex_data(&ex_data);
58
205k
}
59
60
205k
X509 *X509_new() { return New<X509Impl>(); }
61
62
205k
X509Impl::~X509Impl() {
63
205k
  CRYPTO_free_ex_data(&g_ex_data_class, &ex_data);
64
65
205k
  asn1_string_cleanup(&serialNumber);
66
205k
  x509_algor_cleanup(&tbs_sig_alg);
67
205k
  x509_name_cleanup(&issuer);
68
205k
  asn1_string_cleanup(&notBefore);
69
205k
  asn1_string_cleanup(&notAfter);
70
205k
  x509_name_cleanup(&subject);
71
205k
  x509_pubkey_cleanup(&key);
72
205k
  ASN1_BIT_STRING_free(issuerUID);
73
205k
  ASN1_BIT_STRING_free(subjectUID);
74
205k
  sk_X509_EXTENSION_pop_free(extensions, X509_EXTENSION_free);
75
205k
  x509_algor_cleanup(&sig_alg);
76
205k
  asn1_string_cleanup(&signature);
77
205k
  CRYPTO_BUFFER_free(buf);
78
205k
  ASN1_OCTET_STRING_free(skid);
79
205k
  AUTHORITY_KEYID_free(akid);
80
205k
  CRL_DIST_POINTS_free(crldp);
81
205k
  GENERAL_NAMES_free(altname);
82
205k
  NAME_CONSTRAINTS_free(nc);
83
205k
  X509_CERT_AUX_free(aux);
84
205k
}
85
86
873k
void X509_free(X509 *x509) {
87
873k
  if (x509 == nullptr) {
88
477k
    return;
89
477k
  }
90
395k
  auto *impl = FromOpaque(x509);
91
395k
  impl->DecRefInternal();
92
395k
}
93
94
X509 *X509_parse_with_algorithms(CRYPTO_BUFFER *buf,
95
                                 const EVP_PKEY_ALG *const *algs,
96
184k
                                 size_t num_algs) {
97
184k
  UniquePtr<X509Impl> ret(FromOpaque(X509_new()));
98
184k
  if (ret == nullptr) {
99
0
    return nullptr;
100
0
  }
101
102
  // Save the buffer to cache the original encoding.
103
184k
  ret->buf = UpRef(buf).release();
104
105
  // Parse the Certificate.
106
184k
  CBS cbs, cert, tbs;
107
184k
  CRYPTO_BUFFER_init_CBS(buf, &cbs);
108
184k
  if (!CBS_get_asn1(&cbs, &cert, CBS_ASN1_SEQUENCE) ||  //
109
184k
      CBS_len(&cbs) != 0 ||
110
      // Bound the length to comfortably fit in an int. Lengths in this
111
      // module often omit overflow checks.
112
184k
      CBS_len(&cert) > INT_MAX / 2 ||
113
184k
      !CBS_get_asn1(&cert, &tbs, CBS_ASN1_SEQUENCE) ||
114
183k
      !x509_parse_algorithm(&cert, &ret->sig_alg) ||
115
      // For just the signature field, we accept non-minimal BER lengths, though
116
      // not indefinite-length encoding. See b/18228011.
117
      //
118
      // TODO(crbug.com/boringssl/354): Switch the affected callers to convert
119
      // the certificate before parsing and then remove this workaround.
120
179k
      !asn1_parse_bit_string_with_bad_length(&cert, &ret->signature) ||
121
178k
      CBS_len(&cert) != 0) {
122
5.90k
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
123
5.90k
    return nullptr;
124
5.90k
  }
125
126
  // Parse the TBSCertificate.
127
178k
  if (CBS_peek_asn1_tag(&tbs, kVersionTag)) {
128
173k
    CBS wrapper;
129
173k
    uint64_t version;
130
173k
    if (!CBS_get_asn1(&tbs, &wrapper, kVersionTag) ||
131
173k
        !CBS_get_asn1_uint64(&wrapper, &version) ||  //
132
173k
        CBS_len(&wrapper) != 0) {
133
297
      OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
134
297
      return nullptr;
135
297
    }
136
    // The version must be one of v1(0), v2(1), or v3(2).
137
    // TODO(https://crbug.com/42290225): Also reject |X509_VERSION_1|. v1 is
138
    // DEFAULT, so DER requires it be omitted.
139
173k
    if (version != X509_VERSION_1 && version != X509_VERSION_2 &&
140
168k
        version != X509_VERSION_3) {
141
620
      OPENSSL_PUT_ERROR(X509, X509_R_INVALID_VERSION);
142
620
      return nullptr;
143
620
    }
144
173k
    ret->version = static_cast<uint8_t>(version);
145
173k
  } else {
146
4.41k
    ret->version = X509_VERSION_1;
147
4.41k
  }
148
177k
  CBS validity;
149
177k
  if (!asn1_parse_integer(&tbs, &ret->serialNumber, /*tag=*/0) ||
150
176k
      !x509_parse_algorithm(&tbs, &ret->tbs_sig_alg) ||
151
176k
      !x509_parse_name(&tbs, &ret->issuer) ||
152
176k
      !CBS_get_asn1(&tbs, &validity, CBS_ASN1_SEQUENCE) ||
153
174k
      !asn1_parse_time(&validity, &ret->notBefore,
154
174k
                       /*allow_utc_timezone_offset=*/1) ||
155
174k
      !asn1_parse_time(&validity, &ret->notAfter,
156
174k
                       /*allow_utc_timezone_offset=*/1) ||
157
174k
      CBS_len(&validity) != 0 ||  //
158
174k
      !x509_parse_name(&tbs, &ret->subject) ||
159
173k
      !x509_parse_public_key(&tbs, &ret->key, Span(algs, num_algs))) {
160
4.13k
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
161
4.13k
    return nullptr;
162
4.13k
  }
163
  // Per RFC 5280, section 4.1.2.8, these fields require v2 or v3:
164
173k
  if (ret->version >= X509_VERSION_2 &&
165
171k
      CBS_peek_asn1_tag(&tbs, kIssuerUIDTag)) {
166
5.13k
    ret->issuerUID = ASN1_BIT_STRING_new();
167
5.13k
    if (ret->issuerUID == nullptr ||
168
5.13k
        !asn1_parse_bit_string(&tbs, ret->issuerUID, kIssuerUIDTag)) {
169
44
      return nullptr;
170
44
    }
171
5.13k
  }
172
173k
  if (ret->version >= X509_VERSION_2 &&
173
171k
      CBS_peek_asn1_tag(&tbs, kSubjectUIDTag)) {
174
326
    ret->subjectUID = ASN1_BIT_STRING_new();
175
326
    if (ret->subjectUID == nullptr ||
176
326
        !asn1_parse_bit_string(&tbs, ret->subjectUID, kSubjectUIDTag)) {
177
61
      return nullptr;
178
61
    }
179
326
  }
180
  // Per RFC 5280, section 4.1.2.9, extensions require v3:
181
173k
  if (ret->version >= X509_VERSION_3 &&
182
166k
      CBS_peek_asn1_tag(&tbs, kExtensionsTag)) {
183
164k
    CBS wrapper;
184
164k
    if (!CBS_get_asn1(&tbs, &wrapper, kExtensionsTag)) {
185
41
      OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
186
41
      return nullptr;
187
41
    }
188
    // TODO(crbug.com/442221114, crbug.com/42290219): Empty extension lists
189
    // should be rejected. Extensions is a SEQUENCE SIZE (1..MAX), so it cannot
190
    // be empty. An empty extensions list is encoded by omitting the OPTIONAL
191
    // field. libpki already rejects this.
192
164k
    const uint8_t *p = CBS_data(&wrapper);
193
164k
    ret->extensions = d2i_X509_EXTENSIONS(nullptr, &p, CBS_len(&wrapper));
194
164k
    if (ret->extensions == nullptr ||
195
162k
        p != CBS_data(&wrapper) + CBS_len(&wrapper)) {
196
1.86k
      OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
197
1.86k
      return nullptr;
198
1.86k
    }
199
164k
  }
200
171k
  if (CBS_len(&tbs) != 0) {
201
1.06k
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
202
1.06k
    return nullptr;
203
1.06k
  }
204
205
170k
  return ret.release();
206
171k
}
207
208
184k
X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf) {
209
184k
  auto algs = GetDefaultEVPAlgorithms();
210
184k
  return X509_parse_with_algorithms(buf, algs.data(), algs.size());
211
184k
}
212
213
12.2k
static UniquePtr<X509> x509_parse(CBS *cbs) {
214
12.2k
  CBS cert;
215
12.2k
  if (!CBS_get_asn1_element(cbs, &cert, CBS_ASN1_SEQUENCE)) {
216
1.23k
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
217
1.23k
    return nullptr;
218
1.23k
  }
219
220
11.0k
  UniquePtr<CRYPTO_BUFFER> buf(CRYPTO_BUFFER_new_from_CBS(&cert, nullptr));
221
11.0k
  if (buf == nullptr) {
222
0
    return nullptr;
223
0
  }
224
11.0k
  return UniquePtr<X509>(X509_parse_from_buffer(buf.get()));
225
11.0k
}
226
227
43.2k
int bssl::x509_marshal_tbs_cert(CBB *cbb, const X509 *x509) {
228
43.2k
  auto *impl = FromOpaque(x509);
229
43.2k
  if (impl->buf != nullptr) {
230
    // Replay the saved TBSCertificate from the |CRYPTO_BUFFER|, to verify
231
    // exactly what we parsed. The |CRYPTO_BUFFER| contains the full
232
    // Certificate, so we need to find the TBSCertificate portion.
233
40.0k
    CBS cbs, cert, tbs;
234
40.0k
    CRYPTO_BUFFER_init_CBS(impl->buf, &cbs);
235
40.0k
    if (!CBS_get_asn1(&cbs, &cert, CBS_ASN1_SEQUENCE) ||
236
40.0k
        !CBS_get_asn1_element(&cert, &tbs, CBS_ASN1_SEQUENCE)) {
237
      // This should be impossible.
238
0
      OPENSSL_PUT_ERROR(X509, ERR_R_INTERNAL_ERROR);
239
0
      return 0;
240
0
    }
241
40.0k
    return CBB_add_bytes(cbb, CBS_data(&tbs), CBS_len(&tbs));
242
40.0k
  }
243
244
  // No saved TBSCertificate encoding. Encode it anew.
245
3.19k
  CBB tbs, version, validity, extensions;
246
3.19k
  if (!CBB_add_asn1(cbb, &tbs, CBS_ASN1_SEQUENCE)) {
247
0
    return 0;
248
0
  }
249
3.19k
  if (impl->version != X509_VERSION_1) {
250
3.16k
    if (!CBB_add_asn1(&tbs, &version, kVersionTag) ||
251
3.16k
        !CBB_add_asn1_uint64(&version, impl->version)) {
252
0
      return 0;
253
0
    }
254
3.16k
  }
255
3.19k
  if (!asn1_marshal_integer(&tbs, &impl->serialNumber, /*tag=*/0) ||
256
3.19k
      !x509_marshal_algorithm(&tbs, &impl->tbs_sig_alg) ||
257
3.19k
      !x509_marshal_name(&tbs, &impl->issuer) ||
258
3.19k
      !CBB_add_asn1(&tbs, &validity, CBS_ASN1_SEQUENCE) ||
259
3.19k
      !asn1_marshal_time(&validity, &impl->notBefore) ||
260
3.19k
      !asn1_marshal_time(&validity, &impl->notAfter) ||
261
3.19k
      !x509_marshal_name(&tbs, &impl->subject) ||
262
3.19k
      !x509_marshal_public_key(&tbs, &impl->key) ||
263
3.19k
      (impl->issuerUID != nullptr &&
264
142
       !asn1_marshal_bit_string(&tbs, impl->issuerUID, kIssuerUIDTag)) ||
265
3.19k
      (impl->subjectUID != nullptr &&
266
56
       !asn1_marshal_bit_string(&tbs, impl->subjectUID, kSubjectUIDTag))) {
267
0
    return 0;
268
0
  }
269
3.19k
  if (impl->extensions != nullptr) {
270
2.84k
    int len = i2d_X509_EXTENSIONS(impl->extensions, nullptr);
271
2.84k
    uint8_t *out;
272
2.84k
    if (len <= 0 ||  //
273
2.84k
        !CBB_add_asn1(&tbs, &extensions, kExtensionsTag) ||
274
2.84k
        !CBB_add_space(&extensions, &out, len) ||
275
2.84k
        i2d_X509_EXTENSIONS(impl->extensions, &out) != len) {
276
0
      return 0;
277
0
    }
278
2.84k
  }
279
3.19k
  return CBB_flush(cbb);
280
3.19k
}
281
282
40.0k
static int x509_marshal(CBB *cbb, const X509 *x509) {
283
40.0k
  CBB cert;
284
40.0k
  auto *impl = FromOpaque(x509);
285
40.0k
  return CBB_add_asn1(cbb, &cert, CBS_ASN1_SEQUENCE) &&
286
40.0k
         x509_marshal_tbs_cert(&cert, x509) &&
287
40.0k
         x509_marshal_algorithm(&cert, &impl->sig_alg) &&
288
40.0k
         asn1_marshal_bit_string(&cert, &impl->signature, /*tag=*/0) &&
289
40.0k
         CBB_flush(cbb);
290
40.0k
}
291
292
12.2k
X509 *d2i_X509(X509 **out, const uint8_t **inp, long len) {
293
12.2k
  return D2IFromCBS(out, inp, len, x509_parse);
294
12.2k
}
295
296
40.0k
int i2d_X509(const X509 *x509, uint8_t **outp) {
297
40.0k
  if (x509 == nullptr) {
298
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE);
299
0
    return -1;
300
0
  }
301
302
40.0k
  return I2DFromCBB(
303
40.0k
      /*initial_capacity=*/256, outp,
304
40.0k
      [&](CBB *cbb) -> bool { return x509_marshal(cbb, x509); });
305
40.0k
}
306
307
0
static int x509_new_cb(ASN1_VALUE **pval, const ASN1_ITEM *it) {
308
0
  *pval = (ASN1_VALUE *)X509_new();
309
0
  return *pval != nullptr;
310
0
}
311
312
0
static void x509_free_cb(ASN1_VALUE **pval, const ASN1_ITEM *it) {
313
0
  X509_free((X509 *)*pval);
314
0
  *pval = nullptr;
315
0
}
316
317
static int x509_parse_cb(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it,
318
0
                         int opt) {
319
0
  if (opt && !CBS_peek_asn1_tag(cbs, CBS_ASN1_SEQUENCE)) {
320
0
    return 1;
321
0
  }
322
323
0
  UniquePtr<X509> ret = x509_parse(cbs);
324
0
  if (ret == nullptr) {
325
0
    return 0;
326
0
  }
327
328
0
  X509_free((X509 *)*pval);
329
0
  *pval = (ASN1_VALUE *)ret.release();
330
0
  return 1;
331
0
}
332
333
static int x509_i2d_cb(ASN1_VALUE **pval, unsigned char **out,
334
0
                       const ASN1_ITEM *it) {
335
0
  return i2d_X509((X509 *)*pval, out);
336
0
}
337
338
static const ASN1_EXTERN_FUNCS x509_extern_funcs = {x509_new_cb, x509_free_cb,
339
                                                    x509_parse_cb, x509_i2d_cb};
340
IMPLEMENT_EXTERN_ASN1(X509, x509_extern_funcs)
341
342
0
X509 *X509_dup(const X509 *x509) {
343
0
  uint8_t *der = nullptr;
344
0
  int len = i2d_X509(x509, &der);
345
0
  if (len < 0) {
346
0
    return nullptr;
347
0
  }
348
349
0
  const uint8_t *inp = der;
350
0
  X509 *ret = d2i_X509(nullptr, &inp, len);
351
0
  OPENSSL_free(der);
352
0
  return ret;
353
0
}
354
355
203k
int X509_up_ref(X509 *x) {
356
203k
  auto *impl = FromOpaque(x);
357
203k
  impl->UpRefInternal();
358
203k
  return 1;
359
203k
}
360
361
int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
362
                          CRYPTO_EX_dup *dup_unused,
363
0
                          CRYPTO_EX_free *free_func) {
364
0
  return CRYPTO_get_ex_new_index_ex(&g_ex_data_class, argl, argp, free_func);
365
0
}
366
367
0
int X509_set_ex_data(X509 *r, int idx, void *arg) {
368
0
  auto *impl = FromOpaque(r);
369
0
  return (CRYPTO_set_ex_data(&impl->ex_data, idx, arg));
370
0
}
371
372
0
void *X509_get_ex_data(X509 *r, int idx) {
373
0
  auto *impl = FromOpaque(r);
374
0
  return (CRYPTO_get_ex_data(&impl->ex_data, idx));
375
0
}
376
377
// X509_AUX ASN1 routines. X509_AUX is the name given to a certificate with
378
// extra info tagged on the end. Since these functions set how a certificate
379
// is trusted they should only be used when the certificate comes from a
380
// reliable source such as local storage.
381
382
0
X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length) {
383
0
  const unsigned char *q = *pp;
384
0
  X509 *ret;
385
0
  int freeret = 0;
386
387
0
  if (!a || *a == nullptr) {
388
0
    freeret = 1;
389
0
  }
390
0
  ret = d2i_X509(a, &q, length);
391
  // If certificate unreadable then forget it
392
0
  if (!ret) {
393
0
    return nullptr;
394
0
  }
395
0
  auto *impl = FromOpaque(ret);
396
  // update length
397
0
  length -= q - *pp;
398
  // Parse auxiliary information if there is any.
399
0
  if (length > 0 && !d2i_X509_CERT_AUX(&impl->aux, &q, length)) {
400
0
    goto err;
401
0
  }
402
0
  *pp = q;
403
0
  return ret;
404
0
err:
405
0
  if (freeret) {
406
0
    X509_free(ret);
407
0
    if (a) {
408
0
      *a = nullptr;
409
0
    }
410
0
  }
411
0
  return nullptr;
412
0
}
413
414
// Serialize trusted certificate to *pp or just return the required buffer
415
// length if pp == NULL.  We ultimately want to avoid modifying *pp in the
416
// error path, but that depends on similar hygiene in lower-level functions.
417
// Here we avoid compounding the problem.
418
0
static int i2d_x509_aux_internal(const X509 *a, unsigned char **pp) {
419
0
  int length, tmplen;
420
0
  unsigned char *start = pp != nullptr ? *pp : nullptr;
421
422
0
  assert(pp == nullptr || *pp != nullptr);
423
424
  // This might perturb *pp on error, but fixing that belongs in i2d_X509()
425
  // not here.  It should be that if a == NULL length is zero, but we check
426
  // both just in case.
427
0
  length = i2d_X509(a, pp);
428
0
  if (length <= 0 || a == nullptr) {
429
0
    return length;
430
0
  }
431
432
0
  auto *impl = FromOpaque(a);
433
0
  if (impl->aux != nullptr) {
434
0
    tmplen = i2d_X509_CERT_AUX(impl->aux, pp);
435
0
    if (tmplen < 0) {
436
0
      if (start != nullptr) {
437
0
        *pp = start;
438
0
      }
439
0
      return tmplen;
440
0
    }
441
0
    length += tmplen;
442
0
  }
443
444
0
  return length;
445
0
}
446
447
// Serialize trusted certificate to *pp, or just return the required buffer
448
// length if pp == NULL.
449
//
450
// When pp is not NULL, but *pp == NULL, we allocate the buffer, but since
451
// we're writing two ASN.1 objects back to back, we can't have i2d_X509() do
452
// the allocation, nor can we allow i2d_X509_CERT_AUX() to increment the
453
// allocated buffer.
454
0
int i2d_X509_AUX(const X509 *a, unsigned char **pp) {
455
0
  int length;
456
0
  unsigned char *tmp;
457
458
  // Buffer provided by caller
459
0
  if (pp == nullptr || *pp != nullptr) {
460
0
    return i2d_x509_aux_internal(a, pp);
461
0
  }
462
463
  // Obtain the combined length
464
0
  if ((length = i2d_x509_aux_internal(a, nullptr)) <= 0) {
465
0
    return length;
466
0
  }
467
468
  // Allocate requisite combined storage
469
0
  *pp = tmp = reinterpret_cast<uint8_t *>(OPENSSL_malloc(length));
470
0
  if (tmp == nullptr) {
471
0
    return -1;  // Push error onto error stack?
472
0
  }
473
474
  // Encode, but keep *pp at the originally malloced pointer
475
0
  length = i2d_x509_aux_internal(a, &tmp);
476
0
  if (length <= 0) {
477
0
    OPENSSL_free(*pp);
478
0
    *pp = nullptr;
479
0
  }
480
0
  return length;
481
0
}
482
483
3.19k
int i2d_re_X509_tbs(X509 *x509, uint8_t **outp) {
484
3.19k
  auto *impl = FromOpaque(x509);
485
3.19k
  CRYPTO_BUFFER_free(impl->buf);
486
3.19k
  impl->buf = nullptr;
487
3.19k
  return i2d_X509_tbs(x509, outp);
488
3.19k
}
489
490
3.19k
int i2d_X509_tbs(const X509 *x509, uint8_t **outp) {
491
3.19k
  return I2DFromCBB(/*initial_capacity=*/128, outp, [&](CBB *cbb) -> bool {
492
3.19k
    return x509_marshal_tbs_cert(cbb, x509);
493
3.19k
  });
494
3.19k
}
495
496
0
int X509_set1_signature_algo(X509 *x509, const X509_ALGOR *algo) {
497
0
  auto *impl = FromOpaque(x509);
498
0
  return X509_ALGOR_copy(&impl->sig_alg, algo) &&
499
0
         X509_ALGOR_copy(&impl->tbs_sig_alg, algo);
500
0
}
501
502
0
int X509_set1_signature_value(X509 *x509, const uint8_t *sig, size_t sig_len) {
503
0
  return ASN1_STRING_set(&FromOpaque(x509)->signature, sig, sig_len);
504
0
}
505
506
void X509_get0_signature(const ASN1_BIT_STRING **psig, const X509_ALGOR **palg,
507
0
                         const X509 *x) {
508
0
  const auto *impl = FromOpaque(x);
509
0
  if (psig) {
510
0
    *psig = &impl->signature;
511
0
  }
512
0
  if (palg) {
513
0
    *palg = &impl->sig_alg;
514
0
  }
515
0
}
516
517
0
int X509_get_signature_nid(const X509 *x) {
518
0
  const auto *impl = FromOpaque(x);
519
0
  return OBJ_obj2nid(impl->sig_alg.algorithm);
520
0
}