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-builder.c
Go to the documentation of this file.
1 /* der-builder.c - Straightforward DER object builder
2  * Copyright (C) 2020 g10 Code GmbH
3  *
4  * This file is part of KSBA.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * This file 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1-or-later
19  */
20 
21 /* This is a new way in KSBA to build DER objects without the need and
22  * overhead of using an ASN.1 module. It further avoids a lot of error
23  * checking because the error checking is delayed to the last call.
24  *
25  * For an example on how to use it see cms.c
26  */
27 
28 #include <config.h>
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <assert.h>
34 
35 #include "util.h"
36 #include "asn1-constants.h"
37 #include "convert.h"
38 #include "ber-help.h"
39 #include "der-builder.h"
40 
41 
42 
43 struct item_s
44 {
45  unsigned int tag;
46  unsigned int class:2;
47  unsigned int hdrlen:10; /* Computed size of tag+length field. */
48  unsigned int is_constructed:1; /* This is a constructed element. */
49  unsigned int encapsulate:1; /* This encapsulates other objects. */
50  unsigned int verbatim:1; /* Copy the value verbatim. */
51  unsigned int is_stop:1; /* This is a STOP item. */
52  const void *value;
53  size_t valuelen;
54  char *buffer; /* Malloced space or NULL. */
55 };
56 
57 
58 /* Our DER context object; it may eventually be extended to also
59  * feature a parser. */
60 struct ksba_der_s
61 {
62  gpg_error_t error; /* Last error. */
63  size_t nallocateditems; /* Number of allocated items. */
64  size_t nitems; /* Number of used items. */
65  struct item_s *items; /* Array of items. */
66  int laststop; /* Used as return value of compute_length. */
67  unsigned int finished:1;/* The object has been constructed. */
68 };
69 
70 
71 /* Release a DER object. */
72 void
74 {
75  int idx;
76 
77  if (!d)
78  return;
79 
80  for (idx=0; idx < d->nitems; idx++)
81  xfree (d->items[idx].buffer);
82  xfree (d->items);
83  xfree (d);
84 }
85 
86 
87 /* Allocate a new DER builder instance. Returns NULL on error.
88  * NITEMS can be used to tell the number of DER items needed so to
89  * reduce the number of automatic reallocations. */
91 _ksba_der_builder_new (unsigned int nitems)
92 {
93  ksba_der_t d;
94 
95  d = xtrycalloc (1, sizeof *d);
96  if (!d)
97  return NULL;
98  if (nitems)
99  {
100  d->nallocateditems = nitems;
101  d->items = xtrycalloc (d->nallocateditems, sizeof *d->items);
102  if (!d->items)
103  {
104  xfree (d);
105  return NULL;
106  }
107  }
108 
109  return d;
110 }
111 
112 
113 /* Reset a DER build context so that a new sequence can be build. */
114 void
116 {
117  int idx;
118 
119  if (!d)
120  return; /* Oops. */
121  for (idx=0; idx < d->nitems; idx++)
122  {
123  if (d->items[idx].buffer)
124  {
125  xfree (d->items[idx].buffer);
126  d->items[idx].buffer = NULL;
127  }
128  d->items[idx].hdrlen = 0;
129  d->items[idx].is_constructed = 0;
130  d->items[idx].encapsulate = 0;
131  d->items[idx].verbatim = 0;
132  d->items[idx].is_stop = 0;
133  d->items[idx].value = NULL;
134  }
135  d->nitems = 0;
136  d->finished = 0;
137  d->error = 0;
138 }
139 
140 
141 /* Make sure the array of items is large enough for one new item.
142  * Records any error in D and returns true in that case. True is also
143  * returned if D is in finished state. */
144 static int
146 {
147  struct item_s *newitems;
148 
149  if (!d || d->error || d->finished)
150  return 1;
151 
152  if (d->nitems == d->nallocateditems)
153  {
154  d->nallocateditems += 32;
155  newitems = _ksba_reallocarray (d->items, d->nitems,
156  d->nallocateditems, sizeof *newitems);
157  if (!newitems)
159  else
160  d->items = newitems;
161  }
162  return !!d->error;
163 }
164 
165 
166 /* Add a new primitive element to the builder instance D. The element
167  * is described by CLASS, TAG, VALUE, and VALUELEN. CLASS and TAG
168  * must describe a primitive element and (VALUE,VALUELEN) specify its
169  * value. The value is a pointer and its object must not be changed
170  * as long as the instance D exists. For a TYPE_NULL tag no value is
171  * expected. Errors are not returned but recorded for later
172  * retrieval. */
173 void
174 _ksba_der_add_ptr (ksba_der_t d, int class, int tag,
175  void *value, size_t valuelen)
176 {
177  if (ensure_space (d))
178  return;
179  d->items[d->nitems].class = class & 0x03;
180  d->items[d->nitems].tag = tag;
181  d->items[d->nitems].value = value;
182  d->items[d->nitems].valuelen = valuelen;
183  d->nitems++;
184 }
185 
186 
187 /* This is a low level function which assumes that D has been
188  * validated, VALUE is not NULL and enough space for a new item is
189  * available. It takes ownership of VALUE. VERBATIM is usually
190  * passed as false */
191 static void
192 add_val_core (ksba_der_t d, int class, int tag, void *value, size_t valuelen,
193  int verbatim)
194 {
195  d->items[d->nitems].buffer = value;
196  d->items[d->nitems].class = class & 0x03;
197  d->items[d->nitems].tag = tag;
198  d->items[d->nitems].value = value;
199  d->items[d->nitems].valuelen = valuelen;
200  d->items[d->nitems].verbatim = !!verbatim;
201  d->nitems++;
202 }
203 
204 
205 /* This is the same as ksba_der_add_ptr but it takes a copy of the
206  * value and thus the caller does not need to care about keeping the
207  * value. */
208 void
209 _ksba_der_add_val (ksba_der_t d, int class, int tag,
210  const void *value, size_t valuelen)
211 {
212  void *p;
213 
214  if (ensure_space (d))
215  return;
216  if (!value || !valuelen)
217  {
219  return;
220  }
221  p = xtrymalloc (valuelen);
222  if (!p)
223  {
225  return;
226  }
227  memcpy (p, value, valuelen);
228  add_val_core (d, class, tag, p, valuelen, 0);
229 }
230 
231 
232 /* Add an OBJECT ID element to D. The OID is given in decimal dotted
233  * format as OIDSTR. */
234 void
236 {
237  gpg_error_t err;
238  unsigned char *buf;
239  size_t len;
240 
241  if (ensure_space (d))
242  return;
243 
244  err = ksba_oid_from_str (oidstr, &buf, &len);
245  if (err)
246  d->error = err;
247  else
248  add_val_core (d, 0, TYPE_OBJECT_ID, buf, len, 0);
249 }
250 
251 
252 /* Add a BIT STRING to D. Using a separate function allows to easily
253  * pass the number of unused bits. */
254 void
255 _ksba_der_add_bts (ksba_der_t d, const void *value, size_t valuelen,
256  unsigned int unusedbits)
257 {
258  unsigned char *p;
259 
260  if (ensure_space (d))
261  return;
262  if (!value || !valuelen || unusedbits > 7)
263  {
265  return;
266  }
267  p = xtrymalloc (1+valuelen);
268  if (!p)
269  {
271  return;
272  }
273  p[0] = unusedbits;
274  memcpy (p+1, value, valuelen);
275  add_val_core (d, 0, TYPE_BIT_STRING, p, 1+valuelen, 0);
276 }
277 
278 
279 /* Add (VALUE, VALUELEN) as an INTEGER to D. If FORCE_POSITIVE iset
280  * set a 0 or positive number is stored regardless of what is in
281  * (VALUE, VALUELEN). */
282 void
283 _ksba_der_add_int (ksba_der_t d, const void *value, size_t valuelen,
284  int force_positive)
285 {
286  unsigned char *p;
287  int need_extra;
288 
289  if (ensure_space (d))
290  return;
291  if (!value || !valuelen)
292  need_extra = 1; /* Assume the integer value 0 was meant. */
293  else
294  need_extra = (force_positive && (*(const unsigned char*)value & 0x80));
295 
296  p = xtrymalloc (need_extra+valuelen);
297  if (!p)
298  {
300  return;
301  }
302  if (need_extra)
303  p[0] = 0;
304  if (valuelen)
305  memcpy (p+need_extra, value, valuelen);
306  add_val_core (d, 0, TYPE_INTEGER, p, need_extra+valuelen, 0);
307 }
308 
309 
310 /* This function allows to add a pre-constructed DER object to the
311  * builder. It should be a valid DER object but its values is not
312  * further checked and copied verbatim to the final DER object
313  * constructed for the handle D. */
314 void
315 _ksba_der_add_der (ksba_der_t d, const void *der, size_t derlen)
316 {
317  void *p;
318 
319  if (ensure_space (d))
320  return;
321  if (!der || !derlen)
322  {
324  return;
325  }
326  p = xtrymalloc (derlen);
327  if (!p)
328  {
330  return;
331  }
332  memcpy (p, der, derlen);
333  add_val_core (d, 0, 0, p, derlen, 1);
334 }
335 
336 
337 /* Add a new constructed object to the builder instance D. The object
338  * is described by CLASS and TAG which must describe a constructed
339  * object. The elements of the constructed objects are added with
340  * more call using the add functions. To close a constructed element
341  * a call to tlv_builer_add_end is required. Errors are not returned
342  * but recorded for later retrieval. */
343 void
344 _ksba_der_add_tag (ksba_der_t d, int class, int tag)
345 {
346  if (ensure_space (d))
347  return;
348  d->items[d->nitems].class = class & 0x03;
349  d->items[d->nitems].tag = tag;
350  d->items[d->nitems].is_constructed = 1;
351  d->items[d->nitems].encapsulate = !!(class & 0x80);
352  d->nitems++;
353 }
354 
355 
356 /* A call to this function closes a constructed element. This must be
357  * called even for an empty constructed element. */
358 void
360 {
361  if (ensure_space (d))
362  return;
363  d->items[d->nitems].is_stop = 1;
364  d->nitems++;
365 }
366 
367 
368 /* Return the length of the TL header of a to be constructed TLV.
369  * LENGTH gives the length of the value, if it is 0 indefinite length
370  * is assumed. LENGTH is ignored for the NULL tag. On error 0 is
371  * returned. Note that this function is similar to _ksba_ber_count_tl
372  * but we want our own copy here. */
373 static unsigned int
374 count_tl (int class, int tag, size_t length)
375 {
376  unsigned int hdrlen = 0;
377  int i, t;
378 
379  if (tag < 0x1f)
380  hdrlen++;
381  else
382  {
383  hdrlen++;
384 
385  for (i = 0, t = tag; t > 0; i++)
386  t >>= 7;
387  hdrlen += i;
388  }
389 
390  if (!tag && !class)
391  hdrlen++; /* end tag */
392  else if (tag == TYPE_NULL && !class)
393  hdrlen++; /* NULL tag */
394  else if (!length)
395  hdrlen++; /* indefinite length */
396  else if (length < 128)
397  hdrlen++;
398  else
399  {
400  i = (length <= 0xff ? 1:
401  length <= 0xffff ? 2:
402  length <= 0xffffff ? 3: 4);
403 
404  hdrlen++;
405  if (i > 3)
406  hdrlen++;
407  if (i > 2)
408  hdrlen++;
409  if (i > 1)
410  hdrlen++;
411  hdrlen++;
412  }
413 
414  return hdrlen;
415 }
416 
417 
418 /* Write TAG of CLASS to BUFFER. CONSTRUCTED is a flag telling
419  * whether the value is constructed. LENGTH gives the length of the
420  * value, if it is 0 undefinite length is assumed. LENGTH is ignored
421  * for the NULL tag. TAG must be less that 0x1f. The caller must
422  * make sure that the written TL field does not overflow the
423  * buffer. */
424 static void
425 write_tl (unsigned char *buffer, int class, int tag,
426  int constructed, size_t length)
427 {
428  int i, savei, t;
429 
430  if (tag < 0x1f)
431  {
432  *buffer = (class << 6) | tag;
433  if (constructed)
434  *buffer |= 0x20;
435  buffer++;
436  }
437  else
438  {
439  *buffer = (class << 6) | 0x1f;
440  if (constructed)
441  *buffer |= 0x20;
442  buffer++;
443 
444  for (i = 0, t = tag; t > 0; i++)
445  t >>= 7;
446  savei = i;
447  t = tag;
448  while (i-- > 0)
449  {
450  buffer[i] = t & 0x7f;
451  if (i != savei - 1)
452  buffer[i] |= 0x80;
453  t >>= 7;
454  }
455  buffer += savei;
456  }
457 
458  if (!tag && !class)
459  *buffer++ = 0; /* end tag */
460  else if (tag == TYPE_NULL && !class)
461  *buffer++ = 0; /* NULL tag */
462  else if (!length)
463  *buffer++ = 0x80; /* indefinite length */
464  else if (length < 128)
465  *buffer++ = length;
466  else
467  {
468  /* If we know the sizeof a size_t we could support larger
469  * objects - however this is pretty ridiculous */
470  i = (length <= 0xff ? 1:
471  length <= 0xffff ? 2:
472  length <= 0xffffff ? 3: 4);
473 
474  *buffer++ = (0x80 | i);
475  if (i > 3)
476  *buffer++ = length >> 24;
477  if (i > 2)
478  *buffer++ = length >> 16;
479  if (i > 1)
480  *buffer++ = length >> 8;
481  *buffer++ = length;
482  }
483 }
484 
485 
486 /* Compute and set the length of all constructed elements in the item
487  * array of D starting at IDX up to the corresponding stop item. On
488  * error d->error is set. */
489 static size_t
491 {
492  size_t total = 0;
493 
494  if (d->error)
495  return 0;
496 
497  for (; idx < d->nitems; idx++)
498  {
499  if (d->items[idx].is_stop)
500  {
501  d->laststop = idx;
502  break;
503  }
504  if (d->items[idx].verbatim)
505  {
506  total += d->items[idx].valuelen;
507  continue;
508  }
509  if (d->items[idx].is_constructed)
510  {
511  d->items[idx].valuelen = compute_lengths (d, idx+1);
512  if (d->error)
513  return 0;
514  /* Note: The last processed IDX is stored at d->LASTSTOP. */
515  }
516  d->items[idx].hdrlen = count_tl (d->items[idx].class,
517  d->items[idx].tag,
518  d->items[idx].valuelen);
519  if (!d->items[idx].hdrlen)
520  {
521  if (d->error)
522  d->error = gpg_error (GPG_ERR_ENCODING_PROBLEM);
523  return 0; /* Error. */
524  }
525 
526  total += d->items[idx].hdrlen + d->items[idx].valuelen;
527  if (d->items[idx].is_constructed)
528  {
529  if (d->items[idx].encapsulate && d->items[idx].tag == TYPE_BIT_STRING)
530  total++; /* Account for the unused bits octet. */
531  idx = d->laststop;
532  }
533  }
534  return total;
535 }
536 
537 
538 /* Return the constructed DER object at D. On success the object is
539  * stored at R_OBJ and its length at R_OBJLEN. The caller needs to
540  * release that memory. On error NULL is stored at R_OBJ and an error
541  * code is returned. Further the number of successful calls prior to
542  * the error are stored at R_OBJLEN. Note than an error may stem from
543  * any of the previous call made to this object or from constructing
544  * the DER object. If this function is called with NULL for R_OBJ
545  * only the current error state is returned and no further processing
546  * is done. This can be used to figure which of the add calls induced
547  * the error.
548  */
549 gpg_error_t
550 _ksba_der_builder_get (ksba_der_t d, unsigned char **r_obj, size_t *r_objlen)
551 {
552  gpg_error_t err;
553  int idx;
554  unsigned char *buffer = NULL;
555  unsigned char *p;
556  size_t bufsize, buflen;
557  int encap_bts;
558 
559  *r_obj = NULL;
560  *r_objlen = 0;
561 
562  if (!d)
563  return gpg_error (GPG_ERR_INV_ARG);
564  if (d->error)
565  {
566  err = d->error;
567  if (r_objlen)
568  *r_objlen = d->nitems;
569  goto leave;
570  }
571  if (!r_obj)
572  return 0;
573 
574  if (!d->finished)
575  {
576  if (d->nitems == 1)
577  ; /* Single item does not need an end tag. */
578  else if (!d->nitems || !d->items[d->nitems-1].is_stop)
579  {
580  err = gpg_error (GPG_ERR_NO_OBJ);
581  goto leave;
582  }
583 
584  compute_lengths (d, 0);
585  err = d->error;
586  if (err)
587  goto leave;
588 
589  d->finished = 1;
590  }
591 
592  /* If the first element is a primitive element we rightly assume no
593  * other elements follow. It is the user's duty to build a valid
594  * ASN.1 object. */
595  bufsize = d->items[0].hdrlen + d->items[0].valuelen;
596 
597  /* for (idx=0; idx < d->nitems; idx++) */
598  /* gpgrt_log_debug ("DERB[%2d]: c=%d t=%2d %s p=%p h=%u l=%zu\n", */
599  /* idx, */
600  /* d->items[idx].class, */
601  /* d->items[idx].tag, */
602  /* d->items[idx].verbatim? "verbatim": */
603  /* d->items[idx].is_stop? "stop": */
604  /* d->items[idx].is_constructed? "cons":"prim", */
605  /* d->items[idx].value, */
606  /* d->items[idx].hdrlen, */
607  /* d->items[idx].valuelen); */
608 
609  buffer = xtrymalloc (bufsize);
610  if (!buffer)
611  {
612  err = gpg_error_from_syserror ();
613  goto leave;
614  }
615  buflen = 0;
616  p = buffer;
617 
618  for (idx=0; idx < d->nitems; idx++)
619  {
620  if (d->items[idx].is_stop)
621  continue;
622  if (!d->items[idx].verbatim)
623  {
624  /* For data encapsulated in a bit string we need to adjust
625  * for the unused bits octet. */
626  encap_bts = (d->items[idx].encapsulate && !d->items[idx].class
627  && d->items[idx].tag == TYPE_BIT_STRING);
628 
629  if (buflen + d->items[idx].hdrlen + encap_bts > bufsize)
630  {
631  err = gpg_error (GPG_ERR_BUG);
632  goto leave;
633  }
634  write_tl (p, d->items[idx].class, d->items[idx].tag,
635  (d->items[idx].is_constructed
636  && !d->items[idx].encapsulate),
637  d->items[idx].valuelen + encap_bts);
638  p += d->items[idx].hdrlen;
639  buflen += d->items[idx].hdrlen;
640  if (encap_bts)
641  {
642  *p++ = 0;
643  buflen++;
644  }
645  }
646  if (d->items[idx].value)
647  {
648  if (buflen + d->items[idx].valuelen > bufsize)
649  {
650  err = gpg_error (GPG_ERR_BUG);
651  goto leave;
652  }
653  memcpy (p, d->items[idx].value, d->items[idx].valuelen);
654  p += d->items[idx].valuelen;
655  buflen += d->items[idx].valuelen;
656  }
657  }
658  assert (buflen == bufsize);
659 
660  *r_obj = buffer;
661  *r_objlen = buflen;
662  buffer = NULL;
663 
664  leave:
665  xfree (buffer);
666  return err;
667 }
@ TYPE_NULL
@ TYPE_OBJECT_ID
@ TYPE_INTEGER
@ TYPE_BIT_STRING
void _ksba_der_add_end(ksba_der_t d)
Definition: der-builder.c:359
void _ksba_der_add_ptr(ksba_der_t d, int class, int tag, void *value, size_t valuelen)
Definition: der-builder.c:174
gpg_error_t _ksba_der_builder_get(ksba_der_t d, unsigned char **r_obj, size_t *r_objlen)
Definition: der-builder.c:550
static int ensure_space(ksba_der_t d)
Definition: der-builder.c:145
static size_t compute_lengths(ksba_der_t d, int idx)
Definition: der-builder.c:490
void _ksba_der_add_oid(ksba_der_t d, const char *oidstr)
Definition: der-builder.c:235
static unsigned int count_tl(int class, int tag, size_t length)
Definition: der-builder.c:374
void _ksba_der_add_der(ksba_der_t d, const void *der, size_t derlen)
Definition: der-builder.c:315
void _ksba_der_release(ksba_der_t d)
Definition: der-builder.c:73
static void add_val_core(ksba_der_t d, int class, int tag, void *value, size_t valuelen, int verbatim)
Definition: der-builder.c:192
void _ksba_der_builder_reset(ksba_der_t d)
Definition: der-builder.c:115
static void write_tl(unsigned char *buffer, int class, int tag, int constructed, size_t length)
Definition: der-builder.c:425
void _ksba_der_add_bts(ksba_der_t d, const void *value, size_t valuelen, unsigned int unusedbits)
Definition: der-builder.c:255
void _ksba_der_add_int(ksba_der_t d, const void *value, size_t valuelen, int force_positive)
Definition: der-builder.c:283
ksba_der_t _ksba_der_builder_new(unsigned int nitems)
Definition: der-builder.c:91
void _ksba_der_add_tag(ksba_der_t d, int class, int tag)
Definition: der-builder.c:344
void _ksba_der_add_val(ksba_der_t d, int class, int tag, const void *value, size_t valuelen)
Definition: der-builder.c:209
const char * oidstr
Definition: dn.c:57
#define gpg_error_from_syserror()
Definition: gen-help.h:88
#define GPG_ERR_BUG
Definition: gen-help.h:83
#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
const unsigned char * der
Definition: keyinfo.c:367
unsigned int derlen
Definition: keyinfo.c:366
gpg_error_t ksba_oid_from_str(const char *string, unsigned char **rbuf, size_t *rlength)
unsigned int encapsulate
Definition: der-builder.c:49
char * buffer
Definition: der-builder.c:54
unsigned int class
Definition: der-builder.c:46
unsigned int tag
Definition: der-builder.c:45
const void * value
Definition: der-builder.c:52
unsigned int hdrlen
Definition: der-builder.c:47
unsigned int is_stop
Definition: der-builder.c:51
size_t valuelen
Definition: der-builder.c:53
unsigned int is_constructed
Definition: der-builder.c:48
unsigned int verbatim
Definition: der-builder.c:50
gpg_error_t error
Definition: der-builder.c:62
size_t nallocateditems
Definition: der-builder.c:63
size_t nitems
Definition: der-builder.c:64
unsigned int finished
Definition: der-builder.c:67
struct item_s * items
Definition: der-builder.c:65
int laststop
Definition: der-builder.c:66
void * _ksba_reallocarray(void *a, size_t oldnmemb, size_t nmemb, size_t size)
Definition: util.c:187
#define xfree(a)
Definition: util.h:58
#define xtrycalloc(a, b)
Definition: util.h:55