Line data Source code
1 : /* der-decoder.c - Distinguished Encoding Rules Encoder
2 : * Copyright (C) 2001, 2004, 2008, 2012 g10 Code GmbH
3 : *
4 : * This file is part of KSBA.
5 : *
6 : * KSBA is free software; you can redistribute it and/or modify
7 : * it under the terms of either
8 : *
9 : * - the GNU Lesser General Public License as published by the Free
10 : * Software Foundation; either version 3 of the License, or (at
11 : * your option) any later version.
12 : *
13 : * or
14 : *
15 : * - the GNU General Public License as published by the Free
16 : * Software Foundation; either version 2 of the License, or (at
17 : * your option) any later version.
18 : *
19 : * or both in parallel, as here.
20 : *
21 : * KSBA is distributed in the hope that it will be useful, but WITHOUT
22 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 : * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
24 : * License for more details.
25 : *
26 : * You should have received a copies of the GNU General Public License
27 : * and the GNU Lesser General Public License along with this program;
28 : * if not, see <http://www.gnu.org/licenses/>.
29 : */
30 :
31 : #include <config.h>
32 : #include <stdio.h>
33 : #include <stdlib.h>
34 : #include <string.h>
35 : #include <assert.h>
36 : #include "util.h"
37 :
38 : #include "ksba.h"
39 : #include "asn1-func.h"
40 : #include "ber-help.h"
41 : #include "der-encoder.h"
42 : #include "convert.h"
43 :
44 : struct der_encoder_s {
45 : AsnNode module; /* the ASN.1 structure */
46 : ksba_writer_t writer;
47 : const char *last_errdesc; /* string with the error description */
48 : AsnNode root; /* of the expanded parse tree */
49 : int debug;
50 : };
51 :
52 : /* To be useful for the DER encoder we store all data direct as the
53 : binary image, so we use the VALTYPE_MEM */
54 : static gpg_error_t
55 0 : store_value (AsnNode node, const void *buffer, size_t length)
56 : {
57 0 : _ksba_asn_set_value (node, VALTYPE_MEM, buffer, length);
58 0 : return 0;
59 : }
60 :
61 : static void
62 0 : clear_value (AsnNode node)
63 : {
64 0 : _ksba_asn_set_value (node, VALTYPE_NULL, NULL, 0);
65 0 : }
66 :
67 :
68 :
69 :
70 : DerEncoder
71 0 : _ksba_der_encoder_new (void)
72 : {
73 : DerEncoder d;
74 :
75 0 : d = xtrycalloc (1, sizeof *d);
76 0 : if (!d)
77 0 : return NULL;
78 :
79 0 : return d;
80 : }
81 :
82 : void
83 0 : _ksba_der_encoder_release (DerEncoder d)
84 : {
85 0 : xfree (d);
86 0 : }
87 :
88 :
89 : /**
90 : * _ksba_der_encoder_set_module:
91 : * @d: Decoder object
92 : * @module: ASN.1 Parse tree
93 : *
94 : * Initialize the decoder with the ASN.1 module. Note, that this is a
95 : * shallow copy of the module. Fixme: What about ref-counting of
96 : * AsnNodes?
97 : *
98 : * Return value: 0 on success or an error code
99 : **/
100 : gpg_error_t
101 0 : _ksba_der_encoder_set_module (DerEncoder d, ksba_asn_tree_t module)
102 : {
103 0 : if (!d || !module)
104 0 : return gpg_error (GPG_ERR_INV_VALUE);
105 0 : if (d->module)
106 0 : return gpg_error (GPG_ERR_CONFLICT); /* module already set */
107 :
108 0 : d->module = module->parse_tree;
109 0 : return 0;
110 : }
111 :
112 :
113 : gpg_error_t
114 0 : _ksba_der_encoder_set_writer (DerEncoder d, ksba_writer_t w)
115 : {
116 0 : if (!d || !w)
117 0 : return gpg_error (GPG_ERR_INV_VALUE);
118 0 : if (d->writer)
119 0 : return gpg_error (GPG_ERR_CONFLICT); /* reader already set */
120 :
121 0 : d->writer = w;
122 0 : return 0;
123 : }
124 :
125 :
126 :
127 : /*
128 : Helpers to construct and write out objects
129 : */
130 :
131 :
132 : /* Create and write a
133 :
134 : AlgorithmIdentifier ::= SEQUENCE {
135 : algorithm OBJECT IDENTIFIER,
136 : parameters ANY DEFINED BY algorithm OPTIONAL
137 : }
138 :
139 : where parameters will be set to NULL if parm is NULL or to an octet
140 : string with the given parm. As a special hack parameter will not be
141 : written if PARM is given but parmlen is 0. */
142 : gpg_error_t
143 0 : _ksba_der_write_algorithm_identifier (ksba_writer_t w, const char *oid,
144 : const void *parm, size_t parmlen)
145 : {
146 : gpg_error_t err;
147 : unsigned char *buf;
148 : size_t len;
149 0 : int no_null = (parm && !parmlen);
150 :
151 0 : err = ksba_oid_from_str (oid, &buf, &len);
152 0 : if (err)
153 0 : return err;
154 :
155 : /* write the sequence */
156 : /* fixme: the the length to encode the TLV values are actually not
157 : just 2 byte each but depend on the length of the values - for
158 : our purposes the static values do work. */
159 0 : err = _ksba_ber_write_tl (w, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1,
160 0 : (no_null? 2:4) + len + (parm? parmlen:0));
161 0 : if (err)
162 0 : goto leave;
163 :
164 : /* the OBJECT ID header and the value */
165 0 : err = _ksba_ber_write_tl (w, TYPE_OBJECT_ID, CLASS_UNIVERSAL, 0, len);
166 0 : if (!err)
167 0 : err = ksba_writer_write (w, buf, len);
168 0 : if (err)
169 0 : goto leave;
170 :
171 : /* Write the parameter */
172 0 : if (no_null)
173 : ;
174 0 : else if (parm)
175 : {
176 0 : err = _ksba_ber_write_tl (w, TYPE_OCTET_STRING, CLASS_UNIVERSAL,
177 : 0, parmlen);
178 0 : if (!err)
179 0 : err = ksba_writer_write (w, parm, parmlen);
180 : }
181 : else
182 : {
183 0 : err = _ksba_ber_write_tl (w, TYPE_NULL, CLASS_UNIVERSAL, 0, 0);
184 : }
185 :
186 : leave:
187 0 : xfree (buf);
188 0 : return err;
189 : }
190 :
191 :
192 :
193 :
194 :
195 : /*************************************************
196 : *** Copy data from a tree image to the tree ***
197 : *************************************************/
198 :
199 : /* Copy all values from the tree SRC (with values store in SRCIMAGE)
200 : to the tree DST */
201 : gpg_error_t
202 0 : _ksba_der_copy_tree (AsnNode dst_root,
203 : AsnNode src_root, const unsigned char *src_image)
204 : {
205 : AsnNode s, d;
206 :
207 0 : s = src_root;
208 0 : d = dst_root;
209 : /* note: we use the is_any flags becuase an inserted copy may have
210 : already changed the any tag to the actual type */
211 0 : while (s && d && (s->type == d->type || d->flags.is_any))
212 : {
213 0 : if (d->flags.is_any)
214 0 : d->type = s->type;
215 :
216 0 : if (s->flags.in_array && s->right)
217 : {
218 0 : if (!_ksba_asn_insert_copy (d))
219 0 : return gpg_error (GPG_ERR_ENOMEM);
220 : }
221 :
222 0 : if ( !_ksba_asn_is_primitive (s->type) )
223 : ;
224 0 : else if (s->off == -1)
225 0 : clear_value (d);
226 : else
227 0 : store_value (d, src_image + s->off + s->nhdr, s->len);
228 :
229 0 : s = _ksba_asn_walk_tree (src_root, s);
230 0 : d = _ksba_asn_walk_tree (dst_root, d);
231 : }
232 :
233 0 : if (s || d)
234 : {
235 : /* fputs ("ksba_der_copy_tree: trees don't match\nSOURCE TREE:\n", stderr); */
236 : /* _ksba_asn_node_dump_all (src_root, stderr); */
237 : /* fputs ("DESTINATION TREE:\n", stderr); */
238 : /* _ksba_asn_node_dump_all (dst_root, stderr); */
239 0 : return gpg_error (GPG_ERR_ENCODING_PROBLEM);
240 : }
241 0 : return 0;
242 : }
243 :
244 :
245 :
246 : /*********************************************
247 : ********** Store data in a tree *************
248 : *********************************************/
249 :
250 :
251 : gpg_error_t
252 0 : _ksba_der_store_time (AsnNode node, const ksba_isotime_t atime)
253 : {
254 : char buf[50], *p;
255 : int need_gen;
256 : gpg_error_t err;
257 :
258 : /* First check that ATIME is indeed as formatted as expected. */
259 0 : err = _ksba_assert_time_format (atime);
260 0 : if (err)
261 0 : return err;
262 :
263 0 : memcpy (buf, atime, 8);
264 0 : memcpy (buf+8, atime+9, 6);
265 0 : strcpy (buf+14, "Z");
266 :
267 : /* We need to use generalized time beginning with the year 2050. */
268 0 : need_gen = (_ksba_cmp_time (atime, "20500101T000000") >= 0);
269 :
270 0 : if (node->type == TYPE_ANY)
271 0 : node->type = need_gen? TYPE_GENERALIZED_TIME : TYPE_UTC_TIME;
272 0 : else if (node->type == TYPE_CHOICE)
273 : { /* find a suitable choice to store the value */
274 : AsnNode n;
275 :
276 0 : for (n=node->down; n; n=n->right)
277 : {
278 0 : if ( (need_gen && n->type == TYPE_GENERALIZED_TIME)
279 0 : || (!need_gen && n->type == TYPE_UTC_TIME))
280 : {
281 0 : node = n;
282 0 : break;
283 : }
284 : }
285 : }
286 :
287 0 : if (node->type == TYPE_GENERALIZED_TIME
288 0 : || node->type == TYPE_UTC_TIME)
289 : {
290 0 : p = node->type == TYPE_UTC_TIME? (buf+2):buf;
291 0 : return store_value (node, p, strlen (p));
292 : }
293 : else
294 0 : return gpg_error (GPG_ERR_INV_VALUE);
295 : }
296 :
297 : /* Store the utf-8 STRING in NODE. */
298 : gpg_error_t
299 0 : _ksba_der_store_string (AsnNode node, const char *string)
300 : {
301 0 : if (node->type == TYPE_CHOICE)
302 : {
303 : /* find a suitable choice to store the value */
304 : }
305 :
306 :
307 0 : if (node->type == TYPE_PRINTABLE_STRING)
308 : {
309 0 : return store_value (node, string, strlen (string));
310 : }
311 : else
312 0 : return gpg_error (GPG_ERR_INV_VALUE);
313 : }
314 :
315 :
316 : /* Store the integer VALUE in NODE. VALUE is assumed to be a DER
317 : encoded integer prefixed with 4 bytes given its length in network
318 : byte order. */
319 : gpg_error_t
320 0 : _ksba_der_store_integer (AsnNode node, const unsigned char *value)
321 : {
322 0 : if (node->type == TYPE_INTEGER)
323 : {
324 : size_t len;
325 :
326 0 : len = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
327 0 : return store_value (node, value+4, len);
328 : }
329 : else
330 0 : return gpg_error (GPG_ERR_INV_VALUE);
331 : }
332 :
333 : gpg_error_t
334 0 : _ksba_der_store_oid (AsnNode node, const char *oid)
335 : {
336 : gpg_error_t err;
337 :
338 0 : if (node->type == TYPE_ANY)
339 0 : node->type = TYPE_OBJECT_ID;
340 :
341 0 : if (node->type == TYPE_OBJECT_ID)
342 : {
343 : unsigned char *buf;
344 : size_t len;
345 :
346 0 : err = ksba_oid_from_str (oid, &buf, &len);
347 0 : if (err)
348 0 : return err;
349 0 : err = store_value (node, buf, len);
350 0 : xfree (buf);
351 0 : return err;
352 : }
353 : else
354 0 : return gpg_error (GPG_ERR_INV_VALUE);
355 : }
356 :
357 :
358 : gpg_error_t
359 0 : _ksba_der_store_octet_string (AsnNode node, const char *buf, size_t len)
360 : {
361 0 : if (node->type == TYPE_ANY)
362 0 : node->type = TYPE_OCTET_STRING;
363 :
364 0 : if (node->type == TYPE_OCTET_STRING)
365 : {
366 0 : return store_value (node, buf, len);
367 : }
368 : else
369 0 : return gpg_error (GPG_ERR_INV_VALUE);
370 : }
371 :
372 :
373 : gpg_error_t
374 0 : _ksba_der_store_sequence (AsnNode node, const unsigned char *buf, size_t len)
375 : {
376 0 : if (node->type == TYPE_ANY)
377 0 : node->type = TYPE_PRE_SEQUENCE;
378 :
379 0 : if (node->type == TYPE_SEQUENCE || node->type == TYPE_PRE_SEQUENCE)
380 : {
381 0 : return store_value (node, buf, len);
382 : }
383 : else
384 0 : return gpg_error (GPG_ERR_INV_VALUE);
385 : }
386 :
387 :
388 : gpg_error_t
389 0 : _ksba_der_store_null (AsnNode node)
390 : {
391 0 : if (node->type == TYPE_ANY)
392 0 : node->type = TYPE_NULL;
393 :
394 0 : if (node->type == TYPE_NULL)
395 : {
396 0 : clear_value (node);
397 0 : return 0;
398 : }
399 : else
400 0 : return gpg_error (GPG_ERR_INV_VALUE);
401 : }
402 :
403 :
404 : /*
405 : Actual DER encoder
406 : */
407 :
408 : /* We have a value for this node. Calculate the length of the header
409 : and store it in node->nhdr and store the length of the value in
410 : node->value. We assume that this is a primitive node and has a
411 : value of type VALTYPE_MEM. */
412 : static void
413 0 : set_nhdr_and_len (AsnNode node, unsigned long length)
414 : {
415 0 : int buflen = 0;
416 :
417 0 : if (node->type == TYPE_SET_OF || node->type == TYPE_SEQUENCE_OF)
418 0 : buflen++;
419 0 : else if (node->type == TYPE_TAG)
420 0 : buflen++;
421 0 : else if (node->type < 0x1f || node->type == TYPE_PRE_SEQUENCE)
422 0 : buflen++;
423 : else
424 : {
425 0 : never_reached ();
426 : /* Fixme: tags with values above 31 are not yet implemented */
427 : }
428 :
429 0 : if (!node->type /*&& !class*/)
430 0 : buflen++; /* end tag */
431 0 : else if (node->type == TYPE_NULL /*&& !class*/)
432 0 : buflen++; /* NULL tag */
433 0 : else if (!length)
434 0 : buflen++; /* indefinite length */
435 0 : else if (length < 128)
436 0 : buflen++;
437 : else
438 : {
439 0 : buflen += (length <= 0xff ? 2:
440 0 : length <= 0xffff ? 3:
441 0 : length <= 0xffffff ? 4: 5);
442 : }
443 :
444 0 : node->len = length;
445 0 : node->nhdr = buflen;
446 0 : }
447 :
448 : /* Like above but put now put it into buffer. return the number of
449 : bytes copied. There is no need to do length checking here */
450 : static size_t
451 0 : copy_nhdr_and_len (unsigned char *buffer, AsnNode node)
452 : {
453 0 : unsigned char *p = buffer;
454 : int tag, class;
455 : unsigned long length;
456 :
457 0 : tag = node->type;
458 0 : class = CLASS_UNIVERSAL;
459 0 : length = node->len;
460 :
461 0 : if (tag == TYPE_SET_OF)
462 0 : tag = TYPE_SET;
463 0 : else if (tag == TYPE_SEQUENCE_OF)
464 0 : tag = TYPE_SEQUENCE;
465 0 : else if (tag == TYPE_PRE_SEQUENCE)
466 0 : tag = TYPE_SEQUENCE;
467 0 : else if (tag == TYPE_TAG)
468 : {
469 0 : class = CLASS_CONTEXT; /* Hmmm: we no way to handle other classes */
470 0 : tag = node->value.v_ulong;
471 : }
472 0 : if (tag < 0x1f)
473 : {
474 0 : *p = (class << 6) | tag;
475 0 : if (!_ksba_asn_is_primitive (tag))
476 0 : *p |= 0x20;
477 0 : p++;
478 : }
479 : else
480 : {
481 : /* fixme: Not_Implemented*/
482 : }
483 :
484 0 : if (!tag && !class)
485 0 : *p++ = 0; /* end tag */
486 0 : else if (tag == TYPE_NULL && !class)
487 0 : *p++ = 0; /* NULL tag */
488 0 : else if (!length)
489 0 : *p++ = 0x80; /* indefinite length - can't happen! */
490 0 : else if (length < 128)
491 0 : *p++ = length;
492 : else
493 : {
494 : int i;
495 :
496 : /* fixme: if we know the sizeof an ulong we could support larger
497 : objects - however this is pretty ridiculous */
498 0 : i = (length <= 0xff ? 1:
499 0 : length <= 0xffff ? 2:
500 0 : length <= 0xffffff ? 3: 4);
501 :
502 0 : *p++ = (0x80 | i);
503 0 : if (i > 3)
504 0 : *p++ = length >> 24;
505 0 : if (i > 2)
506 0 : *p++ = length >> 16;
507 0 : if (i > 1)
508 0 : *p++ = length >> 8;
509 0 : *p++ = length;
510 : }
511 :
512 0 : return p - buffer;
513 : }
514 :
515 :
516 :
517 : static unsigned long
518 0 : sum_up_lengths (AsnNode root)
519 : {
520 : AsnNode n;
521 0 : unsigned long len = 0;
522 :
523 0 : if (root->type == TYPE_NULL)
524 0 : return root->nhdr;
525 :
526 0 : if (!(n=root->down) || _ksba_asn_is_primitive (root->type))
527 0 : len = root->len;
528 : else
529 : {
530 0 : for (; n; n = n->right)
531 0 : len += sum_up_lengths (n);
532 : }
533 0 : if ( !_ksba_asn_is_primitive (root->type)
534 0 : && root->type != TYPE_CHOICE
535 0 : && len
536 0 : && !root->flags.is_implicit)
537 : { /* this is a constructed one */
538 0 : set_nhdr_and_len (root, len);
539 : }
540 :
541 0 : return len? (len + root->nhdr):0;
542 : }
543 :
544 : /* Create a DER encoding from the value tree ROOT and return an
545 : allocated image of appropriate length in r_image and r_imagelen.
546 : The value tree is modified so that it can be used the same way as a
547 : parsed one, i.e the elements off, and len are set to point into
548 : image. */
549 : gpg_error_t
550 0 : _ksba_der_encode_tree (AsnNode root,
551 : unsigned char **r_image, size_t *r_imagelen)
552 : {
553 : AsnNode n;
554 : unsigned char *image;
555 : size_t imagelen, len;
556 :
557 : /* clear out all fields */
558 0 : for (n=root; n ; n = _ksba_asn_walk_tree (root, n))
559 : {
560 0 : n->off = -1;
561 0 : n->len = 0;
562 0 : n->nhdr = 0;
563 : }
564 :
565 : /* Set default values */
566 : /* FIXME */
567 :
568 : /* calculate the length of the headers. These are the tag and
569 : length fields of all primitive elements */
570 0 : for (n=root; n ; n = _ksba_asn_walk_tree (root, n))
571 : {
572 0 : if (_ksba_asn_is_primitive (n->type)
573 0 : && !n->flags.is_implicit
574 0 : && ((n->valuetype == VALTYPE_MEM && n->value.v_mem.len)
575 0 : || n->type == TYPE_NULL))
576 0 : set_nhdr_and_len (n, n->value.v_mem.len);
577 : }
578 :
579 : /* Now calculate the length of all constructed types */
580 0 : imagelen = sum_up_lengths (root);
581 :
582 : #if 0
583 : /* set off to zero, so that it can be dumped */
584 : for (n=root; n ; n = _ksba_asn_walk_tree (root, n))
585 : n->off = 0;
586 : fputs ("DER encoded value Tree:\n", stderr);
587 : _ksba_asn_node_dump_all (root, stderr);
588 : for (n=root; n ; n = _ksba_asn_walk_tree (root, n))
589 : n->off = -1;
590 : #endif
591 :
592 : /* now we can create an encoding in image */
593 0 : image = xtrymalloc (imagelen);
594 0 : if (!image)
595 0 : return gpg_error (GPG_ERR_ENOMEM);
596 0 : len = 0;
597 0 : for (n=root; n ; n = _ksba_asn_walk_tree (root, n))
598 : {
599 : size_t nbytes;
600 :
601 0 : if (!n->nhdr)
602 0 : continue;
603 0 : assert (n->off == -1);
604 0 : assert (len < imagelen);
605 0 : n->off = len;
606 0 : nbytes = copy_nhdr_and_len (image+len, n);
607 0 : len += nbytes;
608 0 : if ( _ksba_asn_is_primitive (n->type)
609 0 : && n->valuetype == VALTYPE_MEM
610 0 : && n->value.v_mem.len )
611 : {
612 0 : nbytes = n->value.v_mem.len;
613 0 : assert (len + nbytes <= imagelen);
614 0 : memcpy (image+len, n->value.v_mem.buf, nbytes);
615 0 : len += nbytes;
616 : }
617 : }
618 :
619 0 : assert (len == imagelen);
620 :
621 0 : *r_image = image;
622 0 : if (r_imagelen)
623 0 : *r_imagelen = imagelen;
624 0 : return 0;
625 : }
|