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