/src/opensc/src/libopensc/asn1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * asn1.c: ASN.1 decoding functions (DER) |
3 | | * |
4 | | * Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #ifdef HAVE_CONFIG_H |
22 | | #include "config.h" |
23 | | #endif |
24 | | |
25 | | #include <assert.h> |
26 | | #include <ctype.h> |
27 | | #include <stddef.h> |
28 | | #include <stdio.h> |
29 | | #include <stdlib.h> |
30 | | #include <string.h> |
31 | | #include <limits.h> |
32 | | |
33 | | #include "internal.h" |
34 | | #include "asn1.h" |
35 | | |
36 | | static int asn1_decode(sc_context_t *ctx, struct sc_asn1_entry *asn1, |
37 | | const u8 *in, size_t len, const u8 **newp, size_t *len_left, |
38 | | int choice, int depth); |
39 | | static int asn1_encode(sc_context_t *ctx, const struct sc_asn1_entry *asn1, |
40 | | u8 **ptr, size_t *size, int depth); |
41 | | static int asn1_write_element(sc_context_t *ctx, unsigned int tag, |
42 | | const u8 * data, size_t datalen, u8 ** out, size_t * outlen); |
43 | | |
44 | | static const char *tag2str(unsigned int tag) |
45 | 0 | { |
46 | 0 | static const char *tags[] = { |
47 | 0 | "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", /* 0-4 */ |
48 | 0 | "NULL", "OBJECT IDENTIFIER", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", /* 5-9 */ |
49 | 0 | "ENUMERATED", "Universal 11", "UTF8String", "Universal 13", /* 10-13 */ |
50 | 0 | "Universal 14", "Universal 15", "SEQUENCE", "SET", /* 15-17 */ |
51 | 0 | "NumericString", "PrintableString", "T61String", /* 18-20 */ |
52 | 0 | "VideotexString", "IA5String", "UTCTIME", "GENERALIZEDTIME", /* 21-24 */ |
53 | 0 | "GraphicString", "VisibleString", "GeneralString", /* 25-27 */ |
54 | 0 | "UniversalString", "Universal 29", "BMPString" /* 28-30 */ |
55 | 0 | }; |
56 | |
|
57 | 0 | if (tag > 30) |
58 | 0 | return "(unknown)"; |
59 | 0 | return tags[tag]; |
60 | 0 | } |
61 | | |
62 | | int sc_asn1_read_tag(const u8 ** buf, size_t buflen, unsigned int *cla_out, |
63 | | unsigned int *tag_out, size_t *taglen) |
64 | 52.7k | { |
65 | 52.7k | const u8 *p = *buf; |
66 | 52.7k | size_t left = buflen, len; |
67 | 52.7k | unsigned int cla, tag, i; |
68 | | |
69 | 52.7k | *buf = NULL; |
70 | | |
71 | 52.7k | if (left == 0 || !p || buflen == 0) |
72 | 157 | return SC_ERROR_INVALID_ASN1_OBJECT; |
73 | 52.6k | if (*p == 0xff || *p == 0) { |
74 | | /* end of data reached */ |
75 | 4.76k | *taglen = 0; |
76 | 4.76k | *tag_out = SC_ASN1_TAG_EOC; |
77 | 4.76k | return SC_SUCCESS; |
78 | 4.76k | } |
79 | | |
80 | | /* parse tag byte(s) |
81 | | * Resulted tag is presented by integer that has not to be |
82 | | * confused with the 'tag number' part of ASN.1 tag. |
83 | | */ |
84 | 47.8k | cla = (*p & SC_ASN1_TAG_CLASS) | (*p & SC_ASN1_TAG_CONSTRUCTED); |
85 | 47.8k | tag = *p & SC_ASN1_TAG_PRIMITIVE; |
86 | 47.8k | if (left < 1) |
87 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
88 | 47.8k | p++; |
89 | 47.8k | left--; |
90 | 47.8k | if (tag == SC_ASN1_TAG_PRIMITIVE) { |
91 | | /* high tag number */ |
92 | 1.03k | size_t n = SC_ASN1_TAGNUM_SIZE - 1; |
93 | | /* search the last tag octet */ |
94 | 1.56k | do { |
95 | 1.56k | if (left == 0 || n == 0) |
96 | | /* either an invalid tag or it doesn't fit in |
97 | | * unsigned int */ |
98 | 73 | return SC_ERROR_INVALID_ASN1_OBJECT; |
99 | 1.49k | tag <<= 8; |
100 | 1.49k | tag |= *p; |
101 | 1.49k | p++; |
102 | 1.49k | left--; |
103 | 1.49k | n--; |
104 | 1.49k | } while (tag & 0x80); |
105 | 1.03k | } |
106 | | |
107 | | /* parse length byte(s) */ |
108 | 47.7k | if (left == 0) |
109 | 108 | return SC_ERROR_INVALID_ASN1_OBJECT; |
110 | 47.6k | len = *p; |
111 | 47.6k | p++; |
112 | 47.6k | left--; |
113 | 47.6k | if (len & 0x80) { |
114 | 7.90k | len &= 0x7f; |
115 | 7.90k | unsigned int a = 0; |
116 | 7.90k | if (len > sizeof a || len > left) |
117 | 6.87k | return SC_ERROR_INVALID_ASN1_OBJECT; |
118 | 1.60k | for (i = 0; i < len; i++) { |
119 | 578 | a <<= 8; |
120 | 578 | a |= *p; |
121 | 578 | p++; |
122 | 578 | left--; |
123 | 578 | } |
124 | 1.02k | len = a; |
125 | 1.02k | } |
126 | | |
127 | 40.7k | *cla_out = cla; |
128 | 40.7k | *tag_out = tag; |
129 | 40.7k | *taglen = len; |
130 | 40.7k | *buf = p; |
131 | | |
132 | 40.7k | if (len > left) |
133 | 6.03k | return SC_ERROR_ASN1_END_OF_CONTENTS; |
134 | | |
135 | 34.7k | return SC_SUCCESS; |
136 | 40.7k | } |
137 | | |
138 | | void sc_format_asn1_entry(struct sc_asn1_entry *entry, void *parm, void *arg, |
139 | | int set_present) |
140 | 49.0k | { |
141 | 49.0k | entry->parm = parm; |
142 | 49.0k | entry->arg = arg; |
143 | 49.0k | if (set_present) |
144 | 2.92k | entry->flags |= SC_ASN1_PRESENT; |
145 | 49.0k | } |
146 | | |
147 | | void sc_copy_asn1_entry(const struct sc_asn1_entry *src, |
148 | | struct sc_asn1_entry *dest) |
149 | 18.3k | { |
150 | 67.3k | while (src->name != NULL) { |
151 | 49.0k | *dest = *src; |
152 | 49.0k | dest++; |
153 | 49.0k | src++; |
154 | 49.0k | } |
155 | 18.3k | dest->name = NULL; |
156 | 18.3k | } |
157 | | |
158 | | static void print_indent(size_t depth) |
159 | 0 | { |
160 | 0 | for (; depth > 0; depth--) { |
161 | 0 | putchar(' '); |
162 | 0 | } |
163 | 0 | } |
164 | | |
165 | | static void print_hex(const u8 * buf, size_t buflen, size_t depth) |
166 | 0 | { |
167 | 0 | size_t lines_len = buflen * 5 + 128; |
168 | 0 | char *lines = malloc(lines_len); |
169 | 0 | char *line = lines; |
170 | |
|
171 | 0 | if (buf == NULL || buflen == 0 || lines == NULL) { |
172 | 0 | free(lines); |
173 | 0 | return; |
174 | 0 | } |
175 | | |
176 | 0 | sc_hex_dump(buf, buflen, lines, lines_len); |
177 | |
|
178 | 0 | while (*line != '\0') { |
179 | 0 | char *line_end = strchr(line, '\n'); |
180 | 0 | ptrdiff_t width = line_end - line; |
181 | 0 | if (!line_end || width <= 1) { |
182 | | /* don't print empty lines */ |
183 | 0 | break; |
184 | 0 | } |
185 | 0 | if (buflen > 8) { |
186 | 0 | putchar('\n'); |
187 | 0 | print_indent(depth); |
188 | 0 | } else { |
189 | 0 | printf(": "); |
190 | 0 | } |
191 | 0 | printf("%.*s", (int) width, line); |
192 | 0 | line = line_end + 1; |
193 | 0 | } |
194 | |
|
195 | 0 | free(lines); |
196 | 0 | } |
197 | | |
198 | | static void print_ascii(const u8 * buf, size_t buflen) |
199 | 0 | { |
200 | 0 | for (; 0 < buflen; buflen--, buf++) { |
201 | 0 | if (isprint(*buf)) |
202 | 0 | printf("%c", *buf); |
203 | 0 | else |
204 | 0 | putchar('.'); |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | | static void sc_asn1_print_octet_string(const u8 * buf, size_t buflen, size_t depth) |
209 | 0 | { |
210 | 0 | print_hex(buf, buflen, depth); |
211 | 0 | } |
212 | | |
213 | | static void sc_asn1_print_utf8string(const u8 * buf, size_t buflen) |
214 | 0 | { |
215 | | /* FIXME UTF-8 is not ASCII */ |
216 | 0 | print_ascii(buf, buflen); |
217 | 0 | } |
218 | | |
219 | | static void sc_asn1_print_integer(const u8 * buf, size_t buflen) |
220 | 0 | { |
221 | 0 | size_t a = 0; |
222 | |
|
223 | 0 | if (buflen > sizeof(a)) { |
224 | 0 | printf("0x%s", sc_dump_hex(buf, buflen)); |
225 | 0 | } else { |
226 | 0 | size_t i; |
227 | 0 | for (i = 0; i < buflen; i++) { |
228 | 0 | a <<= 8; |
229 | 0 | a |= buf[i]; |
230 | 0 | } |
231 | 0 | printf("%"SC_FORMAT_LEN_SIZE_T"u", a); |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | | static void sc_asn1_print_boolean(const u8 * buf, size_t buflen) |
236 | 0 | { |
237 | 0 | if (!buflen) |
238 | 0 | return; |
239 | | |
240 | 0 | if (buf[0]) |
241 | 0 | printf("true"); |
242 | 0 | else |
243 | 0 | printf("false"); |
244 | 0 | } |
245 | | |
246 | | static void sc_asn1_print_bit_string(const u8 * buf, size_t buflen, size_t depth) |
247 | 0 | { |
248 | 0 | #ifndef _WIN32 |
249 | 0 | long long a = 0; |
250 | | #else |
251 | | __int64 a = 0; |
252 | | #endif |
253 | 0 | int r, i; |
254 | |
|
255 | 0 | if (buflen > sizeof(a) + 1) { |
256 | 0 | print_hex(buf, buflen, depth); |
257 | 0 | } else { |
258 | 0 | r = sc_asn1_decode_bit_string(buf, buflen, &a, sizeof(a), 1); |
259 | 0 | if (r < 0) { |
260 | 0 | printf("decode error, "); |
261 | | /* try again without the strict mode */ |
262 | 0 | r = sc_asn1_decode_bit_string(buf, buflen, &a, sizeof(a), 0); |
263 | 0 | if (r < 0) { |
264 | 0 | printf("even for lax decoding"); |
265 | 0 | return ; |
266 | 0 | } |
267 | 0 | } |
268 | 0 | for (i = r - 1; i >= 0; i--) { |
269 | 0 | printf("%c", ((a >> i) & 1) ? '1' : '0'); |
270 | 0 | } |
271 | 0 | } |
272 | 0 | } |
273 | | |
274 | | #ifdef ENABLE_OPENSSL |
275 | | #include <openssl/objects.h> |
276 | | |
277 | | static void openssl_print_object_sn(const char *s) |
278 | 0 | { |
279 | 0 | ASN1_OBJECT *obj = OBJ_txt2obj(s, 0); |
280 | 0 | if (obj) { |
281 | 0 | int nid = OBJ_obj2nid(obj); |
282 | 0 | if (nid != NID_undef) { |
283 | 0 | printf(", %s", OBJ_nid2sn(nid)); |
284 | 0 | } |
285 | 0 | ASN1_OBJECT_free(obj); |
286 | 0 | } |
287 | 0 | } |
288 | | #else |
289 | | static void openssl_print_object_sn(const char *s) |
290 | | { |
291 | | } |
292 | | #endif |
293 | | |
294 | | static void sc_asn1_print_object_id(const u8 * buf, size_t buflen) |
295 | 0 | { |
296 | 0 | struct sc_object_id oid; |
297 | 0 | const char *sbuf; |
298 | |
|
299 | 0 | if (sc_asn1_decode_object_id(buf, buflen, &oid)) { |
300 | 0 | printf("decode error"); |
301 | 0 | return; |
302 | 0 | } |
303 | | |
304 | 0 | sbuf = sc_dump_oid(&oid); |
305 | 0 | printf(" %s", sbuf); |
306 | 0 | openssl_print_object_sn(sbuf); |
307 | 0 | } |
308 | | |
309 | | static void sc_asn1_print_utctime(const u8 * buf, size_t buflen) |
310 | 0 | { |
311 | 0 | if (buflen < 8) { |
312 | 0 | printf("Error in decoding.\n"); |
313 | 0 | return; |
314 | 0 | } |
315 | | |
316 | 0 | print_ascii(buf, 2); /* YY */ |
317 | 0 | putchar('-'); |
318 | 0 | print_ascii(buf+2, 2); /* MM */ |
319 | 0 | putchar('-'); |
320 | 0 | print_ascii(buf+4, 2); /* DD */ |
321 | 0 | putchar(' '); |
322 | 0 | print_ascii(buf+6, 2); /* hh */ |
323 | 0 | buf += 8; |
324 | 0 | buflen -= 8; |
325 | 0 | if (buflen >= 2 && isdigit(buf[0]) && isdigit(buf[1])) { |
326 | 0 | putchar(':'); |
327 | 0 | print_ascii(buf, 2); /* mm */ |
328 | 0 | buf += 2; |
329 | 0 | buflen -= 2; |
330 | 0 | } |
331 | 0 | if (buflen >= 2 && isdigit(buf[0]) && isdigit(buf[1])) { |
332 | 0 | putchar(':'); |
333 | 0 | print_ascii(buf, 2); /* ss */ |
334 | 0 | buf += 2; |
335 | 0 | buflen -= 2; |
336 | 0 | } |
337 | 0 | if (buflen >= 4 && '.' == buf[0]) { |
338 | 0 | print_ascii(buf, 4); /* fff */ |
339 | 0 | buf += 4; |
340 | 0 | buflen -= 4; |
341 | 0 | } |
342 | |
|
343 | 0 | if (buflen >= 1 && 'Z' == buf[0]) { |
344 | 0 | printf(" UTC"); |
345 | 0 | } else if (buflen >= 5 && ('-' == buf[0] || '+' == buf[0])) { |
346 | 0 | putchar(' '); |
347 | 0 | print_ascii(buf, 3); /* +/-hh */ |
348 | 0 | putchar(':'); |
349 | 0 | print_ascii(buf+3, 2); /* mm */ |
350 | 0 | } |
351 | 0 | } |
352 | | |
353 | | static void sc_asn1_print_generalizedtime(const u8 * buf, size_t buflen) |
354 | 0 | { |
355 | 0 | if (buflen < 8) { |
356 | 0 | printf("Error in decoding.\n"); |
357 | 0 | return; |
358 | 0 | } |
359 | | |
360 | 0 | print_ascii(buf, 2); |
361 | 0 | sc_asn1_print_utctime(buf + 2, buflen - 2); |
362 | 0 | } |
363 | | |
364 | | static void print_tags_recursive(const u8 * buf0, const u8 * buf, |
365 | | size_t buflen, size_t depth) |
366 | 0 | { |
367 | 0 | int r; |
368 | 0 | size_t i; |
369 | 0 | size_t bytesleft = buflen; |
370 | 0 | const char *classes[4] = { |
371 | 0 | "Universal", |
372 | 0 | "Application", |
373 | 0 | "Context", |
374 | 0 | "Private" |
375 | 0 | }; |
376 | 0 | const u8 *p = buf; |
377 | |
|
378 | 0 | while (bytesleft >= 2) { |
379 | 0 | unsigned int cla = 0, tag = 0; |
380 | 0 | size_t hlen; |
381 | 0 | const u8 *tagp = p; |
382 | 0 | size_t len; |
383 | |
|
384 | 0 | r = sc_asn1_read_tag(&tagp, bytesleft, &cla, &tag, &len); |
385 | 0 | if (r != SC_SUCCESS || (tagp == NULL && tag != SC_ASN1_TAG_EOC)) { |
386 | 0 | printf("Error in decoding.\n"); |
387 | 0 | return; |
388 | 0 | } |
389 | 0 | hlen = tagp - p; |
390 | 0 | if (cla == 0 && tag == 0) { |
391 | 0 | printf("Zero tag, finishing\n"); |
392 | 0 | break; |
393 | 0 | } |
394 | 0 | print_indent(depth); |
395 | | /* let i be the length of the tag in bytes */ |
396 | 0 | for (i = 1; i < sizeof tag - 1; i++) { |
397 | 0 | if (!(tag >> 8*i)) |
398 | 0 | break; |
399 | 0 | } |
400 | 0 | printf("%02X", cla<<(i-1)*8 | tag); |
401 | |
|
402 | 0 | if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_UNIVERSAL) { |
403 | 0 | printf(" %s", tag2str(tag)); |
404 | 0 | } else { |
405 | 0 | printf(" %s %-2u", |
406 | 0 | classes[cla >> 6], |
407 | 0 | i == 1 ? tag & SC_ASN1_TAG_PRIMITIVE : tag & (((unsigned int) ~0) >> (i-1)*8)); |
408 | 0 | } |
409 | 0 | if (!((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_UNIVERSAL |
410 | 0 | && tag == SC_ASN1_TAG_NULL && len == 0)) { |
411 | 0 | printf(" (%"SC_FORMAT_LEN_SIZE_T"u byte%s)", |
412 | 0 | len, |
413 | 0 | len != 1 ? "s" : ""); |
414 | 0 | } |
415 | |
|
416 | 0 | if (len + hlen > bytesleft) { |
417 | 0 | printf(" Illegal length!\n"); |
418 | 0 | return; |
419 | 0 | } |
420 | 0 | p += hlen + len; |
421 | 0 | bytesleft -= hlen + len; |
422 | |
|
423 | 0 | if (cla & SC_ASN1_TAG_CONSTRUCTED) { |
424 | 0 | putchar('\n'); |
425 | 0 | print_tags_recursive(buf0, tagp, len, depth + 2*i + 1); |
426 | 0 | continue; |
427 | 0 | } |
428 | | |
429 | 0 | switch (tag) { |
430 | 0 | case SC_ASN1_TAG_BIT_STRING: |
431 | 0 | printf(": "); |
432 | 0 | sc_asn1_print_bit_string(tagp, len, depth + 2*i + 1); |
433 | 0 | break; |
434 | 0 | case SC_ASN1_TAG_OCTET_STRING: |
435 | 0 | sc_asn1_print_octet_string(tagp, len, depth + 2*i + 1); |
436 | 0 | break; |
437 | 0 | case SC_ASN1_TAG_OBJECT: |
438 | 0 | printf(": "); |
439 | 0 | sc_asn1_print_object_id(tagp, len); |
440 | 0 | break; |
441 | 0 | case SC_ASN1_TAG_INTEGER: |
442 | 0 | case SC_ASN1_TAG_ENUMERATED: |
443 | 0 | printf(": "); |
444 | 0 | sc_asn1_print_integer(tagp, len); |
445 | 0 | break; |
446 | 0 | case SC_ASN1_TAG_IA5STRING: |
447 | 0 | case SC_ASN1_TAG_PRINTABLESTRING: |
448 | 0 | case SC_ASN1_TAG_T61STRING: |
449 | 0 | case SC_ASN1_TAG_UTF8STRING: |
450 | 0 | printf(": "); |
451 | 0 | sc_asn1_print_utf8string(tagp, len); |
452 | 0 | break; |
453 | 0 | case SC_ASN1_TAG_BOOLEAN: |
454 | 0 | printf(": "); |
455 | 0 | sc_asn1_print_boolean(tagp, len); |
456 | 0 | break; |
457 | 0 | case SC_ASN1_GENERALIZEDTIME: |
458 | 0 | printf(": "); |
459 | 0 | sc_asn1_print_generalizedtime(tagp, len); |
460 | 0 | break; |
461 | 0 | case SC_ASN1_UTCTIME: |
462 | 0 | printf(": "); |
463 | 0 | sc_asn1_print_utctime(tagp, len); |
464 | 0 | break; |
465 | 0 | } |
466 | | |
467 | 0 | if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_APPLICATION) { |
468 | 0 | print_hex(tagp, len, depth + 2*i + 1); |
469 | 0 | } |
470 | |
|
471 | 0 | if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_CONTEXT) { |
472 | 0 | print_hex(tagp, len, depth + 2*i + 1); |
473 | 0 | } |
474 | |
|
475 | 0 | putchar('\n'); |
476 | 0 | } |
477 | 0 | } |
478 | | |
479 | | void sc_asn1_print_tags(const u8 * buf, size_t buflen) |
480 | 0 | { |
481 | 0 | print_tags_recursive(buf, buf, buflen, 0); |
482 | 0 | } |
483 | | |
484 | | const u8 *sc_asn1_find_tag(sc_context_t *ctx, const u8 * buf, |
485 | | size_t buflen, unsigned int tag_in, size_t *taglen_in) |
486 | 6.60k | { |
487 | 6.60k | size_t left = buflen, taglen; |
488 | 6.60k | const u8 *p = buf; |
489 | | |
490 | 6.60k | *taglen_in = 0; |
491 | 10.9k | while (left >= 2) { |
492 | 9.68k | unsigned int cla = 0, tag, mask = 0xff00; |
493 | | |
494 | 9.68k | buf = p; |
495 | | /* read a tag */ |
496 | 9.68k | if (sc_asn1_read_tag(&p, left, &cla, &tag, &taglen) != SC_SUCCESS |
497 | 9.68k | || p == NULL) |
498 | 1.21k | return NULL; |
499 | | |
500 | 8.46k | left -= (p - buf); |
501 | | /* we need to shift the class byte to the leftmost |
502 | | * byte of the tag */ |
503 | 9.44k | while ((tag & mask) != 0) { |
504 | 981 | cla <<= 8; |
505 | 981 | mask <<= 8; |
506 | 981 | } |
507 | | /* compare the read tag with the given tag */ |
508 | 8.46k | if ((tag | cla) == tag_in) { |
509 | | /* we have a match => return length and value part */ |
510 | 4.12k | if (taglen > left) |
511 | 0 | return NULL; |
512 | 4.12k | *taglen_in = taglen; |
513 | 4.12k | return p; |
514 | 4.12k | } |
515 | | /* otherwise continue reading tags */ |
516 | 4.33k | left -= taglen; |
517 | 4.33k | p += taglen; |
518 | 4.33k | } |
519 | 1.26k | return NULL; |
520 | 6.60k | } |
521 | | |
522 | | const u8 *sc_asn1_skip_tag(sc_context_t *ctx, const u8 ** buf, size_t *buflen, |
523 | | unsigned int tag_in, size_t *taglen_out) |
524 | 35.2k | { |
525 | 35.2k | const u8 *p = *buf; |
526 | 35.2k | size_t len = *buflen, taglen; |
527 | 35.2k | unsigned int cla = 0, tag; |
528 | | |
529 | 35.2k | if (sc_asn1_read_tag((const u8 **) &p, len, &cla, &tag, &taglen) != SC_SUCCESS |
530 | 35.2k | || p == NULL) |
531 | 14.9k | return NULL; |
532 | 20.2k | switch (cla & 0xC0) { |
533 | 645 | case SC_ASN1_TAG_UNIVERSAL: |
534 | 645 | if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_UNI) |
535 | 645 | return NULL; |
536 | 0 | break; |
537 | 4.21k | case SC_ASN1_TAG_APPLICATION: |
538 | 4.21k | if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_APP) |
539 | 4.21k | return NULL; |
540 | 0 | break; |
541 | 15.2k | case SC_ASN1_TAG_CONTEXT: |
542 | 15.2k | if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_CTX) |
543 | 0 | return NULL; |
544 | 15.2k | break; |
545 | 15.2k | case SC_ASN1_TAG_PRIVATE: |
546 | 149 | if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_PRV) |
547 | 149 | return NULL; |
548 | 0 | break; |
549 | 20.2k | } |
550 | 15.2k | if (cla & SC_ASN1_TAG_CONSTRUCTED) { |
551 | 283 | if ((tag_in & SC_ASN1_CONS) == 0) |
552 | 283 | return NULL; |
553 | 283 | } else |
554 | 14.9k | if (tag_in & SC_ASN1_CONS) |
555 | 0 | return NULL; |
556 | 14.9k | if ((tag_in & SC_ASN1_TAG_MASK) != tag) |
557 | 6.90k | return NULL; |
558 | 8.06k | len -= (p - *buf); /* header size */ |
559 | 8.06k | if (taglen > len) { |
560 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, |
561 | 0 | "too long ASN.1 object (size %"SC_FORMAT_LEN_SIZE_T"u while only %"SC_FORMAT_LEN_SIZE_T"u available)\n", |
562 | 0 | taglen, len); |
563 | 0 | return NULL; |
564 | 0 | } |
565 | 8.06k | *buflen -= (p - *buf) + taglen; |
566 | 8.06k | *buf = p + taglen; /* point to next tag */ |
567 | 8.06k | *taglen_out = taglen; |
568 | 8.06k | return p; |
569 | 8.06k | } |
570 | | |
571 | | const u8 *sc_asn1_verify_tag(sc_context_t *ctx, const u8 * buf, size_t buflen, |
572 | | unsigned int tag_in, size_t *taglen_out) |
573 | 0 | { |
574 | 0 | return sc_asn1_skip_tag(ctx, &buf, &buflen, tag_in, taglen_out); |
575 | 0 | } |
576 | | |
577 | | static int decode_bit_string(const u8 * inbuf, size_t inlen, void *outbuf, |
578 | | size_t outlen, int invert, const int strict) |
579 | 0 | { |
580 | 0 | const u8 *in = inbuf; |
581 | 0 | u8 *out = (u8 *) outbuf; |
582 | 0 | int i, count = 0; |
583 | 0 | int zero_bits; |
584 | 0 | size_t octets_left; |
585 | |
|
586 | 0 | if (inlen < 1) |
587 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
588 | | |
589 | | /* The formatting is only enforced by SHALL keyword so we should accept |
590 | | * by default also non-strict values. */ |
591 | 0 | if (strict) { |
592 | | /* 8.6.2.3 If the bitstring is empty, there shall be no |
593 | | * subsequent octets,and the initial octet shall be zero. */ |
594 | 0 | if (inlen == 1 && *in != 0) |
595 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
596 | | /* ITU-T Rec. X.690 8.6.2.2: The number shall be in the range zero to seven. */ |
597 | 0 | if ((*in & ~0x07) != 0) |
598 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
599 | 0 | } |
600 | | |
601 | 0 | memset(outbuf, 0, outlen); |
602 | 0 | zero_bits = *in & 0x07; |
603 | 0 | in++; |
604 | 0 | octets_left = inlen - 1; |
605 | 0 | if (outlen < octets_left) |
606 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
607 | | |
608 | 0 | while (octets_left) { |
609 | | /* 1st octet of input: ABCDEFGH, where A is the MSB */ |
610 | | /* 1st octet of output: HGFEDCBA, where A is the LSB */ |
611 | | /* first bit in bit string is the LSB in first resulting octet */ |
612 | 0 | int bits_to_go; |
613 | |
|
614 | 0 | *out = 0; |
615 | 0 | if (octets_left == 1 && zero_bits > 0) { |
616 | 0 | bits_to_go = 8 - zero_bits; |
617 | | /* Verify the padding is zero bits */ |
618 | 0 | if (*in & (1 << (zero_bits-1))) { |
619 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
620 | 0 | } |
621 | 0 | } else |
622 | 0 | bits_to_go = 8; |
623 | 0 | if (invert) |
624 | 0 | for (i = 0; i < bits_to_go; i++) { |
625 | 0 | *out |= ((*in >> (7 - i)) & 1) << i; |
626 | 0 | } |
627 | 0 | else { |
628 | 0 | *out = *in; |
629 | 0 | } |
630 | 0 | out++; |
631 | 0 | in++; |
632 | 0 | octets_left--; |
633 | 0 | count++; |
634 | 0 | } |
635 | 0 | return (count * 8) - zero_bits; |
636 | 0 | } |
637 | | |
638 | | int sc_asn1_decode_bit_string(const u8 * inbuf, size_t inlen, |
639 | | void *outbuf, size_t outlen, const int strict) |
640 | 0 | { |
641 | 0 | return decode_bit_string(inbuf, inlen, outbuf, outlen, 1, strict); |
642 | 0 | } |
643 | | |
644 | | int sc_asn1_decode_bit_string_ni(const u8 * inbuf, size_t inlen, |
645 | | void *outbuf, size_t outlen, const int strict) |
646 | 0 | { |
647 | 0 | return decode_bit_string(inbuf, inlen, outbuf, outlen, 0, strict); |
648 | 0 | } |
649 | | |
650 | | static int encode_bit_string(const u8 * inbuf, size_t bits_left, u8 **outbuf, |
651 | | size_t *outlen, int invert) |
652 | 0 | { |
653 | 0 | const u8 *in = inbuf; |
654 | 0 | u8 *out; |
655 | 0 | size_t bytes, skipped = 0; |
656 | |
|
657 | 0 | bytes = BYTES4BITS(bits_left) + 1; |
658 | 0 | *outbuf = out = malloc(bytes); |
659 | 0 | if (out == NULL) |
660 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
661 | 0 | *outlen = bytes; |
662 | 0 | out += 1; |
663 | 0 | while (bits_left) { |
664 | 0 | size_t i, bits_to_go = 8; |
665 | |
|
666 | 0 | *out = 0; |
667 | 0 | if (bits_left < 8) { |
668 | 0 | bits_to_go = bits_left; |
669 | 0 | skipped = 8 - bits_left; |
670 | 0 | } |
671 | 0 | if (invert) { |
672 | 0 | for (i = 0; i < bits_to_go; i++) |
673 | 0 | *out |= ((*in >> i) & 1) << (7 - i); |
674 | 0 | } else { |
675 | 0 | *out = *in; |
676 | 0 | if (bits_left < 8) |
677 | 0 | return SC_ERROR_NOT_SUPPORTED; /* FIXME */ |
678 | 0 | } |
679 | 0 | bits_left -= bits_to_go; |
680 | 0 | out++, in++; |
681 | 0 | } |
682 | 0 | out = *outbuf; |
683 | 0 | out[0] = skipped; |
684 | 0 | return 0; |
685 | 0 | } |
686 | | |
687 | | /* |
688 | | * Bitfields are just bit strings, stored in an unsigned int |
689 | | * (taking endianness into account) |
690 | | */ |
691 | | static int decode_bit_field(const u8 * inbuf, size_t inlen, void *outbuf, size_t outlen, const int strict) |
692 | 0 | { |
693 | 0 | u8 data[sizeof(unsigned int)]; |
694 | 0 | unsigned int field = 0; |
695 | 0 | int i, n; |
696 | |
|
697 | 0 | if (outlen != sizeof(data)) |
698 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
699 | | |
700 | 0 | n = decode_bit_string(inbuf, inlen, data, sizeof(data), 1, strict); |
701 | 0 | if (n < 0) |
702 | 0 | return n; |
703 | | |
704 | 0 | for (i = 0; i < n; i += 8) { |
705 | 0 | field |= ((unsigned int) data[i/8] << i); |
706 | 0 | } |
707 | 0 | memcpy(outbuf, &field, outlen); |
708 | 0 | return 0; |
709 | 0 | } |
710 | | |
711 | | static int encode_bit_field(const u8 *inbuf, size_t inlen, |
712 | | u8 **outbuf, size_t *outlen) |
713 | 0 | { |
714 | 0 | u8 data[sizeof(unsigned int)]; |
715 | 0 | unsigned int field = 0; |
716 | 0 | size_t i, bits; |
717 | |
|
718 | 0 | if (inlen != sizeof(data)) |
719 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
720 | | |
721 | | /* count the bits */ |
722 | 0 | memcpy(&field, inbuf, inlen); |
723 | 0 | for (bits = 0; field; bits++) |
724 | 0 | field >>= 1; |
725 | |
|
726 | 0 | memcpy(&field, inbuf, inlen); |
727 | 0 | for (i = 0; i < bits; i += 8) |
728 | 0 | data[i/8] = field >> i; |
729 | |
|
730 | 0 | return encode_bit_string(data, bits, outbuf, outlen, 1); |
731 | 0 | } |
732 | | |
733 | | int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out, int strict) |
734 | 0 | { |
735 | 0 | int a = 0, is_negative = 0; |
736 | 0 | size_t i = 0; |
737 | |
|
738 | 0 | if (inlen == 0) { |
739 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
740 | 0 | } |
741 | 0 | if (inlen > sizeof(int)) { |
742 | 0 | return SC_ERROR_NOT_SUPPORTED; |
743 | 0 | } |
744 | 0 | if (inbuf[0] & 0x80) { |
745 | 0 | if (strict && inlen > 1 && inbuf[0] == 0xff && (inbuf[1] & 0x80)) { |
746 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
747 | 0 | } |
748 | 0 | is_negative = 1; |
749 | 0 | a |= 0xff^(*inbuf++); |
750 | 0 | i = 1; |
751 | 0 | } else { |
752 | 0 | if (strict && inlen > 1 && inbuf[0] == 0x00 && (inbuf[1] & 0x80) == 0) { |
753 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
754 | 0 | } |
755 | 0 | } |
756 | 0 | for (; i < inlen; i++) { |
757 | 0 | if (a > (INT_MAX >> 8) || a < (INT_MIN + (1<<8))) { |
758 | 0 | return SC_ERROR_NOT_SUPPORTED; |
759 | 0 | } |
760 | 0 | a <<= 8; |
761 | 0 | if (is_negative) { |
762 | 0 | a |= 0xff^(*inbuf++); |
763 | 0 | } else { |
764 | 0 | a |= *inbuf++; |
765 | 0 | } |
766 | 0 | } |
767 | 0 | if (is_negative) { |
768 | | /* Calculate Two's complement from previously positive number */ |
769 | 0 | a = (-1 * a) - 1; |
770 | 0 | } |
771 | 0 | *out = a; |
772 | 0 | return 0; |
773 | 0 | } |
774 | | |
775 | | static int asn1_encode_integer(int in, u8 ** obj, size_t * objsize) |
776 | 0 | { |
777 | 0 | int i = sizeof(in) * 8, skip_zero, skip_sign; |
778 | 0 | u8 *p, b; |
779 | |
|
780 | 0 | if (in < 0) |
781 | 0 | { |
782 | 0 | skip_sign = 1; |
783 | 0 | skip_zero= 0; |
784 | 0 | } |
785 | 0 | else |
786 | 0 | { |
787 | 0 | skip_sign = 0; |
788 | 0 | skip_zero= 1; |
789 | 0 | } |
790 | 0 | *obj = p = malloc(sizeof(in)+1); |
791 | 0 | if (*obj == NULL) |
792 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
793 | 0 | do { |
794 | 0 | i -= 8; |
795 | 0 | b = in >> i; |
796 | 0 | if (skip_sign) |
797 | 0 | { |
798 | 0 | if (b != 0xff) |
799 | 0 | skip_sign = 0; |
800 | 0 | if (b & 0x80) |
801 | 0 | { |
802 | 0 | *p = b; |
803 | 0 | if (0xff == b) |
804 | 0 | continue; |
805 | 0 | } |
806 | 0 | else |
807 | 0 | { |
808 | 0 | p++; |
809 | 0 | skip_sign = 0; |
810 | 0 | } |
811 | 0 | } |
812 | 0 | if (b == 0 && skip_zero) |
813 | 0 | continue; |
814 | 0 | if (skip_zero) { |
815 | 0 | skip_zero = 0; |
816 | | /* prepend 0x00 if MSb is 1 and integer positive */ |
817 | 0 | if ((b & 0x80) != 0 && in > 0) |
818 | 0 | *p++ = 0; |
819 | 0 | } |
820 | 0 | *p++ = b; |
821 | 0 | } while (i > 0); |
822 | 0 | if (skip_sign) |
823 | 0 | p++; |
824 | 0 | *objsize = p - *obj; |
825 | 0 | if (*objsize == 0) { |
826 | 0 | *objsize = 1; |
827 | 0 | (*obj)[0] = 0; |
828 | 0 | } |
829 | 0 | return 0; |
830 | 0 | } |
831 | | |
832 | | int |
833 | | sc_asn1_decode_object_id(const u8 *inbuf, size_t inlen, struct sc_object_id *id) |
834 | 0 | { |
835 | 0 | int large_second_octet = 0; |
836 | 0 | unsigned int a = 0; |
837 | 0 | const u8 *p = inbuf; |
838 | 0 | int *octet; |
839 | |
|
840 | 0 | if (inlen == 0 || inbuf == NULL || id == NULL) |
841 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
842 | | |
843 | 0 | sc_init_oid(id); |
844 | 0 | octet = id->value; |
845 | | |
846 | | /* The first octet can be 0, 1 or 2 and is derived from the first byte */ |
847 | 0 | a = MIN(*p / 40, 2); |
848 | 0 | *octet++ = a; |
849 | | |
850 | | /* The second octet fits here if the previous was 0 or 1 and second one is smaller than 40. |
851 | | * for the value 2 we can go up to 47. Otherwise the first bit needs to be set |
852 | | * and we continue reading further */ |
853 | 0 | if ((*p & 0x80) == 0) { |
854 | 0 | *octet++ = *p - (a * 40); |
855 | 0 | inlen--; |
856 | 0 | } else { |
857 | 0 | large_second_octet = 1; |
858 | 0 | } |
859 | |
|
860 | 0 | while (inlen) { |
861 | 0 | if (!large_second_octet) |
862 | 0 | p++; |
863 | | /* This signalizes empty most significant bits, which means |
864 | | * the unsigned integer encoding is not minimal */ |
865 | 0 | if (*p == 0x80) { |
866 | 0 | sc_init_oid(id); |
867 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
868 | 0 | } |
869 | | /* Use unsigned type here so we can process the whole INT range. |
870 | | * Values can not be negative */ |
871 | 0 | a = *p & 0x7F; |
872 | 0 | inlen--; |
873 | 0 | while (inlen && *p & 0x80) { |
874 | | /* Limit the OID values to int size and do not overflow */ |
875 | 0 | if (a > (UINT_MAX>>7)) { |
876 | 0 | sc_init_oid(id); |
877 | 0 | return SC_ERROR_NOT_SUPPORTED; |
878 | 0 | } |
879 | 0 | p++; |
880 | 0 | a <<= 7; |
881 | 0 | a |= *p & 0x7F; |
882 | 0 | inlen--; |
883 | 0 | } |
884 | 0 | if (*p & 0x80) { |
885 | | /* We dropped out from previous cycle on the end of |
886 | | * data while still expecting continuation of value */ |
887 | 0 | sc_init_oid(id); |
888 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
889 | 0 | } |
890 | 0 | if (large_second_octet) { |
891 | 0 | a -= (2 * 40); |
892 | 0 | } |
893 | 0 | if (a > INT_MAX) { |
894 | 0 | sc_init_oid(id); |
895 | 0 | return SC_ERROR_NOT_SUPPORTED; |
896 | 0 | } |
897 | 0 | *octet++ = a; |
898 | 0 | if (octet - id->value >= SC_MAX_OBJECT_ID_OCTETS) { |
899 | 0 | sc_init_oid(id); |
900 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
901 | 0 | } |
902 | 0 | large_second_octet = 0; |
903 | 0 | } |
904 | | |
905 | 0 | return 0; |
906 | 0 | } |
907 | | |
908 | | int |
909 | | sc_asn1_encode_object_id(u8 **buf, size_t *buflen, const struct sc_object_id *id) |
910 | 2.92k | { |
911 | 2.92k | u8 temp[SC_MAX_OBJECT_ID_OCTETS*5], *p = temp; |
912 | 2.92k | int i; |
913 | | |
914 | 2.92k | if (!buflen || !id) |
915 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
916 | | |
917 | | /* an OID must have at least two components */ |
918 | 2.92k | if (id->value[0] == -1 || id->value[1] == -1) |
919 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
920 | | |
921 | 20.7k | for (i = 0; i < SC_MAX_OBJECT_ID_OCTETS; i++) { |
922 | 20.7k | unsigned int k, shift; |
923 | | |
924 | 20.7k | if (id->value[i] == -1) |
925 | 2.92k | break; |
926 | | |
927 | 17.8k | k = id->value[i]; |
928 | 17.8k | switch (i) { |
929 | 2.92k | case 0: |
930 | 2.92k | if (k > 2) |
931 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
932 | 2.92k | *p = k * 40; |
933 | 2.92k | break; |
934 | 2.92k | case 1: |
935 | 2.92k | if (k > 39 && id->value[0] < 2) { |
936 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
937 | 0 | } |
938 | | /* We can encode larger IDs to multiple bytes |
939 | | * similarly as the following IDs */ |
940 | 2.92k | k += *p; |
941 | | /* fall through */ |
942 | 14.8k | default: |
943 | 14.8k | shift = 28; |
944 | 69.8k | while (shift && (k >> shift) == 0) |
945 | 55.0k | shift -= 7; |
946 | 19.3k | while (shift) { |
947 | 4.49k | *p++ = 0x80 | ((k >> shift) & 0x7f); |
948 | 4.49k | shift -= 7; |
949 | 4.49k | } |
950 | 14.8k | *p++ = k & 0x7F; |
951 | 14.8k | break; |
952 | 17.8k | } |
953 | 17.8k | } |
954 | | |
955 | 2.92k | *buflen = p - temp; |
956 | | |
957 | 2.92k | if (buf) { |
958 | 2.92k | *buf = malloc(*buflen); |
959 | 2.92k | if (!*buf) |
960 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
961 | 2.92k | memcpy(*buf, temp, *buflen); |
962 | 2.92k | } |
963 | 2.92k | return 0; |
964 | 2.92k | } |
965 | | |
966 | | static int sc_asn1_decode_utf8string(const u8 *inbuf, size_t inlen, |
967 | | u8 *out, size_t *outlen) |
968 | 0 | { |
969 | 0 | if (inlen+1 > *outlen) |
970 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
971 | 0 | *outlen = inlen+1; |
972 | 0 | memcpy(out, inbuf, inlen); |
973 | 0 | out[inlen] = 0; |
974 | 0 | return 0; |
975 | 0 | } |
976 | | |
977 | | /* |
978 | | * This assumes the tag is already encoded |
979 | | */ |
980 | | int sc_asn1_put_tag(unsigned int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 **ptr) |
981 | 43.7k | { |
982 | 43.7k | size_t c = 0; |
983 | 43.7k | unsigned int tag_len, ii; |
984 | 43.7k | u8 *p = out; |
985 | 43.7k | u8 tag_char[4] = {0, 0, 0, 0}; |
986 | | |
987 | | /* Check tag */ |
988 | 43.7k | if (tag == 0 || tag > 0xFFFFFFFF) { |
989 | | /* A tag of 0x00 is not valid and at most 4-byte tag names are supported. */ |
990 | 0 | return SC_ERROR_INVALID_DATA; |
991 | 0 | } |
992 | 87.5k | for (tag_len = 0; tag; tag >>= 8) { |
993 | | /* Note: tag char will be reversed order. */ |
994 | 43.7k | tag_char[tag_len++] = tag & 0xFF; |
995 | 43.7k | } |
996 | | |
997 | 43.7k | if (tag_len > 1) { |
998 | 0 | if ((tag_char[tag_len - 1] & SC_ASN1_TAG_PRIMITIVE) != SC_ASN1_TAG_ESCAPE_MARKER) { |
999 | | /* First byte is not escape marker. */ |
1000 | 0 | return SC_ERROR_INVALID_DATA; |
1001 | 0 | } |
1002 | 0 | for (ii = 1; ii < tag_len - 1; ii++) { |
1003 | 0 | if ((tag_char[ii] & 0x80) != 0x80) { |
1004 | | /* MS bit is not 'one'. */ |
1005 | 0 | return SC_ERROR_INVALID_DATA; |
1006 | 0 | } |
1007 | 0 | } |
1008 | 0 | if ((tag_char[0] & 0x80) != 0x00) { |
1009 | | /* MS bit of the last byte is not 'zero'. */ |
1010 | 0 | return SC_ERROR_INVALID_DATA; |
1011 | 0 | } |
1012 | 0 | } |
1013 | | |
1014 | | /* Calculate the number of additional bytes necessary to encode the length. */ |
1015 | | /* c+1 is the size of the length field. */ |
1016 | 43.7k | if (datalen > 127) { |
1017 | 66 | c = 1; |
1018 | 78 | while (datalen >> (c << 3)) |
1019 | 12 | c++; |
1020 | 66 | } |
1021 | 43.7k | if (outlen == 0 || out == NULL) { |
1022 | | /* Caller only asks for the length that would be written. */ |
1023 | 196 | return (int)(tag_len + (c + 1) + datalen); |
1024 | 196 | } |
1025 | | /* We will write the tag, so check the length. */ |
1026 | 43.5k | if (outlen < tag_len + (c+1) + datalen) |
1027 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
1028 | 87.1k | for (ii=0;ii<tag_len;ii++) |
1029 | 43.5k | *p++ = tag_char[tag_len - ii - 1]; |
1030 | | |
1031 | 43.5k | if (c > 0) { |
1032 | 33 | *p++ = 0x80 | c; |
1033 | 72 | while (c--) |
1034 | 39 | *p++ = (datalen >> (c << 3)) & 0xFF; |
1035 | 33 | } |
1036 | 43.5k | else { |
1037 | 43.5k | *p++ = datalen & 0x7F; |
1038 | 43.5k | } |
1039 | 43.5k | if(data && datalen > 0) { |
1040 | 43.4k | memcpy(p, data, datalen); |
1041 | 43.4k | p += datalen; |
1042 | 43.4k | } |
1043 | 43.5k | if (ptr != NULL) |
1044 | 43.5k | *ptr = p; |
1045 | 43.5k | return 0; |
1046 | 43.5k | } |
1047 | | |
1048 | | int sc_asn1_write_element(sc_context_t *ctx, unsigned int tag, |
1049 | | const u8 * data, size_t datalen, u8 ** out, size_t * outlen) |
1050 | 0 | { |
1051 | 0 | return asn1_write_element(ctx, tag, data, datalen, out, outlen); |
1052 | 0 | } |
1053 | | |
1054 | | static int asn1_write_element(sc_context_t *ctx, unsigned int tag, |
1055 | | const u8 * data, size_t datalen, u8 ** out, size_t * outlen) |
1056 | 2.92k | { |
1057 | 2.92k | unsigned char t; |
1058 | 2.92k | unsigned char *buf, *p; |
1059 | 2.92k | int c = 0; |
1060 | 2.92k | unsigned short_tag; |
1061 | 2.92k | unsigned char tag_char[3] = {0, 0, 0}; |
1062 | 2.92k | size_t tag_len, ii; |
1063 | | |
1064 | 2.92k | short_tag = tag & SC_ASN1_TAG_MASK; |
1065 | 5.85k | for (tag_len = 0; short_tag >> (8 * tag_len); tag_len++) |
1066 | 2.92k | tag_char[tag_len] = (short_tag >> (8 * tag_len)) & 0xFF; |
1067 | 2.92k | if (!tag_len) |
1068 | 0 | tag_len = 1; |
1069 | | |
1070 | 2.92k | if (tag_len > 1) { |
1071 | 0 | if ((tag_char[tag_len - 1] & SC_ASN1_TAG_PRIMITIVE) != SC_ASN1_TAG_ESCAPE_MARKER) |
1072 | 0 | SC_TEST_RET(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_INVALID_DATA, "First byte of the long tag is not 'escape marker'"); |
1073 | | |
1074 | 0 | for (ii = 1; ii < tag_len - 1; ii++) |
1075 | 0 | if (!(tag_char[ii] & 0x80)) |
1076 | 0 | SC_TEST_RET(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_INVALID_DATA, "MS bit expected to be 'one'"); |
1077 | | |
1078 | 0 | if (tag_char[0] & 0x80) |
1079 | 0 | SC_TEST_RET(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_INVALID_DATA, "MS bit of the last byte expected to be 'zero'"); |
1080 | 0 | } |
1081 | | |
1082 | 2.92k | t = tag_char[tag_len - 1] & 0x1F; |
1083 | | |
1084 | 2.92k | switch (tag & SC_ASN1_CLASS_MASK) { |
1085 | 2.92k | case SC_ASN1_UNI: |
1086 | 2.92k | break; |
1087 | 0 | case SC_ASN1_APP: |
1088 | 0 | t |= SC_ASN1_TAG_APPLICATION; |
1089 | 0 | break; |
1090 | 0 | case SC_ASN1_CTX: |
1091 | 0 | t |= SC_ASN1_TAG_CONTEXT; |
1092 | 0 | break; |
1093 | 0 | case SC_ASN1_PRV: |
1094 | 0 | t |= SC_ASN1_TAG_PRIVATE; |
1095 | 0 | break; |
1096 | 2.92k | } |
1097 | 2.92k | if (tag & SC_ASN1_CONS) |
1098 | 0 | t |= SC_ASN1_TAG_CONSTRUCTED; |
1099 | 2.92k | if (datalen > 127) { |
1100 | 0 | c = 1; |
1101 | 0 | while (datalen >> (c << 3)) |
1102 | 0 | c++; |
1103 | 0 | } |
1104 | | |
1105 | 2.92k | *outlen = tag_len + 1 + c + datalen; |
1106 | 2.92k | buf = malloc(*outlen); |
1107 | 2.92k | if (buf == NULL) |
1108 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_OUT_OF_MEMORY); |
1109 | | |
1110 | 2.92k | *out = p = buf; |
1111 | 2.92k | *p++ = t; |
1112 | 2.92k | for (ii=1;ii<tag_len;ii++) |
1113 | 0 | *p++ = tag_char[tag_len - ii - 1]; |
1114 | | |
1115 | 2.92k | if (c) { |
1116 | 0 | *p++ = 0x80 | c; |
1117 | 0 | while (c--) |
1118 | 0 | *p++ = (datalen >> (c << 3)) & 0xFF; |
1119 | 0 | } |
1120 | 2.92k | else { |
1121 | 2.92k | *p++ = datalen & 0x7F; |
1122 | 2.92k | } |
1123 | 2.92k | if (datalen && data) { |
1124 | 2.92k | memcpy(p, data, datalen); |
1125 | 2.92k | } |
1126 | | |
1127 | 2.92k | return SC_SUCCESS; |
1128 | 2.92k | } |
1129 | | |
1130 | | static const struct sc_asn1_entry c_asn1_path_ext[3] = { |
1131 | | { "aid", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 0x0F, 0, NULL, NULL }, |
1132 | | { "path", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, 0, NULL, NULL }, |
1133 | | { NULL, 0, 0, 0, NULL, NULL } |
1134 | | }; |
1135 | | static const struct sc_asn1_entry c_asn1_path[5] = { |
1136 | | { "path", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, |
1137 | | { "index", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, |
1138 | | { "length", SC_ASN1_INTEGER, SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL, NULL }, |
1139 | | /* For some multi-applications PKCS#15 card the ODF records can hold the references to |
1140 | | * the xDF files and objects placed elsewhere then under the application DF of the ODF itself. |
1141 | | * In such a case the 'path' ASN1 data includes also the ID of the target application (AID). |
1142 | | * This path extension do not make a part of PKCS#15 standard. |
1143 | | */ |
1144 | | { "pathExtended", SC_ASN1_STRUCT, SC_ASN1_CTX | 1 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1145 | | { NULL, 0, 0, 0, NULL, NULL } |
1146 | | }; |
1147 | | |
1148 | | static int asn1_decode_path(sc_context_t *ctx, const u8 *in, size_t len, |
1149 | | sc_path_t *path, int depth) |
1150 | 0 | { |
1151 | 0 | int idx, count, r; |
1152 | 0 | struct sc_asn1_entry asn1_path_ext[3], asn1_path[5]; |
1153 | 0 | unsigned char path_value[SC_MAX_PATH_SIZE], aid_value[SC_MAX_AID_SIZE]; |
1154 | 0 | size_t path_len = sizeof(path_value), aid_len = sizeof(aid_value); |
1155 | |
|
1156 | 0 | memset(path, 0, sizeof(struct sc_path)); |
1157 | |
|
1158 | 0 | sc_copy_asn1_entry(c_asn1_path_ext, asn1_path_ext); |
1159 | 0 | sc_copy_asn1_entry(c_asn1_path, asn1_path); |
1160 | |
|
1161 | 0 | sc_format_asn1_entry(asn1_path_ext + 0, aid_value, &aid_len, 0); |
1162 | 0 | sc_format_asn1_entry(asn1_path_ext + 1, path_value, &path_len, 0); |
1163 | |
|
1164 | 0 | sc_format_asn1_entry(asn1_path + 0, path_value, &path_len, 0); |
1165 | 0 | sc_format_asn1_entry(asn1_path + 1, &idx, NULL, 0); |
1166 | 0 | sc_format_asn1_entry(asn1_path + 2, &count, NULL, 0); |
1167 | 0 | sc_format_asn1_entry(asn1_path + 3, asn1_path_ext, NULL, 0); |
1168 | |
|
1169 | 0 | r = asn1_decode(ctx, asn1_path, in, len, NULL, NULL, 0, depth + 1); |
1170 | 0 | if (r) |
1171 | 0 | return r; |
1172 | | |
1173 | 0 | if (asn1_path[3].flags & SC_ASN1_PRESENT) { |
1174 | | /* extended path present: set 'path' and 'aid' */ |
1175 | 0 | memcpy(path->aid.value, aid_value, aid_len); |
1176 | 0 | path->aid.len = aid_len; |
1177 | |
|
1178 | 0 | memcpy(path->value, path_value, path_len); |
1179 | 0 | path->len = path_len; |
1180 | 0 | } |
1181 | 0 | else if (asn1_path[0].flags & SC_ASN1_PRESENT) { |
1182 | | /* path present: set 'path' */ |
1183 | 0 | memcpy(path->value, path_value, path_len); |
1184 | 0 | path->len = path_len; |
1185 | 0 | } |
1186 | 0 | else { |
1187 | | /* failed if both 'path' and 'pathExtended' are absent */ |
1188 | 0 | return SC_ERROR_ASN1_OBJECT_NOT_FOUND; |
1189 | 0 | } |
1190 | | |
1191 | 0 | if (path->len == 2) |
1192 | 0 | path->type = SC_PATH_TYPE_FILE_ID; |
1193 | 0 | else if (path->aid.len && path->len > 2) |
1194 | 0 | path->type = SC_PATH_TYPE_FROM_CURRENT; |
1195 | 0 | else |
1196 | 0 | path->type = SC_PATH_TYPE_PATH; |
1197 | |
|
1198 | 0 | if ((asn1_path[1].flags & SC_ASN1_PRESENT) && (asn1_path[2].flags & SC_ASN1_PRESENT)) { |
1199 | 0 | path->index = idx; |
1200 | 0 | path->count = count; |
1201 | 0 | } |
1202 | 0 | else { |
1203 | 0 | path->index = 0; |
1204 | 0 | path->count = -1; |
1205 | 0 | } |
1206 | |
|
1207 | 0 | return SC_SUCCESS; |
1208 | 0 | } |
1209 | | |
1210 | | static int asn1_encode_path(sc_context_t *ctx, const sc_path_t *path, |
1211 | | u8 **buf, size_t *bufsize, int depth, unsigned int parent_flags) |
1212 | 0 | { |
1213 | 0 | int r; |
1214 | 0 | struct sc_asn1_entry asn1_path[5]; |
1215 | 0 | sc_path_t tpath = *path; |
1216 | |
|
1217 | 0 | sc_copy_asn1_entry(c_asn1_path, asn1_path); |
1218 | 0 | sc_format_asn1_entry(asn1_path + 0, (void *) &tpath.value, (void *) &tpath.len, 1); |
1219 | |
|
1220 | 0 | asn1_path[0].flags |= parent_flags; |
1221 | 0 | if (path->count > 0) { |
1222 | 0 | sc_format_asn1_entry(asn1_path + 1, (void *) &tpath.index, NULL, 1); |
1223 | 0 | sc_format_asn1_entry(asn1_path + 2, (void *) &tpath.count, NULL, 1); |
1224 | 0 | } |
1225 | 0 | r = asn1_encode(ctx, asn1_path, buf, bufsize, depth + 1); |
1226 | 0 | return r; |
1227 | 0 | } |
1228 | | |
1229 | | |
1230 | | static const struct sc_asn1_entry c_asn1_se[2] = { |
1231 | | { "seInfo", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
1232 | | { NULL, 0, 0, 0, NULL, NULL } |
1233 | | }; |
1234 | | |
1235 | | static const struct sc_asn1_entry c_asn1_se_info[4] = { |
1236 | | { "se", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, |
1237 | | { "owner",SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, SC_ASN1_OPTIONAL, NULL, NULL }, |
1238 | | { "aid", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, |
1239 | | { NULL, 0, 0, 0, NULL, NULL } |
1240 | | }; |
1241 | | |
1242 | | static int asn1_decode_se_info(sc_context_t *ctx, const u8 *obj, size_t objlen, |
1243 | | sc_pkcs15_sec_env_info_t ***se, size_t *num, int depth) |
1244 | 0 | { |
1245 | 0 | struct sc_pkcs15_sec_env_info **ses; |
1246 | 0 | const unsigned char *ptr = obj; |
1247 | 0 | size_t idx, ptrlen = objlen; |
1248 | 0 | int ret; |
1249 | |
|
1250 | 0 | LOG_FUNC_CALLED(ctx); |
1251 | |
|
1252 | 0 | ses = calloc(SC_MAX_SE_NUM, sizeof(sc_pkcs15_sec_env_info_t *)); |
1253 | 0 | if (ses == NULL) { |
1254 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_OUT_OF_MEMORY); |
1255 | 0 | } |
1256 | | |
1257 | 0 | for (idx=0; idx < SC_MAX_SE_NUM && ptrlen; ) { |
1258 | 0 | struct sc_asn1_entry asn1_se[2]; |
1259 | 0 | struct sc_asn1_entry asn1_se_info[4]; |
1260 | 0 | struct sc_pkcs15_sec_env_info si; |
1261 | |
|
1262 | 0 | sc_copy_asn1_entry(c_asn1_se, asn1_se); |
1263 | 0 | sc_copy_asn1_entry(c_asn1_se_info, asn1_se_info); |
1264 | |
|
1265 | 0 | si.aid.len = sizeof(si.aid.value); |
1266 | 0 | sc_format_asn1_entry(asn1_se_info + 0, &si.se, NULL, 0); |
1267 | 0 | sc_format_asn1_entry(asn1_se_info + 1, &si.owner, NULL, 0); |
1268 | 0 | sc_format_asn1_entry(asn1_se_info + 2, &si.aid.value, &si.aid.len, 0); |
1269 | 0 | sc_format_asn1_entry(asn1_se + 0, asn1_se_info, NULL, 0); |
1270 | |
|
1271 | 0 | ret = asn1_decode(ctx, asn1_se, ptr, ptrlen, &ptr, &ptrlen, 0, depth+1); |
1272 | 0 | if (ret != SC_SUCCESS) |
1273 | 0 | goto err; |
1274 | 0 | if (!(asn1_se_info[1].flags & SC_ASN1_PRESENT)) |
1275 | 0 | sc_init_oid(&si.owner); |
1276 | |
|
1277 | 0 | ses[idx] = calloc(1, sizeof(sc_pkcs15_sec_env_info_t)); |
1278 | 0 | if (ses[idx] == NULL) { |
1279 | 0 | ret = SC_ERROR_OUT_OF_MEMORY; |
1280 | 0 | goto err; |
1281 | 0 | } |
1282 | | |
1283 | 0 | memcpy(ses[idx], &si, sizeof(struct sc_pkcs15_sec_env_info)); |
1284 | 0 | idx++; |
1285 | 0 | } |
1286 | | |
1287 | 0 | *se = ses; |
1288 | 0 | *num = idx; |
1289 | 0 | ret = SC_SUCCESS; |
1290 | 0 | err: |
1291 | 0 | if (ret != SC_SUCCESS) { |
1292 | 0 | size_t i; |
1293 | 0 | for (i = 0; i < idx; i++) |
1294 | 0 | if (ses[i]) |
1295 | 0 | free(ses[i]); |
1296 | 0 | free(ses); |
1297 | 0 | } |
1298 | |
|
1299 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, ret); |
1300 | 0 | } |
1301 | | |
1302 | | |
1303 | | static int asn1_encode_se_info(sc_context_t *ctx, |
1304 | | struct sc_pkcs15_sec_env_info **se, size_t se_num, |
1305 | | unsigned char **buf, size_t *bufsize, int depth) |
1306 | 0 | { |
1307 | 0 | unsigned char *ptr = NULL, *out = NULL, *p; |
1308 | 0 | size_t ptrlen = 0, outlen = 0, idx; |
1309 | 0 | int ret; |
1310 | |
|
1311 | 0 | for (idx=0; idx < se_num; idx++) { |
1312 | 0 | struct sc_asn1_entry asn1_se[2]; |
1313 | 0 | struct sc_asn1_entry asn1_se_info[4]; |
1314 | |
|
1315 | 0 | sc_copy_asn1_entry(c_asn1_se, asn1_se); |
1316 | 0 | sc_copy_asn1_entry(c_asn1_se_info, asn1_se_info); |
1317 | |
|
1318 | 0 | sc_format_asn1_entry(asn1_se_info + 0, &se[idx]->se, NULL, 1); |
1319 | 0 | if (sc_valid_oid(&se[idx]->owner)) |
1320 | 0 | sc_format_asn1_entry(asn1_se_info + 1, &se[idx]->owner, NULL, 1); |
1321 | 0 | if (se[idx]->aid.len) |
1322 | 0 | sc_format_asn1_entry(asn1_se_info + 2, &se[idx]->aid.value, &se[idx]->aid.len, 1); |
1323 | 0 | sc_format_asn1_entry(asn1_se + 0, asn1_se_info, NULL, 1); |
1324 | |
|
1325 | 0 | ret = sc_asn1_encode(ctx, asn1_se, &ptr, &ptrlen); |
1326 | 0 | if (ret != SC_SUCCESS) |
1327 | 0 | goto err; |
1328 | | |
1329 | 0 | if (!ptrlen) |
1330 | 0 | continue; |
1331 | 0 | p = (unsigned char *) realloc(out, outlen + ptrlen); |
1332 | 0 | if (!p) { |
1333 | 0 | ret = SC_ERROR_OUT_OF_MEMORY; |
1334 | 0 | goto err; |
1335 | 0 | } |
1336 | 0 | out = p; |
1337 | 0 | memcpy(out + outlen, ptr, ptrlen); |
1338 | 0 | outlen += ptrlen; |
1339 | 0 | free(ptr); |
1340 | 0 | ptr = NULL; |
1341 | 0 | ptrlen = 0; |
1342 | 0 | } |
1343 | | |
1344 | 0 | *buf = out; |
1345 | 0 | *bufsize = outlen; |
1346 | 0 | ret = SC_SUCCESS; |
1347 | 0 | err: |
1348 | 0 | if (ret != SC_SUCCESS && out != NULL) |
1349 | 0 | free(out); |
1350 | 0 | return ret; |
1351 | 0 | } |
1352 | | |
1353 | | /* TODO: According to specification type of 'SecurityCondition' is 'CHOICE'. |
1354 | | * Do it at least for SC_ASN1_PKCS15_ID(authId), SC_ASN1_STRUCT(authReference) and NULL(always). */ |
1355 | | static const struct sc_asn1_entry c_asn1_access_control_rule[3] = { |
1356 | | { "accessMode", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, |
1357 | | { "securityCondition", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, |
1358 | | { NULL, 0, 0, 0, NULL, NULL } |
1359 | | }; |
1360 | | |
1361 | | /* |
1362 | | * in src/libopensc/pkcs15.h SC_PKCS15_MAX_ACCESS_RULES defined as 8 |
1363 | | */ |
1364 | | static const struct sc_asn1_entry c_asn1_access_control_rules[SC_PKCS15_MAX_ACCESS_RULES + 1] = { |
1365 | | { "accessControlRule", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1366 | | { "accessControlRule", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1367 | | { "accessControlRule", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1368 | | { "accessControlRule", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1369 | | { "accessControlRule", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1370 | | { "accessControlRule", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1371 | | { "accessControlRule", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1372 | | { "accessControlRule", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1373 | | { NULL, 0, 0, 0, NULL, NULL } |
1374 | | }; |
1375 | | |
1376 | | static const struct sc_asn1_entry c_asn1_com_obj_attr[6] = { |
1377 | | { "label", SC_ASN1_UTF8STRING, SC_ASN1_TAG_UTF8STRING, SC_ASN1_OPTIONAL, NULL, NULL }, |
1378 | | { "flags", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, |
1379 | | { "authId", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, |
1380 | | { "userConsent", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL }, |
1381 | | { "accessControlRules", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1382 | | { NULL, 0, 0, 0, NULL, NULL } |
1383 | | }; |
1384 | | |
1385 | | static const struct sc_asn1_entry c_asn1_p15_obj[5] = { |
1386 | | { "commonObjectAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
1387 | | { "classAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
1388 | | { "subClassAttributes", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL }, |
1389 | | { "typeAttributes", SC_ASN1_STRUCT, SC_ASN1_CTX | 1 | SC_ASN1_CONS, 0, NULL, NULL }, |
1390 | | { NULL, 0, 0, 0, NULL, NULL } |
1391 | | }; |
1392 | | |
1393 | | static int asn1_decode_p15_object(sc_context_t *ctx, const u8 *in, |
1394 | | size_t len, struct sc_asn1_pkcs15_object *obj, |
1395 | | int depth) |
1396 | 0 | { |
1397 | 0 | struct sc_pkcs15_object *p15_obj = obj->p15_obj; |
1398 | 0 | struct sc_asn1_entry asn1_c_attr[6], asn1_p15_obj[5]; |
1399 | 0 | struct sc_asn1_entry asn1_ac_rules[SC_PKCS15_MAX_ACCESS_RULES + 1], asn1_ac_rule[SC_PKCS15_MAX_ACCESS_RULES][3]; |
1400 | 0 | size_t flags_len = sizeof(p15_obj->flags); |
1401 | 0 | size_t label_len = sizeof(p15_obj->label); |
1402 | 0 | size_t access_mode_len = sizeof(p15_obj->access_rules[0].access_mode); |
1403 | 0 | int r, ii; |
1404 | |
|
1405 | 0 | for (ii=0; ii<SC_PKCS15_MAX_ACCESS_RULES; ii++) |
1406 | 0 | sc_copy_asn1_entry(c_asn1_access_control_rule, asn1_ac_rule[ii]); |
1407 | 0 | sc_copy_asn1_entry(c_asn1_access_control_rules, asn1_ac_rules); |
1408 | | |
1409 | |
|
1410 | 0 | sc_copy_asn1_entry(c_asn1_com_obj_attr, asn1_c_attr); |
1411 | 0 | sc_copy_asn1_entry(c_asn1_p15_obj, asn1_p15_obj); |
1412 | 0 | sc_format_asn1_entry(asn1_c_attr + 0, p15_obj->label, &label_len, 0); |
1413 | 0 | sc_format_asn1_entry(asn1_c_attr + 1, &p15_obj->flags, &flags_len, 0); |
1414 | 0 | sc_format_asn1_entry(asn1_c_attr + 2, &p15_obj->auth_id, NULL, 0); |
1415 | 0 | sc_format_asn1_entry(asn1_c_attr + 3, &p15_obj->user_consent, NULL, 0); |
1416 | |
|
1417 | 0 | for (ii=0; ii<SC_PKCS15_MAX_ACCESS_RULES; ii++) { |
1418 | 0 | sc_format_asn1_entry(asn1_ac_rule[ii] + 0, &p15_obj->access_rules[ii].access_mode, &access_mode_len, 0); |
1419 | 0 | sc_format_asn1_entry(asn1_ac_rule[ii] + 1, &p15_obj->access_rules[ii].auth_id, NULL, 0); |
1420 | 0 | sc_format_asn1_entry(asn1_ac_rules + ii, asn1_ac_rule[ii], NULL, 0); |
1421 | 0 | } |
1422 | 0 | sc_format_asn1_entry(asn1_c_attr + 4, asn1_ac_rules, NULL, 0); |
1423 | |
|
1424 | 0 | sc_format_asn1_entry(asn1_p15_obj + 0, asn1_c_attr, NULL, 0); |
1425 | 0 | sc_format_asn1_entry(asn1_p15_obj + 1, obj->asn1_class_attr, NULL, 0); |
1426 | 0 | sc_format_asn1_entry(asn1_p15_obj + 2, obj->asn1_subclass_attr, NULL, 0); |
1427 | 0 | sc_format_asn1_entry(asn1_p15_obj + 3, obj->asn1_type_attr, NULL, 0); |
1428 | |
|
1429 | 0 | r = asn1_decode(ctx, asn1_p15_obj, in, len, NULL, NULL, 0, depth + 1); |
1430 | 0 | return r; |
1431 | 0 | } |
1432 | | |
1433 | | static int asn1_encode_p15_object(sc_context_t *ctx, const struct sc_asn1_pkcs15_object *obj, |
1434 | | u8 **buf, size_t *bufsize, int depth) |
1435 | 0 | { |
1436 | 0 | struct sc_pkcs15_object p15_obj = *obj->p15_obj; |
1437 | 0 | struct sc_asn1_entry asn1_c_attr[6], asn1_p15_obj[5]; |
1438 | 0 | struct sc_asn1_entry asn1_ac_rules[SC_PKCS15_MAX_ACCESS_RULES + 1], asn1_ac_rule[SC_PKCS15_MAX_ACCESS_RULES][3]; |
1439 | 0 | size_t label_len = strlen(p15_obj.label); |
1440 | 0 | size_t flags_len; |
1441 | 0 | size_t access_mode_len; |
1442 | 0 | int r, ii; |
1443 | |
|
1444 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "encode p15 obj(type:0x%X,access_mode:0x%X)", p15_obj.type, p15_obj.access_rules[0].access_mode); |
1445 | 0 | if (p15_obj.access_rules[0].access_mode) { |
1446 | 0 | for (ii=0; ii<SC_PKCS15_MAX_ACCESS_RULES; ii++) { |
1447 | 0 | sc_copy_asn1_entry(c_asn1_access_control_rule, asn1_ac_rule[ii]); |
1448 | 0 | if (p15_obj.access_rules[ii].auth_id.len == 0) { |
1449 | 0 | asn1_ac_rule[ii][1].type = SC_ASN1_NULL; |
1450 | 0 | asn1_ac_rule[ii][1].tag = SC_ASN1_TAG_NULL; |
1451 | 0 | } |
1452 | 0 | } |
1453 | 0 | sc_copy_asn1_entry(c_asn1_access_control_rules, asn1_ac_rules); |
1454 | 0 | } |
1455 | |
|
1456 | 0 | sc_copy_asn1_entry(c_asn1_com_obj_attr, asn1_c_attr); |
1457 | 0 | sc_copy_asn1_entry(c_asn1_p15_obj, asn1_p15_obj); |
1458 | 0 | if (label_len != 0) |
1459 | 0 | sc_format_asn1_entry(asn1_c_attr + 0, (void *) p15_obj.label, &label_len, 1); |
1460 | 0 | if (p15_obj.flags) { |
1461 | 0 | flags_len = sizeof(p15_obj.flags); |
1462 | 0 | sc_format_asn1_entry(asn1_c_attr + 1, (void *) &p15_obj.flags, &flags_len, 1); |
1463 | 0 | } |
1464 | 0 | if (p15_obj.auth_id.len) |
1465 | 0 | sc_format_asn1_entry(asn1_c_attr + 2, (void *) &p15_obj.auth_id, NULL, 1); |
1466 | 0 | if (p15_obj.user_consent) |
1467 | 0 | sc_format_asn1_entry(asn1_c_attr + 3, (void *) &p15_obj.user_consent, NULL, 1); |
1468 | |
|
1469 | 0 | if (p15_obj.access_rules[0].access_mode) { |
1470 | 0 | for (ii=0; p15_obj.access_rules[ii].access_mode; ii++) { |
1471 | 0 | access_mode_len = sizeof(p15_obj.access_rules[ii].access_mode); |
1472 | 0 | sc_format_asn1_entry(asn1_ac_rule[ii] + 0, (void *) &p15_obj.access_rules[ii].access_mode, &access_mode_len, 1); |
1473 | 0 | sc_format_asn1_entry(asn1_ac_rule[ii] + 1, (void *) &p15_obj.access_rules[ii].auth_id, NULL, 1); |
1474 | 0 | sc_format_asn1_entry(asn1_ac_rules + ii, asn1_ac_rule[ii], NULL, 1); |
1475 | 0 | } |
1476 | 0 | sc_format_asn1_entry(asn1_c_attr + 4, asn1_ac_rules, NULL, 1); |
1477 | 0 | } |
1478 | |
|
1479 | 0 | sc_format_asn1_entry(asn1_p15_obj + 0, asn1_c_attr, NULL, 1); |
1480 | 0 | sc_format_asn1_entry(asn1_p15_obj + 1, obj->asn1_class_attr, NULL, 1); |
1481 | 0 | if (obj->asn1_subclass_attr != NULL && obj->asn1_subclass_attr->name) |
1482 | 0 | sc_format_asn1_entry(asn1_p15_obj + 2, obj->asn1_subclass_attr, NULL, 1); |
1483 | 0 | sc_format_asn1_entry(asn1_p15_obj + 3, obj->asn1_type_attr, NULL, 1); |
1484 | |
|
1485 | 0 | r = asn1_encode(ctx, asn1_p15_obj, buf, bufsize, depth + 1); |
1486 | 0 | return r; |
1487 | 0 | } |
1488 | | |
1489 | | static int asn1_decode_entry(sc_context_t *ctx,struct sc_asn1_entry *entry, |
1490 | | const u8 *obj, size_t objlen, int depth) |
1491 | 8.06k | { |
1492 | 8.06k | void *parm = entry->parm; |
1493 | 8.06k | int (*callback_func)(sc_context_t *nctx, void *arg, const u8 *nobj, |
1494 | 8.06k | size_t nobjlen, int ndepth); |
1495 | 8.06k | size_t *len = (size_t *) entry->arg; |
1496 | 8.06k | int r = 0; |
1497 | | |
1498 | 8.06k | callback_func = parm; |
1499 | | |
1500 | 8.06k | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "%*.*sdecoding '%s', raw data:%s%s\n", |
1501 | 8.06k | depth, depth, "", entry->name, |
1502 | 8.06k | sc_dump_hex(obj, objlen > 16 ? 16 : objlen), |
1503 | 8.06k | objlen > 16 ? "..." : ""); |
1504 | | |
1505 | 8.06k | switch (entry->type) { |
1506 | 0 | case SC_ASN1_STRUCT: |
1507 | 0 | if (parm != NULL) |
1508 | 0 | r = asn1_decode(ctx, (struct sc_asn1_entry *) parm, obj, |
1509 | 0 | objlen, NULL, NULL, 0, depth + 1); |
1510 | 0 | break; |
1511 | 0 | case SC_ASN1_NULL: |
1512 | 0 | break; |
1513 | 0 | case SC_ASN1_BOOLEAN: |
1514 | 0 | if (parm != NULL) { |
1515 | 0 | if (objlen != 1) { |
1516 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, |
1517 | 0 | "invalid ASN.1 object length: %"SC_FORMAT_LEN_SIZE_T"u\n", |
1518 | 0 | objlen); |
1519 | 0 | r = SC_ERROR_INVALID_ASN1_OBJECT; |
1520 | 0 | } else |
1521 | 0 | *((int *) parm) = obj[0] ? 1 : 0; |
1522 | 0 | } |
1523 | 0 | break; |
1524 | 0 | case SC_ASN1_INTEGER: |
1525 | 0 | case SC_ASN1_ENUMERATED: |
1526 | 0 | if (parm != NULL) { |
1527 | 0 | r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm, 0); |
1528 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "%*.*sdecoding '%s' returned %d\n", depth, depth, "", |
1529 | 0 | entry->name, *((int *) entry->parm)); |
1530 | 0 | } |
1531 | 0 | break; |
1532 | 0 | case SC_ASN1_BIT_STRING_NI: |
1533 | 0 | case SC_ASN1_BIT_STRING: |
1534 | 0 | if (parm != NULL) { |
1535 | 0 | int invert = entry->type == SC_ASN1_BIT_STRING ? 1 : 0; |
1536 | 0 | assert(len != NULL); |
1537 | 0 | if (objlen < 1) { |
1538 | 0 | r = SC_ERROR_INVALID_ASN1_OBJECT; |
1539 | 0 | break; |
1540 | 0 | } |
1541 | 0 | if (entry->flags & SC_ASN1_ALLOC) { |
1542 | 0 | u8 **buf = (u8 **) parm; |
1543 | 0 | if (objlen > 1) { |
1544 | 0 | *buf = malloc(objlen-1); |
1545 | 0 | if (*buf == NULL) { |
1546 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1547 | 0 | break; |
1548 | 0 | } |
1549 | 0 | } |
1550 | 0 | *len = objlen-1; |
1551 | 0 | parm = *buf; |
1552 | 0 | } |
1553 | 0 | r = decode_bit_string(obj, objlen, (u8 *) parm, *len, invert, 0); |
1554 | 0 | if (r >= 0) { |
1555 | 0 | *len = r; |
1556 | 0 | r = 0; |
1557 | 0 | } |
1558 | 0 | } |
1559 | 0 | break; |
1560 | 0 | case SC_ASN1_BIT_FIELD: |
1561 | 0 | if (parm != NULL) |
1562 | 0 | r = decode_bit_field(obj, objlen, (u8 *) parm, *len, 0); |
1563 | 0 | break; |
1564 | 8.06k | case SC_ASN1_OCTET_STRING: |
1565 | 8.06k | if (parm != NULL) { |
1566 | 8.06k | size_t c; |
1567 | 8.06k | assert(len != NULL); |
1568 | | |
1569 | | /* Strip off padding zero */ |
1570 | 8.06k | if ((entry->flags & SC_ASN1_UNSIGNED) |
1571 | 8.06k | && objlen > 1 && obj[0] == 0x00) { |
1572 | 0 | objlen--; |
1573 | 0 | obj++; |
1574 | 0 | } |
1575 | | |
1576 | | /* Allocate buffer if needed */ |
1577 | 8.06k | if (entry->flags & SC_ASN1_ALLOC) { |
1578 | 0 | u8 **buf = (u8 **) parm; |
1579 | 0 | if (objlen > 0) { |
1580 | 0 | *buf = malloc(objlen); |
1581 | 0 | if (*buf == NULL) { |
1582 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1583 | 0 | break; |
1584 | 0 | } |
1585 | 0 | } |
1586 | 0 | c = *len = objlen; |
1587 | 0 | parm = *buf; |
1588 | 0 | } else |
1589 | 8.06k | c = objlen > *len ? *len : objlen; |
1590 | | |
1591 | 8.06k | memcpy(parm, obj, c); |
1592 | 8.06k | *len = c; |
1593 | 8.06k | } |
1594 | 8.06k | break; |
1595 | 8.06k | case SC_ASN1_GENERALIZEDTIME: |
1596 | 0 | if (parm != NULL) { |
1597 | 0 | size_t c; |
1598 | 0 | assert(len != NULL); |
1599 | 0 | if (entry->flags & SC_ASN1_ALLOC) { |
1600 | 0 | u8 **buf = (u8 **) parm; |
1601 | 0 | if (objlen > 0) { |
1602 | 0 | *buf = malloc(objlen); |
1603 | 0 | if (*buf == NULL) { |
1604 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1605 | 0 | break; |
1606 | 0 | } |
1607 | 0 | } |
1608 | 0 | c = *len = objlen; |
1609 | 0 | parm = *buf; |
1610 | 0 | } else |
1611 | 0 | c = objlen > *len ? *len : objlen; |
1612 | | |
1613 | 0 | memcpy(parm, obj, c); |
1614 | 0 | *len = c; |
1615 | 0 | } |
1616 | 0 | break; |
1617 | 0 | case SC_ASN1_OBJECT: |
1618 | 0 | if (parm != NULL) |
1619 | 0 | r = sc_asn1_decode_object_id(obj, objlen, (struct sc_object_id *) parm); |
1620 | 0 | break; |
1621 | 0 | case SC_ASN1_PRINTABLESTRING: |
1622 | 0 | case SC_ASN1_UTF8STRING: |
1623 | 0 | if (parm != NULL) { |
1624 | 0 | assert(len != NULL); |
1625 | 0 | if (entry->flags & SC_ASN1_ALLOC) { |
1626 | 0 | u8 **buf = (u8 **) parm; |
1627 | 0 | *buf = malloc(objlen+1); |
1628 | 0 | if (*buf == NULL) { |
1629 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1630 | 0 | break; |
1631 | 0 | } |
1632 | 0 | *len = objlen+1; |
1633 | 0 | parm = *buf; |
1634 | 0 | } |
1635 | 0 | r = sc_asn1_decode_utf8string(obj, objlen, (u8 *) parm, len); |
1636 | 0 | if (entry->flags & SC_ASN1_ALLOC) { |
1637 | 0 | *len -= 1; |
1638 | 0 | } |
1639 | 0 | } |
1640 | 0 | break; |
1641 | 0 | case SC_ASN1_PATH: |
1642 | 0 | if (entry->parm != NULL) |
1643 | 0 | r = asn1_decode_path(ctx, obj, objlen, (sc_path_t *) parm, depth); |
1644 | 0 | break; |
1645 | 0 | case SC_ASN1_PKCS15_ID: |
1646 | 0 | if (entry->parm != NULL) { |
1647 | 0 | struct sc_pkcs15_id *id = (struct sc_pkcs15_id *) parm; |
1648 | 0 | size_t c = objlen > sizeof(id->value) ? sizeof(id->value) : objlen; |
1649 | |
|
1650 | 0 | memcpy(id->value, obj, c); |
1651 | 0 | id->len = c; |
1652 | 0 | } |
1653 | 0 | break; |
1654 | 0 | case SC_ASN1_PKCS15_OBJECT: |
1655 | 0 | if (entry->parm != NULL) |
1656 | 0 | r = asn1_decode_p15_object(ctx, obj, objlen, (struct sc_asn1_pkcs15_object *) parm, depth); |
1657 | 0 | break; |
1658 | 0 | case SC_ASN1_ALGORITHM_ID: |
1659 | 0 | if (entry->parm != NULL) |
1660 | 0 | r = sc_asn1_decode_algorithm_id(ctx, obj, objlen, (struct sc_algorithm_id *) parm, depth); |
1661 | 0 | break; |
1662 | 0 | case SC_ASN1_SE_INFO: |
1663 | 0 | if (entry->parm != NULL) |
1664 | 0 | r = asn1_decode_se_info(ctx, obj, objlen, (sc_pkcs15_sec_env_info_t ***)entry->parm, len, depth); |
1665 | 0 | break; |
1666 | 0 | case SC_ASN1_CALLBACK: |
1667 | 0 | if (entry->parm != NULL) |
1668 | 0 | r = callback_func(ctx, entry->arg, obj, objlen, depth); |
1669 | 0 | break; |
1670 | 0 | default: |
1671 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "invalid ASN.1 type: %d\n", entry->type); |
1672 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
1673 | 8.06k | } |
1674 | 8.06k | if (r) { |
1675 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "decoding of ASN.1 object '%s' failed: %s\n", entry->name, |
1676 | 0 | sc_strerror(r)); |
1677 | 0 | return r; |
1678 | 0 | } |
1679 | 8.06k | entry->flags |= SC_ASN1_PRESENT; |
1680 | 8.06k | return 0; |
1681 | 8.06k | } |
1682 | | |
1683 | 12.7k | static void sc_free_entry(struct sc_asn1_entry *asn1) { |
1684 | 12.7k | int idx = 0; |
1685 | 12.7k | struct sc_asn1_entry *entry = asn1; |
1686 | | |
1687 | 12.7k | if (!asn1) |
1688 | 0 | return; |
1689 | | |
1690 | 50.9k | for (idx = 0; asn1[idx].name != NULL; idx++) { |
1691 | 38.2k | entry = &asn1[idx]; |
1692 | 38.2k | switch (entry->type) { |
1693 | 0 | case SC_ASN1_CHOICE: |
1694 | 0 | case SC_ASN1_STRUCT: |
1695 | 0 | sc_free_entry((struct sc_asn1_entry *) entry->parm); |
1696 | 0 | break; |
1697 | 38.2k | case SC_ASN1_OCTET_STRING: |
1698 | 38.2k | case SC_ASN1_BIT_STRING_NI: |
1699 | 38.2k | case SC_ASN1_BIT_STRING: |
1700 | 38.2k | case SC_ASN1_GENERALIZEDTIME: |
1701 | 38.2k | case SC_ASN1_PRINTABLESTRING: |
1702 | 38.2k | case SC_ASN1_UTF8STRING: |
1703 | 38.2k | if ((entry->flags & SC_ASN1_ALLOC) && (entry->flags & SC_ASN1_PRESENT)) { |
1704 | 0 | u8 **buf = (u8 **)entry->parm; |
1705 | 0 | free(*buf); |
1706 | 0 | *buf = NULL; |
1707 | 0 | } |
1708 | 38.2k | break; |
1709 | 0 | default: |
1710 | 0 | break; |
1711 | 38.2k | } |
1712 | 38.2k | } |
1713 | 12.7k | } |
1714 | | |
1715 | | static int asn1_decode(sc_context_t *ctx, struct sc_asn1_entry *asn1, |
1716 | | const u8 *in, size_t len, const u8 **newp, size_t *len_left, |
1717 | | int choice, int depth) |
1718 | 15.3k | { |
1719 | 15.3k | int r, idx = 0; |
1720 | 15.3k | const u8 *p = in, *obj; |
1721 | 15.3k | struct sc_asn1_entry *entry = asn1; |
1722 | 15.3k | size_t left = len, objlen; |
1723 | | |
1724 | 15.3k | sc_debug(ctx, SC_LOG_DEBUG_ASN1, |
1725 | 15.3k | "%*.*s""called, left=%"SC_FORMAT_LEN_SIZE_T"u, depth %d%s\n", |
1726 | 15.3k | depth, depth, "", left, depth, choice ? ", choice" : ""); |
1727 | | |
1728 | 15.3k | if (!p) |
1729 | 0 | return SC_ERROR_ASN1_OBJECT_NOT_FOUND; |
1730 | 15.3k | if (left < 2) { |
1731 | 668 | while (asn1->name && (asn1->flags & SC_ASN1_OPTIONAL)) |
1732 | 334 | asn1++; |
1733 | | /* If all elements were optional, there's nothing |
1734 | | * to complain about */ |
1735 | 334 | if (asn1->name == NULL) |
1736 | 0 | return 0; |
1737 | 334 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "End of ASN.1 stream, " |
1738 | 334 | "non-optional field \"%s\" not found\n", |
1739 | 334 | asn1->name); |
1740 | 334 | return SC_ERROR_ASN1_OBJECT_NOT_FOUND; |
1741 | 334 | } |
1742 | 15.0k | if (p[0] == 0 || p[0] == 0xFF || len == 0) |
1743 | 598 | return SC_ERROR_ASN1_END_OF_CONTENTS; |
1744 | | |
1745 | 36.9k | for (idx = 0; asn1[idx].name != NULL; idx++) { |
1746 | 35.2k | entry = &asn1[idx]; |
1747 | | |
1748 | 35.2k | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "Looking for '%s', tag 0x%x%s%s\n", |
1749 | 35.2k | entry->name, entry->tag, choice? ", CHOICE" : "", |
1750 | 35.2k | (entry->flags & SC_ASN1_OPTIONAL)? ", OPTIONAL": ""); |
1751 | | |
1752 | | /* Special case CHOICE has no tag */ |
1753 | 35.2k | if (entry->type == SC_ASN1_CHOICE) { |
1754 | 0 | r = asn1_decode(ctx, |
1755 | 0 | (struct sc_asn1_entry *) entry->parm, |
1756 | 0 | p, left, &p, &left, 1, depth + 1); |
1757 | 0 | if (r >= 0) |
1758 | 0 | r = 0; |
1759 | 0 | goto decode_ok; |
1760 | 0 | } |
1761 | | |
1762 | 35.2k | obj = sc_asn1_skip_tag(ctx, &p, &left, entry->tag, &objlen); |
1763 | 35.2k | if (obj == NULL) { |
1764 | 27.1k | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "'%s' not present\n", entry->name); |
1765 | 27.1k | if (choice) |
1766 | 0 | continue; |
1767 | 27.1k | if (entry->flags & SC_ASN1_OPTIONAL) |
1768 | 14.4k | continue; |
1769 | 12.7k | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "mandatory ASN.1 object '%s' not found\n", entry->name); |
1770 | 12.7k | if (left) { |
1771 | 12.5k | u8 line[128], *linep = line; |
1772 | 12.5k | size_t i; |
1773 | | |
1774 | 12.5k | line[0] = 0; |
1775 | 110k | for (i = 0; i < 10 && i < left; i++) { |
1776 | 98.1k | sprintf((char *) linep, "%02X ", p[i]); |
1777 | 98.1k | linep += 3; |
1778 | 98.1k | } |
1779 | 12.5k | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "next tag: %s\n", line); |
1780 | 12.5k | } |
1781 | 12.7k | sc_free_entry(asn1); |
1782 | 12.7k | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_ASN1_OBJECT_NOT_FOUND); |
1783 | 12.7k | } |
1784 | 8.06k | r = asn1_decode_entry(ctx, entry, obj, objlen, depth); |
1785 | | |
1786 | 8.06k | decode_ok: |
1787 | 8.06k | if (r) |
1788 | 0 | return r; |
1789 | 8.06k | if (choice) |
1790 | 0 | break; |
1791 | 8.06k | } |
1792 | 1.70k | if (choice && asn1[idx].name == NULL) /* No match */ |
1793 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_ASN1_OBJECT_NOT_FOUND); |
1794 | 1.70k | if (newp != NULL) |
1795 | 0 | *newp = p; |
1796 | 1.70k | if (len_left != NULL) |
1797 | 0 | *len_left = left; |
1798 | 1.70k | if (choice) |
1799 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, idx); |
1800 | 1.70k | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, 0); |
1801 | 1.70k | } |
1802 | | |
1803 | | int sc_asn1_decode(sc_context_t *ctx, struct sc_asn1_entry *asn1, |
1804 | | const u8 *in, size_t len, const u8 **newp, size_t *len_left) |
1805 | 15.3k | { |
1806 | 15.3k | return asn1_decode(ctx, asn1, in, len, newp, len_left, 0, 0); |
1807 | 15.3k | } |
1808 | | |
1809 | | int sc_asn1_decode_choice(sc_context_t *ctx, struct sc_asn1_entry *asn1, |
1810 | | const u8 *in, size_t len, const u8 **newp, size_t *len_left) |
1811 | 0 | { |
1812 | 0 | return asn1_decode(ctx, asn1, in, len, newp, len_left, 1, 0); |
1813 | 0 | } |
1814 | | |
1815 | | static int asn1_encode_entry(sc_context_t *ctx, const struct sc_asn1_entry *entry, |
1816 | | u8 **obj, size_t *objlen, int depth) |
1817 | 2.92k | { |
1818 | 2.92k | void *parm = entry->parm; |
1819 | 2.92k | int (*callback_func)(sc_context_t *nctx, void *arg, u8 **nobj, |
1820 | 2.92k | size_t *nobjlen, int ndepth); |
1821 | 2.92k | const size_t *len = (const size_t *) entry->arg; |
1822 | 2.92k | int r = 0; |
1823 | 2.92k | u8 * buf = NULL; |
1824 | 2.92k | size_t buflen = 0; |
1825 | | |
1826 | 2.92k | callback_func = parm; |
1827 | | |
1828 | 2.92k | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "%*.*sencoding '%s'%s\n", |
1829 | 2.92k | depth, depth, "", entry->name, |
1830 | 2.92k | (entry->flags & SC_ASN1_PRESENT)? "" : " (not present)"); |
1831 | 2.92k | if (!(entry->flags & SC_ASN1_PRESENT)) |
1832 | 0 | goto no_object; |
1833 | 2.92k | sc_debug(ctx, SC_LOG_DEBUG_ASN1, |
1834 | 2.92k | "%*.*stype=%d, tag=0x%02x, parm=%p, len=%"SC_FORMAT_LEN_SIZE_T"u\n", |
1835 | 2.92k | depth, depth, "", entry->type, entry->tag, parm, |
1836 | 2.92k | len ? *len : 0); |
1837 | | |
1838 | 2.92k | if (entry->type == SC_ASN1_CHOICE) { |
1839 | 0 | const struct sc_asn1_entry *list, *choice = NULL; |
1840 | |
|
1841 | 0 | list = (const struct sc_asn1_entry *) parm; |
1842 | 0 | while (list->name != NULL) { |
1843 | 0 | if (list->flags & SC_ASN1_PRESENT) { |
1844 | 0 | if (choice) { |
1845 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, |
1846 | 0 | "ASN.1 problem: more than " |
1847 | 0 | "one CHOICE when encoding %s: " |
1848 | 0 | "%s and %s both present\n", |
1849 | 0 | entry->name, |
1850 | 0 | choice->name, |
1851 | 0 | list->name); |
1852 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
1853 | 0 | } |
1854 | 0 | choice = list; |
1855 | 0 | } |
1856 | 0 | list++; |
1857 | 0 | } |
1858 | 0 | if (choice == NULL) |
1859 | 0 | goto no_object; |
1860 | 0 | return asn1_encode_entry(ctx, choice, obj, objlen, depth + 1); |
1861 | 0 | } |
1862 | | |
1863 | 2.92k | if (entry->type != SC_ASN1_NULL && parm == NULL) { |
1864 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "unexpected parm == NULL\n"); |
1865 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
1866 | 0 | } |
1867 | | |
1868 | 2.92k | switch (entry->type) { |
1869 | 0 | case SC_ASN1_STRUCT: |
1870 | 0 | r = asn1_encode(ctx, (const struct sc_asn1_entry *) parm, &buf, |
1871 | 0 | &buflen, depth + 1); |
1872 | 0 | break; |
1873 | 0 | case SC_ASN1_NULL: |
1874 | 0 | buf = NULL; |
1875 | 0 | buflen = 0; |
1876 | 0 | break; |
1877 | 0 | case SC_ASN1_BOOLEAN: |
1878 | 0 | buf = malloc(1); |
1879 | 0 | if (buf == NULL) { |
1880 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1881 | 0 | break; |
1882 | 0 | } |
1883 | 0 | buf[0] = *((int *) parm) ? 0xFF : 0; |
1884 | 0 | buflen = 1; |
1885 | 0 | break; |
1886 | 0 | case SC_ASN1_INTEGER: |
1887 | 0 | case SC_ASN1_ENUMERATED: |
1888 | 0 | r = asn1_encode_integer(*((int *) entry->parm), &buf, &buflen); |
1889 | 0 | break; |
1890 | 0 | case SC_ASN1_BIT_STRING_NI: |
1891 | 0 | case SC_ASN1_BIT_STRING: |
1892 | 0 | if (len != NULL) { |
1893 | 0 | if (entry->type == SC_ASN1_BIT_STRING) |
1894 | 0 | r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 1); |
1895 | 0 | else |
1896 | 0 | r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 0); |
1897 | 0 | } else { |
1898 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
1899 | 0 | } |
1900 | 0 | break; |
1901 | 0 | case SC_ASN1_BIT_FIELD: |
1902 | 0 | if (len != NULL) { |
1903 | 0 | r = encode_bit_field((const u8 *) parm, *len, &buf, &buflen); |
1904 | 0 | } else { |
1905 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
1906 | 0 | } |
1907 | 0 | break; |
1908 | 0 | case SC_ASN1_PRINTABLESTRING: |
1909 | 0 | case SC_ASN1_OCTET_STRING: |
1910 | 0 | case SC_ASN1_UTF8STRING: |
1911 | 0 | if (len != NULL) { |
1912 | 0 | buf = malloc(*len + 1); |
1913 | 0 | if (buf == NULL) { |
1914 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1915 | 0 | break; |
1916 | 0 | } |
1917 | 0 | buflen = 0; |
1918 | | /* If the integer is supposed to be unsigned, insert |
1919 | | * a padding byte if the MSB is one */ |
1920 | 0 | if ((entry->flags & SC_ASN1_UNSIGNED) |
1921 | 0 | && (((u8 *) parm)[0] & 0x80)) { |
1922 | 0 | buf[buflen++] = 0x00; |
1923 | 0 | } |
1924 | 0 | memcpy(buf + buflen, parm, *len); |
1925 | 0 | buflen += *len; |
1926 | 0 | } else { |
1927 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
1928 | 0 | } |
1929 | 0 | break; |
1930 | 0 | case SC_ASN1_GENERALIZEDTIME: |
1931 | 0 | if (len != NULL) { |
1932 | 0 | buf = malloc(*len); |
1933 | 0 | if (buf == NULL) { |
1934 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1935 | 0 | break; |
1936 | 0 | } |
1937 | 0 | memcpy(buf, parm, *len); |
1938 | 0 | buflen = *len; |
1939 | 0 | } else { |
1940 | 0 | r = SC_ERROR_INVALID_ARGUMENTS; |
1941 | 0 | } |
1942 | 0 | break; |
1943 | 2.92k | case SC_ASN1_OBJECT: |
1944 | 2.92k | r = sc_asn1_encode_object_id(&buf, &buflen, (struct sc_object_id *) parm); |
1945 | 2.92k | break; |
1946 | 0 | case SC_ASN1_PATH: |
1947 | 0 | r = asn1_encode_path(ctx, (const sc_path_t *) parm, &buf, &buflen, depth, entry->flags); |
1948 | 0 | break; |
1949 | 0 | case SC_ASN1_PKCS15_ID: |
1950 | 0 | { |
1951 | 0 | const struct sc_pkcs15_id *id = (const struct sc_pkcs15_id *) parm; |
1952 | |
|
1953 | 0 | buf = malloc(id->len); |
1954 | 0 | if (buf == NULL) { |
1955 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
1956 | 0 | break; |
1957 | 0 | } |
1958 | 0 | memcpy(buf, id->value, id->len); |
1959 | 0 | buflen = id->len; |
1960 | 0 | } |
1961 | 0 | break; |
1962 | 0 | case SC_ASN1_PKCS15_OBJECT: |
1963 | 0 | r = asn1_encode_p15_object(ctx, (const struct sc_asn1_pkcs15_object *) parm, &buf, &buflen, depth); |
1964 | 0 | break; |
1965 | 0 | case SC_ASN1_ALGORITHM_ID: |
1966 | 0 | r = sc_asn1_encode_algorithm_id(ctx, &buf, &buflen, (const struct sc_algorithm_id *) parm, depth); |
1967 | 0 | break; |
1968 | 0 | case SC_ASN1_SE_INFO: |
1969 | 0 | if (!len) |
1970 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
1971 | 0 | r = asn1_encode_se_info(ctx, (struct sc_pkcs15_sec_env_info **)parm, *len, &buf, &buflen, depth); |
1972 | 0 | break; |
1973 | 0 | case SC_ASN1_CALLBACK: |
1974 | 0 | r = callback_func(ctx, entry->arg, &buf, &buflen, depth); |
1975 | 0 | break; |
1976 | 0 | default: |
1977 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "invalid ASN.1 type: %d\n", entry->type); |
1978 | 0 | return SC_ERROR_INVALID_ASN1_OBJECT; |
1979 | 2.92k | } |
1980 | 2.92k | if (r) { |
1981 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "encoding of ASN.1 object '%s' failed: %s\n", entry->name, |
1982 | 0 | sc_strerror(r)); |
1983 | 0 | if (buf) |
1984 | 0 | free(buf); |
1985 | 0 | return r; |
1986 | 0 | } |
1987 | | |
1988 | | /* Treatment of OPTIONAL elements: |
1989 | | * - if the encoding has 0 length, and the element is OPTIONAL, |
1990 | | * we don't write anything (unless it's an ASN1 NULL and the |
1991 | | * SC_ASN1_PRESENT flag is set). |
1992 | | * - if the encoding has 0 length, but the element is non-OPTIONAL, |
1993 | | * constructed, we write a empty element (e.g. a SEQUENCE of |
1994 | | * length 0). In case of an ASN1 NULL just write the tag and |
1995 | | * length (i.e. 0x05,0x00). |
1996 | | * - any other empty objects are considered bogus |
1997 | | */ |
1998 | 2.92k | no_object: |
1999 | 2.92k | if (!buflen && entry->flags & SC_ASN1_OPTIONAL && !(entry->flags & SC_ASN1_PRESENT)) { |
2000 | | /* This happens when we try to encode e.g. the |
2001 | | * subClassAttributes, which may be empty */ |
2002 | 0 | *obj = NULL; |
2003 | 0 | *objlen = 0; |
2004 | 0 | r = 0; |
2005 | 2.92k | } else if (!buflen && (entry->flags & SC_ASN1_EMPTY_ALLOWED)) { |
2006 | 0 | *obj = NULL; |
2007 | 0 | *objlen = 0; |
2008 | 0 | r = asn1_write_element(ctx, entry->tag, buf, buflen, obj, objlen); |
2009 | 0 | if (r) |
2010 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "error writing ASN.1 tag and length: %s\n", sc_strerror(r)); |
2011 | 2.92k | } else if (buflen || entry->type == SC_ASN1_NULL || entry->tag & SC_ASN1_CONS) { |
2012 | 2.92k | r = asn1_write_element(ctx, entry->tag, buf, buflen, obj, objlen); |
2013 | 2.92k | if (r) |
2014 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "error writing ASN.1 tag and length: %s\n", |
2015 | 2.92k | sc_strerror(r)); |
2016 | 2.92k | } else if (!(entry->flags & SC_ASN1_PRESENT)) { |
2017 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "cannot encode non-optional ASN.1 object: not given by caller\n"); |
2018 | 0 | r = SC_ERROR_INVALID_ASN1_OBJECT; |
2019 | 0 | } else { |
2020 | 0 | sc_debug(ctx, SC_LOG_DEBUG_ASN1, "cannot encode empty non-optional ASN.1 object\n"); |
2021 | 0 | r = SC_ERROR_INVALID_ASN1_OBJECT; |
2022 | 0 | } |
2023 | 2.92k | if (buf) |
2024 | 2.92k | free(buf); |
2025 | 2.92k | if (r >= 0) |
2026 | 2.92k | sc_debug(ctx, SC_LOG_DEBUG_ASN1, |
2027 | 2.92k | "%*.*slength of encoded item=%"SC_FORMAT_LEN_SIZE_T"u\n", |
2028 | 2.92k | depth, depth, "", *objlen); |
2029 | 2.92k | return r; |
2030 | 2.92k | } |
2031 | | |
2032 | | static int asn1_encode(sc_context_t *ctx, const struct sc_asn1_entry *asn1, |
2033 | | u8 **ptr, size_t *size, int depth) |
2034 | 2.92k | { |
2035 | 2.92k | int r, idx = 0; |
2036 | 2.92k | u8 *obj = NULL, *buf = NULL, *tmp; |
2037 | 2.92k | size_t total = 0, objsize; |
2038 | | |
2039 | 2.92k | if (asn1 == NULL) { |
2040 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2041 | 0 | } |
2042 | | |
2043 | 5.85k | for (idx = 0; asn1[idx].name != NULL; idx++) { |
2044 | 2.92k | r = asn1_encode_entry(ctx, &asn1[idx], &obj, &objsize, depth); |
2045 | 2.92k | if (r) { |
2046 | 0 | if (obj) |
2047 | 0 | free(obj); |
2048 | 0 | if (buf) |
2049 | 0 | free(buf); |
2050 | 0 | return r; |
2051 | 0 | } |
2052 | | /* in case of an empty (optional) element continue with |
2053 | | * the next asn1 element */ |
2054 | 2.92k | if (!objsize) |
2055 | 0 | continue; |
2056 | 2.92k | tmp = (u8 *) realloc(buf, total + objsize); |
2057 | 2.92k | if (!tmp) { |
2058 | 0 | if (obj) |
2059 | 0 | free(obj); |
2060 | 0 | if (buf) |
2061 | 0 | free(buf); |
2062 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
2063 | 0 | } |
2064 | 2.92k | buf = tmp; |
2065 | 2.92k | memcpy(buf + total, obj, objsize); |
2066 | 2.92k | free(obj); |
2067 | 2.92k | obj = NULL; |
2068 | 2.92k | total += objsize; |
2069 | 2.92k | } |
2070 | 2.92k | *ptr = buf; |
2071 | 2.92k | *size = total; |
2072 | 2.92k | return 0; |
2073 | 2.92k | } |
2074 | | |
2075 | | int sc_asn1_encode(sc_context_t *ctx, const struct sc_asn1_entry *asn1, |
2076 | | u8 **ptr, size_t *size) |
2077 | 0 | { |
2078 | 0 | return asn1_encode(ctx, asn1, ptr, size, 0); |
2079 | 0 | } |
2080 | | |
2081 | | int _sc_asn1_encode(sc_context_t *ctx, const struct sc_asn1_entry *asn1, |
2082 | | u8 **ptr, size_t *size, int depth) |
2083 | 2.92k | { |
2084 | 2.92k | return asn1_encode(ctx, asn1, ptr, size, depth); |
2085 | 2.92k | } |
2086 | | |
2087 | | int |
2088 | | _sc_asn1_decode(sc_context_t *ctx, struct sc_asn1_entry *asn1, |
2089 | | const u8 *in, size_t len, const u8 **newp, size_t *left, |
2090 | | int choice, int depth) |
2091 | 0 | { |
2092 | 0 | return asn1_decode(ctx, asn1, in, len, newp, left, choice, depth); |
2093 | 0 | } |
2094 | | |
2095 | | int |
2096 | | sc_der_copy(sc_pkcs15_der_t *dst, const sc_pkcs15_der_t *src) |
2097 | 0 | { |
2098 | 0 | if (!dst || !src) |
2099 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2100 | 0 | memset(dst, 0, sizeof(*dst)); |
2101 | 0 | if (src->len) { |
2102 | 0 | if (!src->value) |
2103 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2104 | 0 | dst->value = malloc(src->len); |
2105 | 0 | if (!dst->value) |
2106 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
2107 | 0 | dst->len = src->len; |
2108 | 0 | memcpy(dst->value, src->value, src->len); |
2109 | 0 | } |
2110 | 0 | return SC_SUCCESS; |
2111 | 0 | } |
2112 | | |
2113 | | int |
2114 | | sc_encode_oid (struct sc_context *ctx, struct sc_object_id *id, |
2115 | | unsigned char **out, size_t *size) |
2116 | 2.92k | { |
2117 | 2.92k | static const struct sc_asn1_entry c_asn1_object_id[2] = { |
2118 | 2.92k | { "oid", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, SC_ASN1_ALLOC, NULL, NULL }, |
2119 | 2.92k | { NULL, 0, 0, 0, NULL, NULL } |
2120 | 2.92k | }; |
2121 | 2.92k | struct sc_asn1_entry asn1_object_id[2]; |
2122 | 2.92k | int rv; |
2123 | | |
2124 | 2.92k | sc_copy_asn1_entry(c_asn1_object_id, asn1_object_id); |
2125 | 2.92k | sc_format_asn1_entry(asn1_object_id + 0, id, NULL, 1); |
2126 | | |
2127 | 2.92k | rv = _sc_asn1_encode(ctx, asn1_object_id, out, size, 1); |
2128 | 2.92k | LOG_TEST_RET(ctx, rv, "Cannot encode object ID"); |
2129 | | |
2130 | 2.92k | return SC_SUCCESS; |
2131 | 2.92k | } |
2132 | | |
2133 | | |
2134 | | #define C_ASN1_SIG_VALUE_SIZE 2 |
2135 | | static struct sc_asn1_entry c_asn1_sig_value[C_ASN1_SIG_VALUE_SIZE] = { |
2136 | | { "ECDSA-Sig-Value", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, |
2137 | | { NULL, 0, 0, 0, NULL, NULL } |
2138 | | }; |
2139 | | |
2140 | | #define C_ASN1_SIG_VALUE_COEFFICIENTS_SIZE 3 |
2141 | | static struct sc_asn1_entry c_asn1_sig_value_coefficients[C_ASN1_SIG_VALUE_COEFFICIENTS_SIZE] = { |
2142 | | { "r", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL }, |
2143 | | { "s", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL }, |
2144 | | { NULL, 0, 0, 0, NULL, NULL } |
2145 | | }; |
2146 | | |
2147 | | |
2148 | | int |
2149 | | sc_asn1_sig_value_rs_to_sequence(struct sc_context *ctx, unsigned char *in, size_t inlen, |
2150 | | unsigned char **buf, size_t *buflen) |
2151 | 0 | { |
2152 | 0 | struct sc_asn1_entry asn1_sig_value[C_ASN1_SIG_VALUE_SIZE]; |
2153 | 0 | struct sc_asn1_entry asn1_sig_value_coefficients[C_ASN1_SIG_VALUE_COEFFICIENTS_SIZE]; |
2154 | 0 | unsigned char *r = in, *s = in + inlen/2; |
2155 | 0 | size_t r_len = inlen/2, s_len = inlen/2; |
2156 | 0 | int rv; |
2157 | |
|
2158 | 0 | LOG_FUNC_CALLED(ctx); |
2159 | | |
2160 | | /* R/S are filled up with zeroes, we do not want that in sequence format */ |
2161 | 0 | while(r_len > 1 && *r == 0x00) { |
2162 | 0 | r++; |
2163 | 0 | r_len--; |
2164 | 0 | } |
2165 | 0 | while(s_len > 1 && *s == 0x00) { |
2166 | 0 | s++; |
2167 | 0 | s_len--; |
2168 | 0 | } |
2169 | |
|
2170 | 0 | sc_copy_asn1_entry(c_asn1_sig_value, asn1_sig_value); |
2171 | 0 | sc_format_asn1_entry(asn1_sig_value + 0, asn1_sig_value_coefficients, NULL, 1); |
2172 | |
|
2173 | 0 | sc_copy_asn1_entry(c_asn1_sig_value_coefficients, asn1_sig_value_coefficients); |
2174 | 0 | sc_format_asn1_entry(asn1_sig_value_coefficients + 0, r, &r_len, 1); |
2175 | 0 | sc_format_asn1_entry(asn1_sig_value_coefficients + 1, s, &s_len, 1); |
2176 | |
|
2177 | 0 | rv = sc_asn1_encode(ctx, asn1_sig_value, buf, buflen); |
2178 | 0 | LOG_TEST_RET(ctx, rv, "ASN.1 encoding ECDSA-SIg-Value failed"); |
2179 | | |
2180 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
2181 | 0 | } |
2182 | | |
2183 | | |
2184 | | int |
2185 | | sc_asn1_sig_value_sequence_to_rs(struct sc_context *ctx, const unsigned char *in, size_t inlen, |
2186 | | unsigned char *buf, size_t buflen) |
2187 | 0 | { |
2188 | 0 | struct sc_asn1_entry asn1_sig_value[C_ASN1_SIG_VALUE_SIZE]; |
2189 | 0 | struct sc_asn1_entry asn1_sig_value_coefficients[C_ASN1_SIG_VALUE_COEFFICIENTS_SIZE]; |
2190 | 0 | unsigned char *r = NULL, *s = NULL; |
2191 | 0 | size_t r_len = 0, s_len = 0, halflen = buflen/2; |
2192 | 0 | int rv; |
2193 | |
|
2194 | 0 | LOG_FUNC_CALLED(ctx); |
2195 | 0 | if (!buf || !buflen) |
2196 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
2197 | | |
2198 | 0 | sc_copy_asn1_entry(c_asn1_sig_value, asn1_sig_value); |
2199 | 0 | sc_format_asn1_entry(asn1_sig_value + 0, asn1_sig_value_coefficients, NULL, 0); |
2200 | |
|
2201 | 0 | sc_copy_asn1_entry(c_asn1_sig_value_coefficients, asn1_sig_value_coefficients); |
2202 | 0 | sc_format_asn1_entry(asn1_sig_value_coefficients + 0, &r, &r_len, 0); |
2203 | 0 | sc_format_asn1_entry(asn1_sig_value_coefficients + 1, &s, &s_len, 0); |
2204 | |
|
2205 | 0 | rv = sc_asn1_decode(ctx, asn1_sig_value, in, inlen, NULL, NULL); |
2206 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "ASN.1 decoding ECDSA-Sig-Value failed"); |
2207 | | |
2208 | 0 | if (halflen < r_len || halflen < s_len) { |
2209 | 0 | rv = SC_ERROR_BUFFER_TOO_SMALL; |
2210 | 0 | goto err; |
2211 | 0 | } |
2212 | | |
2213 | 0 | memset(buf, 0, buflen); |
2214 | 0 | if (r_len > 0) |
2215 | 0 | memcpy(buf + (halflen - r_len), r, r_len); |
2216 | 0 | if (s_len > 0) |
2217 | 0 | memcpy(buf + (buflen - s_len), s, s_len); |
2218 | |
|
2219 | 0 | sc_log(ctx, "r(%"SC_FORMAT_LEN_SIZE_T"u): %s", halflen, |
2220 | 0 | sc_dump_hex(buf, halflen)); |
2221 | 0 | sc_log(ctx, "s(%"SC_FORMAT_LEN_SIZE_T"u): %s", halflen, |
2222 | 0 | sc_dump_hex(buf + halflen, halflen)); |
2223 | |
|
2224 | 0 | rv = SC_SUCCESS; |
2225 | 0 | err: |
2226 | 0 | free(r); |
2227 | 0 | free(s); |
2228 | |
|
2229 | 0 | LOG_FUNC_RETURN(ctx, rv); |
2230 | 0 | } |
2231 | | |
2232 | 0 | int sc_asn1_decode_ecdsa_signature(sc_context_t *ctx, const u8 *data, size_t datalen, size_t fieldsize, u8 **out, size_t outlen) { |
2233 | 0 | int i, r; |
2234 | 0 | const unsigned char *pseq, *pint, *pend; |
2235 | 0 | unsigned int cla, tag; |
2236 | 0 | size_t seqlen, intlen; |
2237 | |
|
2238 | 0 | if (!ctx || !data || !out || !(*out)) { |
2239 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
2240 | 0 | } |
2241 | 0 | if (outlen < 2 * fieldsize) { |
2242 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Output too small for EC signature"); |
2243 | 0 | } |
2244 | | |
2245 | 0 | memset(*out, 0, outlen); |
2246 | |
|
2247 | 0 | pseq = data; |
2248 | 0 | r = sc_asn1_read_tag(&pseq, datalen, &cla, &tag, &seqlen); |
2249 | 0 | if (pseq == NULL || r < 0 || seqlen == 0 || (cla | tag) != 0x30) |
2250 | 0 | LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Can not find 0x30 tag"); |
2251 | | |
2252 | 0 | pint = pseq; |
2253 | 0 | pend = pseq + seqlen; |
2254 | 0 | for (i = 0; i < 2; i++) { |
2255 | 0 | r = sc_asn1_read_tag(&pint, (pend - pint), &cla, &tag, &intlen); |
2256 | 0 | if (pint == NULL || r < 0 || intlen == 0 || (cla | tag) != 0x02) { |
2257 | 0 | r = SC_ERROR_INVALID_DATA; |
2258 | 0 | LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INVALID_DATA, "Can not find 0x02"); |
2259 | 0 | } |
2260 | | |
2261 | 0 | if (intlen == fieldsize + 1) { /* drop leading 00 if present */ |
2262 | 0 | if (*pint != 0x00) { |
2263 | 0 | r = SC_ERROR_INVALID_DATA; |
2264 | 0 | LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INVALID_DATA, "Signature too long"); |
2265 | 0 | } |
2266 | 0 | pint++; |
2267 | 0 | intlen--; |
2268 | 0 | } |
2269 | 0 | if (intlen > fieldsize) { |
2270 | 0 | r = SC_ERROR_INVALID_DATA; |
2271 | 0 | LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INVALID_DATA, "Signature too long"); |
2272 | 0 | } |
2273 | 0 | memcpy(*out + fieldsize * i + fieldsize - intlen , pint, intlen); |
2274 | 0 | pint += intlen; /* next integer */ |
2275 | 0 | } |
2276 | 0 | r = (int)(2 * fieldsize); |
2277 | 0 | err: |
2278 | 0 | LOG_FUNC_RETURN(ctx, r); |
2279 | 0 | } |
2280 | | |