Coverage Report

Created: 2026-09-04 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/build/include/public/botan/der_enc.h
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
#ifndef BOTAN_DER_ENCODER_H_
9
#define BOTAN_DER_ENCODER_H_
10
11
#include <botan/asn1_obj.h>
12
#include <botan/secmem.h>
13
#include <functional>
14
#include <optional>
15
#include <span>
16
#include <vector>
17
18
namespace Botan {
19
20
class BigInt;
21
22
/**
23
* General DER Encoding Object
24
*/
25
class BOTAN_PUBLIC_API(2, 0) DER_Encoder final {
26
   public:
27
      /**
28
      * Callback type invoked with each chunk of encoded output
29
      */
30
      typedef std::function<void(const uint8_t[], size_t)> append_fn;
31
32
      /**
33
      * DER encode, writing to an internal buffer
34
      * Use get_contents or get_contents_unlocked to read the results
35
      * after all encoding is completed.
36
      */
37
0
      DER_Encoder() = default;
38
39
      /**
40
      * DER encode, writing to @param vec
41
      * If this constructor is used, get_contents* may not be called.
42
      */
43
      BOTAN_FUTURE_EXPLICIT DER_Encoder(secure_vector<uint8_t>& vec);
44
45
      /**
46
      * DER encode, writing to @param vec
47
      * If this constructor is used, get_contents* may not be called.
48
      */
49
      BOTAN_FUTURE_EXPLICIT DER_Encoder(std::vector<uint8_t>& vec);
50
51
      /**
52
      * DER encode, calling append to write output
53
      * If this constructor is used, get_contents* may not be called.
54
      */
55
0
      BOTAN_FUTURE_EXPLICIT DER_Encoder(append_fn append) : m_append_output(std::move(append)) {}
56
57
      /**
58
      * Return the encoded contents
59
      *
60
      * Throws Invalid_State if any constructed encoding is still open, or if
61
      * this encoder was constructed with an output vector or append function.
62
      */
63
      secure_vector<uint8_t> get_contents();
64
65
      /**
66
      * Return the encoded contents as a std::vector
67
      *
68
      * If using this function, instead pass a std::vector to the
69
      * constructor of DER_Encoder where the output will be placed. This
70
      * avoids several unnecessary copies.
71
      */
72
      BOTAN_DEPRECATED("Use DER_Encoder(vector) instead") std::vector<uint8_t> get_contents_unlocked();
73
74
      /**
75
      * Start a constructed encoding with the given tagging. Must be closed with
76
      * end_cons(). Contents are emitted in the order they are encoded.
77
      *
78
      * @param type_tag the type tag of the constructed encoding
79
      * @param class_tag the class tag of the constructed encoding
80
      */
81
      DER_Encoder& start_cons(ASN1_Type type_tag, ASN1_Class class_tag);
82
83
      /**
84
      * Start a SEQUENCE. Must be closed with end_cons().
85
      */
86
100k
      DER_Encoder& start_sequence() { return start_cons(ASN1_Type::Sequence, ASN1_Class::Universal); }
87
88
      /**
89
      * Start a SET/SET OF. Must be closed with end_cons(). Contents are DER sorted.
90
      */
91
0
      DER_Encoder& start_set() { return start_cons(ASN1_Type::Set, ASN1_Class::Universal); }
92
93
      /**
94
       * Start a SET/SET OF with an alternate tag. Contents are still DER sorted.
95
       *
96
       * @param type_tag the type tag of the constructed encoding
97
       * @param class_tag the class tag of the constructed encoding
98
       */
99
      DER_Encoder& start_set(ASN1_Type type_tag, ASN1_Class class_tag);
100
101
      /**
102
      * Start a SET/SET OF with a context specific tag. Contents are still DER sorted.
103
      *
104
      * @param tag the context specific tag number
105
      */
106
0
      DER_Encoder& start_set(uint32_t tag) { return start_set(ASN1_Type(tag), ASN1_Class::ContextSpecific); }
107
108
      /**
109
      * Start an IMPLICIT context specific constructed encoding
110
      *
111
      * @param tag the context specific tag number
112
      */
113
35.0k
      DER_Encoder& start_context_specific(uint32_t tag) {
114
35.0k
         return start_cons(ASN1_Type(tag), ASN1_Class::ContextSpecific);
115
35.0k
      }
116
117
      /**
118
      * Start an EXPLICIT context specific constructed encoding
119
      *
120
      * @param tag the context specific tag number
121
      */
122
0
      DER_Encoder& start_explicit_context_specific(uint32_t tag) {
123
0
         return start_cons(ASN1_Type(tag), ASN1_Class::ExplicitContextSpecific);
124
0
      }
125
126
      /**
127
      * Finish the innermost open constructed encoding
128
      *
129
      * Throws Invalid_State if no constructed encoding is open.
130
      */
131
      DER_Encoder& end_cons();
132
133
      /**
134
      * Start a context specific constructed encoding, an alias for
135
      * start_context_specific()
136
      *
137
      * @param type_tag the context specific tag number
138
      */
139
      DER_Encoder& start_explicit(uint16_t type_tag);
140
141
      /**
142
      * Finish the innermost open constructed encoding, an alias for end_cons()
143
      */
144
      DER_Encoder& end_explicit();
145
146
      /**
147
      * Insert raw bytes directly into the output stream
148
      */
149
      DER_Encoder& raw_bytes(const uint8_t val[], size_t len);
150
151
      /**
152
      * Insert raw bytes directly into the output stream
153
      */
154
69.6k
      DER_Encoder& raw_bytes(std::span<const uint8_t> val) { return raw_bytes(val.data(), val.size()); }
155
156
      /**
157
      * Encode a NULL
158
      */
159
      DER_Encoder& encode_null();
160
161
      /**
162
      * Encode a BOOLEAN
163
      */
164
      DER_Encoder& encode(bool b);
165
166
      /**
167
      * Encode an INTEGER
168
      */
169
      DER_Encoder& encode(size_t s);
170
171
      /**
172
      * Encode an INTEGER
173
      */
174
      DER_Encoder& encode(const BigInt& n);
175
176
      /**
177
      * Encode an OCTET STRING or an octet aligned BIT STRING
178
      *
179
      * @param val the contents of the object
180
      * @param real_type either ASN1_Type::OctetString or ASN1_Type::BitString
181
      */
182
      DER_Encoder& encode(std::span<const uint8_t> val, ASN1_Type real_type);
183
184
      /**
185
       * Encode a BIT STRING, with `bits` not including the initial unused-bits octet.
186
       */
187
      DER_Encoder& encode_bitstring(std::span<const uint8_t> bits,
188
                                    size_t unused_bits = 0,
189
                                    ASN1_Type type_tag = ASN1_Type::BitString,
190
                                    ASN1_Class class_tag = ASN1_Class::Universal);
191
192
      /**
193
      * Encode a BIT STRING
194
      *
195
      * @param bits the value to encode
196
      * @param type_tag the type tag to encode with
197
      * @param class_tag the class tag to encode with
198
      */
199
      DER_Encoder& encode_bitstring(const ASN1_BitString& bits,
200
                                    ASN1_Type type_tag = ASN1_Type::BitString,
201
                                    ASN1_Class class_tag = ASN1_Class::Universal);
202
203
      /**
204
      * Encode a BIT STRING with no unused bits
205
      *
206
      * @param bytes the bits to encode
207
      * @param type_tag the type tag to encode with
208
      * @param class_tag the class tag to encode with
209
      */
210
      DER_Encoder& encode_octet_aligned_bitstring(std::span<const uint8_t> bytes,
211
                                                  ASN1_Type type_tag = ASN1_Type::BitString,
212
17.2k
                                                  ASN1_Class class_tag = ASN1_Class::Universal) {
213
17.2k
         return encode_bitstring(bytes, 0, type_tag, class_tag);
214
17.2k
      }
215
216
      /**
217
      * Helper for encoding BIT STRING elements that are actually bit sets, rather
218
      * than being OCTET STRINGS with the wrong type.
219
      */
220
      DER_Encoder& encode_named_bitstring(uint64_t bits,
221
                                          size_t width,
222
                                          ASN1_Type type_tag = ASN1_Type::BitString,
223
                                          ASN1_Class class_tag = ASN1_Class::Universal);
224
225
      /**
226
      * Encode an OCTET STRING or an octet aligned BIT STRING
227
      *
228
      * @param val the contents of the object
229
      * @param len the length of val in bytes
230
      * @param real_type either ASN1_Type::OctetString or ASN1_Type::BitString
231
      */
232
0
      DER_Encoder& encode(const uint8_t val[], size_t len, ASN1_Type real_type) {
233
0
         return this->encode(std::span{val, len}, real_type);
234
0
      }
235
236
      /**
237
      * Encode a BOOLEAN with an IMPLICIT tagging
238
      *
239
      * @param b the value to encode
240
      * @param type_tag the type tag to encode with
241
      * @param class_tag the class tag to encode with
242
      */
243
      DER_Encoder& encode(bool b, ASN1_Type type_tag, ASN1_Class class_tag = ASN1_Class::ContextSpecific);
244
245
      /**
246
      * Encode an INTEGER with an IMPLICIT tagging
247
      *
248
      * @param s the value to encode
249
      * @param type_tag the type tag to encode with
250
      * @param class_tag the class tag to encode with
251
      */
252
      DER_Encoder& encode(size_t s, ASN1_Type type_tag, ASN1_Class class_tag = ASN1_Class::ContextSpecific);
253
254
      /**
255
      * Encode an INTEGER with an IMPLICIT tagging
256
      *
257
      * @param n the value to encode
258
      * @param type_tag the type tag to encode with
259
      * @param class_tag the class tag to encode with
260
      */
261
      DER_Encoder& encode(const BigInt& n, ASN1_Type type_tag, ASN1_Class class_tag = ASN1_Class::ContextSpecific);
262
263
      /**
264
      * Encode an OCTET STRING or octet aligned BIT STRING with an IMPLICIT tagging
265
      *
266
      * @param value the contents of the object
267
      * @param real_type either ASN1_Type::OctetString or ASN1_Type::BitString
268
      * @param type_tag the type tag to encode with
269
      * @param class_tag the class tag to encode with
270
      */
271
      DER_Encoder& encode(std::span<const uint8_t> value,
272
                          ASN1_Type real_type,
273
                          ASN1_Type type_tag,
274
                          ASN1_Class class_tag = ASN1_Class::ContextSpecific);
275
276
      /**
277
      * Encode an OCTET STRING or octet aligned BIT STRING with an IMPLICIT tagging
278
      *
279
      * @param v the contents of the object
280
      * @param len the length of v in bytes
281
      * @param real_type either ASN1_Type::OctetString or ASN1_Type::BitString
282
      * @param type_tag the type tag to encode with
283
      * @param class_tag the class tag to encode with
284
      */
285
      DER_Encoder& encode(const uint8_t v[],
286
                          size_t len,
287
                          ASN1_Type real_type,
288
                          ASN1_Type type_tag,
289
0
                          ASN1_Class class_tag = ASN1_Class::ContextSpecific) {
290
0
         return encode(std::span{v, len}, real_type, type_tag, class_tag);
291
0
      }
292
293
      /**
294
      * Encode a value unless it is equal to the DEFAULT
295
      *
296
      * @param value the value to encode
297
      * @param default_value the value which should be omitted
298
      */
299
      template <typename T>
300
      BOTAN_DEPRECATED("Use the version that takes a std::optional")
301
      DER_Encoder& encode_optional(const T& value, const T& default_value) {
302
         if(value != default_value) {
303
            encode(value);
304
         }
305
         return (*this);
306
      }
307
308
      /**
309
      * Encode a value if it is set, otherwise write nothing
310
      *
311
      * @param value the value to encode
312
      */
313
      template <typename T>
314
0
      DER_Encoder& encode_optional(const std::optional<T>& value) {
315
0
         if(value) {
316
0
            encode(*value);
317
0
         }
318
0
         return (*this);
319
0
      }
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_optional<bool>(std::__1::optional<bool> const&)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_optional<unsigned long>(std::__1::optional<unsigned long> const&)
320
321
      /**
322
      * Encode each element of the vector in turn
323
      *
324
      * @param values the values to encode
325
      */
326
      template <typename T>
327
0
      DER_Encoder& encode_list(const std::vector<T>& values) {
328
0
         for(size_t i = 0; i != values.size(); ++i) {
329
0
            encode(values[i]);
330
0
         }
331
0
         return (*this);
332
0
      }
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::BigInt>(std::__1::vector<Botan::BigInt, std::__1::allocator<Botan::BigInt> > const&)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::OID>(std::__1::vector<Botan::OID, std::__1::allocator<Botan::OID> > const&)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::GeneralSubtree>(std::__1::vector<Botan::GeneralSubtree, std::__1::allocator<Botan::GeneralSubtree> > const&)
Unexecuted instantiation: x509_ext.cpp:Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::Cert_Extension::(anonymous namespace)::Policy_Information>(std::__1::vector<Botan::Cert_Extension::(anonymous namespace)::Policy_Information, std::__1::allocator<Botan::Cert_Extension::(anonymous namespace)::Policy_Information> > const&)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::Cert_Extension::CRL_Distribution_Points::Distribution_Point>(std::__1::vector<Botan::Cert_Extension::CRL_Distribution_Points::Distribution_Point, std::__1::allocator<Botan::Cert_Extension::CRL_Distribution_Points::Distribution_Point> > const&)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::Cert_Extension::IPAddressBlocks::IPAddressFamily>(std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressFamily, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressFamily> > const&)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> >(std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const&)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> >(std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const&)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::Cert_Extension::ASBlocks::ASIdOrRange>(std::__1::vector<Botan::Cert_Extension::ASBlocks::ASIdOrRange, std::__1::allocator<Botan::Cert_Extension::ASBlocks::ASIdOrRange> > const&)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_list<Botan::X509_Certificate>(std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&)
333
334
      /**
335
      * Request for an object to encode itself to this stream
336
      *
337
      * @param obj the object to encode
338
      */
339
      DER_Encoder& encode(const ASN1_Object& obj);
340
341
      /**
342
      * Write the contents of another encoder to this stream if pred is true
343
      *
344
      * @param pred if false nothing is written
345
      * @param enc the encoder whose contents are written
346
      */
347
0
      DER_Encoder& encode_if(bool pred, DER_Encoder& enc) {
348
0
         if(pred) {
349
0
            return raw_bytes(enc.get_contents());
350
0
         }
351
0
         return (*this);
352
0
      }
353
354
      /**
355
      * Encode an object if pred is true
356
      *
357
      * @param pred if false nothing is written
358
      * @param obj the object to encode
359
      */
360
0
      DER_Encoder& encode_if(bool pred, const ASN1_Object& obj) {
361
0
         if(pred) {
362
0
            encode(obj);
363
0
         }
364
0
         return (*this);
365
0
      }
366
367
      /**
368
      * Encode an INTEGER if pred is true
369
      *
370
      * @param pred if false nothing is written
371
      * @param num the value to encode
372
      */
373
0
      DER_Encoder& encode_if(bool pred, size_t num) {
374
0
         if(pred) {
375
0
            encode(num);
376
0
         }
377
0
         return (*this);
378
0
      }
379
380
      /**
381
      * Encode a BOOLEAN if pred is true
382
      *
383
      * @param pred if false nothing is written
384
      * @param num the value to encode
385
      */
386
0
      DER_Encoder& encode_if(bool pred, bool num) {
387
0
         if(pred) {
388
0
            encode(num);
389
0
         }
390
0
         return (*this);
391
0
      }
392
393
      /**
394
      * Write a tag and length header followed by the given contents
395
      *
396
      * @param type_tag the type tag to encode with
397
      * @param class_tag the class tag to encode with
398
      * @param rep the contents of the object
399
      * @param length the length of rep in bytes
400
      */
401
      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag, const uint8_t rep[], size_t length);
402
403
      /**
404
      * Write a tag and length header followed by the given contents
405
      *
406
      * @param type_tag the type tag to encode with
407
      * @param class_tag the class tag to encode with
408
      * @param rep the contents of the object
409
      */
410
250k
      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag, std::span<const uint8_t> rep) {
411
250k
         return add_object(type_tag, class_tag, rep.data(), rep.size());
412
250k
      }
413
414
      /**
415
      * Write a tag and length header followed by the given contents
416
      *
417
      * @param type_tag the type tag to encode with
418
      * @param class_tag the class tag to encode with
419
      * @param rep the contents of the object
420
      */
421
224k
      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag, const std::vector<uint8_t>& rep) {
422
224k
         return add_object(type_tag, class_tag, std::span{rep});
423
224k
      }
424
425
      /**
426
      * Write a tag and length header followed by the given contents
427
      *
428
      * @param type_tag the type tag to encode with
429
      * @param class_tag the class tag to encode with
430
      * @param rep the contents of the object
431
      */
432
17.2k
      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag, const secure_vector<uint8_t>& rep) {
433
17.2k
         return add_object(type_tag, class_tag, std::span{rep});
434
17.2k
      }
435
436
      /**
437
      * Write a tag and length header followed by the given contents
438
      *
439
      * @param type_tag the type tag to encode with
440
      * @param class_tag the class tag to encode with
441
      * @param str the contents of the object
442
      */
443
      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag, std::string_view str);
444
445
      /**
446
      * Write a tag and length header followed by a single byte of contents
447
      *
448
      * @param type_tag the type tag to encode with
449
      * @param class_tag the class tag to encode with
450
      * @param val the contents of the object
451
      */
452
      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag, uint8_t val);
453
454
      /**
455
       * Encode `value` and emit just its body bytes under an IMPLICIT
456
       * `type_tag`/`class_tag` (e.g. for `[N] IMPLICIT OBJECT IDENTIFIER` where the
457
       * body is an OID's arc bytes but the tag must be `[N]`). The
458
       * primitive/constructed bit is copied from `value`.
459
       */
460
      template <typename T>
461
      DER_Encoder& encode_implicit(const T& value,
462
                                   ASN1_Type type_tag,
463
0
                                   ASN1_Class class_tag = ASN1_Class::ContextSpecific) {
464
0
         std::vector<uint8_t> tlv;
465
0
         DER_Encoder(tlv).encode(value);
466
0
         return add_object_tlv(type_tag, class_tag, std::move(tlv));
467
0
      }
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_implicit<Botan::AlternativeName>(Botan::AlternativeName const&, Botan::ASN1_Type, Botan::ASN1_Class)
Unexecuted instantiation: Botan::DER_Encoder& Botan::DER_Encoder::encode_implicit<Botan::OID>(Botan::OID const&, Botan::ASN1_Type, Botan::ASN1_Class)
468
469
   private:
470
      DER_Encoder& add_object_tlv(ASN1_Type type_tag, ASN1_Class class_tag, std::vector<uint8_t> tlv);
471
472
      DER_Encoder& start_cons(ASN1_Type type_tag, ASN1_Class class_tag, bool sort_contents);
473
474
      class DER_Sequence final {
475
         public:
476
            uint32_t tag_of() const;
477
478
            void push_contents(DER_Encoder& der);
479
480
            void add_bytes(const uint8_t val[], size_t len);
481
482
            void add_bytes(const uint8_t hdr[], size_t hdr_len, const uint8_t val[], size_t val_len);
483
484
            DER_Sequence(ASN1_Type type_tag, ASN1_Class class_tag, bool sort_contents);
485
486
            DER_Sequence(DER_Sequence&& seq) noexcept :
487
322k
                  m_type_tag(seq.m_type_tag),
488
322k
                  m_class_tag(seq.m_class_tag),
489
322k
                  m_sort_contents(seq.m_sort_contents),
490
322k
                  m_contents(std::move(seq.m_contents)),
491
322k
                  m_set_contents(std::move(seq.m_set_contents)) {}
492
493
0
            DER_Sequence& operator=(DER_Sequence&& seq) noexcept {
494
0
               std::swap(m_type_tag, seq.m_type_tag);
495
0
               std::swap(m_class_tag, seq.m_class_tag);
496
0
               std::swap(m_sort_contents, seq.m_sort_contents);
497
0
               std::swap(m_contents, seq.m_contents);
498
0
               std::swap(m_set_contents, seq.m_set_contents);
499
0
               return (*this);
500
0
            }
501
502
            DER_Sequence(const DER_Sequence& seq) = default;
503
            DER_Sequence& operator=(const DER_Sequence& seq) = default;
504
458k
            ~DER_Sequence() = default;
505
506
         private:
507
            ASN1_Type m_type_tag;
508
            ASN1_Class m_class_tag;
509
            bool m_sort_contents;
510
            secure_vector<uint8_t> m_contents;
511
            std::vector<secure_vector<uint8_t>> m_set_contents;
512
      };
513
514
      append_fn m_append_output;
515
      secure_vector<uint8_t> m_default_outbuf;
516
      std::vector<DER_Sequence> m_subsequences;
517
};
518
519
}  // namespace Botan
520
521
#endif