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