Coverage Report

Created: 2025-11-16 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/asn1/der_enc.cpp
Line
Count
Source
1
/*
2
* DER Encoder
3
* (C) 1999-2007,2018 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/der_enc.h>
9
10
#include <botan/asn1_obj.h>
11
#include <botan/bigint.h>
12
#include <botan/internal/bit_ops.h>
13
#include <botan/internal/fmt.h>
14
#include <botan/internal/loadstor.h>
15
#include <botan/internal/mem_utils.h>
16
#include <algorithm>
17
18
namespace Botan {
19
20
namespace {
21
22
/*
23
* DER encode an ASN.1 type tag
24
*/
25
9
void encode_tag(std::vector<uint8_t>& encoded_tag, ASN1_Type type_tag_e, ASN1_Class class_tag_e) {
26
9
   const uint32_t type_tag = static_cast<uint32_t>(type_tag_e);
27
9
   const uint32_t class_tag = static_cast<uint32_t>(class_tag_e);
28
29
9
   if((class_tag | 0xE0) != 0xE0) {
30
0
      throw Encoding_Error(fmt("DER_Encoder: Invalid class tag {}", std::to_string(class_tag)));
31
0
   }
32
33
9
   if(type_tag <= 30) {
34
9
      encoded_tag.push_back(static_cast<uint8_t>(type_tag | class_tag));
35
9
   } else {
36
0
      size_t blocks = high_bit(static_cast<uint32_t>(type_tag)) + 6;
37
0
      blocks = (blocks - (blocks % 7)) / 7;
38
39
0
      BOTAN_ASSERT_NOMSG(blocks > 0);
40
41
0
      encoded_tag.push_back(static_cast<uint8_t>(class_tag | 0x1F));
42
0
      for(size_t i = 0; i != blocks - 1; ++i) {
43
0
         encoded_tag.push_back(0x80 | ((type_tag >> 7 * (blocks - i - 1)) & 0x7F));
44
0
      }
45
0
      encoded_tag.push_back(type_tag & 0x7F);
46
0
   }
47
9
}
48
49
/*
50
* DER encode an ASN.1 length field
51
*/
52
9
void encode_length(std::vector<uint8_t>& encoded_length, size_t length) {
53
9
   if(length <= 127) {
54
9
      encoded_length.push_back(static_cast<uint8_t>(length));
55
9
   } else {
56
0
      const size_t bytes_needed = significant_bytes(length);
57
58
0
      encoded_length.push_back(static_cast<uint8_t>(0x80 | bytes_needed));
59
60
0
      for(size_t i = sizeof(length) - bytes_needed; i < sizeof(length); ++i) {
61
0
         encoded_length.push_back(get_byte_var(i, length));
62
0
      }
63
0
   }
64
9
}
65
66
}  // namespace
67
68
0
DER_Encoder::DER_Encoder(secure_vector<uint8_t>& vec) {
69
0
   m_append_output = [&vec](const uint8_t b[], size_t l) { vec.insert(vec.end(), b, b + l); };
70
0
}
71
72
9
DER_Encoder::DER_Encoder(std::vector<uint8_t>& vec) {
73
18
   m_append_output = [&vec](const uint8_t b[], size_t l) { vec.insert(vec.end(), b, b + l); };
74
9
}
75
76
/*
77
* Push the encoded SEQUENCE/SET to the encoder stream
78
*/
79
0
void DER_Encoder::DER_Sequence::push_contents(DER_Encoder& der) {
80
0
   const auto real_class_tag = m_class_tag | ASN1_Class::Constructed;
81
82
0
   if(m_type_tag == ASN1_Type::Set) {
83
0
      std::sort(m_set_contents.begin(), m_set_contents.end());
84
0
      for(const auto& set_elem : m_set_contents) {
85
0
         m_contents += set_elem;
86
0
      }
87
0
      m_set_contents.clear();
88
0
   }
89
90
0
   der.add_object(m_type_tag, real_class_tag, m_contents.data(), m_contents.size());
91
0
   m_contents.clear();
92
0
}
93
94
/*
95
* Add an encoded value to the SEQUENCE/SET
96
*/
97
0
void DER_Encoder::DER_Sequence::add_bytes(const uint8_t data[], size_t length) {
98
0
   if(m_type_tag == ASN1_Type::Set) {
99
0
      m_set_contents.push_back(secure_vector<uint8_t>(data, data + length));
100
0
   } else {
101
0
      m_contents += std::make_pair(data, length);
102
0
   }
103
0
}
104
105
0
void DER_Encoder::DER_Sequence::add_bytes(const uint8_t hdr[], size_t hdr_len, const uint8_t val[], size_t val_len) {
106
0
   if(m_type_tag == ASN1_Type::Set) {
107
0
      secure_vector<uint8_t> m;
108
0
      m.reserve(hdr_len + val_len);
109
0
      m += std::make_pair(hdr, hdr_len);
110
0
      m += std::make_pair(val, val_len);
111
0
      m_set_contents.push_back(std::move(m));
112
0
   } else {
113
0
      m_contents += std::make_pair(hdr, hdr_len);
114
0
      m_contents += std::make_pair(val, val_len);
115
0
   }
116
0
}
117
118
/*
119
* Return the type and class taggings
120
*/
121
0
uint32_t DER_Encoder::DER_Sequence::tag_of() const {
122
0
   return m_type_tag | m_class_tag;
123
0
}
124
125
/*
126
* DER_Sequence Constructor
127
*/
128
DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Type type_tag, ASN1_Class class_tag) :
129
0
      m_type_tag(type_tag), m_class_tag(class_tag) {}
130
131
/*
132
* Return the encoded contents
133
*/
134
0
secure_vector<uint8_t> DER_Encoder::get_contents() {
135
0
   if(!m_subsequences.empty()) {
136
0
      throw Invalid_State("DER_Encoder: Sequence hasn't been marked done");
137
0
   }
138
139
0
   if(m_append_output) {
140
0
      throw Invalid_State("DER_Encoder Cannot get contents when using output vector");
141
0
   }
142
143
0
   secure_vector<uint8_t> output;
144
0
   std::swap(output, m_default_outbuf);
145
0
   return output;
146
0
}
147
148
0
std::vector<uint8_t> DER_Encoder::get_contents_unlocked() {
149
0
   if(!m_subsequences.empty()) {
150
0
      throw Invalid_State("DER_Encoder: Sequence hasn't been marked done");
151
0
   }
152
153
0
   if(m_append_output) {
154
0
      throw Invalid_State("DER_Encoder Cannot get contents when using output vector");
155
0
   }
156
157
0
   std::vector<uint8_t> output(m_default_outbuf.begin(), m_default_outbuf.end());
158
0
   m_default_outbuf.clear();
159
0
   return output;
160
0
}
161
162
/*
163
* Start a new ASN.1 SEQUENCE/SET/EXPLICIT
164
*/
165
0
DER_Encoder& DER_Encoder::start_cons(ASN1_Type type_tag, ASN1_Class class_tag) {
166
0
   m_subsequences.push_back(DER_Sequence(type_tag, class_tag));
167
0
   return (*this);
168
0
}
169
170
/*
171
* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT
172
*/
173
0
DER_Encoder& DER_Encoder::end_cons() {
174
0
   if(m_subsequences.empty()) {
175
0
      throw Invalid_State("DER_Encoder::end_cons: No such sequence");
176
0
   }
177
178
0
   DER_Sequence last_seq = std::move(m_subsequences[m_subsequences.size() - 1]);
179
0
   m_subsequences.pop_back();
180
0
   last_seq.push_contents(*this);
181
182
0
   return (*this);
183
0
}
184
185
/*
186
* Start a new ASN.1 EXPLICIT encoding
187
*/
188
0
DER_Encoder& DER_Encoder::start_explicit(uint16_t type_no) {
189
0
   ASN1_Type type_tag = static_cast<ASN1_Type>(type_no);
190
191
   // This would confuse DER_Sequence
192
0
   if(type_tag == ASN1_Type::Set) {
193
0
      throw Internal_Error("DER_Encoder.start_explicit(SET) not supported");
194
0
   }
195
196
0
   return start_cons(type_tag, ASN1_Class::ContextSpecific);
197
0
}
198
199
/*
200
* Finish the current ASN.1 EXPLICIT encoding
201
*/
202
0
DER_Encoder& DER_Encoder::end_explicit() {
203
0
   return end_cons();
204
0
}
205
206
/*
207
* Write raw bytes into the stream
208
*/
209
0
DER_Encoder& DER_Encoder::raw_bytes(const uint8_t bytes[], size_t length) {
210
0
   if(!m_subsequences.empty()) {
211
0
      m_subsequences[m_subsequences.size() - 1].add_bytes(bytes, length);
212
0
   } else if(m_append_output) {
213
0
      m_append_output(bytes, length);
214
0
   } else {
215
0
      m_default_outbuf += std::make_pair(bytes, length);
216
0
   }
217
218
0
   return (*this);
219
0
}
220
221
/*
222
* Write the encoding of the byte(s)
223
*/
224
9
DER_Encoder& DER_Encoder::add_object(ASN1_Type type_tag, ASN1_Class class_tag, const uint8_t rep[], size_t length) {
225
9
   std::vector<uint8_t> hdr;
226
9
   encode_tag(hdr, type_tag, class_tag);
227
9
   encode_length(hdr, length);
228
229
9
   if(!m_subsequences.empty()) {
230
0
      m_subsequences[m_subsequences.size() - 1].add_bytes(hdr.data(), hdr.size(), rep, length);
231
9
   } else if(m_append_output) {
232
9
      m_append_output(hdr.data(), hdr.size());
233
9
      m_append_output(rep, length);
234
9
   } else {
235
0
      m_default_outbuf += hdr;
236
0
      m_default_outbuf += std::make_pair(rep, length);
237
0
   }
238
239
9
   return (*this);
240
9
}
241
242
/*
243
* Encode a NULL object
244
*/
245
0
DER_Encoder& DER_Encoder::encode_null() {
246
0
   return add_object(ASN1_Type::Null, ASN1_Class::Universal, nullptr, 0);
247
0
}
248
249
/*
250
* DER encode a BOOLEAN
251
*/
252
0
DER_Encoder& DER_Encoder::encode(bool is_true) {
253
0
   return encode(is_true, ASN1_Type::Boolean, ASN1_Class::Universal);
254
0
}
255
256
/*
257
* DER encode a small INTEGER
258
*/
259
0
DER_Encoder& DER_Encoder::encode(size_t n) {
260
0
   return encode(BigInt::from_u64(n), ASN1_Type::Integer, ASN1_Class::Universal);
261
0
}
262
263
/*
264
* DER encode a small INTEGER
265
*/
266
0
DER_Encoder& DER_Encoder::encode(const BigInt& n) {
267
0
   return encode(n, ASN1_Type::Integer, ASN1_Class::Universal);
268
0
}
269
270
/*
271
* Encode this object
272
*/
273
0
DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length, ASN1_Type real_type) {
274
0
   return encode(bytes, length, real_type, real_type, ASN1_Class::Universal);
275
0
}
276
277
/*
278
* DER encode a BOOLEAN
279
*/
280
0
DER_Encoder& DER_Encoder::encode(bool is_true, ASN1_Type type_tag, ASN1_Class class_tag) {
281
0
   uint8_t val = is_true ? 0xFF : 0x00;
282
0
   return add_object(type_tag, class_tag, &val, 1);
283
0
}
284
285
/*
286
* DER encode a small INTEGER
287
*/
288
0
DER_Encoder& DER_Encoder::encode(size_t n, ASN1_Type type_tag, ASN1_Class class_tag) {
289
0
   return encode(BigInt::from_u64(n), type_tag, class_tag);
290
0
}
291
292
/*
293
* DER encode an INTEGER
294
*/
295
0
DER_Encoder& DER_Encoder::encode(const BigInt& n, ASN1_Type type_tag, ASN1_Class class_tag) {
296
0
   if(n == 0) {
297
0
      return add_object(type_tag, class_tag, 0);
298
0
   }
299
300
0
   const size_t extra_zero = (n.bits() % 8 == 0) ? 1 : 0;
301
302
0
   auto contents = n.serialize(n.bytes() + extra_zero);
303
0
   if(n < 0) {
304
0
      for(unsigned char& content : contents) {
305
0
         content = ~content;
306
0
      }
307
0
      for(size_t i = contents.size(); i > 0; --i) {
308
0
         contents[i - 1] += 1;
309
0
         if(contents[i - 1] != 0) {
310
0
            break;
311
0
         }
312
0
      }
313
0
   }
314
315
0
   return add_object(type_tag, class_tag, contents);
316
0
}
317
318
/*
319
* DER encode an OCTET STRING or BIT STRING
320
*/
321
DER_Encoder& DER_Encoder::encode(
322
0
   const uint8_t bytes[], size_t length, ASN1_Type real_type, ASN1_Type type_tag, ASN1_Class class_tag) {
323
0
   if(real_type != ASN1_Type::OctetString && real_type != ASN1_Type::BitString) {
324
0
      throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string");
325
0
   }
326
327
0
   if(real_type == ASN1_Type::BitString) {
328
0
      secure_vector<uint8_t> encoded;
329
0
      encoded.push_back(0);
330
0
      encoded += std::make_pair(bytes, length);
331
0
      return add_object(type_tag, class_tag, encoded);
332
0
   } else {
333
0
      return add_object(type_tag, class_tag, bytes, length);
334
0
   }
335
0
}
336
337
9
DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj) {
338
9
   obj.encode_into(*this);
339
9
   return (*this);
340
9
}
341
342
/*
343
* Write the encoding of the byte(s)
344
*/
345
0
DER_Encoder& DER_Encoder::add_object(ASN1_Type type_tag, ASN1_Class class_tag, std::string_view rep_str) {
346
0
   return add_object(type_tag, class_tag, as_span_of_bytes(rep_str));
347
0
}
348
349
/*
350
* Write the encoding of the byte
351
*/
352
0
DER_Encoder& DER_Encoder::add_object(ASN1_Type type_tag, ASN1_Class class_tag, uint8_t rep) {
353
0
   return add_object(type_tag, class_tag, std::span<const uint8_t>{&rep, 1});
354
0
}
355
356
}  // namespace Botan