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