libksba  1.6.0
About: KSBA is a library to make the tasks of working with X.509 certificates, CMS data and related objects more easy.
  Fossies Dox: libksba-1.6.0.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

der-encoder.c
Go to the documentation of this file.
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 */
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 store_value (AsnNode node, const void *buffer, size_t length)
56 {
57  _ksba_asn_set_value (node, VALTYPE_MEM, buffer, length);
58  return 0;
59 }
60 
61 static void
63 {
64  _ksba_asn_set_value (node, VALTYPE_NULL, NULL, 0);
65 }
66 
67 
68 
69 ␌
72 {
73  DerEncoder d;
74 
75  d = xtrycalloc (1, sizeof *d);
76  if (!d)
77  return NULL;
78 
79  return d;
80 }
81 
82 void
84 {
85  xfree (d);
86 }
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
102 {
103  if (!d || !module)
104  return gpg_error (GPG_ERR_INV_VALUE);
105  if (d->module)
106  return gpg_error (GPG_ERR_CONFLICT); /* module already set */
107 
108  d->module = module->parse_tree;
109  return 0;
110 }
111 
112 
113 gpg_error_t
115 {
116  if (!d || !w)
117  return gpg_error (GPG_ERR_INV_VALUE);
118  if (d->writer)
119  return gpg_error (GPG_ERR_CONFLICT); /* reader already set */
120 
121  d->writer = w;
122  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
144  const void *parm, size_t parmlen)
145 {
146  gpg_error_t err;
147  unsigned char *buf;
148  size_t len;
149  int no_null = (parm && !parmlen);
150 
151  err = ksba_oid_from_str (oid, &buf, &len);
152  if (err)
153  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. */
160  (no_null? 2:4) + len + (parm? parmlen:0));
161  if (err)
162  goto leave;
163 
164  /* the OBJECT ID header and the value */
166  if (!err)
167  err = ksba_writer_write (w, buf, len);
168  if (err)
169  goto leave;
170 
171  /* Write the parameter */
172  if (no_null)
173  ;
174  else if (parm)
175  {
177  0, parmlen);
178  if (!err)
179  err = ksba_writer_write (w, parm, parmlen);
180  }
181  else
182  {
183  err = _ksba_ber_write_tl (w, TYPE_NULL, CLASS_UNIVERSAL, 0, 0);
184  }
185 
186  leave:
187  xfree (buf);
188  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
203  AsnNode src_root, const unsigned char *src_image)
204 {
205  AsnNode s, d;
206 
207  s = src_root;
208  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  while (s && d && (s->type == d->type || d->flags.is_any))
212  {
213  if (d->flags.is_any)
214  d->type = s->type;
215 
216  if (s->flags.in_array && s->right)
217  {
218  if (!_ksba_asn_insert_copy (d))
219  return gpg_error (GPG_ERR_ENOMEM);
220  }
221 
222  if ( !_ksba_asn_is_primitive (s->type) )
223  ;
224  else if (s->off == -1)
225  clear_value (d);
226  else
227  store_value (d, src_image + s->off + s->nhdr, s->len);
228 
229  s = _ksba_asn_walk_tree (src_root, s);
230  d = _ksba_asn_walk_tree (dst_root, d);
231  }
232 
233  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  return gpg_error (GPG_ERR_ENCODING_PROBLEM);
240  }
241  return 0;
242 }
243 
244 
245 ␌
246 /*********************************************
247  ********** Store data in a tree *************
248  *********************************************/
249 
250 
251 gpg_error_t
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  err = _ksba_assert_time_format (atime);
260  if (err)
261  return err;
262 
263  memcpy (buf, atime, 8);
264  memcpy (buf+8, atime+9, 6);
265  strcpy (buf+14, "Z");
266 
267  /* We need to use generalized time beginning with the year 2050. */
268  need_gen = (_ksba_cmp_time (atime, "20500101T000000") >= 0);
269 
270  if (node->type == TYPE_ANY)
271  node->type = need_gen? TYPE_GENERALIZED_TIME : TYPE_UTC_TIME;
272  else if (node->type == TYPE_CHOICE)
273  { /* find a suitable choice to store the value */
274  AsnNode n;
275 
276  for (n=node->down; n; n=n->right)
277  {
278  if ( (need_gen && n->type == TYPE_GENERALIZED_TIME)
279  || (!need_gen && n->type == TYPE_UTC_TIME))
280  {
281  node = n;
282  break;
283  }
284  }
285  }
286 
287  if (node->type == TYPE_GENERALIZED_TIME
288  || node->type == TYPE_UTC_TIME)
289  {
290  p = node->type == TYPE_UTC_TIME? (buf+2):buf;
291  return store_value (node, p, strlen (p));
292  }
293  else
294  return gpg_error (GPG_ERR_INV_VALUE);
295 }
296 
297 /* Store the utf-8 STRING in NODE. */
298 gpg_error_t
299 _ksba_der_store_string (AsnNode node, const char *string)
300 {
301  if (node->type == TYPE_CHOICE)
302  {
303  /* find a suitable choice to store the value */
304  }
305 
306 
307  if (node->type == TYPE_PRINTABLE_STRING)
308  {
309  return store_value (node, string, strlen (string));
310  }
311  else
312  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 _ksba_der_store_integer (AsnNode node, const unsigned char *value)
321 {
322  if (node->type == TYPE_INTEGER)
323  {
324  size_t len;
325 
326  len = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
327  return store_value (node, value+4, len);
328  }
329  else
330  return gpg_error (GPG_ERR_INV_VALUE);
331 }
332 
333 gpg_error_t
334 _ksba_der_store_oid (AsnNode node, const char *oid)
335 {
336  gpg_error_t err;
337 
338  if (node->type == TYPE_ANY)
339  node->type = TYPE_OBJECT_ID;
340 
341  if (node->type == TYPE_OBJECT_ID)
342  {
343  unsigned char *buf;
344  size_t len;
345 
346  err = ksba_oid_from_str (oid, &buf, &len);
347  if (err)
348  return err;
349  err = store_value (node, buf, len);
350  xfree (buf);
351  return err;
352  }
353  else
354  return gpg_error (GPG_ERR_INV_VALUE);
355 }
356 
357 
358 gpg_error_t
359 _ksba_der_store_octet_string (AsnNode node, const char *buf, size_t len)
360 {
361  if (node->type == TYPE_ANY)
362  node->type = TYPE_OCTET_STRING;
363 
364  if (node->type == TYPE_OCTET_STRING)
365  {
366  return store_value (node, buf, len);
367  }
368  else
369  return gpg_error (GPG_ERR_INV_VALUE);
370 }
371 
372 
373 gpg_error_t
374 _ksba_der_store_sequence (AsnNode node, const unsigned char *buf, size_t len)
375 {
376  if (node->type == TYPE_ANY)
377  node->type = TYPE_PRE_SEQUENCE;
378 
379  if (node->type == TYPE_SEQUENCE || node->type == TYPE_PRE_SEQUENCE)
380  {
381  return store_value (node, buf, len);
382  }
383  else
384  return gpg_error (GPG_ERR_INV_VALUE);
385 }
386 
387 
388 gpg_error_t
390 {
391  if (node->type == TYPE_ANY)
392  node->type = TYPE_NULL;
393 
394  if (node->type == TYPE_NULL)
395  {
396  clear_value (node);
397  return 0;
398  }
399  else
400  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 set_nhdr_and_len (AsnNode node, unsigned long length)
414 {
415  int buflen = 0;
416 
417  if (node->type == TYPE_SET_OF || node->type == TYPE_SEQUENCE_OF)
418  buflen++;
419  else if (node->type == TYPE_TAG)
420  buflen++;
421  else if (node->type < 0x1f || node->type == TYPE_PRE_SEQUENCE)
422  buflen++;
423  else
424  {
425  never_reached ();
426  /* Fixme: tags with values above 31 are not yet implemented */
427  }
428 
429  if (!node->type /*&& !class*/)
430  buflen++; /* end tag */
431  else if (node->type == TYPE_NULL /*&& !class*/)
432  buflen++; /* NULL tag */
433  else if (!length)
434  buflen++; /* indefinite length */
435  else if (length < 128)
436  buflen++;
437  else
438  {
439  buflen += (length <= 0xff ? 2:
440  length <= 0xffff ? 3:
441  length <= 0xffffff ? 4: 5);
442  }
443 
444  node->len = length;
445  node->nhdr = buflen;
446 }
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 copy_nhdr_and_len (unsigned char *buffer, AsnNode node)
452 {
453  unsigned char *p = buffer;
454  int tag, class;
455  unsigned long length;
456 
457  tag = node->type;
458  class = CLASS_UNIVERSAL;
459  length = node->len;
460 
461  if (tag == TYPE_SET_OF)
462  tag = TYPE_SET;
463  else if (tag == TYPE_SEQUENCE_OF)
464  tag = TYPE_SEQUENCE;
465  else if (tag == TYPE_PRE_SEQUENCE)
466  tag = TYPE_SEQUENCE;
467  else if (tag == TYPE_TAG)
468  {
469  class = CLASS_CONTEXT; /* Hmmm: we no way to handle other classes */
470  tag = node->value.v_ulong;
471  }
472  if (tag < 0x1f)
473  {
474  *p = (class << 6) | tag;
475  if (!_ksba_asn_is_primitive (tag))
476  *p |= 0x20;
477  p++;
478  }
479  else
480  {
481  /* fixme: Not_Implemented*/
482  }
483 
484  if (!tag && !class)
485  *p++ = 0; /* end tag */
486  else if (tag == TYPE_NULL && !class)
487  *p++ = 0; /* NULL tag */
488  else if (!length)
489  *p++ = 0x80; /* indefinite length - can't happen! */
490  else if (length < 128)
491  *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  i = (length <= 0xff ? 1:
499  length <= 0xffff ? 2:
500  length <= 0xffffff ? 3: 4);
501 
502  *p++ = (0x80 | i);
503  if (i > 3)
504  *p++ = length >> 24;
505  if (i > 2)
506  *p++ = length >> 16;
507  if (i > 1)
508  *p++ = length >> 8;
509  *p++ = length;
510  }
511 
512  return p - buffer;
513 }
514 
515 
516 
517 static unsigned long
519 {
520  AsnNode n;
521  unsigned long len = 0;
522 
523  if (root->type == TYPE_NULL)
524  return root->nhdr;
525 
526  if (!(n=root->down) || _ksba_asn_is_primitive (root->type))
527  len = root->len;
528  else
529  {
530  for (; n; n = n->right)
531  len += sum_up_lengths (n);
532  }
533  if ( !_ksba_asn_is_primitive (root->type)
534  && root->type != TYPE_CHOICE
535  && len
536  && !root->flags.is_implicit)
537  { /* this is a constructed one */
538  set_nhdr_and_len (root, len);
539  }
540 
541  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
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  for (n=root; n ; n = _ksba_asn_walk_tree (root, n))
559  {
560  n->off = -1;
561  n->len = 0;
562  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  for (n=root; n ; n = _ksba_asn_walk_tree (root, n))
571  {
573  && !n->flags.is_implicit
574  && ((n->valuetype == VALTYPE_MEM && n->value.v_mem.len)
575  || n->type == TYPE_NULL))
577  }
578 
579  /* Now calculate the length of all constructed types */
580  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  image = xtrymalloc (imagelen);
594  if (!image)
595  return gpg_error (GPG_ERR_ENOMEM);
596  len = 0;
597  for (n=root; n ; n = _ksba_asn_walk_tree (root, n))
598  {
599  size_t nbytes;
600 
601  if (!n->nhdr)
602  continue;
603  assert (n->off == -1);
604  assert (len < imagelen);
605  n->off = len;
606  nbytes = copy_nhdr_and_len (image+len, n);
607  len += nbytes;
608  if ( _ksba_asn_is_primitive (n->type)
609  && n->valuetype == VALTYPE_MEM
610  && n->value.v_mem.len )
611  {
612  nbytes = n->value.v_mem.len;
613  assert (len + nbytes <= imagelen);
614  memcpy (image+len, n->value.v_mem.buf, nbytes);
615  len += nbytes;
616  }
617  }
618 
619  assert (len == imagelen);
620 
621  *r_image = image;
622  if (r_imagelen)
623  *r_imagelen = imagelen;
624  return 0;
625 }
@ TYPE_SEQUENCE_OF
@ TYPE_OCTET_STRING
@ TYPE_NULL
@ TYPE_TAG
@ TYPE_GENERALIZED_TIME
@ TYPE_OBJECT_ID
@ TYPE_INTEGER
@ TYPE_SET_OF
@ TYPE_PRE_SEQUENCE
@ TYPE_PRINTABLE_STRING
@ TYPE_SEQUENCE
@ TYPE_SET
@ TYPE_UTC_TIME
@ TYPE_CHOICE
@ TYPE_ANY
@ CLASS_CONTEXT
@ CLASS_UNIVERSAL
void _ksba_asn_set_value(AsnNode node, enum asn_value_type vtype, const void *value, size_t len)
Definition: asn1-func.c:127
AsnNode _ksba_asn_insert_copy(AsnNode node)
Definition: asn1-func.c:1258
int _ksba_asn_is_primitive(node_type_t type)
Definition: asn1-func.c:87
void _ksba_asn_node_dump_all(AsnNode root, FILE *fp)
Definition: asn1-func.c:547
AsnNode _ksba_asn_walk_tree(AsnNode root, AsnNode node)
Definition: asn1-func.c:790
@ VALTYPE_MEM
Definition: asn1-func.h:72
@ VALTYPE_NULL
Definition: asn1-func.h:69
gpg_error_t _ksba_ber_write_tl(ksba_writer_t writer, unsigned long tag, enum tag_class class, int constructed, unsigned long length)
Definition: ber-help.c:316
const char * oid
Definition: cms.c:71
gpg_error_t _ksba_assert_time_format(const ksba_isotime_t atime)
Definition: time.c:102
int _ksba_cmp_time(const ksba_isotime_t a, const ksba_isotime_t b)
Definition: time.c:145
gpg_error_t _ksba_der_encoder_set_writer(DerEncoder d, ksba_writer_t w)
Definition: der-encoder.c:114
static gpg_error_t store_value(AsnNode node, const void *buffer, size_t length)
Definition: der-encoder.c:55
static unsigned long sum_up_lengths(AsnNode root)
Definition: der-encoder.c:518
static void set_nhdr_and_len(AsnNode node, unsigned long length)
Definition: der-encoder.c:413
gpg_error_t _ksba_der_store_sequence(AsnNode node, const unsigned char *buf, size_t len)
Definition: der-encoder.c:374
gpg_error_t _ksba_der_store_null(AsnNode node)
Definition: der-encoder.c:389
gpg_error_t _ksba_der_store_integer(AsnNode node, const unsigned char *value)
Definition: der-encoder.c:320
void _ksba_der_encoder_release(DerEncoder d)
Definition: der-encoder.c:83
gpg_error_t _ksba_der_write_algorithm_identifier(ksba_writer_t w, const char *oid, const void *parm, size_t parmlen)
Definition: der-encoder.c:143
gpg_error_t _ksba_der_copy_tree(AsnNode dst_root, AsnNode src_root, const unsigned char *src_image)
Definition: der-encoder.c:202
gpg_error_t _ksba_der_encode_tree(AsnNode root, unsigned char **r_image, size_t *r_imagelen)
Definition: der-encoder.c:550
gpg_error_t _ksba_der_encoder_set_module(DerEncoder d, ksba_asn_tree_t module)
Definition: der-encoder.c:101
gpg_error_t _ksba_der_store_oid(AsnNode node, const char *oid)
Definition: der-encoder.c:334
gpg_error_t _ksba_der_store_string(AsnNode node, const char *string)
Definition: der-encoder.c:299
gpg_error_t _ksba_der_store_time(AsnNode node, const ksba_isotime_t atime)
Definition: der-encoder.c:252
static size_t copy_nhdr_and_len(unsigned char *buffer, AsnNode node)
Definition: der-encoder.c:451
static void clear_value(AsnNode node)
Definition: der-encoder.c:62
gpg_error_t _ksba_der_store_octet_string(AsnNode node, const char *buf, size_t len)
Definition: der-encoder.c:359
DerEncoder _ksba_der_encoder_new(void)
Definition: der-encoder.c:71
#define GPG_ERR_INV_VALUE
Definition: gen-help.h:82
#define xtrymalloc(a)
Definition: gen-help.h:38
#define gpg_error(a)
Definition: gen-help.h:87
#define never_reached()
Definition: gen-help.h:73
gpg_error_t ksba_oid_from_str(const char *string, unsigned char **rbuf, size_t *rlength)
gpg_error_t ksba_writer_write(ksba_writer_t w, const void *buffer, size_t length)
char ksba_isotime_t[16]
Definition: ksba.h:212
union asn_value_u value
Definition: asn1-func.h:104
AsnNode right
Definition: asn1-func.h:111
enum asn_value_type valuetype
Definition: asn1-func.h:103
AsnNode down
Definition: asn1-func.h:110
node_type_t type
Definition: asn1-func.h:100
struct node_flag_s flags
Definition: asn1-func.h:101
AsnNode root
Definition: der-encoder.c:48
AsnNode module
Definition: der-encoder.c:45
const char * last_errdesc
Definition: der-encoder.c:47
ksba_writer_t writer
Definition: der-encoder.c:46
AsnNode parse_tree
Definition: asn1-func.h:118
int in_array
Definition: asn1-func.h:58
int is_implicit
Definition: asn1-func.h:55
int is_any
Definition: asn1-func.h:59
size_t len
Definition: asn1-func.h:81
unsigned long v_ulong
Definition: asn1-func.h:85
unsigned char * buf
Definition: asn1-func.h:82
struct asn_value_u::@1 v_mem
#define xfree(a)
Definition: util.h:58
#define xtrycalloc(a, b)
Definition: util.h:55