Coverage Report

Created: 2026-02-14 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/bytestring/internal.h
Line
Count
Source
1
// Copyright 2014 The BoringSSL Authors
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
#ifndef OPENSSL_HEADER_CRYPTO_BYTESTRING_INTERNAL_H
16
#define OPENSSL_HEADER_CRYPTO_BYTESTRING_INTERNAL_H
17
18
#include <openssl/asn1.h>
19
#include <openssl/bytestring.h>
20
#include <openssl/err.h>
21
22
#include <type_traits>
23
24
#include "../mem_internal.h"
25
26
27
BSSL_NAMESPACE_BEGIN
28
29
// CBS_asn1_ber_to_der reads a BER element from |in|. If it finds
30
// indefinite-length elements or constructed strings then it converts the BER
31
// data to DER, sets |out| to the converted contents and |*out_storage| to a
32
// buffer which the caller must release with |OPENSSL_free|. Otherwise, it sets
33
// |out| to the original BER element in |in| and |*out_storage| to NULL.
34
// Additionally, |*in| will be advanced over the BER element.
35
//
36
// This function should successfully process any valid BER input, however it
37
// will not convert all of BER's deviations from DER. BER is ambiguous between
38
// implicitly-tagged SEQUENCEs of strings and implicitly-tagged constructed
39
// strings. Implicitly-tagged strings must be parsed with
40
// |CBS_get_ber_implicitly_tagged_string| instead of |CBS_get_asn1|. The caller
41
// must also account for BER variations in the contents of a primitive.
42
//
43
// It returns one on success and zero otherwise.
44
OPENSSL_EXPORT int CBS_asn1_ber_to_der(CBS *in, CBS *out,
45
                                       uint8_t **out_storage);
46
47
// CBS_get_asn1_implicit_string parses a BER string of primitive type
48
// |inner_tag| implicitly-tagged with |outer_tag|. It sets |out| to the
49
// contents. If concatenation was needed, it sets |*out_storage| to a buffer
50
// which the caller must release with |OPENSSL_free|. Otherwise, it sets
51
// |*out_storage| to NULL.
52
//
53
// This function does not parse all of BER. It requires the string be
54
// definite-length. Constructed strings are allowed, but all children of the
55
// outermost element must be primitive. The caller should use
56
// |CBS_asn1_ber_to_der| before running this function.
57
//
58
// It returns one on success and zero otherwise.
59
OPENSSL_EXPORT int CBS_get_asn1_implicit_string(CBS *in, CBS *out,
60
                                                uint8_t **out_storage,
61
                                                CBS_ASN1_TAG outer_tag,
62
                                                CBS_ASN1_TAG inner_tag);
63
64
// CBB_finish_i2d calls |CBB_finish| on |cbb| which must have been initialized
65
// with |CBB_init|. If |outp| is not NULL then the result is written to |*outp|
66
// and |*outp| is advanced just past the output. It returns the number of bytes
67
// in the result, whether written or not, or a negative value on error. On
68
// error, it calls |CBB_cleanup| on |cbb|.
69
//
70
// This function may be used to help implement legacy i2d ASN.1 functions.
71
int CBB_finish_i2d(CBB *cbb, uint8_t **outp);
72
73
// CBBAsSpan returns a span containing |cbb|'s contents. It does not flush
74
// |cbb|. The span is valid until the next operation to |cbb|.
75
//
76
// To avoid unfinalized length prefixes, it is a fatal error to call this on a
77
// CBB with any active children.
78
3.05k
inline Span<uint8_t> CBBAsSpan(const CBB *cbb) {
79
3.05k
  return Span(CBB_data(cbb), CBB_len(cbb));
80
3.05k
}
81
82
// CBBFinishArray behaves like |CBB_finish| but stores the result in an Array.
83
OPENSSL_EXPORT bool CBBFinishArray(CBB *cbb, Array<uint8_t> *out);
84
85
// D2IFromCBS takes a functor of type |Unique<T>(CBS*)| and implements the d2i
86
// calling convention. For compatibility with functions that don't tag their
87
// return value (e.g. public APIs), |T*(CBS)| is also accepted. The callback can
88
// assume that the |CBS|'s length fits in |long|. The callback should not access
89
// |out|, |inp|, or |len| directly.
90
template <typename T, typename CBSFunc>
91
17.3k
inline T *D2IFromCBS(T **out, const uint8_t **inp, long len, CBSFunc func) {
92
17.3k
  static_assert(std::is_invocable_v<CBSFunc, CBS *>);
93
17.3k
  static_assert(
94
17.3k
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, UniquePtr<T>> ||
95
17.3k
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, T *>);
96
17.3k
  if (len < 0) {
97
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL);
98
0
    return nullptr;
99
0
  }
100
17.3k
  CBS cbs;
101
17.3k
  CBS_init(&cbs, *inp, len);
102
17.3k
  UniquePtr<T> ret(func(&cbs));
103
17.3k
  if (ret == nullptr) {
104
11.7k
    return nullptr;
105
11.7k
  }
106
5.59k
  if (out != nullptr) {
107
0
    UniquePtr<T> free_out(*out);
108
0
    *out = ret.get();
109
0
  }
110
5.59k
  *inp = CBS_data(&cbs);
111
5.59k
  return ret.release();
112
17.3k
}
Unexecuted instantiation: ssl_x509.cc:ssl_session_st* bssl::D2IFromCBS<ssl_session_st, d2i_SSL_SESSION::$_0>(ssl_session_st**, unsigned char const**, long, d2i_SSL_SESSION::$_0)
Unexecuted instantiation: ec_asn1.cc:ec_key_st* bssl::D2IFromCBS<ec_key_st, d2i_ECPrivateKey::$_0>(ec_key_st**, unsigned char const**, long, d2i_ECPrivateKey::$_0)
Unexecuted instantiation: ec_group_st* bssl::D2IFromCBS<ec_group_st, ec_group_st* (*)(cbs_st*)>(ec_group_st**, unsigned char const**, long, ec_group_st* (*)(cbs_st*))
Unexecuted instantiation: ec_asn1.cc:ec_key_st* bssl::D2IFromCBS<ec_key_st, d2i_ECParameters::$_0>(ec_key_st**, unsigned char const**, long, d2i_ECParameters::$_0)
Unexecuted instantiation: ecdsa_sig_st* bssl::D2IFromCBS<ecdsa_sig_st, ecdsa_sig_st* (*)(cbs_st*)>(ecdsa_sig_st**, unsigned char const**, long, ecdsa_sig_st* (*)(cbs_st*))
evp_asn1.cc:evp_pkey_st* bssl::D2IFromCBS<evp_pkey_st, d2i_PrivateKey::$_0>(evp_pkey_st**, unsigned char const**, long, d2i_PrivateKey::$_0)
Line
Count
Source
91
4.49k
inline T *D2IFromCBS(T **out, const uint8_t **inp, long len, CBSFunc func) {
92
4.49k
  static_assert(std::is_invocable_v<CBSFunc, CBS *>);
93
4.49k
  static_assert(
94
4.49k
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, UniquePtr<T>> ||
95
4.49k
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, T *>);
96
4.49k
  if (len < 0) {
97
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL);
98
0
    return nullptr;
99
0
  }
100
4.49k
  CBS cbs;
101
4.49k
  CBS_init(&cbs, *inp, len);
102
4.49k
  UniquePtr<T> ret(func(&cbs));
103
4.49k
  if (ret == nullptr) {
104
4.48k
    return nullptr;
105
4.48k
  }
106
5
  if (out != nullptr) {
107
0
    UniquePtr<T> free_out(*out);
108
0
    *out = ret.get();
109
0
  }
110
5
  *inp = CBS_data(&cbs);
111
5
  return ret.release();
112
4.49k
}
Unexecuted instantiation: evp_asn1.cc:evp_pkey_st* bssl::D2IFromCBS<evp_pkey_st, d2i_PublicKey::$_0>(evp_pkey_st**, unsigned char const**, long, d2i_PublicKey::$_0)
Unexecuted instantiation: evp_pkey_st* bssl::D2IFromCBS<evp_pkey_st, evp_pkey_st* (*)(cbs_st*)>(evp_pkey_st**, unsigned char const**, long, evp_pkey_st* (*)(cbs_st*))
Unexecuted instantiation: evp_asn1.cc:rsa_st* bssl::D2IFromCBS<rsa_st, d2i_RSA_PUBKEY::$_0>(rsa_st**, unsigned char const**, long, d2i_RSA_PUBKEY::$_0)
Unexecuted instantiation: evp_asn1.cc:dsa_st* bssl::D2IFromCBS<dsa_st, d2i_DSA_PUBKEY::$_0>(dsa_st**, unsigned char const**, long, d2i_DSA_PUBKEY::$_0)
Unexecuted instantiation: evp_asn1.cc:ec_key_st* bssl::D2IFromCBS<ec_key_st, d2i_EC_PUBKEY::$_0>(ec_key_st**, unsigned char const**, long, d2i_EC_PUBKEY::$_0)
rsa_st* bssl::D2IFromCBS<rsa_st, rsa_st* (*)(cbs_st*)>(rsa_st**, unsigned char const**, long, rsa_st* (*)(cbs_st*))
Line
Count
Source
91
2
inline T *D2IFromCBS(T **out, const uint8_t **inp, long len, CBSFunc func) {
92
2
  static_assert(std::is_invocable_v<CBSFunc, CBS *>);
93
2
  static_assert(
94
2
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, UniquePtr<T>> ||
95
2
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, T *>);
96
2
  if (len < 0) {
97
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL);
98
0
    return nullptr;
99
0
  }
100
2
  CBS cbs;
101
2
  CBS_init(&cbs, *inp, len);
102
2
  UniquePtr<T> ret(func(&cbs));
103
2
  if (ret == nullptr) {
104
0
    return nullptr;
105
0
  }
106
2
  if (out != nullptr) {
107
0
    UniquePtr<T> free_out(*out);
108
0
    *out = ret.get();
109
0
  }
110
2
  *inp = CBS_data(&cbs);
111
2
  return ret.release();
112
2
}
Unexecuted instantiation: x_algor.cc:X509_algor_st* bssl::D2IFromCBS<X509_algor_st, d2i_X509_ALGOR::$_0>(X509_algor_st**, unsigned char const**, long, d2i_X509_ALGOR::$_0)
x_name.cc:X509_name_st* bssl::D2IFromCBS<X509_name_st, d2i_X509_NAME::$_0>(X509_name_st**, unsigned char const**, long, d2i_X509_NAME::$_0)
Line
Count
Source
91
1.14k
inline T *D2IFromCBS(T **out, const uint8_t **inp, long len, CBSFunc func) {
92
1.14k
  static_assert(std::is_invocable_v<CBSFunc, CBS *>);
93
1.14k
  static_assert(
94
1.14k
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, UniquePtr<T>> ||
95
1.14k
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, T *>);
96
1.14k
  if (len < 0) {
97
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL);
98
0
    return nullptr;
99
0
  }
100
1.14k
  CBS cbs;
101
1.14k
  CBS_init(&cbs, *inp, len);
102
1.14k
  UniquePtr<T> ret(func(&cbs));
103
1.14k
  if (ret == nullptr) {
104
443
    return nullptr;
105
443
  }
106
706
  if (out != nullptr) {
107
0
    UniquePtr<T> free_out(*out);
108
0
    *out = ret.get();
109
0
  }
110
706
  *inp = CBS_data(&cbs);
111
706
  return ret.release();
112
1.14k
}
Unexecuted instantiation: x_pubkey.cc:X509_pubkey_st* bssl::D2IFromCBS<X509_pubkey_st, d2i_X509_PUBKEY::$_0>(X509_pubkey_st**, unsigned char const**, long, d2i_X509_PUBKEY::$_0)
x509_st* bssl::D2IFromCBS<x509_st, std::__1::unique_ptr<x509_st, bssl::internal::Deleter> (*)(cbs_st*)>(x509_st**, unsigned char const**, long, std::__1::unique_ptr<x509_st, bssl::internal::Deleter> (*)(cbs_st*))
Line
Count
Source
91
11.6k
inline T *D2IFromCBS(T **out, const uint8_t **inp, long len, CBSFunc func) {
92
11.6k
  static_assert(std::is_invocable_v<CBSFunc, CBS *>);
93
11.6k
  static_assert(
94
11.6k
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, UniquePtr<T>> ||
95
11.6k
      std::is_same_v<std::invoke_result_t<CBSFunc, CBS *>, T *>);
96
11.6k
  if (len < 0) {
97
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL);
98
0
    return nullptr;
99
0
  }
100
11.6k
  CBS cbs;
101
11.6k
  CBS_init(&cbs, *inp, len);
102
11.6k
  UniquePtr<T> ret(func(&cbs));
103
11.6k
  if (ret == nullptr) {
104
6.79k
    return nullptr;
105
6.79k
  }
106
4.87k
  if (out != nullptr) {
107
0
    UniquePtr<T> free_out(*out);
108
0
    *out = ret.get();
109
0
  }
110
4.87k
  *inp = CBS_data(&cbs);
111
4.87k
  return ret.release();
112
11.6k
}
Unexecuted instantiation: a_object.cc:asn1_object_st* bssl::D2IFromCBS<asn1_object_st, d2i_ASN1_OBJECT::$_0>(asn1_object_st**, unsigned char const**, long, d2i_ASN1_OBJECT::$_0)
Unexecuted instantiation: a_object.cc:asn1_object_st* bssl::D2IFromCBS<asn1_object_st, c2i_ASN1_OBJECT::$_0>(asn1_object_st**, unsigned char const**, long, c2i_ASN1_OBJECT::$_0)
Unexecuted instantiation: dh_st* bssl::D2IFromCBS<dh_st, dh_st* (*)(cbs_st*)>(dh_st**, unsigned char const**, long, dh_st* (*)(cbs_st*))
Unexecuted instantiation: DSA_SIG_st* bssl::D2IFromCBS<DSA_SIG_st, DSA_SIG_st* (*)(cbs_st*)>(DSA_SIG_st**, unsigned char const**, long, DSA_SIG_st* (*)(cbs_st*))
Unexecuted instantiation: dsa_st* bssl::D2IFromCBS<dsa_st, dsa_st* (*)(cbs_st*)>(dsa_st**, unsigned char const**, long, dsa_st* (*)(cbs_st*))
113
114
// I2DFromCBB takes a functor of type |bool(CBB*)| and implements the i2d
115
// calling convention. It internally makes a |CBB| with the specified initial
116
// capacity. The callback should not access |outp| directly.
117
template <typename CBBFunc>
118
52.7k
inline int I2DFromCBB(size_t initial_capacity, uint8_t **outp, CBBFunc func) {
119
52.7k
  static_assert(std::is_invocable_v<CBBFunc, CBB *>);
120
52.7k
  static_assert(std::is_same_v<std::invoke_result_t<CBBFunc, CBB *>, bool>);
121
52.7k
  ScopedCBB cbb;
122
52.7k
  if (!CBB_init(cbb.get(), initial_capacity) || !func(cbb.get())) {
123
0
    return -1;
124
0
  }
125
52.7k
  return CBB_finish_i2d(cbb.get(), outp);
126
52.7k
}
Unexecuted instantiation: ec_asn1.cc:int bssl::I2DFromCBB<i2d_ECPrivateKey::$_0>(unsigned long, unsigned char**, i2d_ECPrivateKey::$_0)
Unexecuted instantiation: ec_asn1.cc:int bssl::I2DFromCBB<i2d_ECPKParameters::$_0>(unsigned long, unsigned char**, i2d_ECPKParameters::$_0)
Unexecuted instantiation: ec_asn1.cc:int bssl::I2DFromCBB<i2d_ECParameters::$_0>(unsigned long, unsigned char**, i2d_ECParameters::$_0)
Unexecuted instantiation: ec_asn1.cc:int bssl::I2DFromCBB<i2o_ECPublicKey::$_0>(unsigned long, unsigned char**, i2o_ECPublicKey::$_0)
Unexecuted instantiation: ecdsa_asn1.cc:int bssl::I2DFromCBB<i2d_ECDSA_SIG::$_0>(unsigned long, unsigned char**, i2d_ECDSA_SIG::$_0)
Unexecuted instantiation: evp_asn1.cc:int bssl::I2DFromCBB<i2d_PUBKEY::$_0>(unsigned long, unsigned char**, i2d_PUBKEY::$_0)
Unexecuted instantiation: rsa_asn1.cc:int bssl::I2DFromCBB<i2d_RSAPublicKey::$_0>(unsigned long, unsigned char**, i2d_RSAPublicKey::$_0)
Unexecuted instantiation: rsa_asn1.cc:int bssl::I2DFromCBB<i2d_RSAPrivateKey::$_0>(unsigned long, unsigned char**, i2d_RSAPrivateKey::$_0)
Unexecuted instantiation: x_algor.cc:int bssl::I2DFromCBB<i2d_X509_ALGOR::$_0>(unsigned long, unsigned char**, i2d_X509_ALGOR::$_0)
x_name.cc:int bssl::I2DFromCBB<i2d_x509_name_entry(X509_name_entry_st const*, unsigned char**)::$_0>(unsigned long, unsigned char**, i2d_x509_name_entry(X509_name_entry_st const*, unsigned char**)::$_0)
Line
Count
Source
118
25.0k
inline int I2DFromCBB(size_t initial_capacity, uint8_t **outp, CBBFunc func) {
119
25.0k
  static_assert(std::is_invocable_v<CBBFunc, CBB *>);
120
25.0k
  static_assert(std::is_same_v<std::invoke_result_t<CBBFunc, CBB *>, bool>);
121
25.0k
  ScopedCBB cbb;
122
25.0k
  if (!CBB_init(cbb.get(), initial_capacity) || !func(cbb.get())) {
123
0
    return -1;
124
0
  }
125
25.0k
  return CBB_finish_i2d(cbb.get(), outp);
126
25.0k
}
Unexecuted instantiation: x_pubkey.cc:int bssl::I2DFromCBB<i2d_X509_PUBKEY::$_0>(unsigned long, unsigned char**, i2d_X509_PUBKEY::$_0)
x_x509.cc:int bssl::I2DFromCBB<i2d_X509::$_0>(unsigned long, unsigned char**, i2d_X509::$_0)
Line
Count
Source
118
24.7k
inline int I2DFromCBB(size_t initial_capacity, uint8_t **outp, CBBFunc func) {
119
24.7k
  static_assert(std::is_invocable_v<CBBFunc, CBB *>);
120
24.7k
  static_assert(std::is_same_v<std::invoke_result_t<CBBFunc, CBB *>, bool>);
121
24.7k
  ScopedCBB cbb;
122
24.7k
  if (!CBB_init(cbb.get(), initial_capacity) || !func(cbb.get())) {
123
0
    return -1;
124
0
  }
125
24.7k
  return CBB_finish_i2d(cbb.get(), outp);
126
24.7k
}
x_x509.cc:int bssl::I2DFromCBB<i2d_X509_tbs::$_0>(unsigned long, unsigned char**, i2d_X509_tbs::$_0)
Line
Count
Source
118
2.90k
inline int I2DFromCBB(size_t initial_capacity, uint8_t **outp, CBBFunc func) {
119
2.90k
  static_assert(std::is_invocable_v<CBBFunc, CBB *>);
120
2.90k
  static_assert(std::is_same_v<std::invoke_result_t<CBBFunc, CBB *>, bool>);
121
2.90k
  ScopedCBB cbb;
122
2.90k
  if (!CBB_init(cbb.get(), initial_capacity) || !func(cbb.get())) {
123
0
    return -1;
124
0
  }
125
2.90k
  return CBB_finish_i2d(cbb.get(), outp);
126
2.90k
}
Unexecuted instantiation: a_object.cc:int bssl::I2DFromCBB<i2d_ASN1_OBJECT::$_0>(unsigned long, unsigned char**, i2d_ASN1_OBJECT::$_0)
Unexecuted instantiation: dh_asn1.cc:int bssl::I2DFromCBB<i2d_DHparams::$_0>(unsigned long, unsigned char**, i2d_DHparams::$_0)
Unexecuted instantiation: dsa_asn1.cc:int bssl::I2DFromCBB<i2d_DSA_SIG::$_0>(unsigned long, unsigned char**, i2d_DSA_SIG::$_0)
Unexecuted instantiation: dsa_asn1.cc:int bssl::I2DFromCBB<i2d_DSAPublicKey::$_0>(unsigned long, unsigned char**, i2d_DSAPublicKey::$_0)
Unexecuted instantiation: dsa_asn1.cc:int bssl::I2DFromCBB<i2d_DSAPrivateKey::$_0>(unsigned long, unsigned char**, i2d_DSAPrivateKey::$_0)
Unexecuted instantiation: dsa_asn1.cc:int bssl::I2DFromCBB<i2d_DSAparams::$_0>(unsigned long, unsigned char**, i2d_DSAparams::$_0)
127
128
BSSL_NAMESPACE_END
129
130
#endif  // OPENSSL_HEADER_CRYPTO_BYTESTRING_INTERNAL_H