Line data Source code
1 : /**
2 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #ifndef CORE_CRYPTO_SPCRYPTOASN1_H_
24 : #define CORE_CRYPTO_SPCRYPTOASN1_H_
25 :
26 : #include "SPCommon.h"
27 :
28 : namespace STAPPLER_VERSIONIZED stappler::crypto {
29 :
30 : template <typename T>
31 : struct Asn1DecoderTraits {
32 : using success = char;
33 : using failure = long;
34 :
35 : InvokerCallTest_MakeCallTest(onBeginSet, success, failure);
36 : InvokerCallTest_MakeCallTest(onEndSet, success, failure);
37 : InvokerCallTest_MakeCallTest(onBeginSequence, success, failure);
38 : InvokerCallTest_MakeCallTest(onEndSequence, success, failure);
39 : InvokerCallTest_MakeCallTest(onOid, success, failure);
40 : InvokerCallTest_MakeCallTest(onNull, success, failure);
41 : InvokerCallTest_MakeCallTest(onInteger, success, failure);
42 : InvokerCallTest_MakeCallTest(onBigInteger, success, failure);
43 : InvokerCallTest_MakeCallTest(onBoolean, success, failure);
44 : InvokerCallTest_MakeCallTest(onBytes, success, failure);
45 : InvokerCallTest_MakeCallTest(onString, success, failure);
46 : InvokerCallTest_MakeCallTest(onCustom, success, failure);
47 : };
48 :
49 : template <typename Interface, typename ReaderType, typename Traits = Asn1DecoderTraits<ReaderType>>
50 : struct Asn1Decoder {
51 : using Bytes = typename Interface::BytesType;
52 : using StringStream = typename Interface::StringStreamType;
53 :
54 : enum Type : uint8_t {
55 : Boolean = 0x01,
56 : Integer = 0x02,
57 : BitString = 0x03,
58 : OctetString = 0x04,
59 : Null = 0x05,
60 : Oid = 0x06,
61 : Utf8String = 0x0C,
62 : Sequence = 0x10,
63 : Set = 0x11,
64 : PrintableString = 0x13,
65 : T61String = 0x14,
66 : AsciiString = 0x16,
67 : UtcTime = 0x17,
68 : Time = 0x18,
69 : UniversalString = 0x1C,
70 : BmpString = 0x1E,
71 : HighForm = 0x1F,
72 : Primitive = 0x00,
73 :
74 : ConstructedBit = 0x20,
75 : ContextSpecificBit = 0x80,
76 : };
77 :
78 13450 : size_t decodeSize(BytesViewNetwork &r) {
79 13450 : size_t size = 0;
80 13450 : auto sizeByte = r.readUnsigned();
81 13450 : if (sizeByte & 0x80) {
82 3174 : auto count = sizeByte & (~0x80);
83 3174 : switch (count) {
84 1151 : case 1: size = r.readUnsigned(); break;
85 2023 : case 2: size = r.readUnsigned16(); break;
86 0 : case 3: size = r.readUnsigned24(); break;
87 0 : case 4: size = r.readUnsigned32(); break;
88 0 : case 8: size = r.readUnsigned64(); break;
89 0 : default: return 0; break;
90 : }
91 : } else {
92 10276 : size = sizeByte;
93 : }
94 13450 : return size;
95 : }
96 :
97 13450 : bool decodeValue(ReaderType &reader, BytesViewNetwork &r) {
98 13450 : auto b = r.readUnsigned();
99 13450 : Type type = Type(b & 0x1F);
100 13450 : switch (type) {
101 25 : case Primitive:
102 25 : if (b & (ContextSpecificBit | ConstructedBit)) {
103 25 : return decodeAny(reader, r);
104 : } else {
105 0 : return decodeUnknown(reader, r, b);
106 : }
107 : break;
108 0 : case Boolean: return decodeBoolean(reader, r); break;
109 2100 : case Integer: return decodeInteger(reader, r); break;
110 3125 : case Oid: return decodeOid(reader, r); break;
111 5050 : case Sequence: return decodeSequence(reader, r); break;
112 150 : case Set: return decodeSet(reader, r); break;
113 1250 : case OctetString: return decodeOctetString(reader, r); break;
114 825 : case Null:
115 825 : r += decodeSize(r);
116 : if constexpr (Traits::onNull) {
117 825 : reader.onNull(*this);
118 : } else if constexpr (Traits::onCustom) {
119 0 : reader.onCustom(*this, uint8_t(type), BytesViewNetwork());
120 : }
121 825 : return true;
122 : break;
123 200 : case Utf8String:
124 : case UniversalString:
125 : case AsciiString:
126 : case PrintableString:
127 : case T61String:
128 : case BmpString:
129 : case UtcTime:
130 : case Time:
131 200 : return decodeString(reader, r, type);
132 : break;
133 0 : case HighForm:
134 0 : return false;
135 : break;
136 725 : case BitString:
137 725 : return decodeBitString(reader, r, b & ConstructedBit);
138 : break;
139 0 : default:
140 0 : return decodeUnknown(reader, r, b); break;
141 : }
142 : return false;
143 : }
144 :
145 5050 : bool decodeSequence(ReaderType &reader, BytesViewNetwork &r) {
146 5050 : auto size = decodeSize(r);
147 5050 : if (size == 0) {
148 0 : return false;
149 : }
150 :
151 5050 : BytesViewNetwork nextR(r.data(), size);
152 5050 : r += size;
153 :
154 5050 : if constexpr (Traits::onBeginSequence) { reader.onBeginSequence(*this); }
155 16825 : while(!nextR.empty()) {
156 11775 : if (!decodeValue(reader, nextR)) {
157 0 : if constexpr (Traits::onEndSequence) { reader.onEndSequence(*this); }
158 0 : return false;
159 : }
160 : }
161 5050 : if constexpr (Traits::onEndSequence) { reader.onEndSequence(*this); }
162 :
163 5050 : return true;
164 : }
165 :
166 150 : bool decodeSet(ReaderType &reader, BytesViewNetwork &r) {
167 150 : auto size = decodeSize(r);
168 150 : if (size == 0) {
169 0 : return false;
170 : }
171 :
172 150 : BytesViewNetwork nextR(r.data(), size);
173 150 : r += size;
174 :
175 150 : if constexpr (Traits::onBeginSet) { reader.onBeginSet(*this); }
176 300 : while(!nextR.empty()) {
177 150 : if (!decodeValue(reader, nextR)) {
178 0 : if constexpr (Traits::onEndSet) { reader.onEndSet(*this); }
179 0 : return false;
180 : }
181 : }
182 150 : if constexpr (Traits::onEndSet) { reader.onEndSet(*this); }
183 :
184 150 : return true;
185 : }
186 :
187 0 : bool decodeUnknown(ReaderType &reader, BytesViewNetwork &r, uint8_t t) {
188 0 : auto size = decodeSize(r);
189 0 : r += size;
190 :
191 0 : if constexpr (Traits::onCustom) { reader.onCustom(*this, t, BytesViewNetwork(r.data(), size)); }
192 0 : return true;
193 : }
194 :
195 25 : bool decodeAny(ReaderType &reader, BytesViewNetwork &r) {
196 25 : auto size = decodeSize(r);
197 25 : if (size == 0) {
198 0 : return false;
199 : }
200 :
201 25 : BytesViewNetwork nextR(r.data(), size);
202 25 : if (decodeValue(reader, nextR)) {
203 25 : r += size;
204 25 : return true;
205 : }
206 0 : return false;
207 : }
208 :
209 3125 : bool decodeOid(ReaderType &reader, BytesViewNetwork &r) {
210 3125 : auto size = decodeSize(r);
211 3125 : if (size == 0) {
212 0 : return false;
213 : }
214 :
215 3125 : StringStream str;
216 :
217 3125 : BytesViewNetwork nextR(r.data(), size);
218 :
219 3125 : auto first = nextR.readUnsigned();
220 :
221 3125 : str << int(first / 40) << "." << int(first % 40);
222 :
223 3125 : uint32_t accum = 0;
224 25875 : while (!nextR.empty()) {
225 22750 : auto value = nextR.readUnsigned();
226 22750 : if (value & 0x80) {
227 6425 : accum = accum << 7 | (value & (~0x80));
228 : } else {
229 16325 : str << "." << (accum << 7 | value);
230 16325 : accum = 0;
231 : }
232 : }
233 :
234 :
235 : if constexpr (Traits::onOid) {
236 3125 : reader.onOid(*this, str.str());
237 : } else if constexpr (Traits::onCustom) {
238 0 : reader.onCustom(*this, uint8_t(Oid), BytesViewNetwork(r.data(), size));
239 : }
240 :
241 3125 : r += size;
242 :
243 3125 : return true;
244 3125 : }
245 :
246 2100 : bool decodeInteger(ReaderType &reader, BytesViewNetwork &r) {
247 2100 : auto size = decodeSize(r);
248 2100 : if (size == 0) {
249 0 : return false;
250 : }
251 :
252 : if constexpr (Traits::onInteger) {
253 2050 : switch(size) {
254 525 : case 1: reader.onInteger(*this, reinterpretValue<int8_t>(r.readUnsigned())); break;
255 150 : case 2: reader.onInteger(*this, reinterpretValue<int16_t>(r.readUnsigned16())); break;
256 300 : case 3: {
257 300 : auto val = r.readUnsigned24();
258 300 : if (val <= 0x7FFFFF) {
259 300 : reader.onInteger(*this, val);
260 : } else {
261 0 : reader.onInteger(*this, val - 0x1000000);
262 : }
263 : }
264 300 : break;
265 0 : case 4: reader.onInteger(*this, reinterpretValue<int32_t>(r.readUnsigned32())); break;
266 0 : case 8: reader.onInteger(*this, reinterpretValue<int64_t>(r.readUnsigned64())); break;
267 1075 : default:
268 1075 : if (size >= 8) {
269 : if constexpr (Traits::onBigInteger) {
270 1075 : reader.onBigInteger(*this, BytesViewNetwork(r.data(), size));
271 1075 : r += size;
272 : } else {
273 : return false;
274 : }
275 : } else {
276 0 : uint64_t accum = 0;
277 0 : for (uint32_t i = 0; i < size; ++ i) {
278 0 : accum = (accum << 8) | r.readUnsigned();
279 : }
280 0 : uint64_t base = 1ULL << (size * 8 - 1);
281 0 : if (accum > base) {
282 0 : reader.onInteger(*this, accum - (1ULL << (size * 8)));
283 : } else {
284 0 : reader.onInteger(*this, accum);
285 : }
286 : }
287 :
288 1075 : break;
289 : }
290 : } else if constexpr (Traits::onBigInteger) {
291 50 : reader.onBigInteger(*this, BytesViewNetwork(r.data(), size));
292 50 : r += size;
293 : } else if constexpr (Traits::onCustom) {
294 : reader.onCustom(*this, uint8_t(Integer), BytesViewNetwork(r.data(), size));
295 : r += size;
296 : } else {
297 : r += size;
298 : }
299 :
300 2100 : return true;
301 : }
302 :
303 0 : bool decodeBoolean(ReaderType &reader, BytesViewNetwork &r) {
304 0 : auto size = decodeSize(r);
305 0 : if (size == 1) {
306 : if constexpr (Traits::onBoolean) {
307 0 : auto value = r.readUnsigned();
308 0 : reader.onBoolean(*this, value != 0);
309 : } else if constexpr (Traits::onCustom) {
310 0 : reader.onCustom(*this, uint8_t(Boolean), BytesViewNetwork(r.data(), size));
311 0 : r += size;
312 : }
313 0 : return true;
314 : }
315 :
316 0 : return false;
317 : }
318 :
319 1250 : bool decodeOctetString(ReaderType &reader, BytesViewNetwork &r) {
320 1250 : auto size = decodeSize(r);
321 1250 : if (size > 0) {
322 : if constexpr (Traits::onBytes) {
323 1250 : reader.onBytes(*this, BytesViewNetwork(r.data(), size));
324 : } else if constexpr (Traits::onCustom) {
325 0 : reader.onCustom(*this, uint8_t(OctetString), BytesViewNetwork(r.data(), size));
326 : }
327 1250 : r += size;
328 1250 : return true;
329 : }
330 :
331 0 : return true;
332 : }
333 :
334 200 : bool decodeString(ReaderType &reader, BytesViewNetwork &r, Type t) {
335 200 : auto size = decodeSize(r);
336 : if constexpr (Traits::onString) {
337 200 : reader.onString(*this, BytesViewNetwork(r.data(), size), t);
338 : } else if constexpr (Traits::onCustom) {
339 0 : reader.onCustom(*this, uint8_t(t), BytesViewNetwork(r.data(), size));
340 : }
341 200 : r += size;
342 200 : return true;
343 : }
344 :
345 725 : bool decodeBitString(ReaderType &reader, BytesViewNetwork &r, bool constructed) {
346 725 : auto size = decodeSize(r);
347 :
348 725 : if (!constructed) {
349 700 : if (size > 1) {
350 700 : auto unused = r.readUnsigned();
351 :
352 700 : if (unused > 0 && unused < 8) {
353 0 : Bytes b; b.resize(size - 1);
354 0 : memcpy(b.data(), r.data(), size - 1);
355 :
356 0 : uint8_t mask = 0xFF << unused;
357 0 : b.back() = b.back() & mask;
358 :
359 : if constexpr (Traits::onBytes) {
360 0 : reader.onBytes(*this, BytesViewNetwork(b.data(), b.size()));
361 : } else if constexpr (Traits::onCustom) {
362 0 : reader.onCustom(*this, uint8_t(BitString), BytesViewNetwork(b.data(), b.size()));
363 : }
364 0 : r += size - 1;
365 0 : return true;
366 700 : } else if (unused == 0) {
367 : if constexpr (Traits::onBytes) {
368 700 : reader.onBytes(*this, BytesViewNetwork(r.data(), size - 1));
369 : } else if constexpr (Traits::onCustom) {
370 0 : reader.onCustom(*this, uint8_t(BitString), BytesViewNetwork(r.data(), size - 1));
371 : }
372 700 : r += size - 1;
373 700 : return true;
374 : }
375 : }
376 0 : return false;
377 : } else {
378 25 : r += size;
379 25 : return true;
380 : }
381 : }
382 :
383 : bool decode(ReaderType &reader, const Bytes &source) {
384 : return decode(reader, BytesViewNetwork(source));
385 : }
386 :
387 1500 : bool decode(ReaderType &reader, const BytesViewNetwork &source) {
388 1500 : BytesViewNetwork r(source);
389 :
390 3000 : while (!r.empty()) {
391 1500 : if (!decodeValue(reader, r)) {
392 0 : return false;
393 : }
394 : }
395 :
396 1500 : return true;
397 : }
398 : };
399 :
400 : }
401 :
402 : #endif /* CORE_CRYPTO_SPCRYPTOASN1_H_ */
|