Pārlūkot izejas kodu

add ASN.1-identifier functions

Steffen Jaeckel 7 gadi atpakaļ
vecāks
revīzija
1b3a757345

+ 54 - 7
src/headers/tomcrypt_pk.h

@@ -520,6 +520,18 @@ typedef enum ltc_asn1_type_ {
  LTC_ASN1_CUSTOM_TYPE,
 } ltc_asn1_type;
 
+typedef enum {
+   LTC_ASN1_CL_UNIVERSAL = 0x0,
+   LTC_ASN1_CL_APPLICATION = 0x1,
+   LTC_ASN1_CL_CONTEXT_SPECIFIC = 0x2,
+   LTC_ASN1_CL_PRIVATE = 0x3,
+} ltc_asn1_class;
+
+typedef enum {
+   LTC_ASN1_PC_PRIMITIVE = 0x0,
+   LTC_ASN1_PC_CONSTRUCTED = 0x1,
+} ltc_asn1_pc;
+
 /** A LTC ASN.1 list type */
 typedef struct ltc_asn1_list_ {
    /** The LTC ASN.1 enumerated type identifier */
@@ -528,12 +540,17 @@ typedef struct ltc_asn1_list_ {
    void         *data;
    /** The size of the input or resulting output */
    unsigned long size;
-   /** The used flag, this is used by the CHOICE ASN.1 type to indicate which choice was made */
+   /** The used flag
+    * 1. This is used by the CHOICE ASN.1 type to indicate which choice was made
+    * 2. This is used by the ASN.1 decoder to indicate if an element is used
+    * 3. This is used by the flexi-decoder to indicate the first byte of the identifier */
    int           used;
    /** Flag used to indicate optional items in ASN.1 sequences */
    int           optional;
-   /** Flag used to indicate context specific tags on ASN.1 sequence items */
-   unsigned char tag;
+   /** ASN.1 identifier */
+   ltc_asn1_class class;
+   ltc_asn1_pc    pc;
+   ulong64        tag;
    /** prev/next entry in the list */
    struct ltc_asn1_list_ *prev, *next, *child, *parent;
 } ltc_asn1_list;
@@ -546,14 +563,36 @@ typedef struct ltc_asn1_list_ {
       LTC_MACRO_list[LTC_MACRO_temp].data = (void*)(Data);  \
       LTC_MACRO_list[LTC_MACRO_temp].size = (Size);  \
       LTC_MACRO_list[LTC_MACRO_temp].used = 0;       \
-      LTC_MACRO_list[LTC_MACRO_temp].tag = 0;        \
       LTC_MACRO_list[LTC_MACRO_temp].optional = 0;   \
+      LTC_MACRO_list[LTC_MACRO_temp].class = 0;      \
+      LTC_MACRO_list[LTC_MACRO_temp].pc = 0;         \
+      LTC_MACRO_list[LTC_MACRO_temp].tag = 0;        \
    } while (0)
 
-int der_encode_asn1_length(unsigned long len, unsigned char* out, unsigned long* outlen);
-int der_decode_asn1_length(const unsigned char* len, unsigned long* lenlen, unsigned long* outlen);
-int der_length_asn1_length(unsigned long len, unsigned long *outlen);
+#define __LTC_SET_ASN1_IDENTIFIER(list, index, Class, Pc, Tag)      \
+   do {                                                           \
+      int LTC_MACRO_temp            = (index);                    \
+      ltc_asn1_list *LTC_MACRO_list = (list);                     \
+      LTC_MACRO_list[LTC_MACRO_temp].type = LTC_ASN1_CUSTOM_TYPE; \
+      LTC_MACRO_list[LTC_MACRO_temp].class = (Class);             \
+      LTC_MACRO_list[LTC_MACRO_temp].pc = (Pc);                   \
+      LTC_MACRO_list[LTC_MACRO_temp].tag = (Tag);                 \
+   } while (0)
 
+#define LTC_SET_ASN1_CUSTOM_CONSTRUCTED(list, index, Class, Tag, Data)    \
+   do {                                                           \
+      int LTC_MACRO_temp##__LINE__ = (index);                     \
+      LTC_SET_ASN1(list, LTC_MACRO_temp##__LINE__, LTC_ASN1_CUSTOM_TYPE, Data, 1);   \
+      __LTC_SET_ASN1_IDENTIFIER(list, LTC_MACRO_temp##__LINE__, Class, LTC_ASN1_PC_CONSTRUCTED, Tag);       \
+   } while (0)
+
+#define LTC_SET_ASN1_CUSTOM_PRIMITIVE(list, index, Class, Tag, Type, Data, Size)    \
+   do {                                                           \
+      int LTC_MACRO_temp##__LINE__ = (index);                     \
+      LTC_SET_ASN1(list, LTC_MACRO_temp##__LINE__, LTC_ASN1_CUSTOM_TYPE, Data, Size);   \
+      __LTC_SET_ASN1_IDENTIFIER(list, LTC_MACRO_temp##__LINE__, Class, LTC_ASN1_PC_PRIMITIVE, Tag);       \
+      list[LTC_MACRO_temp##__LINE__].used = (int)(Type);       \
+   } while (0)
 
 extern const char*          der_asn1_class_to_string_map[];
 extern const unsigned long  der_asn1_class_to_string_map_sz;
@@ -580,6 +619,14 @@ int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
 
 #ifdef LTC_SOURCE
 /* internal helper functions */
+int der_encode_asn1_identifier(const ltc_asn1_list *id, unsigned char *out, unsigned long *outlen);
+int der_decode_asn1_identifier(const unsigned char *in, unsigned long *inlen, ltc_asn1_list *id);
+int der_length_asn1_identifier(const ltc_asn1_list *id, unsigned long *idlen);
+
+int der_encode_asn1_length(unsigned long len, unsigned char* out, unsigned long* outlen);
+int der_decode_asn1_length(const unsigned char* len, unsigned long* lenlen, unsigned long* outlen);
+int der_length_asn1_length(unsigned long len, unsigned long *outlen);
+
 int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
                            unsigned long *outlen, unsigned long *payloadlen);
 

+ 136 - 0
src/pk/asn1/der/general/der_decode_asn1_identifier.c

@@ -0,0 +1,136 @@
+/* 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_asn1_identifier.c
+  ASN.1 DER, decode the ASN.1 Identifier, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+/* c.f. X.680 & X.690, some decisions backed by X.690 ch. 10.2 */
+static const unsigned char tag_constructed_map[] =
+{
+ /*  0 */
+ 255,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /*  5 */
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 10 */
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 15 */
+ 255,
+ LTC_ASN1_PC_CONSTRUCTED,
+ LTC_ASN1_PC_CONSTRUCTED,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 20 */
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 25 */
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ LTC_ASN1_PC_PRIMITIVE,
+ /* 30 */
+ LTC_ASN1_PC_PRIMITIVE,
+};
+ static const unsigned long tag_constructed_map_sz = sizeof(tag_constructed_map)/sizeof(tag_constructed_map[0]);
+
+/**
+  Decode the ASN.1 Identifier
+  @param id    Where to store the decoded Identifier
+  @param in    Where to read the Identifier from
+  @param inlen [in/out] The size of in available/read
+  @return CRYPT_OK if successful
+*/
+int der_decode_asn1_identifier(const unsigned char *in, unsigned long *inlen, ltc_asn1_list *id)
+{
+   ulong64 tmp;
+   unsigned long tag_len;
+   int err;
+
+   LTC_ARGCHK(id    != NULL);
+   LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(inlen != NULL);
+
+   if (*inlen == 0) {
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   tag_len = 1;
+   id->class = (in[0] >> 6) & 0x3;
+   id->pc = (in[0] >> 5) & 0x1;
+   id->tag = in[0] & 0x1f;
+
+   err = CRYPT_OK;
+   if (id->tag == 0x1f) {
+      id->tag = 0;
+      do {
+         if (*inlen < tag_len) {
+            /* break the loop and trigger the BOF error-code */
+            tmp = 0xff;
+            break;
+         }
+         id->tag <<= 7;
+         id->tag |= in[tag_len] & 0x7f;
+         tmp = in[tag_len] & 0x80;
+         tag_len++;
+      } while ((tmp != 0) && (tag_len < 10));
+
+      if (tmp != 0) {
+         err = CRYPT_BUFFER_OVERFLOW;
+      } else if (id->tag < 0x1f) {
+         err = CRYPT_PK_ASN1_ERROR;
+      }
+   }
+
+   if (err != CRYPT_OK) {
+      id->pc = 0;
+      id->class = 0;
+      id->tag = 0;
+   } else {
+      *inlen = tag_len;
+      if ((id->class == LTC_ASN1_CL_UNIVERSAL) &&
+            (id->tag < der_asn1_tag_to_type_map_sz) &&
+            (id->tag < tag_constructed_map_sz) &&
+            (id->pc == tag_constructed_map[id->tag])) {
+         id->type = der_asn1_tag_to_type_map[id->tag];
+      } else {
+         if ((id->class == LTC_ASN1_CL_UNIVERSAL) && (id->tag == 0)) {
+            id->type = LTC_ASN1_EOL;
+         } else {
+            id->type = LTC_ASN1_CUSTOM_TYPE;
+         }
+      }
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 97 - 0
src/pk/asn1/der/general/der_encode_asn1_identifier.c

@@ -0,0 +1,97 @@
+/* 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_asn1_identifier.c
+  ASN.1 DER, encode the ASN.1 Identifier, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+/**
+  Encode the ASN.1 Identifier
+  @param id       The ASN.1 Identifer to encode
+  @param out      Where to write the identifier to
+  @param outlen   [in/out] The size of out available/written
+  @return CRYPT_OK if successful
+*/
+int der_encode_asn1_identifier(const ltc_asn1_list *id, unsigned char *out, unsigned long *outlen)
+{
+   ulong64 tmp;
+   unsigned long tag_len;
+
+   LTC_ARGCHK(id  != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   if (id->type != LTC_ASN1_CUSTOM_TYPE) {
+      if (id->type >= der_asn1_type_to_identifier_map_sz) {
+         return CRYPT_INVALID_ARG;
+      }
+      if (der_asn1_type_to_identifier_map[id->type] == -1) {
+         return CRYPT_INVALID_ARG;
+      }
+      if (out != NULL) {
+         *out = der_asn1_type_to_identifier_map[id->type];
+      }
+      *outlen = 1;
+      return CRYPT_OK;
+   } else {
+      if (id->class < LTC_ASN1_CL_UNIVERSAL || id->class > LTC_ASN1_CL_PRIVATE) {
+         return CRYPT_INVALID_ARG;
+      }
+      if (id->pc < LTC_ASN1_PC_PRIMITIVE || id->pc > LTC_ASN1_PC_CONSTRUCTED) {
+         return CRYPT_INVALID_ARG;
+      }
+      if (id->tag > (ULONG_MAX >> (8 + 7))) {
+         return CRYPT_INVALID_ARG;
+      }
+   }
+
+   if (out != NULL) {
+      if (*outlen < 1) {
+         return CRYPT_BUFFER_OVERFLOW;
+      }
+
+      out[0] = id->class << 6 | id->pc << 5;
+   }
+
+   if (id->tag < 0x1f) {
+      if (out != NULL) {
+         out[0] |= id->tag & 0x1f;
+      }
+      *outlen = 1;
+   } else {
+      tag_len = 0;
+      tmp = id->tag;
+      do {
+         tag_len++;
+         tmp >>= 7;
+      } while (tmp);
+
+      if (out != NULL) {
+         if (*outlen < tag_len + 1) {
+            return CRYPT_BUFFER_OVERFLOW;
+         }
+         out[0] |= 0x1f;
+         for (tmp = 1; tmp <= tag_len; ++tmp) {
+            out[tmp] = ((id->tag >> (7 * (tag_len - tmp))) & 0x7f) | 0x80;
+         }
+         out[tag_len] &= ~0x80;
+      }
+      *outlen = tag_len + 1;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 33 - 0
src/pk/asn1/der/general/der_length_asn1_identifier.c

@@ -0,0 +1,33 @@
+/* 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_asn1_identifier.c
+  ASN.1 DER, determine the length when encoding the ASN.1 Identifier, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+/**
+  Determine the length required when encoding the ASN.1 Identifier
+  @param id    The ASN.1 identifier to encode
+  @param idlen [out] The required length to encode list
+  @return CRYPT_OK if successful
+*/
+
+int der_length_asn1_identifier(const ltc_asn1_list *id, unsigned long *idlen)
+{
+   return der_encode_asn1_identifier(id, NULL, idlen);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */