Added SILC_ASN1_ANY_PRIMITIVE to encode/decode any pre-encoded
authorPekka Riikonen <priikone@silcnet.org>
Thu, 29 Dec 2005 21:06:03 +0000 (21:06 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 29 Dec 2005 21:06:03 +0000 (21:06 +0000)
primitive data type.

lib/silcasn1/silcasn1.c
lib/silcasn1/silcasn1.h
lib/silcasn1/silcasn1_decode.c
lib/silcasn1/silcasn1_encode.c
lib/silcasn1/silcasn1_i.h
lib/silcasn1/silcber.c
lib/silcasn1/tests/test_silcasn1.c

index 29b48d38e40e8bb10eebdbba6280d5b87c8f3bac..ccf77c2b8ca85e816e0117ac4edbedf2fefbf83d 100644 (file)
@@ -88,9 +88,10 @@ const char *silc_asn1_tag_name(SilcAsn1Tag tag)
     return "choice";
   case SILC_ASN1_TAG_ANY:
     return "any";
+  case SILC_ASN1_TAG_ANY_PRIMITIVE:
+    return "any primitive";
   case SILC_ASN1_TAG_SEQUENCE_OF:
     return "sequence of";
-
   case SILC_ASN1_TAG_SEQUENCE:
     return "sequence";
   case SILC_ASN1_TAG_SET:
index a620d69c38506b2c153c5207c8305f0bbb5d17ac..57c31905b9108e8285452b57a3c9f13a3275e495 100644 (file)
@@ -443,6 +443,52 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
 #define SILC_ASN1_ANY(x) SILC_ASN1_U1(ANY, x)
 #define SILC_ASN1_ANY_T(o, t, x) SILC_ASN1_T1(ANY, o, t, x)
 
+/****f* silcasn1/SilcASN1API/SILC_ASN1_ANY_PRIMITIVE
+ *
+ * SYNOPSIS
+ *
+ *    Encoding:
+ *    SILC_ASN1_ANY_PRIMITIVE(tag, buffer)
+ *    SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, buffer)
+ *
+ *    Decoding:
+ *    SILC_ASN1_ANY_PRIMITIVE(tag, &buffer)
+ *    SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, &buffer)
+ *
+ * DESCRIPTION
+ *
+ *    Special macro used to encode pre-encoded primitive data blob.  The data
+ *    can be any primitive type that is already encoded in correct format.
+ *    The caller is responsible of making sure the data is formatted
+ *    correctly.  When decoding this returns the raw data blob and the caller
+ *    must know of what type and format it is.  The buffer type is SilcBuffer.
+ *
+ *    This macro can be used in cases when the data to be encoded is already
+ *    in encoded format, and it only needs to be added to ASN.1 tree.  The
+ *    SILC_ASN1_ANY cannot be used with primitives when tagging implicitly,
+ *    in these cases this macro can be used.
+ *
+ *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
+ *
+ * EXAMPLE
+ *
+ *    // Get MP integer in encoded format
+ *    mpbuf = mp_get_octet_string(mp);
+ *
+ *    // Encode the MP integer data to the tree
+ *    silc_asn1_encode(asn1, tree,
+ *                     SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_INTEGER, mpbuf),
+ *                     SILC_ASN1_END);
+ *
+ *    // Decode the MP integer data from the tree
+ *    silc_asn1_decode(asn1, tree,
+ *                     SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_INTEGER, &buffer),
+ *                     SILC_ASN1_END);
+ *
+ ***/
+#define SILC_ASN1_ANY_PRIMITIVE(t, x) SILC_ASN1_T1(ANY_PRIMITIVE, 0, t, x)
+#define SILC_ASN1_ANY_PRIMITIVE_T(o, t, x) SILC_ASN1_T1(ANY_PRIMITIVE, o, t, x)
+
 /****f* silcasn1/SilcASN1API/SILC_ASN1_SEQUENCE
  *
  * SYNOPSIS
index 17354ac154d8601858ff8184488a3a00dda16991..34b93ca26ab182020458843602b5556469b3f439 100644 (file)
@@ -296,12 +296,19 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type,
     indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
 
     /* By default UNIVERSAL is implied unless the following conditions
-       are met when CONTEXT will apply. */
+       are met when CONTEXT will apply.  For SILC_ASN1_TAG_ANY_PRIMITIVE
+       the class is changed only if flags dictate it. */
     if (ber_class == SILC_BER_CLASS_UNIVERSAL) {
-      if (tag != type ||
-         opts & SILC_ASN1_IMPLICIT ||
-         opts & SILC_ASN1_EXPLICIT)
-       ber_class = SILC_BER_CLASS_CONTEXT;
+      if (type == SILC_ASN1_TAG_ANY_PRIMITIVE) {
+       if (opts & SILC_ASN1_IMPLICIT ||
+           opts & SILC_ASN1_EXPLICIT)
+         ber_class = SILC_BER_CLASS_CONTEXT;
+      } else {
+       if (tag != type ||
+           opts & SILC_ASN1_IMPLICIT ||
+           opts & SILC_ASN1_EXPLICIT)
+         ber_class = SILC_BER_CLASS_CONTEXT;
+      }
     }
 
     /* Now decode a BER encoded block from the source buffer.  It must be
@@ -411,6 +418,16 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type,
          break;
        }
 
+      case SILC_ASN1_TAG_ANY_PRIMITIVE:
+       {
+         /* ANY_PRIMITIVE returns the raw data blob of any primitive type. */
+         SILC_ASN1_VAD(asn1, opts, SilcBufferStruct, prim);
+
+         *prim = silc_buffer_srealloc_size(stack1, *prim, rdata_len);
+         silc_buffer_put(*prim, rdata, rdata_len);
+         break;
+       }
+
       case SILC_ASN1_TAG_SEQUENCE:
       case SILC_ASN1_TAG_SET:
        {
index 350fac946456bc73bf1fa0926784c3bede5d4386..123539f6fcd93d42b690832db1a0fbd14e430efb 100644 (file)
@@ -91,12 +91,19 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
     indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
 
     /* By default UNIVERSAL is implied unless the following conditions
-       are met when CONTEXT will apply. */
+       are met when CONTEXT will apply.  For SILC_ASN1_TAG_ANY_PRIMITIVE
+       the class is changed only if flags dictate it. */
     if (ber_class == SILC_BER_CLASS_UNIVERSAL) {
-      if (tag != type ||
-         opts & SILC_ASN1_IMPLICIT ||
-         opts & SILC_ASN1_EXPLICIT)
-       ber_class = SILC_BER_CLASS_CONTEXT;
+      if (type == SILC_ASN1_TAG_ANY_PRIMITIVE) {
+       if (opts & SILC_ASN1_IMPLICIT ||
+           opts & SILC_ASN1_EXPLICIT)
+         ber_class = SILC_BER_CLASS_CONTEXT;
+      } else {
+       if (tag != type ||
+           opts & SILC_ASN1_IMPLICIT ||
+           opts & SILC_ASN1_EXPLICIT)
+         ber_class = SILC_BER_CLASS_CONTEXT;
+      }
     }
 
 #ifdef SILC_DEBUG
@@ -197,6 +204,24 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
        break;
       }
 
+    case SILC_ASN1_TAG_ANY_PRIMITIVE:
+      {
+       /* ANY_PRIMITIVE is any primitive in encoded format. */
+       SilcBuffer prim = va_arg(asn1->ap, SilcBuffer);
+       if (!prim)
+         break;
+
+       /* Encode the primitive data */
+       len = silc_ber_encoded_len(tag, silc_buffer_len(prim), FALSE);
+       dest = silc_buffer_srealloc_size(stack1, dest,
+                                        silc_buffer_truelen(dest) + len);
+       ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
+                             tag, prim->data, silc_buffer_len(prim), FALSE);
+       if (!ret)
+         goto fail;
+       break;
+      }
+
     case SILC_ASN1_TAG_SEQUENCE:
     case SILC_ASN1_TAG_SET:
       {
index 394ba3bac254317f7219c327dd66a0bdc270b2c2..b602010548b5eb11bf37ce19fec8724f3700a395 100644 (file)
@@ -36,11 +36,12 @@ struct SilcAsn1Object {
 #define SILC_ASN1_RECURSION_DEPTH 512
 
 /* Implementation specific special tags.  Range is 0x7000 - 0x7fff. */
-#define SILC_ASN1_TAG_ANY          0x7000   /* SILC_ASN1_ANY given  */
-#define SILC_ASN1_TAG_FUNC         0x7001   /* Callback encoder/decoder */
-#define SILC_ASN1_TAG_OPTS         0x7002   /* SILC_ASN1_OPTS given */
-#define SILC_ASN1_TAG_CHOICE       0x7003   /* SILC_ASN1_CHOICE given */
-#define SILC_ASN1_TAG_SEQUENCE_OF  0x7004   /* SILC_ASN1_SEQUENCE_OF given */
+#define SILC_ASN1_TAG_ANY           0x7000  /* SILC_ASN1_ANY given  */
+#define SILC_ASN1_TAG_FUNC          0x7001  /* Callback encoder/decoder */
+#define SILC_ASN1_TAG_OPTS          0x7002  /* SILC_ASN1_OPTS given */
+#define SILC_ASN1_TAG_CHOICE        0x7003  /* SILC_ASN1_CHOICE given */
+#define SILC_ASN1_TAG_SEQUENCE_OF   0x7004  /* SILC_ASN1_SEQUENCE_OF given */
+#define SILC_ASN1_TAG_ANY_PRIMITIVE 0x7005  /* Pre-encoded primitive data */
 
 /* Helper macros for adding the arguments to encoder and decoder. */
 
index 8f43a3d6b6d11e5f13b8c5744f9bb7427c60ee1c..9d83d8b56e43fb08329fe70f1f828aaa20f94a15 100644 (file)
@@ -28,9 +28,9 @@
    include the length of the data in the BER block. */
 
 SilcBool silc_ber_encode(SilcBuffer ber, SilcBerClass ber_class,
-                    SilcBerEncoding encoding, SilcUInt32 tag,
-                    const unsigned char *data, SilcUInt32 data_len,
-                    SilcBool indefinite)
+                        SilcBerEncoding encoding, SilcUInt32 tag,
+                        const unsigned char *data, SilcUInt32 data_len,
+                        SilcBool indefinite)
 {
   int i = 0, c;
   SilcUInt32 tmp;
@@ -115,9 +115,9 @@ SilcBool silc_ber_encode(SilcBuffer ber, SilcBerClass ber_class,
    of the entire BER object is `identifier_len' + `data_len'. */
 
 SilcBool silc_ber_decode(SilcBuffer ber, SilcBerClass *ber_class,
-                    SilcBerEncoding *encoding, SilcUInt32 *tag,
-                    const unsigned char **data, SilcUInt32 *data_len,
-                    SilcBool *indefinite, SilcUInt32 *identifier_len)
+                        SilcBerEncoding *encoding, SilcUInt32 *tag,
+                        const unsigned char **data, SilcUInt32 *data_len,
+                        SilcBool *indefinite, SilcUInt32 *identifier_len)
 {
   int i = 0, c;
   SilcUInt32 t;
index e610be151e30dbd00ff8ddd64f6e2d12ed73cee7..3e2bd3ce72e16560ba873e69a6a7215fe649ee09 100644 (file)
@@ -52,6 +52,7 @@ int main(int argc, char **argv)
   int i;
   unsigned char *str;
   SilcUInt32 str_len;
+  char tmp[32];
 
   memset(&node, 0, sizeof(node));
   memset(&node2, 0, sizeof(node2));
@@ -323,6 +324,112 @@ int main(int argc, char **argv)
   printf("\n");
 
 
+  memset(&node, 0, sizeof(node));
+  SILC_LOG_DEBUG(("Encoding ASN.1 tree (ANY_PRIMITIVE)"));
+  memset(tmp, 0, sizeof(tmp));
+  tmp[0] = 0xff;
+  silc_buffer_set(&node2, tmp, 1);
+  SILC_LOG_DEBUG(("Encoding success"));
+  success =
+    silc_asn1_encode(asn1, &node,
+                    SILC_ASN1_SEQUENCE,
+                      SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_BOOLEAN,
+                                              &node2),
+                    SILC_ASN1_END, SILC_ASN1_END);
+  if (!success) {
+    SILC_LOG_DEBUG(("Encoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Encoding success"));
+  SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
+  memset(&node2, 0, sizeof(node2));
+  SILC_LOG_DEBUG(("Decoding ASN.1 tree (ANY_PRIMITIVE)"));
+  success =
+    silc_asn1_decode(asn1, &node,
+                    SILC_ASN1_SEQUENCE,
+                      SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_BOOLEAN,
+                                              &node2),
+                    SILC_ASN1_END, SILC_ASN1_END);
+  if (!success) {
+    SILC_LOG_DEBUG(("Decoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Boolean val %d", node2.data[0]));
+  if (node2.data[0] != 0xff) {
+    SILC_LOG_DEBUG(("Decoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Decoding success"));
+  memset(&node, 0, sizeof(node));
+  SILC_LOG_DEBUG(("Encoding ASN.1 tree (ANY_PRIMITIVE)"));
+  memset(tmp, 0, sizeof(tmp));
+  tmp[0] = 0xff;
+  silc_buffer_set(&node2, tmp, 1);
+  SILC_LOG_DEBUG(("Encoding success"));
+  success =
+    silc_asn1_encode(asn1, &node,
+                    SILC_ASN1_SEQUENCE,
+                      SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_BOOLEAN,
+                                              &node2),
+                    SILC_ASN1_END, SILC_ASN1_END);
+  if (!success) {
+    SILC_LOG_DEBUG(("Encoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Encoding success"));
+  SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
+  memset(&node2, 0, sizeof(node2));
+  SILC_LOG_DEBUG(("Decoding ASN.1 tree (ANY_PRIMITIVE)"));
+  success =
+    silc_asn1_decode(asn1, &node,
+                    SILC_ASN1_SEQUENCE,
+                      SILC_ASN1_BOOLEAN(&val),
+                    SILC_ASN1_END, SILC_ASN1_END);
+  if (!success) {
+    SILC_LOG_DEBUG(("Decoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Decoding success"));
+  SILC_LOG_DEBUG(("Boolean val %d", val));
+  memset(&node, 0, sizeof(node));
+  SILC_LOG_DEBUG(("Encoding ASN.1 tree (ANY_PRIMITIVE)"));
+  memset(tmp, 0, sizeof(tmp));
+  tmp[0] = 0xff;
+  silc_buffer_set(&node2, tmp, 1);
+  SILC_LOG_DEBUG(("Encoding success"));
+  success =
+    silc_asn1_encode(asn1, &node,
+                    SILC_ASN1_SEQUENCE,
+                      SILC_ASN1_BOOLEAN(val),
+                    SILC_ASN1_END, SILC_ASN1_END);
+  if (!success) {
+    SILC_LOG_DEBUG(("Encoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Encoding success"));
+  SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
+  memset(&node2, 0, sizeof(node2));
+  SILC_LOG_DEBUG(("Decoding ASN.1 tree (ANY_PRIMITIVE)"));
+  success =
+    silc_asn1_decode(asn1, &node,
+                    SILC_ASN1_SEQUENCE,
+                      SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_BOOLEAN,
+                                              &node2),
+                    SILC_ASN1_END, SILC_ASN1_END);
+  if (!success) {
+    SILC_LOG_DEBUG(("Decoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Boolean val %d", node2.data[0]));
+  if (node2.data[0] != 0xff) {
+    SILC_LOG_DEBUG(("Decoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Decoding success"));
+  memset(&node2, 0, sizeof(node2));
+  printf("\n");
+
+
   memset(&node, 0, sizeof(node));
   SILC_LOG_DEBUG(("Encoding ASN.1 tree 6"));
   success =