From 4a2208546ba22e3da99dc1a2adcf2102246d6c6f Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Thu, 29 Dec 2005 21:06:03 +0000 Subject: [PATCH] Added SILC_ASN1_ANY_PRIMITIVE to encode/decode any pre-encoded primitive data type. --- lib/silcasn1/silcasn1.c | 3 +- lib/silcasn1/silcasn1.h | 46 +++++++++++++ lib/silcasn1/silcasn1_decode.c | 27 ++++++-- lib/silcasn1/silcasn1_encode.c | 35 ++++++++-- lib/silcasn1/silcasn1_i.h | 11 +-- lib/silcasn1/silcber.c | 12 ++-- lib/silcasn1/tests/test_silcasn1.c | 107 +++++++++++++++++++++++++++++ 7 files changed, 219 insertions(+), 22 deletions(-) diff --git a/lib/silcasn1/silcasn1.c b/lib/silcasn1/silcasn1.c index 29b48d38..ccf77c2b 100644 --- a/lib/silcasn1/silcasn1.c +++ b/lib/silcasn1/silcasn1.c @@ -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: diff --git a/lib/silcasn1/silcasn1.h b/lib/silcasn1/silcasn1.h index a620d69c..57c31905 100644 --- a/lib/silcasn1/silcasn1.h +++ b/lib/silcasn1/silcasn1.h @@ -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 diff --git a/lib/silcasn1/silcasn1_decode.c b/lib/silcasn1/silcasn1_decode.c index 17354ac1..34b93ca2 100644 --- a/lib/silcasn1/silcasn1_decode.c +++ b/lib/silcasn1/silcasn1_decode.c @@ -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: { diff --git a/lib/silcasn1/silcasn1_encode.c b/lib/silcasn1/silcasn1_encode.c index 350fac94..123539f6 100644 --- a/lib/silcasn1/silcasn1_encode.c +++ b/lib/silcasn1/silcasn1_encode.c @@ -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: { diff --git a/lib/silcasn1/silcasn1_i.h b/lib/silcasn1/silcasn1_i.h index 394ba3ba..b6020105 100644 --- a/lib/silcasn1/silcasn1_i.h +++ b/lib/silcasn1/silcasn1_i.h @@ -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. */ diff --git a/lib/silcasn1/silcber.c b/lib/silcasn1/silcber.c index 8f43a3d6..9d83d8b5 100644 --- a/lib/silcasn1/silcber.c +++ b/lib/silcasn1/silcber.c @@ -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; diff --git a/lib/silcasn1/tests/test_silcasn1.c b/lib/silcasn1/tests/test_silcasn1.c index e610be15..3e2bd3ce 100644 --- a/lib/silcasn1/tests/test_silcasn1.c +++ b/lib/silcasn1/tests/test_silcasn1.c @@ -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 = -- 2.24.0