/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 |