Browse Source

add required ASN.1 custom-types functions

Steffen Jaeckel 7 years ago
parent
commit
0d02137a8e

+ 12 - 0
src/headers/tomcrypt_pk.h

@@ -617,6 +617,18 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long  inlen,
 int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
 int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
                         unsigned long *outlen);
                         unsigned long *outlen);
 
 
+
+/* Custom-types */
+int der_encode_custom_type(const ltc_asn1_list *root,
+                                 unsigned char *out, unsigned long *outlen);
+
+int der_decode_custom_type(const unsigned char *in, unsigned long inlen,
+                                 ltc_asn1_list *root);
+
+int der_length_custom_type(const ltc_asn1_list *root,
+                                 unsigned long *outlen,
+                                 unsigned long *payloadlen);
+
 #ifdef LTC_SOURCE
 #ifdef LTC_SOURCE
 /* internal helper functions */
 /* internal helper functions */
 int der_encode_asn1_identifier(const ltc_asn1_list *id, unsigned char *out, unsigned long *outlen);
 int der_encode_asn1_identifier(const ltc_asn1_list *id, unsigned char *out, unsigned long *outlen);

+ 339 - 0
src/pk/asn1/der/custom_type/der_decode_custom_type.c

@@ -0,0 +1,339 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+/**
+  @file der_decode_custom_type.c
+  ASN.1 DER, decode a Custom type, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+/**
+   Decode a Custom type
+   @param in       The DER encoded input
+   @param inlen    The size of the input
+   @param root     The item that defines the custom type to decode
+   @return CRYPT_OK on success
+*/
+int der_decode_custom_type(const unsigned char *in, unsigned long  inlen,
+                           ltc_asn1_list *root)
+{
+   int           err, i;
+   ltc_asn1_type type;
+   ltc_asn1_list ident, *list;
+   unsigned long size, x, y, z, blksize, outlen;
+   unsigned char* in_new = NULL;
+   void          *data;
+
+   LTC_ARGCHK(in   != NULL);
+   LTC_ARGCHK(root != NULL);
+
+   if (root->type != LTC_ASN1_CUSTOM_TYPE) {
+      return CRYPT_INVALID_PACKET;
+   }
+   /* get blk size */
+   if (inlen < 2) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* Alloc a copy of the data for primitive handling. */
+   if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+      in_new = XMALLOC(inlen);
+      if (in_new == NULL) {
+         return CRYPT_MEM;
+      }
+      XMEMCPY(in_new, in, inlen);
+      in = in_new;
+   }
+
+   x = 0;
+   y = inlen;
+   if ((err = der_decode_asn1_identifier(in, &y, &ident)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((ident.type != root->type) ||
+         (ident.class != root->class) ||
+         (ident.pc != root->pc) ||
+         (ident.tag != root->tag)) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+   x += y;
+
+   list = root->data;
+   outlen = root->size;
+
+   if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+      if (der_asn1_type_to_identifier_map[list[0].type] == -1) {
+         err = CRYPT_INVALID_PACKET;
+         goto LBL_ERR;
+      }
+      x -= 1;
+      in_new[x] = (unsigned char)der_asn1_type_to_identifier_map[list[0].type];
+      blksize = inlen - x;
+   } else {
+      y = inlen - x;
+      if ((err = der_decode_asn1_length(&in[x], &y, &blksize)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      x += y;
+   }
+
+   /* would this blksize overflow? */
+   if (x + blksize > inlen) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+   /* mark all as unused */
+   for (i = 0; i < (int)outlen; i++) {
+       list[i].used = 0;
+   }
+
+   /* ok read data */
+   inlen = blksize;
+   for (i = 0; i < (int)outlen; i++) {
+       z    = 0;
+       type = list[i].type;
+       size = list[i].size;
+       data = list[i].data;
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       if (root->pc == LTC_ASN1_PC_PRIMITIVE && i != 0) {
+          err = CRYPT_PK_ASN1_ERROR;
+          goto LBL_ERR;
+       }
+
+       switch (type) {
+           case LTC_ASN1_BOOLEAN:
+               z = inlen;
+               if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) {
+                   goto LBL_ERR;
+               }
+               if ((err = der_length_boolean(&z)) != CRYPT_OK) {
+                   goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_INTEGER:
+               z = inlen;
+               if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               if ((err = der_length_integer(data, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SHORT_INTEGER:
+               z = inlen;
+               if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+
+               break;
+
+           case LTC_ASN1_BIT_STRING:
+               z = inlen;
+               if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_RAW_BIT_STRING:
+               z = inlen;
+               if ((err = der_decode_raw_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_OCTET_STRING:
+               z = inlen;
+               if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_octet_string(size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_NULL:
+               if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) {
+                  err = CRYPT_INVALID_PACKET;
+                  goto LBL_ERR;
+               }
+               z = 2;
+               break;
+
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+               z = inlen;
+               if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_object_identifier(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_TELETEX_STRING:
+               z = inlen;
+               if ((err = der_decode_teletex_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_teletex_string(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_IA5_STRING:
+               z = inlen;
+               if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_ia5_string(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_PRINTABLE_STRING:
+               z = inlen;
+               if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_printable_string(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_UTF8_STRING:
+               z = inlen;
+               if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_UTCTIME:
+               z = inlen;
+               if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_GENERALIZEDTIME:
+               z = inlen;
+               if ((err = der_decode_generalizedtime(in + x, &z, data)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SET:
+               z = inlen;
+               if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SETOF:
+           case LTC_ASN1_SEQUENCE:
+               /* detect if we have the right type */
+               if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
+                  err = CRYPT_INVALID_PACKET;
+                  goto LBL_ERR;
+               }
+
+               z = inlen;
+               if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_CUSTOM_TYPE:
+               z = inlen;
+               if ((err = der_decode_custom_type(in + x, z, &list[i])) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               if ((err = der_length_custom_type(&list[i], &z, NULL)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_CHOICE:
+               z = inlen;
+               if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+           case LTC_ASN1_EOL:
+               err = CRYPT_INVALID_ARG;
+               goto LBL_ERR;
+       }
+       x           += z;
+       inlen       -= z;
+       list[i].used = 1;
+   }
+
+   for (i = 0; i < (int)outlen; i++) {
+      if (list[i].used == 0 && list[i].optional == 0) {
+          err = CRYPT_INVALID_PACKET;
+          goto LBL_ERR;
+      }
+   }
+
+   if (inlen == 0) {
+      err = CRYPT_OK;
+   } else {
+      err = CRYPT_INPUT_TOO_LONG;
+   }
+
+LBL_ERR:
+   if (in_new != NULL) {
+      XFREE(in_new);
+   }
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 234 - 0
src/pk/asn1/der/custom_type/der_encode_custom_type.c

@@ -0,0 +1,234 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+/**
+  @file der_encode_custom_type.c
+  ASN.1 DER, encode a Custom Type, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+/**
+   Encode a Custom Type
+
+   This function is a bit special compared to the others, as it requires the
+   root-ltc_asn1_list where the type is defined.
+
+   @param root      The root of the list of items to encode
+   @param out       [out] The destination
+   @param outlen    [in/out] The size of the output
+   @return CRYPT_OK on success
+*/
+int der_encode_custom_type(const ltc_asn1_list *root,
+                                 unsigned char *out,  unsigned long *outlen)
+{
+   int           err;
+   ltc_asn1_type type;
+   ltc_asn1_list *list;
+   unsigned long size, x, y, z, i, inlen, id_len;
+   void          *data;
+
+   LTC_ARGCHK(root    != NULL);
+   LTC_ARGCHK(out     != NULL);
+   LTC_ARGCHK(outlen  != NULL);
+
+   /* get size of output that will be required */
+   y = 0; z = 0;
+   if ((err = der_length_custom_type(root, &y, &z)) != CRYPT_OK) return CRYPT_INVALID_ARG;
+
+   /* too big ? */
+   if (*outlen < y) {
+      *outlen = y;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto LBL_ERR;
+   }
+
+   /* get length of the identifier, so we know the offset where to start writing */
+   if ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) return CRYPT_INVALID_ARG;
+   x = id_len;
+
+
+   if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+      /* In case it's a PRIMITIVE type we encode directly to the output
+       * but leave space for a potentially longer identifier as it will
+       * simply be replaced afterwards.
+       */
+      x -= 1;
+   } else {
+      /* store length, identifier will be added later */
+      y = *outlen - x;
+      if ((err = der_encode_asn1_length(z, &out[x], &y)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      x += y;
+   }
+
+   list = root->data;
+   inlen = root->size;
+   /* store data */
+   *outlen -= x;
+   for (i = 0; i < inlen; i++) {
+       type = list[i].type;
+       size = list[i].size;
+       data = list[i].data;
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       switch (type) {
+            case LTC_ASN1_BOOLEAN:
+               z = *outlen;
+               if ((err = der_encode_boolean(*((int *)data), out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_INTEGER:
+               z = *outlen;
+               if ((err = der_encode_integer(data, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SHORT_INTEGER:
+               z = *outlen;
+               if ((err = der_encode_short_integer(*((unsigned long*)data), out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_BIT_STRING:
+               z = *outlen;
+               if ((err = der_encode_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_RAW_BIT_STRING:
+               z = *outlen;
+               if ((err = der_encode_raw_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_OCTET_STRING:
+               z = *outlen;
+               if ((err = der_encode_octet_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_NULL:
+               out[x] = 0x05;
+               out[x+1] = 0x00;
+               z = 2;
+               break;
+
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+               z = *outlen;
+               if ((err = der_encode_object_identifier(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_IA5_STRING:
+               z = *outlen;
+               if ((err = der_encode_ia5_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_PRINTABLE_STRING:
+               z = *outlen;
+               if ((err = der_encode_printable_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_UTF8_STRING:
+               z = *outlen;
+               if ((err = der_encode_utf8_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_UTCTIME:
+               z = *outlen;
+               if ((err = der_encode_utctime(data, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_GENERALIZEDTIME:
+               z = *outlen;
+               if ((err = der_encode_generalizedtime(data, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SET:
+               z = *outlen;
+               if ((err = der_encode_set(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SETOF:
+               z = *outlen;
+               if ((err = der_encode_setof(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SEQUENCE:
+               z = *outlen;
+               if ((err = der_encode_sequence_ex(data, size, out + x, &z, type)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_CUSTOM_TYPE:
+               z = *outlen;
+               if ((err = der_encode_custom_type(&list[i], out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_CHOICE:
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+           case LTC_ASN1_EOL:
+           case LTC_ASN1_TELETEX_STRING:
+               err = CRYPT_INVALID_ARG;
+               goto LBL_ERR;
+       }
+
+
+       x       += z;
+       *outlen -= z;
+   }
+
+   if ((err = der_encode_asn1_identifier(root, out, &id_len)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   *outlen = x;
+   err = CRYPT_OK;
+
+LBL_ERR:
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 213 - 0
src/pk/asn1/der/custom_type/der_length_custom_type.c

@@ -0,0 +1,213 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_custom_type.c
+  ASN.1 DER, length of a custom type, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+/**
+   Get the length of a DER custom type
+
+   This function is a bit special compared to the others, as it requires the
+   root-ltc_asn1_list where the type is defined.
+
+   @param root          The root of the struct to encode
+   @param outlen        [out] The length required in octets to store it
+   @param payloadlen    [out] The length of the payload in octets
+   @return CRYPT_OK on success
+*/
+int der_length_custom_type(const ltc_asn1_list *root, unsigned long *outlen, unsigned long *payloadlen)
+{
+   int           err;
+   ltc_asn1_list *list;
+   ltc_asn1_type type;
+   unsigned long size, x, y, i, inlen, id_len;
+   void          *data;
+
+   LTC_ARGCHK(root    != NULL);
+   LTC_ARGCHK(outlen  != NULL);
+
+   if ((root->pc == LTC_ASN1_PC_PRIMITIVE) && (root->size != 1)) {
+      /* In case it's a PRIMITIVE element there has to be
+       * exactly one element following.
+       */
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* get size of output that will be required */
+   if ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) {
+      return err;
+   }
+   y = id_len;
+
+   inlen = root->size;
+   list = root->data;
+   for (i = 0; i < inlen; i++) {
+       type = list[i].type;
+       size = list[i].size;
+       data = list[i].data;
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       /* some items may be optional during import */
+       if (!list[i].used && list[i].optional) continue;
+
+       switch (type) {
+           case LTC_ASN1_BOOLEAN:
+              if ((err = der_length_boolean(&x)) != CRYPT_OK) {
+                 goto LBL_ERR;
+              }
+              y += x;
+              break;
+
+           case LTC_ASN1_INTEGER:
+               if ((err = der_length_integer(data, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_SHORT_INTEGER:
+               if ((err = der_length_short_integer(*((unsigned long *)data), &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_BIT_STRING:
+           case LTC_ASN1_RAW_BIT_STRING:
+               if ((err = der_length_bit_string(size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_OCTET_STRING:
+               if ((err = der_length_octet_string(size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_NULL:
+               y += 2;
+               break;
+
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+               if ((err = der_length_object_identifier(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_IA5_STRING:
+               if ((err = der_length_ia5_string(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_TELETEX_STRING:
+               if ((err = der_length_teletex_string(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_PRINTABLE_STRING:
+               if ((err = der_length_printable_string(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_UTCTIME:
+               if ((err = der_length_utctime(data, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_GENERALIZEDTIME:
+               if ((err = der_length_generalizedtime(data, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_UTF8_STRING:
+               if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_CUSTOM_TYPE:
+               if ((err = der_length_custom_type(&list[i], &x, NULL)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_SET:
+           case LTC_ASN1_SETOF:
+           case LTC_ASN1_SEQUENCE:
+               if ((err = der_length_sequence(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_CHOICE:
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+           case LTC_ASN1_EOL:
+               err = CRYPT_INVALID_ARG;
+               goto LBL_ERR;
+       }
+   }
+
+   if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
+      /* In case it's a PRIMITIVE element we're going
+       * to only replace the identifier of the one element
+       * by the custom identifier.
+       */
+      y -= 1;
+      if (payloadlen != NULL) {
+         *payloadlen = y - id_len;
+      }
+   } else {
+      /* calc length of length */
+      if ((err = der_length_asn1_length(y, &x)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      if (payloadlen != NULL) {
+         *payloadlen = y - id_len;
+      }
+      y += x;
+   }
+
+   /* store size */
+   *outlen = y;
+
+LBL_ERR:
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */