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