aboutsummaryrefslogtreecommitdiffstats
path: root/skeletons
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2004-06-03 03:38:44 +0000
committerLev Walkin <vlm@lionet.info>2004-06-03 03:38:44 +0000
commitf15320bf6b50a0c02636405561ac8323ae901abd (patch)
tree33461d45122896c6dde35f82f5c7d19b62004a6b /skeletons
parent746cb60bbccf47019563665f4aec4b6c462c4163 (diff)
Initial revision
Diffstat (limited to 'skeletons')
-rw-r--r--skeletons/BIT_STRING.c96
-rw-r--r--skeletons/BIT_STRING.h18
-rw-r--r--skeletons/BMPString.c65
-rw-r--r--skeletons/BMPString.h17
-rw-r--r--skeletons/BOOLEAN.c147
-rw-r--r--skeletons/BOOLEAN.h21
-rw-r--r--skeletons/ENUMERATED.c26
-rw-r--r--skeletons/ENUMERATED.h15
-rw-r--r--skeletons/GeneralString.c27
-rw-r--r--skeletons/GeneralString.h15
-rw-r--r--skeletons/GeneralizedTime.c302
-rw-r--r--skeletons/GeneralizedTime.h26
-rw-r--r--skeletons/GraphicString.c27
-rw-r--r--skeletons/GraphicString.h15
-rw-r--r--skeletons/IA5String.c57
-rw-r--r--skeletons/IA5String.h20
-rw-r--r--skeletons/INTEGER.c305
-rw-r--r--skeletons/INTEGER.h33
-rw-r--r--skeletons/ISO646String.c27
-rw-r--r--skeletons/ISO646String.h15
-rw-r--r--skeletons/Makefile.am7
-rw-r--r--skeletons/Makefile.in364
-rw-r--r--skeletons/NULL.c51
-rw-r--r--skeletons/NULL.h19
-rw-r--r--skeletons/NativeEnumerated.c32
-rw-r--r--skeletons/NativeEnumerated.h19
-rw-r--r--skeletons/NativeInteger.c193
-rw-r--r--skeletons/NativeInteger.h24
-rw-r--r--skeletons/NumericString.c62
-rw-r--r--skeletons/NumericString.h17
-rw-r--r--skeletons/OBJECT_IDENTIFIER.c356
-rw-r--r--skeletons/OBJECT_IDENTIFIER.h95
-rw-r--r--skeletons/OCTET_STRING.c588
-rw-r--r--skeletons/OCTET_STRING.h51
-rw-r--r--skeletons/ObjectDescriptor.c27
-rw-r--r--skeletons/ObjectDescriptor.h15
-rw-r--r--skeletons/PrintableString.c81
-rw-r--r--skeletons/PrintableString.h17
-rw-r--r--skeletons/README6
-rw-r--r--skeletons/RELATIVE-OID.c155
-rw-r--r--skeletons/RELATIVE-OID.h30
-rw-r--r--skeletons/T61String.c27
-rw-r--r--skeletons/T61String.h15
-rw-r--r--skeletons/TeletexString.c27
-rw-r--r--skeletons/TeletexString.h15
-rw-r--r--skeletons/UTCTime.c105
-rw-r--r--skeletons/UTCTime.h26
-rw-r--r--skeletons/UTF8String.c112
-rw-r--r--skeletons/UTF8String.h22
-rw-r--r--skeletons/UniversalString.c83
-rw-r--r--skeletons/UniversalString.h17
-rw-r--r--skeletons/VideotexString.c27
-rw-r--r--skeletons/VideotexString.h15
-rw-r--r--skeletons/VisibleString.c81
-rw-r--r--skeletons/VisibleString.h17
-rw-r--r--skeletons/asn_SEQUENCE_OF.c41
-rw-r--r--skeletons/asn_SEQUENCE_OF.h36
-rw-r--r--skeletons/asn_SET_OF.c89
-rw-r--r--skeletons/asn_SET_OF.h46
-rw-r--r--skeletons/asn_types.h63
-rw-r--r--skeletons/ber_decoder.c230
-rw-r--r--skeletons/ber_decoder.h77
-rw-r--r--skeletons/ber_tlv_length.c159
-rw-r--r--skeletons/ber_tlv_length.h40
-rw-r--r--skeletons/ber_tlv_tag.c145
-rw-r--r--skeletons/ber_tlv_tag.h52
-rw-r--r--skeletons/constr_CHOICE.c627
-rw-r--r--skeletons/constr_CHOICE.h65
-rw-r--r--skeletons/constr_SEQUENCE.c588
-rw-r--r--skeletons/constr_SEQUENCE.h53
-rw-r--r--skeletons/constr_SEQUENCE_OF.c84
-rw-r--r--skeletons/constr_SEQUENCE_OF.h21
-rw-r--r--skeletons/constr_SET.c682
-rw-r--r--skeletons/constr_SET.h90
-rw-r--r--skeletons/constr_SET_OF.c530
-rw-r--r--skeletons/constr_SET_OF.h38
-rw-r--r--skeletons/constr_TYPE.c58
-rw-r--r--skeletons/constr_TYPE.h98
-rw-r--r--skeletons/constraints.c111
-rw-r--r--skeletons/constraints.h57
-rw-r--r--skeletons/der_encoder.c143
-rw-r--r--skeletons/der_encoder.h73
-rw-r--r--skeletons/tests/Makefile.am9
-rw-r--r--skeletons/tests/Makefile.in411
-rw-r--r--skeletons/tests/check-GeneralizedTime.c54
-rw-r--r--skeletons/tests/check-INTEGER.c56
-rw-r--r--skeletons/tests/check-OIDs.c228
-rw-r--r--skeletons/tests/check-UTCTime.c54
88 files changed, 9180 insertions, 0 deletions
diff --git a/skeletons/BIT_STRING.c b/skeletons/BIT_STRING.c
new file mode 100644
index 00000000..19b6ff2e
--- /dev/null
+++ b/skeletons/BIT_STRING.c
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <BIT_STRING.h>
+
+/*
+ * BIT STRING basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_BIT_STRING_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (3 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_BIT_STRING = {
+ "BIT STRING",
+ BIT_STRING_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ BIT_STRING_print,
+ OCTET_STRING_free, /* Implemented in terms of OCTET STRING */
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_BIT_STRING_tags,
+ sizeof(asn1_DEF_BIT_STRING_tags)
+ / sizeof(asn1_DEF_BIT_STRING_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+ (void *)-1 /* Special indicator that this is a BIT STRING */
+};
+
+/*
+ * BIT STRING generic constraint.
+ */
+int
+BIT_STRING_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ const BIT_STRING_t *st = sptr;
+
+ if(st && st->buf) {
+ if(st->size) {
+ if(st->size == 1 && st->buf[0] != 0) {
+ _ASN_ERRLOG("%s: invalid padding byte",
+ td->name);
+ return -1;
+ }
+ } else {
+ _ASN_ERRLOG("%s: no padding byte", td->name);
+ return -1;
+ }
+ } else {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * BIT STRING specific contents printer.
+ */
+int
+BIT_STRING_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ static char h2c[16] = "0123456789ABCDEF";
+ char scratch[64];
+ const BIT_STRING_t *st = sptr;
+ uint8_t *buf;
+ uint8_t *end;
+ char *p = scratch;
+
+ if(!st || !st->buf) return cb("<absent>", 8, app_key);
+
+ ilevel += 4;
+ buf = st->buf;
+ end = buf + st->size;
+
+ /*
+ * Hexadecimal dump.
+ */
+ for(buf++; buf < end; buf++) {
+ if(((buf - st->buf) - 1) % 16 == 0) {
+ int i;
+ /* Indentation */
+ if(cb("\n", 1, app_key)) return -1;
+ for(i = 0; i < ilevel; i++) cb(" ", 1, app_key);
+ /* Dump the string */
+ if(cb(scratch, p - scratch, app_key)) return -1;
+ p = scratch;
+ }
+ *p++ = h2c[*buf >> 4];
+ *p++ = h2c[*buf & 0x0F];
+ *p++ = 0x20;
+ }
+
+ /* Dump the incomplete 16-bytes row */
+ return cb(scratch, p - scratch, app_key);
+}
+
diff --git a/skeletons/BIT_STRING.h b/skeletons/BIT_STRING.h
new file mode 100644
index 00000000..1def8bb2
--- /dev/null
+++ b/skeletons/BIT_STRING.h
@@ -0,0 +1,18 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _BIT_STRING_H_
+#define _BIT_STRING_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t BIT_STRING_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_BIT_STRING;
+
+asn_struct_print_f BIT_STRING_print; /* Human-readable output */
+asn_constr_check_f BIT_STRING_constraint;
+
+#endif /* _BIT_STRING_H_ */
diff --git a/skeletons/BMPString.c b/skeletons/BMPString.c
new file mode 100644
index 00000000..596974ea
--- /dev/null
+++ b/skeletons/BMPString.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <BMPString.h>
+
+/*
+ * BMPString basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_BMPString_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (30 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_BMPString = {
+ "BMPString",
+ asn_generic_no_constraint, /* No constraint by default */
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ BMPString_print,
+ OCTET_STRING_free, /* -//- */
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_BMPString_tags,
+ sizeof(asn1_DEF_BMPString_tags)
+ / sizeof(asn1_DEF_BMPString_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
+/*
+ * BMPString specific contents printer.
+ */
+int
+BMPString_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const BMPString_t *st = sptr;
+ uint16_t *wchar;
+ uint16_t *wend;
+ char scratch[128]; /* Scratchpad buffer */
+ char *p;
+
+ if(!st || !st->buf) return cb("<absent>", 8, app_key);
+
+ wchar = (uint16_t *)st->buf;
+ wend = (uint16_t *)(st->buf + st->size);
+ for(p = scratch; wchar < wend; wchar++) {
+ uint16_t wc = (((uint8_t *)wchar)[0] << 8)
+ | ((uint8_t *)wchar)[1]; /* 2 bytes */
+ if(sizeof(scratch) - (p - scratch) < 3) {
+ if(cb(scratch, p - scratch, app_key))
+ return -1;
+ p = scratch;
+ }
+ if(wc < 0x80) {
+ *p++ = (char)wc;
+ } else if(wc < 0x800) {
+ *p++ = 0xc0 | ((wc >> 6));
+ *p++ = 0x80 | ((wc & 0x3f));
+ } else {
+ *p++ = 0xe0 | ((wc >> 12));
+ *p++ = 0x80 | ((wc >> 6) & 0x3f);
+ *p++ = 0x80 | ((wc & 0x3f));
+ }
+ }
+
+ return cb(scratch, p - scratch, app_key);
+}
diff --git a/skeletons/BMPString.h b/skeletons/BMPString.h
new file mode 100644
index 00000000..e3957ca0
--- /dev/null
+++ b/skeletons/BMPString.h
@@ -0,0 +1,17 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _BMPString_H_
+#define _BMPString_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t BMPString_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_BMPString;
+
+asn_struct_print_f BMPString_print; /* Human-readable output */
+
+#endif /* _BMPString_H_ */
diff --git a/skeletons/BOOLEAN.c b/skeletons/BOOLEAN.c
new file mode 100644
index 00000000..705d37e0
--- /dev/null
+++ b/skeletons/BOOLEAN.c
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <BOOLEAN.h>
+
+/*
+ * BOOLEAN basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_BOOLEAN_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (1 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_BOOLEAN = {
+ "BOOLEAN",
+ asn_generic_no_constraint,
+ BOOLEAN_decode_ber,
+ BOOLEAN_encode_der,
+ BOOLEAN_print,
+ BOOLEAN_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_BOOLEAN_tags,
+ sizeof(asn1_DEF_BOOLEAN_tags)/sizeof(asn1_DEF_BOOLEAN_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ 0 /* Always in primitive form */
+};
+
+/*
+ * Decode BOOLEAN type.
+ */
+ber_dec_rval_t
+BOOLEAN_decode_ber(asn1_TYPE_descriptor_t *td,
+ void **bool_structure, void *buf_ptr, size_t size,
+ int tag_mode) {
+ BOOLEAN_t *st = *bool_structure;
+ ber_dec_rval_t rval;
+ ber_dec_ctx_t ctx = { 0 };
+ ber_tlv_len_t length;
+ ber_tlv_len_t lidx;
+
+ if(st == NULL) {
+ st = *bool_structure = CALLOC(1, sizeof(*st));
+ if(st == NULL) {
+ rval.code = RC_FAIL;
+ rval.consumed = 0;
+ return rval;
+ }
+ }
+
+ ASN_DEBUG("Decoding %s as BOOLEAN (tm=%d)",
+ td->name, tag_mode);
+
+ /*
+ * Check tags.
+ */
+ rval = ber_check_tags(td, &ctx,
+ buf_ptr, size, tag_mode, &length, 0);
+ if(rval.code != RC_OK)
+ return rval;
+
+ ASN_DEBUG("Boolean length is %d bytes", (int)length);
+
+ buf_ptr += rval.consumed;
+ size -= rval.consumed;
+ if(length > size) {
+ rval.code = RC_WMORE;
+ rval.consumed = 0;
+ return rval;
+ }
+
+ /*
+ * Compute boolean value.
+ */
+ for(st->value = 0, lidx = 0;
+ (lidx < length) && st->value == 0; lidx++) {
+ /*
+ * Very simple approach: read bytes until the end or
+ * value is already TRUE.
+ * BOOLEAN is not supposed to contain meaningful data anyway.
+ */
+ st->value |= ((uint8_t *)buf_ptr)[lidx];
+ }
+
+ rval.code = RC_OK;
+ rval.consumed += length;
+
+ ASN_DEBUG("Took %ld/%ld bytes to encode %s, value=%ld",
+ (long)rval.consumed, (long)length,
+ td->name, (long)st->value);
+
+ return rval;
+}
+
+der_enc_rval_t
+BOOLEAN_encode_der(asn1_TYPE_descriptor_t *td, void *sptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ der_enc_rval_t erval;
+ BOOLEAN_t *st = sptr;
+
+ erval.encoded = der_write_tags(td, 1, tag_mode, tag, cb, app_key);
+ if(erval.encoded == -1) {
+ erval.failed_type = td;
+ erval.structure_ptr = sptr;
+ return erval;
+ }
+
+ if(cb) {
+ uint8_t bool_value;
+ ssize_t ret;
+
+ bool_value = st->value?0xff:0; /* 0xff mandated by DER */
+ ret = cb(&bool_value, 1, app_key);
+ if(ret == -1) {
+ erval.encoded = -1;
+ erval.failed_type = td;
+ erval.structure_ptr = sptr;
+ return erval;
+ }
+ }
+
+ erval.encoded += 1;
+
+ return erval;
+}
+
+int
+BOOLEAN_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const BOOLEAN_t *st = sptr;
+
+ if(st) {
+ if(st->value)
+ return cb("TRUE", 4, app_key);
+ else
+ return cb("FALSE", 5, app_key);
+ } else {
+ return cb("<absent>", 8, app_key);
+ }
+}
+
+void
+BOOLEAN_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+ if(td && ptr && !contents_only) {
+ FREEMEM(ptr);
+ }
+}
+
diff --git a/skeletons/BOOLEAN.h b/skeletons/BOOLEAN.h
new file mode 100644
index 00000000..234e9f8e
--- /dev/null
+++ b/skeletons/BOOLEAN.h
@@ -0,0 +1,21 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _BOOLEAN_H_
+#define _BOOLEAN_H_
+
+#include <constr_TYPE.h>
+
+typedef struct BOOLEAN {
+ int value;
+} BOOLEAN_t;
+
+extern asn1_TYPE_descriptor_t asn1_DEF_BOOLEAN;
+
+ber_type_decoder_f BOOLEAN_decode_ber;
+der_type_encoder_f BOOLEAN_encode_der;
+asn_struct_print_f BOOLEAN_print;
+asn_struct_free_f BOOLEAN_free;
+
+#endif /* _BOOLEAN_H_ */
diff --git a/skeletons/ENUMERATED.c b/skeletons/ENUMERATED.c
new file mode 100644
index 00000000..1f1ae896
--- /dev/null
+++ b/skeletons/ENUMERATED.c
@@ -0,0 +1,26 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <ENUMERATED.h>
+
+/*
+ * ENUMERATED basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_ENUMERATED_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (10 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_ENUMERATED = {
+ "ENUMERATED",
+ asn_generic_no_constraint,
+ INTEGER_decode_ber, /* Implemented in terms of INTEGER */
+ INTEGER_encode_der, /* Implemented in terms of INTEGER */
+ INTEGER_print, /* Implemented in terms of INTEGER */
+ INTEGER_free, /* Implemented in terms of INTEGER */
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_ENUMERATED_tags,
+ sizeof(asn1_DEF_ENUMERATED_tags)/sizeof(asn1_DEF_ENUMERATED_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ 0 /* Primitive */
+};
+
diff --git a/skeletons/ENUMERATED.h b/skeletons/ENUMERATED.h
new file mode 100644
index 00000000..a0948ed0
--- /dev/null
+++ b/skeletons/ENUMERATED.h
@@ -0,0 +1,15 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _ENUMERATED_H_
+#define _ENUMERATED_H_
+
+#include <constr_TYPE.h>
+#include <INTEGER.h>
+
+typedef INTEGER_t ENUMERATED_t; /* Implemented in terms of INTEGER */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_ENUMERATED;
+
+#endif /* _ENUMERATED_H_ */
diff --git a/skeletons/GeneralString.c b/skeletons/GeneralString.c
new file mode 100644
index 00000000..d69c5f16
--- /dev/null
+++ b/skeletons/GeneralString.c
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <GeneralString.h>
+
+/*
+ * GeneralString basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_GeneralString_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (27 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_GeneralString = {
+ "GeneralString",
+ asn_generic_unknown_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print, /* non-ascii string */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_GeneralString_tags,
+ sizeof(asn1_DEF_GeneralString_tags)
+ / sizeof(asn1_DEF_GeneralString_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
diff --git a/skeletons/GeneralString.h b/skeletons/GeneralString.h
new file mode 100644
index 00000000..6d5bfdf6
--- /dev/null
+++ b/skeletons/GeneralString.h
@@ -0,0 +1,15 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _GeneralString_H_
+#define _GeneralString_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t GeneralString_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_GeneralString;
+
+#endif /* _GeneralString_H_ */
diff --git a/skeletons/GeneralizedTime.c b/skeletons/GeneralizedTime.c
new file mode 100644
index 00000000..01d7a736
--- /dev/null
+++ b/skeletons/GeneralizedTime.c
@@ -0,0 +1,302 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <GeneralizedTime.h>
+#include <time.h>
+#include <errno.h>
+#ifndef __NO_ASSERT_H__
+#include <assert.h>
+#endif /* __NO_ASSERT_H__ */
+
+#ifndef __NO_ASN_TABLE__
+
+/*
+ * GeneralizedTime basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_GeneralizedTime_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (24 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_GeneralizedTime = {
+ "GeneralizedTime",
+ GeneralizedTime_constraint, /* Check validity of time */
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ GeneralizedTime_print,
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_GeneralizedTime_tags,
+ sizeof(asn1_DEF_GeneralizedTime_tags)
+ / sizeof(asn1_DEF_GeneralizedTime_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
+#endif /* __NO_ASN_TABLE__ */
+
+/*
+ * Check that the time looks like the time.
+ */
+int
+GeneralizedTime_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ const GeneralizedTime_t *st = sptr;
+ time_t tloc;
+
+ errno = EPERM; /* Just an unlikely error code */
+ tloc = asn_GT2time(st, 0);
+ if(tloc == -1 && errno != EPERM) {
+ _ASN_ERRLOG("%s: Invalid time format: %s",
+ td->name, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+GeneralizedTime_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const GeneralizedTime_t *st = sptr;
+
+ if(st && st->buf) {
+ char buf[32];
+ struct tm tm;
+ int ret;
+
+ errno = EPERM;
+ if(asn_GT2time(st, &tm) == -1 && errno != EPERM)
+ return cb("<bad-value>", 11, app_key);
+
+ ret = snprintf(buf, sizeof(buf),
+ "%04d-%02d-%02d %02d:%02d%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ assert(ret > 0 && ret < sizeof(buf));
+ return cb(buf, ret, app_key);
+ } else {
+ return cb("<absent>", 8, app_key);
+ }
+}
+
+/*
+ * Where to look for offset from GMT, Phase I.
+ * Several platforms are known.
+ */
+#if defined(__FreeBSD__) || (defined(__GNUC__) && defined(__APPLE_CC__))
+#undef HAVE_TM_ZONE
+#define HAVE_TM_ZONE
+#endif /* BSDs */
+
+/*
+ * Where to look for offset from GMT, Phase II.
+ */
+#ifdef HAVE_TM_ZONE
+#define GMTOFF (tm_s.tm_gmtoff)
+#else /* HAVE_TM_ZONE */
+#define GMTOFF (-timezone)
+#endif /* HAVE_TM_ZONE */
+
+time_t
+asn_GT2time(const GeneralizedTime_t *st, struct tm *_tm) {
+ struct tm tm_s;
+ uint8_t *buf;
+ uint8_t *end;
+ int tm_gmtoff_h = 0;
+ int tm_gmtoff_m = 0;
+ int tm_gmtoff = 0; /* h + m */
+ int offset_specified = 0;
+ time_t tloc;
+
+ if(!st || !st->buf) {
+ errno = EINVAL;
+ return -1;
+ } else {
+ buf = st->buf;
+ end = buf + st->size;
+ }
+
+ if(st->size < 10) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Decode first 10 bytes: "AAAAMMJJhh"
+ */
+ memset(&tm_s, 0, sizeof(tm_s));
+#undef B2F
+#undef B2T
+#define B2F(var) do { \
+ unsigned ch = *buf; \
+ if(ch < 0x30 && ch > 0x39) { \
+ errno = EINVAL; \
+ return -1; \
+ } else { \
+ var = var * 10 + (ch - 0x30); \
+ buf++; \
+ } \
+ } while(0)
+#define B2T(var) B2F(tm_s.var)
+
+ B2T(tm_year); /* 1: A */
+ B2T(tm_year); /* 2: A */
+ B2T(tm_year); /* 3: A */
+ B2T(tm_year); /* 4: A */
+ B2T(tm_mon); /* 5: M */
+ B2T(tm_mon); /* 6: M */
+ B2T(tm_mday); /* 7: J */
+ B2T(tm_mday); /* 8: J */
+ B2T(tm_hour); /* 9: h */
+ B2T(tm_hour); /* 0: h */
+
+ if(buf == end) goto local_finish;
+
+ /*
+ * Parse [mm[ss[(.|,)ffff]]]
+ * ^^
+ */
+ switch(*buf) {
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+ tm_s.tm_min = (*buf++) - 0x30;
+ if(buf == end) { errno = EINVAL; return -1; }
+ B2T(tm_min);
+ break;
+ case 0x2B: case 0x2D: /* +, - */
+ goto offset;
+ case 0x5A: /* Z */
+ goto utc_finish;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(buf == end) goto local_finish;
+
+ /*
+ * Parse [mm[ss[(.|,)ffff]]]
+ * ^^
+ */
+ switch(*buf) {
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+ tm_s.tm_sec = (*buf++) - 0x30;
+ if(buf == end) { errno = EINVAL; return -1; }
+ B2T(tm_sec);
+ break;
+ case 0x2B: case 0x2D: /* +, - */
+ goto offset;
+ case 0x5A: /* Z */
+ goto utc_finish;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(buf == end) goto local_finish;
+
+ /*
+ * Parse [mm[ss[(.|,)ffff]]]
+ * ^ ^
+ */
+ switch(*buf) {
+ case 0x2C: case 0x2E: /* (.|,) */
+ /* Fractions of seconds are not supported
+ * by time_t or struct tm. Skip them */
+ for(buf++; buf < end; buf++) {
+ switch(*buf) {
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ if(buf == end) goto local_finish;
+
+ switch(*buf) {
+ case 0x2B: case 0x2D: /* +, - */
+ goto offset;
+ case 0x5A: /* Z */
+ goto utc_finish;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+
+offset:
+
+ if(end - buf < 3) {
+ errno = EINVAL;
+ return -1;
+ }
+ buf++;
+ B2F(tm_gmtoff_h);
+ B2F(tm_gmtoff_h);
+ if(buf[-3] == 0x2D) /* Negative */
+ tm_gmtoff = -1;
+ else
+ tm_gmtoff = 1;
+
+ if((end - buf) == 2) {
+ B2F(tm_gmtoff_m);
+ B2F(tm_gmtoff_m);
+ } else if(end != buf) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ tm_gmtoff = tm_gmtoff * (3600 * tm_gmtoff_h + 60 * tm_gmtoff_m);
+
+ /* Fall through */
+utc_finish:
+
+ offset_specified = 1;
+
+ /* Fall through */
+local_finish:
+
+ /*
+ * Validation.
+ */
+ if((tm_s.tm_mon > 12 || tm_s.tm_mon < 1)
+ || (tm_s.tm_mday > 31 || tm_s.tm_mday < 1)
+ || (tm_s.tm_hour > 23)
+ || (tm_s.tm_sec > 60)
+ ) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Canonicalize */
+ tm_s.tm_mon -= 1; /* 0 - 11 */
+ tm_s.tm_year -= 1900;
+ tm_s.tm_isdst = -1;
+
+ tloc = mktime(&tm_s);
+ if(tloc == -1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(offset_specified) {
+ /*
+ * Offset from GMT is specified in the time expression.
+ */
+ tloc += GMTOFF - tm_gmtoff;
+ if(_tm && (localtime_r(&tloc, &tm_s) == NULL)) {
+ /* Could not reconstruct the time */
+ return -1;
+ }
+ }
+
+ if(_tm) memcpy(_tm, &tm_s, sizeof(struct tm));
+
+ return tloc;
+}
+
diff --git a/skeletons/GeneralizedTime.h b/skeletons/GeneralizedTime.h
new file mode 100644
index 00000000..d8176be0
--- /dev/null
+++ b/skeletons/GeneralizedTime.h
@@ -0,0 +1,26 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _GeneralizedTime_H_
+#define _GeneralizedTime_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t GeneralizedTime_t; /* Implemented using OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_GeneralizedTime;
+
+asn_constr_check_f GeneralizedTime_constraint;
+asn_struct_print_f GeneralizedTime_print;
+
+/***********************
+ * Some handy helpers. *
+ ***********************/
+
+/* On error returns -1 and errno set to EINVAL */
+struct tm; /* <time.h> */
+time_t asn_GT2time(const GeneralizedTime_t *, struct tm *_optional_tm4fill);
+
+#endif /* _GeneralizedTime_H_ */
diff --git a/skeletons/GraphicString.c b/skeletons/GraphicString.c
new file mode 100644
index 00000000..5c89685e
--- /dev/null
+++ b/skeletons/GraphicString.c
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <GraphicString.h>
+
+/*
+ * GraphicString basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_GraphicString_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (25 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_GraphicString = {
+ "GraphicString",
+ asn_generic_unknown_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print, /* non-ascii string */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_GraphicString_tags,
+ sizeof(asn1_DEF_GraphicString_tags)
+ / sizeof(asn1_DEF_GraphicString_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
diff --git a/skeletons/GraphicString.h b/skeletons/GraphicString.h
new file mode 100644
index 00000000..b37b2c7e
--- /dev/null
+++ b/skeletons/GraphicString.h
@@ -0,0 +1,15 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _GraphicString_H_
+#define _GraphicString_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t GraphicString_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_GraphicString;
+
+#endif /* _GraphicString_H_ */
diff --git a/skeletons/IA5String.c b/skeletons/IA5String.c
new file mode 100644
index 00000000..c4afcb00
--- /dev/null
+++ b/skeletons/IA5String.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <IA5String.h>
+
+/*
+ * IA5String basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_IA5String_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (22 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_IA5String = {
+ "IA5String",
+ IA5String_constraint, /* Constraint on the alphabet */
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print_ascii, /* ASCII subset */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_IA5String_tags,
+ sizeof(asn1_DEF_IA5String_tags)
+ / sizeof(asn1_DEF_IA5String_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
+int
+IA5String_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ const IA5String_t *st = sptr;
+
+ if(st && st->buf) {
+ uint8_t *buf = st->buf;
+ uint8_t *end = buf + st->size;
+ /*
+ * IA5String is generally equivalent to 7bit ASCII.
+ * ISO/ITU-T T.50, 1963.
+ */
+ for(; buf < end; buf++) {
+ if(*buf > 0x7F) {
+ _ASN_ERRLOG("%s: value byte %d out of range: "
+ "%d > 127",
+ td->name,
+ (buf - st->buf) + 1,
+ *buf
+ );
+ return -1;
+ }
+ }
+ } else {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/skeletons/IA5String.h b/skeletons/IA5String.h
new file mode 100644
index 00000000..a80004e8
--- /dev/null
+++ b/skeletons/IA5String.h
@@ -0,0 +1,20 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _IA5String_H_
+#define _IA5String_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t IA5String_t; /* Implemented in terms of OCTET STRING */
+
+/*
+ * IA5String ASN.1 type definition.
+ */
+extern asn1_TYPE_descriptor_t asn1_DEF_IA5String;
+
+asn_constr_check_f IA5String_constraint;
+
+#endif /* _IA5String_H_ */
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
new file mode 100644
index 00000000..b1a8c29b
--- /dev/null
+++ b/skeletons/INTEGER.c
@@ -0,0 +1,305 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <INTEGER.h>
+#include <assert.h>
+#include <errno.h>
+
+/*
+ * INTEGER basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_INTEGER_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_INTEGER = {
+ "INTEGER",
+ asn_generic_no_constraint,
+ INTEGER_decode_ber,
+ INTEGER_encode_der,
+ INTEGER_print,
+ INTEGER_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_INTEGER_tags,
+ sizeof(asn1_DEF_INTEGER_tags)/sizeof(asn1_DEF_INTEGER_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ 0 /* Always in primitive form */
+};
+
+/*
+ * Decode INTEGER type.
+ */
+ber_dec_rval_t
+INTEGER_decode_ber(asn1_TYPE_descriptor_t *td,
+ void **int_structure, void *buf_ptr, size_t size, int tag_mode) {
+ INTEGER_t *st = *int_structure;
+ ber_dec_rval_t rval;
+ ber_dec_ctx_t ctx = { 0 };
+ ber_tlv_len_t length;
+
+ /*
+ * If the structure is not there, allocate it.
+ */
+ if(st == NULL) {
+ st = *int_structure = CALLOC(1, sizeof(*st));
+ if(st == NULL) {
+ rval.code = RC_FAIL;
+ rval.consumed = 0;
+ return rval;
+ }
+ }
+
+ ASN_DEBUG("Decoding %s as INTEGER (tm=%d)",
+ td->name, tag_mode);
+
+ /*
+ * Check tags.
+ */
+ rval = ber_check_tags(td, &ctx,
+ buf_ptr, size, tag_mode, &length, 0);
+ if(rval.code != RC_OK)
+ return rval;
+
+ ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
+
+ /*
+ * Make sure we have this length.
+ */
+ buf_ptr += rval.consumed;
+ size -= rval.consumed;
+ if(length > size) {
+ rval.code = RC_WMORE;
+ rval.consumed = 0;
+ return rval;
+ }
+
+ st->buf = MALLOC(length);
+ if(st->buf) {
+ st->size = length;
+ } else {
+ rval.code = RC_FAIL;
+ rval.consumed = 0;
+ return rval;
+ }
+
+ memcpy(st->buf, buf_ptr, st->size);
+
+ rval.code = RC_OK;
+ rval.consumed += length;
+
+ ASN_DEBUG("Took %ld/%ld bytes to encode %s",
+ (long)rval.consumed,
+ (long)length, td->name);
+
+ return rval;
+}
+
+/*
+ * Encode INTEGER type using DER.
+ */
+der_enc_rval_t
+INTEGER_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ der_enc_rval_t erval;
+ INTEGER_t *st = ptr;
+
+ ASN_DEBUG("%s %s as INTEGER (tm=%d)",
+ cb?"Encoding":"Estimating", sd->name, tag_mode);
+
+ /*
+ * Canonicalize integer in the buffer.
+ * (Remove too long sign extension, remove some first 0x00 bytes)
+ */
+ if(st->buf) {
+ uint8_t *buf = st->buf;
+ uint8_t *end1 = buf + st->size - 1;
+ int shift;
+
+ /* Compute the number of superfluous leading bytes */
+ for(; buf < end1; buf++) {
+ /*
+ * If the contents octets of an integer value encoding
+ * consist of more than one octet, then the bits of the
+ * first octet and bit 8 of the second octet:
+ * a) shall not all be ones; and
+ * b) shall not all be zero.
+ */
+ switch(*buf) {
+ case 0x00: if((buf[1] & 0x80) == 0)
+ continue;
+ break;
+ case 0xff: if((buf[1] & 0x80))
+ continue;
+ break;
+ }
+ break;
+ }
+
+ /* Remove leading superfluous bytes from the integer */
+ shift = buf - st->buf;
+ if(shift) {
+ uint8_t *nb = st->buf;
+ uint8_t *end;
+
+ st->size -= shift; /* New size, minus bad bytes */
+ end = nb + st->size;
+
+ for(; nb < end; nb++, buf++)
+ *nb = *buf;
+ }
+
+ } /* if(1) */
+
+ erval.encoded = der_write_tags(sd, st->size, tag_mode, tag,
+ cb, app_key);
+ ASN_DEBUG("INTEGER %s wrote tags %d", sd->name, (int)erval.encoded);
+ if(erval.encoded == -1) {
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+
+ if(cb && st->buf) {
+ ssize_t ret;
+
+ ret = cb(st->buf, st->size, app_key);
+ if(ret == -1) {
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+ } else {
+ assert(st->buf || st->size == 0);
+ }
+
+ erval.encoded += st->size;
+
+ return erval;
+}
+
+/*
+ * INTEGER specific human-readable output.
+ */
+int
+INTEGER_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const INTEGER_t *st = sptr;
+ char scratch[32];
+ uint8_t *buf = st->buf;
+ uint8_t *buf_end = st->buf + st->size;
+ signed long accum;
+ char *p;
+ int ret;
+
+ if(!st && !st->buf) return cb("<absent>", 8, app_key);
+
+ if(st->size == 0)
+ return cb("0", 1, app_key);
+
+ /* Simple case: the integer size is small */
+ if(st->size < sizeof(accum) || (st->buf[0] & 0x80)) {
+ accum = (st->buf[0] & 0x80) ? -1 : 0;
+ for(; buf < buf_end; buf++)
+ accum = (accum << 8) | *buf;
+ ret = snprintf(scratch, sizeof(scratch), "%ld", accum);
+ assert(ret > 0 && ret < sizeof(scratch));
+ return cb(scratch, ret, app_key);
+ }
+
+ /* Output in the long xx:yy:zz... format */
+ for(p = scratch; buf < buf_end; buf++) {
+ static char h2c[16] = "0123456789ABCDEF";
+ if((p - scratch) >= (sizeof(scratch) / 2)) {
+ /* Flush buffer */
+ if(cb(scratch, p - scratch, app_key))
+ return -1;
+ p = scratch;
+ }
+ *p++ = h2c[*buf >> 4];
+ *p++ = h2c[*buf & 0x0F];
+ *p++ = ':';
+ }
+
+ return cb(scratch, p - scratch, app_key);
+}
+
+void
+INTEGER_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+ INTEGER_t *st = ptr;
+
+ if(!td || !st)
+ return;
+
+ ASN_DEBUG("Freeing %s as INTEGER (%d, %p, %p)",
+ td->name, contents_only, st, st->buf);
+
+ if(st->buf) {
+ FREEMEM(st->buf);
+ }
+
+ if(!contents_only) {
+ FREEMEM(st);
+ }
+}
+
+int
+asn1_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
+ uint8_t *b, *end;
+ size_t size;
+ long l;
+
+ /* Sanity checking */
+ if(!iptr || !iptr->buf || !lptr) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Cache the begin/end of the buffer */
+ b = iptr->buf; /* Start of the INTEGER buffer */
+ size = iptr->size;
+ end = b + size; /* Where to stop */
+
+ if(size > sizeof(long)) {
+ uint8_t *end1 = end - 1;
+ /*
+ * Slightly more advanced processing,
+ * able to >sizeof(long) bytes,
+ * when the actual value is small
+ * (0x0000000000abcdef would yield a fine 0x00abcdef)
+ */
+ /* Skip out the insignificant leading bytes */
+ for(; b < end1; b++) {
+ switch(*b) {
+ case 0x00: if((b[1] & 0x80) == 0) continue; break;
+ case 0xff: if((b[1] & 0x80) != 0) continue; break;
+ }
+ break;
+ }
+
+ size = end - b;
+ if(size > sizeof(long)) {
+ /* Still cannot fit the long */
+ errno = ERANGE;
+ return -1;
+ }
+ }
+
+ /* Shortcut processing of a corner case */
+ if(end == b) {
+ *lptr = 0;
+ return 0;
+ }
+
+ /* Perform the sign initialization */
+ /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */
+ if((*b >> 7)) l = -1; else l = 0;
+
+ /* Conversion engine */
+ for(; b < end; b++)
+ l = (l << 8) | *b;
+
+ *lptr = l;
+ return 0;
+}
diff --git a/skeletons/INTEGER.h b/skeletons/INTEGER.h
new file mode 100644
index 00000000..ef4d3f25
--- /dev/null
+++ b/skeletons/INTEGER.h
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _INTEGER_H_
+#define _INTEGER_H_
+
+#include <constr_TYPE.h>
+
+typedef struct INTEGER {
+ uint8_t *buf; /* Buffer with consecutive INTEGER bits (big-endian) */
+ int size; /* Size of the buffer */
+} INTEGER_t;
+
+extern asn1_TYPE_descriptor_t asn1_DEF_INTEGER;
+
+ber_type_decoder_f INTEGER_decode_ber;
+der_type_encoder_f INTEGER_encode_der;
+asn_struct_print_f INTEGER_print;
+asn_struct_free_f INTEGER_free;
+
+/***********************************
+ * Some handy conversion routines. *
+ ***********************************/
+
+/*
+ * Returns 0 if it was possible to convert, -1 otherwise.
+ * -1/EINVAL: Mandatory argument missing
+ * -1/ERANGE: Value encoded is out of range for long representation
+ */
+int asn1_INTEGER2long(const INTEGER_t *i, long *l);
+
+#endif /* _INTEGER_H_ */
diff --git a/skeletons/ISO646String.c b/skeletons/ISO646String.c
new file mode 100644
index 00000000..08b31698
--- /dev/null
+++ b/skeletons/ISO646String.c
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <ISO646String.h>
+
+/*
+ * ISO646String basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_ISO646String_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (26 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_ISO646String = {
+ "ISO646String",
+ VisibleString_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print_ascii, /* ASCII subset */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_ISO646String_tags,
+ sizeof(asn1_DEF_ISO646String_tags)
+ / sizeof(asn1_DEF_ISO646String_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
diff --git a/skeletons/ISO646String.h b/skeletons/ISO646String.h
new file mode 100644
index 00000000..566ce3be
--- /dev/null
+++ b/skeletons/ISO646String.h
@@ -0,0 +1,15 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _ISO646String_H_
+#define _ISO646String_H_
+
+#include <constr_TYPE.h>
+#include <VisibleString.h>
+
+typedef VisibleString_t ISO646String_t; /* Implemented using VisibleString */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_ISO646String;
+
+#endif /* _ISO646String_H_ */
diff --git a/skeletons/Makefile.am b/skeletons/Makefile.am
new file mode 100644
index 00000000..4a01bf3d
--- /dev/null
+++ b/skeletons/Makefile.am
@@ -0,0 +1,7 @@
+
+SUBDIRS = tests
+
+dist_pkgdata_DATA = *.[ch]
+uninstall-local:
+ -@echo -n " "
+ -rm -f -r $(DESTDIR)$(pkgdatadir)
diff --git a/skeletons/Makefile.in b/skeletons/Makefile.in
new file mode 100644
index 00000000..e8f42241
--- /dev/null
+++ b/skeletons/Makefile.in
@@ -0,0 +1,364 @@
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+ADD_CFLAGS = @ADD_CFLAGS@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AWK = @AWK@
+CC = @CC@
+CONFIGURE_DEPENDS = @CONFIGURE_DEPENDS@
+CPP = @CPP@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+EXEEXT = @EXEEXT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LEX = @LEX@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PATH = @PATH@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+
+SUBDIRS = tests
+
+dist_pkgdata_DATA = *.[ch]
+subdir = skeletons
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+DIST_SOURCES =
+DATA = $(dist_pkgdata_DATA)
+
+
+RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \
+ uninstall-info-recursive all-recursive install-data-recursive \
+ install-exec-recursive installdirs-recursive install-recursive \
+ uninstall-recursive check-recursive installcheck-recursive
+DIST_COMMON = README $(dist_pkgdata_DATA) Makefile.am Makefile.in
+DIST_SUBDIRS = $(SUBDIRS)
+all: all-recursive
+
+.SUFFIXES:
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu skeletons/Makefile
+Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && \
+ CONFIG_HEADERS= CONFIG_LINKS= \
+ CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+uninstall-info-am:
+install-dist_pkgdataDATA: $(dist_pkgdata_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
+ @list='$(dist_pkgdata_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(pkgdatadir)/$$f"; \
+ $(INSTALL_DATA) $$d$$p $(DESTDIR)$(pkgdatadir)/$$f; \
+ done
+
+uninstall-dist_pkgdataDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pkgdata_DATA)'; for p in $$list; do \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " rm -f $(DESTDIR)$(pkgdatadir)/$$f"; \
+ rm -f $(DESTDIR)$(pkgdatadir)/$$f; \
+ done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+GTAGS:
+ here=`CDPATH=: && cd $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ $(mkinstalldirs) "$(distdir)/$$dir"; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ for subdir in $(SUBDIRS); do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" \
+ distdir=../$(distdir)/$$subdir \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
+
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+
+distclean-am: clean-am distclean-generic distclean-libtool \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-dist_pkgdataDATA
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+uninstall-am: uninstall-dist_pkgdataDATA uninstall-info-am \
+ uninstall-local
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \
+ clean-generic clean-libtool clean-recursive distclean \
+ distclean-generic distclean-libtool distclean-recursive \
+ distclean-tags distdir dvi dvi-am dvi-recursive info info-am \
+ info-recursive install install-am install-data install-data-am \
+ install-data-recursive install-dist_pkgdataDATA install-exec \
+ install-exec-am install-exec-recursive install-info \
+ install-info-am install-info-recursive install-man \
+ install-recursive install-strip installcheck installcheck-am \
+ installdirs installdirs-am installdirs-recursive \
+ maintainer-clean maintainer-clean-generic \
+ maintainer-clean-recursive mostlyclean mostlyclean-generic \
+ mostlyclean-libtool mostlyclean-recursive tags tags-recursive \
+ uninstall uninstall-am uninstall-dist_pkgdataDATA \
+ uninstall-info-am uninstall-info-recursive uninstall-local \
+ uninstall-recursive
+
+uninstall-local:
+ -@echo -n " "
+ -rm -f -r $(DESTDIR)$(pkgdatadir)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/skeletons/NULL.c b/skeletons/NULL.c
new file mode 100644
index 00000000..9027e2c1
--- /dev/null
+++ b/skeletons/NULL.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <NULL.h>
+#include <BOOLEAN.h> /* Implemented in terms of BOOLEAN type */
+
+/*
+ * NULL basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_NULL_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (5 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_NULL = {
+ "NULL",
+ asn_generic_no_constraint,
+ BOOLEAN_decode_ber, /* Implemented in terms of BOOLEAN */
+ NULL_encode_der, /* Special handling of DER encoding */
+ NULL_print,
+ BOOLEAN_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_NULL_tags,
+ sizeof(asn1_DEF_NULL_tags)/sizeof(asn1_DEF_NULL_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ 0 /* Always in primitive form */
+};
+
+der_enc_rval_t
+NULL_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ der_enc_rval_t erval;
+
+ erval.encoded = der_write_tags(sd, 0, tag_mode, tag, cb, app_key);
+ if(erval.encoded == -1) {
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ }
+
+ return erval;
+}
+
+int
+NULL_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ if(sptr) {
+ return cb("<present>", 9, app_key);
+ } else {
+ return cb("<absent>", 8, app_key);
+ }
+}
diff --git a/skeletons/NULL.h b/skeletons/NULL.h
new file mode 100644
index 00000000..14f5ffab
--- /dev/null
+++ b/skeletons/NULL.h
@@ -0,0 +1,19 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _NULL_H_
+#define _NULL_H_
+
+#include <constr_TYPE.h>
+
+typedef struct NULL_s {
+ int value;
+} NULL_t;
+
+extern asn1_TYPE_descriptor_t asn1_DEF_NULL;
+
+der_type_encoder_f NULL_encode_der;
+asn_struct_print_f NULL_print;
+
+#endif /* _NULL_H_ */
diff --git a/skeletons/NativeEnumerated.c b/skeletons/NativeEnumerated.c
new file mode 100644
index 00000000..b6d21ed2
--- /dev/null
+++ b/skeletons/NativeEnumerated.c
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Please read the NativeInteger.h for the explanation wrt. differences between
+ * INTEGER and NativeInteger.
+ * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this
+ * implementation deals with the standard (machine-specific) representation
+ * of them instead of using the platform-independent buffer.
+ */
+#include <NativeEnumerated.h>
+
+/*
+ * NativeEnumerated basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_NativeEnumerated_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (10 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_NativeEnumerated = {
+ "ENUMERATED", /* The ASN.1 type is still ENUMERATED */
+ asn_generic_no_constraint,
+ NativeInteger_decode_ber,
+ NativeInteger_encode_der,
+ NativeInteger_print,
+ NativeInteger_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_NativeEnumerated_tags,
+ sizeof(asn1_DEF_NativeEnumerated_tags)/sizeof(asn1_DEF_NativeEnumerated_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ 0 /* Always in primitive form */
+};
diff --git a/skeletons/NativeEnumerated.h b/skeletons/NativeEnumerated.h
new file mode 100644
index 00000000..681147c1
--- /dev/null
+++ b/skeletons/NativeEnumerated.h
@@ -0,0 +1,19 @@
+/*-
+ * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * This type differs from the standard ENUMERATED in that it is modelled using
+ * the fixed machine type (long, int, short), so it can hold only values of
+ * limited length. There is no type (i.e., NativeEnumerated_t, any integer type
+ * will do).
+ * This type may be used when integer range is limited by subtype constraints.
+ */
+#ifndef _NativeEnumerated_H_
+#define _NativeEnumerated_H_
+
+#include <NativeInteger.h>
+
+extern asn1_TYPE_descriptor_t asn1_DEF_NativeEnumerated;
+
+#endif /* _NativeEnumerated_H_ */
diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c
new file mode 100644
index 00000000..d42540ef
--- /dev/null
+++ b/skeletons/NativeInteger.c
@@ -0,0 +1,193 @@
+/*-
+ * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Please read the NativeInteger.h for the explanation wrt. differences between
+ * INTEGER and NativeInteger.
+ * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this
+ * implementation deals with the standard (machine-specific) representation
+ * of them instead of using the platform-independent buffer.
+ */
+#include <NativeInteger.h>
+#include <INTEGER.h>
+#include <assert.h>
+
+/*
+ * NativeInteger basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_NativeInteger_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_NativeInteger = {
+ "INTEGER", /* The ASN.1 type is still INTEGER */
+ asn_generic_no_constraint,
+ NativeInteger_decode_ber,
+ NativeInteger_encode_der,
+ NativeInteger_print,
+ NativeInteger_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_NativeInteger_tags,
+ sizeof(asn1_DEF_NativeInteger_tags)/sizeof(asn1_DEF_NativeInteger_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ 0 /* Always in primitive form */
+};
+
+/*
+ * Decode INTEGER type.
+ */
+ber_dec_rval_t
+NativeInteger_decode_ber(asn1_TYPE_descriptor_t *td,
+ void **int_ptr, void *buf_ptr, size_t size, int tag_mode) {
+ int *Int = *int_ptr;
+ ber_dec_rval_t rval;
+ ber_dec_ctx_t ctx = { 0 };
+ ber_tlv_len_t length;
+
+ /*
+ * If the structure is not there, allocate it.
+ */
+ if(Int == NULL) {
+ Int = *int_ptr = CALLOC(1, sizeof(*Int));
+ if(Int == NULL) {
+ rval.code = RC_FAIL;
+ rval.consumed = 0;
+ return rval;
+ }
+ }
+
+ ASN_DEBUG("Decoding %s as INTEGER (tm=%d)",
+ td->name, tag_mode);
+
+ /*
+ * Check tags.
+ */
+ rval = ber_check_tags(td, &ctx,
+ buf_ptr, size, tag_mode, &length, 0);
+ if(rval.code != RC_OK)
+ return rval;
+
+ ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
+
+ /*
+ * Make sure we have this length.
+ */
+ buf_ptr += rval.consumed;
+ size -= rval.consumed;
+ if(length > size) {
+ rval.code = RC_WMORE;
+ rval.consumed = 0;
+ return rval;
+ }
+
+ /*
+ * ASN.1 encoded INTEGER: buf_ptr, length
+ * Fill the Int, at the same time checking for overflow.
+ * If overflow occured, return with RC_FAIL.
+ */
+ {
+ INTEGER_t tmp;
+ long l;
+ tmp.buf = buf_ptr;
+ tmp.size = length;
+
+ if(asn1_INTEGER2long(&tmp, &l)) {
+ rval.code = RC_FAIL;
+ rval.consumed = 0;
+ return rval;
+ }
+
+ *Int = l;
+
+ /*
+ * Note that int might be shorter than long.
+ * This expression hopefully will be optimized away
+ * by compiler.
+ */
+ if(sizeof(int) != sizeof(long) && (*Int != l)) {
+ *Int = 0; /* Safe value */
+ rval.code = RC_FAIL;
+ rval.consumed = 0;
+ return rval;
+ }
+ }
+
+ rval.code = RC_OK;
+ rval.consumed += length;
+
+ ASN_DEBUG("Took %ld/%ld bytes to encode %s (%d)",
+ (long)rval.consumed, (long)length, td->name, *Int);
+
+ return rval;
+}
+
+/*
+ * Encode the NativeInteger using the standard INTEGER type DER encoder.
+ */
+der_enc_rval_t
+NativeInteger_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ unsigned int Int = *(unsigned int *)ptr; /* Disable sign ext. */
+ der_enc_rval_t erval;
+ INTEGER_t tmp;
+
+#ifdef WORDS_BIGENDIAN /* Opportunistic optimization */
+
+ tmp.buf = &Int;
+ tmp.size = sizeof(Int);
+
+#else /* Works even if WORDS_BIGENDIAN is not set where should've been */
+ uint8_t buf[sizeof(int)];
+ uint8_t *p;
+
+ /* Prepare fake INTEGER */
+ for(p = buf + sizeof(buf) - 1; p >= buf; p--, Int >>= 8)
+ *p = Int & 0xff;
+
+ tmp.buf = buf;
+ tmp.size = sizeof(buf);
+#endif /* WORDS_BIGENDIAN */
+
+ /* Encode fake INTEGER */
+ erval = INTEGER_encode_der(sd, &tmp, tag_mode, tag, cb, app_key);
+ if(erval.encoded == -1) {
+ assert(erval.structure_ptr == &tmp);
+ erval.structure_ptr = ptr;
+ }
+ return erval;
+}
+
+/*
+ * INTEGER specific human-readable output.
+ */
+int
+NativeInteger_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const int *Int = sptr;
+ char scratch[32];
+ int ret;
+
+ if(Int) {
+ ret = snprintf(scratch, sizeof(scratch), "%d", *Int);
+ assert(ret > 0 && ret < sizeof(scratch));
+ return cb(scratch, ret, app_key);
+ } else {
+ return cb("<absent>", 8, app_key);
+ }
+}
+
+void
+NativeInteger_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+
+ if(!td || !ptr)
+ return;
+
+ ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)",
+ td->name, contents_only, ptr);
+
+ if(!contents_only) {
+ FREEMEM(ptr);
+ }
+}
+
diff --git a/skeletons/NativeInteger.h b/skeletons/NativeInteger.h
new file mode 100644
index 00000000..e0f26c78
--- /dev/null
+++ b/skeletons/NativeInteger.h
@@ -0,0 +1,24 @@
+/*-
+ * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * This type differs from the standard INTEGER in that it is modelled using
+ * the fixed machine type (long, int, short), so it can hold only values of
+ * limited length. There is no type (i.e., NativeInteger_t, any integer type
+ * will do).
+ * This type may be used when integer range is limited by subtype constraints.
+ */
+#ifndef _NativeInteger_H_
+#define _NativeInteger_H_
+
+#include <constr_TYPE.h>
+
+extern asn1_TYPE_descriptor_t asn1_DEF_NativeInteger;
+
+ber_type_decoder_f NativeInteger_decode_ber;
+der_type_encoder_f NativeInteger_encode_der;
+asn_struct_print_f NativeInteger_print;
+asn_struct_free_f NativeInteger_free;
+
+#endif /* _NativeInteger_H_ */
diff --git a/skeletons/NumericString.c b/skeletons/NumericString.c
new file mode 100644
index 00000000..a007496c
--- /dev/null
+++ b/skeletons/NumericString.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <NumericString.h>
+
+/*
+ * NumericString basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_NumericString_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (18 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_NumericString = {
+ "NumericString",
+ NumericString_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print_ascii, /* ASCII subset */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_NumericString_tags,
+ sizeof(asn1_DEF_NumericString_tags)
+ / sizeof(asn1_DEF_NumericString_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
+int
+NumericString_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ const NumericString_t *st = sptr;
+
+ if(st && st->buf) {
+ uint8_t *buf = st->buf;
+ uint8_t *end = buf + st->size;
+
+ /*
+ * Check the alphabet of the NumericString.
+ * ASN.1:1984 (X.409)
+ */
+ for(; buf < end; buf++) {
+ switch(*buf) {
+ case 0x20:
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+ continue;
+ }
+ _ASN_ERRLOG("%s: value byte %d "
+ "not in NumericString alphabet (%d)",
+ td->name,
+ (buf - st->buf) + 1,
+ *buf
+ );
+ return -1;
+ }
+ } else {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/skeletons/NumericString.h b/skeletons/NumericString.h
new file mode 100644
index 00000000..71f72c76
--- /dev/null
+++ b/skeletons/NumericString.h
@@ -0,0 +1,17 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _NumericString_H_
+#define _NumericString_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t NumericString_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_NumericString;
+
+asn_constr_check_f NumericString_constraint;
+
+#endif /* _NumericString_H_ */
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
new file mode 100644
index 00000000..bcbcdcaf
--- /dev/null
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -0,0 +1,356 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <OBJECT_IDENTIFIER.h>
+#include <assert.h>
+#include <errno.h>
+
+/*
+ * OBJECT IDENTIFIER basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_OBJECT_IDENTIFIER_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_OBJECT_IDENTIFIER = {
+ "OBJECT IDENTIFIER",
+ OBJECT_IDENTIFIER_constraint,
+ INTEGER_decode_ber, /* Implemented in terms of INTEGER type */
+ OBJECT_IDENTIFIER_encode_der,
+ OBJECT_IDENTIFIER_print,
+ INTEGER_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_OBJECT_IDENTIFIER_tags,
+ sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags)
+ / sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ 0 /* Always in primitive form */
+};
+
+
+/*
+ * Encode OBJECT IDENTIFIER type using DER.
+ */
+der_enc_rval_t
+OBJECT_IDENTIFIER_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ der_enc_rval_t erval;
+ OBJECT_IDENTIFIER_t *st = ptr;
+
+ ASN_DEBUG("%s %s as OBJECT IDENTIFIER (tm=%d)",
+ cb?"Encoding":"Estimating", sd->name, tag_mode);
+
+ erval.encoded = der_write_tags(sd, st->size, tag_mode, tag,
+ cb, app_key);
+ ASN_DEBUG("OBJECT IDENTIFIER %s wrote tags %d",
+ sd->name, (int)erval.encoded);
+ if(erval.encoded == -1) {
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+
+ if(cb && st->buf) {
+ ssize_t ret;
+
+ ret = cb(st->buf, st->size, app_key);
+ if(ret == -1) {
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+ } else {
+ assert(st->buf || st->size == 0);
+ }
+
+ erval.encoded += st->size;
+
+ return erval;
+}
+
+int
+OBJECT_IDENTIFIER_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ const OBJECT_IDENTIFIER_t *st = sptr;
+
+ if(st && st->buf) {
+ if(st->size < 1) {
+ _ASN_ERRLOG("%s: at least one numerical value expected",
+ td->name);
+ return -1;
+ }
+ } else {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+OBJECT_IDENTIFIER_get_arc_l(uint8_t *arcbuf, int arclen, int add, unsigned long *rvalue) {
+ unsigned long accum;
+ uint8_t *arcend = arcbuf + arclen;
+
+ if(arclen * 7 > 8 * sizeof(accum)) {
+ if(arclen * 7 <= 8 * (sizeof(accum) + 1)) {
+ if((*arcbuf & ~0x8f)) {
+ errno = ERANGE; /* Overflow */
+ return -1;
+ }
+ } else {
+ errno = ERANGE; /* Overflow */
+ return -1;
+ }
+ }
+
+ /* Gather all bits into the accumulator */
+ for(accum = 0; arcbuf < arcend; arcbuf++)
+ accum = (accum << 7) | (*arcbuf & ~0x80);
+
+ accum += add; /* Actually, a negative value */
+ assert(accum >= 0);
+
+ *rvalue = accum;
+
+ return 0;
+}
+
+int
+OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ char scratch[64]; /* Conservative estimate */
+ unsigned long accum; /* Bits accumulator */
+ char *p; /* Position in the scratch buffer */
+
+ if(OBJECT_IDENTIFIER_get_arc_l(arcbuf, arclen, add, &accum))
+ return -1;
+
+ /* Fill the scratch buffer in reverse. */
+ p = scratch + sizeof(scratch);
+ for(; accum; accum /= 10)
+ *(--p) = (accum % 10) + 0x30;
+
+ return cb(p, sizeof(scratch) - (p - scratch), app_key);
+}
+
+int
+OBJECT_IDENTIFIER_print(asn1_TYPE_descriptor_t *td, const void *sptr,
+ int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
+ const OBJECT_IDENTIFIER_t *st = sptr;
+ int startn;
+ int add = 0;
+ int i;
+
+ if(!st || !st->buf)
+ return cb("<absent>", 8, app_key);
+
+ /* Dump preamble */
+ if(cb("{ ", 2, app_key))
+ return -1;
+
+ for(i = 0, startn = 0; i < st->size; i++) {
+ uint8_t b = st->buf[i];
+ if((b & 0x80)) /* Continuation expected */
+ continue;
+
+ if(startn == 0) {
+ /*
+ * First two arcs are encoded through the backdoor.
+ */
+ if(i) {
+ add = -80;
+ if(cb("2", 1, app_key)) return -1;
+ } else if(b <= 39) {
+ add = 0;
+ if(cb("0", 1, app_key)) return -1;
+ } else if(b < 79) {
+ add = -40;
+ if(cb("1", 1, app_key)) return -1;
+ } else {
+ add = -80;
+ if(cb("2", 1, app_key)) return -1;
+ }
+ }
+
+ if(cb(" ", 1, app_key)) /* Separate arcs */
+ return -1;
+
+ if(OBJECT_IDENTIFIER_print_arc(&st->buf[startn],
+ i - startn + 1, add,
+ cb, app_key))
+ return -1;
+ startn = i + 1;
+ add = 0;
+ }
+
+ return cb(" }", 2, app_key);
+}
+
+int
+OBJECT_IDENTIFIER_get_arcs_l(OBJECT_IDENTIFIER_t *oid,
+ unsigned long *arcs, int arcs_slots) {
+ unsigned long arc_value;
+ int cur_arc = 0;
+ int startn = 0;
+ int add = 0;
+ int i;
+
+ if(!oid || !oid->buf) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for(i = 0; i < oid->size; i++) {
+ uint8_t b = oid->buf[i];
+ if((b & 0x80)) /* Continuation expected */
+ continue;
+
+ if(startn == 0) {
+ /*
+ * First two arcs are encoded through the backdoor.
+ */
+ if(i) {
+ add = -80;
+ if(cur_arc < arcs_slots) arcs[cur_arc] = 2;
+ cur_arc++;
+ } else if(b <= 39) {
+ add = 0;
+ if(cur_arc < arcs_slots) arcs[cur_arc] = 0;
+ cur_arc++;
+ } else if(b < 79) {
+ add = -40;
+ if(cur_arc < arcs_slots) arcs[cur_arc] = 1;
+ cur_arc++;
+ } else {
+ add = -80;
+ if(cur_arc < arcs_slots) arcs[cur_arc] = 2;
+ cur_arc++;
+ }
+ }
+
+ /* Do not fill */
+ if(cur_arc >= arcs_slots) {
+ startn = i + 1;
+ continue;
+ }
+
+ if(OBJECT_IDENTIFIER_get_arc_l(&oid->buf[startn],
+ i - startn + 1,
+ add, &arc_value))
+ return -1;
+ arcs[cur_arc++] = arc_value;
+ startn = i + 1;
+ add = 0;
+ }
+
+ return cur_arc;
+}
+
+int
+OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, int arcs_slots) {
+ uint8_t *buf;
+ uint8_t *bp;
+ unsigned long long first_value;
+ int size;
+ int i;
+
+ if(oid == NULL || arcs == NULL || arcs_slots < 2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(arcs[0] <= 1) {
+ if(arcs[1] >= 39) {
+ /* 8.19.4: At most 39 subsequent values (including 0) */
+ errno = ERANGE;
+ return -1;
+ }
+ } else if(arcs[0] > 2) {
+ /* 8.19.4: Only three values are allocated from the root node */
+ errno = ERANGE;
+ return -1;
+ }
+
+ first_value = arcs[0] * 40 + arcs[1];
+
+ /*
+ * Roughly estimate the maximum size necessary to encode these arcs.
+ */
+ size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arcs_slots;
+ bp = buf = MALLOC(size + 1);
+ if(!buf) {
+ /* ENOMEM */
+ return -1;
+ }
+
+ /*
+ * Encode the arcs and refine the encoding size.
+ */
+ size = 0;
+
+ {
+ uint8_t tbuf[sizeof(first_value) * 2];
+ uint8_t *tp = tbuf;
+ int arc_len = 0;
+ int add = 0;
+
+ for(; first_value; first_value >>= 7) {
+ unsigned int b7 = first_value & 0x7f;
+ *tp++ = 0x80 | b7;
+ add++;
+ if(b7) { arc_len += add; add = 0; }
+ }
+
+ if(arc_len) {
+ tp = &tbuf[arc_len - 1];
+ /* The last octet does not have bit 8 set. */
+ *tbuf &= 0x7f;
+ for(; tp >= tbuf; tp--)
+ *bp++ = *tp;
+ size += arc_len;
+ } else {
+ *bp++ = 0;
+ size++;
+ }
+ }
+
+ for(i = 2; i < arcs_slots; i++) {
+ unsigned long value = arcs[i];
+ uint8_t tbuf[sizeof(value) * 2]; /* Conservatively sized */
+ uint8_t *tp = tbuf;
+ int arc_len = 0;
+ int add = 0;
+
+ for(; value; value >>= 7) {
+ unsigned int b7 = value & 0x7F;
+ *tp++ = 0x80 | b7;
+ add++;
+ if(b7) { arc_len += add; add = 0; }
+ }
+
+ if(arc_len) {
+ tp = &tbuf[arc_len - 1];
+ /* The last octet does not have bit 8 set. */
+ *tbuf &= 0x7f;
+ for(; tp >= tbuf; tp--)
+ *bp++ = *tp;
+ size += arc_len;
+ } else {
+ *bp++ = 0;
+ size++;
+ }
+ }
+
+ /*
+ * Replace buffer.
+ */
+ oid->size = size;
+ bp = oid->buf;
+ oid->buf = buf;
+ if(bp) FREEMEM(bp);
+
+ return 0;
+}
diff --git a/skeletons/OBJECT_IDENTIFIER.h b/skeletons/OBJECT_IDENTIFIER.h
new file mode 100644
index 00000000..3e71f316
--- /dev/null
+++ b/skeletons/OBJECT_IDENTIFIER.h
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _OBJECT_IDENTIFIER_H_
+#define _OBJECT_IDENTIFIER_H_
+
+#include <constr_TYPE.h>
+#include <INTEGER.h>
+
+typedef INTEGER_t OBJECT_IDENTIFIER_t; /* Implemented in terms of INTEGER */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_OBJECT_IDENTIFIER;
+
+der_type_encoder_f OBJECT_IDENTIFIER_encode_der;
+asn_constr_check_f OBJECT_IDENTIFIER_constraint;
+asn_struct_print_f OBJECT_IDENTIFIER_print;
+
+/**********************************
+ * Some handy conversion routines *
+ **********************************/
+
+/*
+ * Print the specified OBJECT IDENTIFIER arc.
+ */
+int OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen,
+ int add, /* Arbitrary offset, required to process the first two arcs */
+ asn_app_consume_bytes_f *cb, void *app_key);
+
+/*
+ * This function fills an (_arcs) array with OBJECT IDENTIFIER arcs
+ * up to specified (_arcs_slots) elements.
+ * The function always returns the real number of arcs, even if there is no
+ * sufficient (_arcs_slots) provided.
+ *
+ * EXAMPLE:
+ * void print_arcs(OBJECT_IDENTIFIER_t *oid) {
+ * unsigned long fixed_arcs[10]; // Try with fixed space first
+ * unsigned long *arcs = fixed_arcs;
+ * int arcs_slots = sizeof(fixed_arcs)/sizeof(fixed_arcs[0]); // 10
+ * int count; // Real number of arcs.
+ * int i;
+ *
+ * count = OBJECT_IDENTIFIER_get_arcs_l(oid, arcs, arcs_slots);
+ * // If necessary, reallocate arcs array and try again.
+ * if(count > arcs_slots) {
+ * arcs_slots = count;
+ * arcs = malloc(arcs_slots * sizeof(arcs[0]));
+ * if(!arcs) return;
+ * count = OBJECT_IDENTIFIER_get_arcs_l(oid,
+ * arcs, arcs_slots);
+ * assert(count == arcs_slots);
+ * }
+ *
+ * // Print the contents of the arcs array.
+ * for(i = 0; i < count; i++)
+ * printf("%d\n", arcs[i]);
+ *
+ * // Avoid memory leak.
+ * if(arcs != fixed_arcs) free(arcs);
+ * }
+ *
+ * RETURN VALUES:
+ * -1/EINVAL: Invalid arguments (oid is missing)
+ * -1/ERANGE: One or more arcs have value out of array cell type range.
+ * >=0: Number of arcs contained in the OBJECT IDENTIFIER
+ */
+int OBJECT_IDENTIFIER_get_arcs_l(OBJECT_IDENTIFIER_t *_oid,
+ unsigned long *_arcs, int _arcs_slots);
+/*
+int OBJECT_IDENTIFIER_get_arcs_im(OBJECT_IDENTIFIER_t *_oid,
+ uintmax_t *_arcs, int _arcs_slots);
+ */
+
+
+/*
+ * This functions initializes the OBJECT IDENTIFIER object with
+ * the given set of arcs.
+ * The minimum of two arcs must be present; some restrictions apply.
+ * RETURN VALUES:
+ * -1/EINVAL: Invalid arguments
+ * -1/ERANGE: The first two arcs do not conform to ASN.1 restrictions.
+ * -1/ENOMEM: Memory allocation failed
+ * 0: The object was initialized with new arcs.
+ */
+int OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *_oid,
+ unsigned long *arcs, int arcs_slots);
+
+/*
+ * Internal functions.
+ */
+int OBJECT_IDENTIFIER_get_arc_l(uint8_t *arcbuf, int arclen,
+ int add, unsigned long *value);
+
+#endif /* _OBJECT_IDENTIFIER_H_ */
diff --git a/skeletons/OCTET_STRING.c b/skeletons/OCTET_STRING.c
new file mode 100644
index 00000000..fc5c532c
--- /dev/null
+++ b/skeletons/OCTET_STRING.c
@@ -0,0 +1,588 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <OCTET_STRING.h>
+#include <assert.h>
+#include <errno.h>
+
+/*
+ * OCTET STRING basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_OCTET_STRING_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_OCTET_STRING = {
+ "OCTET STRING",
+ asn_generic_no_constraint,
+ OCTET_STRING_decode_ber,
+ OCTET_STRING_encode_der,
+ OCTET_STRING_print, /* non-ascii stuff, generally */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_OCTET_STRING_tags,
+ sizeof(asn1_DEF_OCTET_STRING_tags)
+ / sizeof(asn1_DEF_OCTET_STRING_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine (primitive and constructed) */
+};
+
+#define _CH_PHASE(ctx, inc) do { \
+ if(ctx->phase == 0) \
+ ctx->step = 0; \
+ ctx->phase += inc; \
+ } while(0)
+#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1)
+#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1)
+
+#define ADVANCE(num_bytes) do { \
+ size_t num = num_bytes; \
+ buf_ptr += num; \
+ size -= num; \
+ consumed_myself += num; \
+ } while(0)
+
+#define RETURN(_code) do { \
+ rval.code = _code; \
+ rval.consumed = consumed_myself;\
+ return rval; \
+ } while(0)
+
+#define APPEND(bufptr, bufsize) do { \
+ int _ns = ctx->step; /* Allocated */ \
+ if(_ns <= (st->size + bufsize)) { \
+ void *ptr; \
+ do { _ns = _ns ? _ns<<2 : 16; } \
+ while(_ns <= (st->size + bufsize)); \
+ ptr = REALLOC(st->buf, _ns); \
+ if(ptr) { \
+ st->buf = ptr; \
+ ctx->step = _ns; \
+ } else { \
+ RETURN(RC_FAIL); \
+ } \
+ } \
+ memcpy(st->buf + st->size, bufptr, bufsize); \
+ st->size += bufsize; \
+ if(st->size < 0) \
+ /* Why even care?.. JIC */ \
+ RETURN(RC_FAIL); \
+ /* Convenient nul-termination */ \
+ st->buf[st->size] = '\0'; \
+ } while(0)
+
+/*
+ * The main reason why ASN.1 is still alive is that too much time and effort
+ * is necessary for learning it more or less adequately, thus creating a gut
+ * necessity to demonstrate that aquired skill everywhere afterwards.
+ * No, I am not going to explain what the following stuff is.
+ */
+struct _stack_el {
+ ber_tlv_len_t left; /* What's left to read */
+ int want_nulls; /* Want null "end of content" octets? */
+ int bits_chopped; /* Flag in BIT STRING mode */
+ struct _stack_el *prev;
+ struct _stack_el *next;
+};
+struct _stack {
+ struct _stack_el *tail;
+ struct _stack_el *cur_ptr;
+};
+
+static struct _stack_el *
+_add_stack_el(struct _stack *st) {
+ struct _stack_el *nel;
+
+ if(st->cur_ptr && st->cur_ptr->next) {
+ nel = st->cur_ptr->next;
+ nel->left = 0;
+ nel->want_nulls = 0;
+ nel->bits_chopped = 0;
+ } else {
+ nel = CALLOC(1, sizeof(struct _stack_el));
+ if(nel == NULL)
+ return NULL;
+
+ if(st->tail) {
+ st->tail->next = nel;
+ }
+ nel->prev = st->tail;
+ st->tail = nel;
+ }
+
+ st->cur_ptr = nel;
+
+ return nel;
+}
+
+static struct _stack *
+_new_stack() {
+ struct _stack *st;
+ st = CALLOC(1, sizeof(struct _stack));
+ if(st == NULL)
+ return NULL;
+
+ st->cur_ptr = _add_stack_el(st);
+ if(st->cur_ptr == NULL) {
+ FREEMEM(st);
+ return NULL;
+ }
+
+ return st;
+}
+
+/*
+ * Decode OCTET STRING type.
+ */
+ber_dec_rval_t
+OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
+ void **os_structure, void *buf_ptr, size_t size, int tag_mode) {
+ OCTET_STRING_t *st = *os_structure;
+ ber_dec_rval_t rval;
+ ber_dec_ctx_t *ctx;
+ ssize_t consumed_myself = 0;
+ struct _stack *stck; /* A stack structure */
+ struct _stack_el *sel; /* Stack element */
+ int tlv_constr;
+ /*
+ * This is a some sort of a hack.
+ * The OCTET STRING decoder is being used in BIT STRING mode.
+ */
+ int is_bit_str = td->specifics?1:0;
+
+ ASN_DEBUG("Decoding %s as %s (%ld)",
+ td->name,
+ is_bit_str ? "BIT STRING" : "OCTET STRING",
+ (long)size);
+
+ /*
+ * Create the string if does not exist.
+ */
+ if(st == NULL) {
+ st = *os_structure = CALLOC(1, sizeof(*st));
+ if(st == NULL)
+ RETURN(RC_FAIL);
+ }
+
+ /* Restore parsing context */
+ ctx = &st->_ber_dec_ctx;
+
+ switch(ctx->phase) {
+ case 0:
+ /*
+ * Check tags.
+ */
+ rval = ber_check_tags(td, ctx,
+ buf_ptr, size, tag_mode,
+ &ctx->left, &tlv_constr);
+ if(rval.code != RC_OK) {
+ RETURN(rval.code);
+ }
+
+ ASN_DEBUG("OS length is %d bytes, form %d",
+ (int)ctx->left, tlv_constr);
+
+ if(tlv_constr) {
+ /*
+ * Complex operation, requires stack of expectations.
+ */
+ ctx->ptr = _new_stack();
+ if(ctx->ptr) {
+ stck = ctx->ptr;
+ if(ctx->left < 0) {
+ stck->cur_ptr->want_nulls = -ctx->left;
+ stck->cur_ptr->left = -1;
+ } else {
+ stck->cur_ptr->want_nulls = 0;
+ stck->cur_ptr->left = ctx->left;
+ }
+ ASN_DEBUG("Expectation left=%d wn=%d added",
+ stck->cur_ptr->left,
+ stck->cur_ptr->want_nulls);
+ if(is_bit_str) {
+ APPEND("\0", 1);
+ }
+ } else {
+ RETURN(RC_FAIL);
+ }
+ } else {
+ /*
+ * Jump into stackless primitive decoding.
+ */
+ _CH_PHASE(ctx, 3);
+ ADVANCE(rval.consumed);
+ goto phase3;
+ }
+
+ ADVANCE(rval.consumed);
+ NEXT_PHASE(ctx);
+ /* Fall through */
+ case 1:
+ phase1:
+ /*
+ * Fill the stack with expectations.
+ */
+ stck = ctx->ptr;
+ sel = stck->cur_ptr;
+ do {
+ ber_tlv_tag_t tlv_tag;
+ ber_tlv_len_t tlv_len;
+ ssize_t tl, ll;
+
+ tl = ber_fetch_tag(buf_ptr, size, &tlv_tag);
+ switch(tl) {
+ case -1: RETURN(RC_FAIL);
+ case 0: RETURN(RC_WMORE);
+ }
+
+ tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);
+
+ ll = ber_fetch_length(tlv_constr,
+ buf_ptr + tl, size - tl, &tlv_len);
+ ASN_DEBUG("Got tag=%s, tl=%d, len=%d, ll=%d, {%d, %d}",
+ ber_tlv_tag_string(tlv_tag), tl, tlv_len, ll,
+ ((uint8_t *)buf_ptr)[0],
+ ((uint8_t *)buf_ptr)[1]);
+ switch(ll) {
+ case -1: RETURN(RC_FAIL);
+ case 0: RETURN(RC_WMORE);
+ }
+
+ if(sel->want_nulls
+ && ((uint8_t *)buf_ptr)[0] == 0
+ && ((uint8_t *)buf_ptr)[1] == 0)
+ {
+ sel->want_nulls--;
+ if(sel->want_nulls == 0) {
+ /* Move to the next expectation */
+ sel = stck->cur_ptr = sel->prev;
+ if(sel == NULL) {
+ ADVANCE(2);
+ break;
+ }
+ }
+ if(sel->want_nulls) {
+ /*
+ * Simulate while(TRUE) for this loop.
+ * This is necessary to fetch the next
+ * "end of content" expectation.
+ */
+ ADVANCE(2);
+ tlv_constr = 1;
+ continue;
+ }
+ } else if(tlv_tag != td->tags[td->tags_count-1]) {
+ char buf[2][32];
+ ber_tlv_tag_snprint(tlv_tag,
+ buf[0], sizeof(buf[0]));
+ ber_tlv_tag_snprint(td->tags[td->tags_count-1],
+ buf[1], sizeof(buf[1]));
+ ASN_DEBUG("Tag does not match expectation: %s != %s",
+ buf[0], buf[1]);
+ RETURN(RC_FAIL);
+ }
+
+ /*
+ * Append a new expectation.
+ */
+ sel = _add_stack_el(stck);
+ if(sel) {
+ sel->want_nulls = (tlv_len==-1);
+ sel->left = tlv_len;
+ ASN_DEBUG("Expectation %d %d added",
+ sel->left, sel->want_nulls);
+ } else {
+ RETURN(RC_FAIL);
+ }
+
+ ADVANCE(tl+ll);
+ } while(tlv_constr);
+ if(sel == NULL) {
+ /* Finished operation, "phase out" */
+ _CH_PHASE(ctx, +3);
+ break;
+ }
+
+ NEXT_PHASE(ctx);
+ /* Fall through */
+ case 2:
+ stck = ctx->ptr;
+ sel = stck->cur_ptr;
+ ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld",
+ (long)sel->left, (long)size);
+ {
+ ber_tlv_len_t len;
+
+ assert(sel->left >= 0);
+
+ len = (size < sel->left) ? size : sel->left;
+ if(len > 0) {
+ if(is_bit_str && sel->bits_chopped == 0) {
+ /*
+ * Finalize the previous chunk:
+ * strip down unused bits.
+ */
+ st->buf[st->size-1] &= 0xff << st->buf[0];
+
+ APPEND((buf_ptr+1), (len - 1));
+ st->buf[0] = *(uint8_t *)buf_ptr;
+ sel->bits_chopped = 1;
+ } else {
+ APPEND(buf_ptr, len);
+ }
+ ADVANCE(len);
+ sel->left -= len;
+ }
+
+ if(sel->left) {
+ RETURN(RC_WMORE);
+ } else {
+ sel->left = 0;
+ if(sel->prev)
+ sel = stck->cur_ptr = sel->prev;
+ PREV_PHASE(ctx);
+ goto phase1;
+ }
+ }
+ break;
+ case 3:
+ phase3:
+ /*
+ * Primitive form, no stack required.
+ */
+ if(size < ctx->left) {
+ APPEND(buf_ptr, size);
+ ctx->left -= size;
+ ADVANCE(size);
+ RETURN(RC_WMORE);
+ } else {
+ APPEND(buf_ptr, ctx->left);
+ ADVANCE(ctx->left);
+ ctx->left = 0;
+
+ NEXT_PHASE(ctx);
+ }
+ break;
+ }
+
+ /*
+ * BIT STRING-specific processing.
+ */
+ if(is_bit_str && st->size >= 2) {
+ /* Finalize BIT STRING: zero out unused bits. */
+ st->buf[st->size-1] &= 0xff << st->buf[0];
+ }
+
+ ASN_DEBUG("Took %d bytes to encode %s: [%s]:%d",
+ consumed_myself, td->name, st->buf, st->size);
+
+ rval.code = RC_OK;
+ rval.consumed = consumed_myself;
+
+ return rval;
+}
+
+/*
+ * Encode OCTET STRING type using DER.
+ */
+der_enc_rval_t
+OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ der_enc_rval_t erval;
+ OCTET_STRING_t *st = ptr;
+ int add_byte = 0;
+
+ ASN_DEBUG("%s %s as OCTET STRING",
+ cb?"Estimating":"Encoding", sd->name);
+
+ /*
+ * Canonicalize BIT STRING.
+ */
+ if(sd->specifics && st->buf) {
+ switch(st->size) {
+ case 0: add_byte = 1; break;
+ case 1: st->buf[0] = 0; break;
+ default:
+ /* Finalize BIT STRING: zero out unused bits. */
+ st->buf[st->size-1] &= 0xff << st->buf[0];
+ }
+ }
+
+ erval.encoded = der_write_tags(sd, st->size + add_byte, tag_mode, tag,
+ cb, app_key);
+ if(erval.encoded == -1) {
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+
+ if(cb) {
+ uint8_t zero;
+ uint8_t *buf;
+ int size;
+ ssize_t ret;
+
+ /* BIT STRING-aware handling */
+ if(add_byte) {
+ zero = 0;
+ buf = &zero;
+ size = 1;
+ } else if(st->buf) {
+ buf = st->buf;
+ size = st->size;
+ } else {
+ assert(st->size == 0);
+ buf = 0; /* Not used */
+ size = 0;
+ }
+
+ if(size) {
+ ret = cb(buf, size, app_key);
+ if(ret == -1) {
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+ }
+ }
+
+ erval.encoded += st->size + add_byte;
+
+ return erval;
+}
+
+int
+OCTET_STRING_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ static char h2c[16] = "0123456789ABCDEF";
+ const OCTET_STRING_t *st = sptr;
+ char scratch[16 * 3 + 4];
+ char *p = scratch;
+ uint8_t *buf;
+ uint8_t *end;
+ size_t i;
+ int ret;
+
+ if(!st || !st->buf) return cb("<absent>", 8, app_key);
+
+ /*
+ * Dump the contents of the buffer in hexadecimal.
+ */
+ buf = st->buf;
+ end = buf + st->size;
+ for(i = 0; buf < end; buf++, i++) {
+ if(!(i % 16) && (i || st->size > 16)) {
+ if(cb(scratch, p - scratch, app_key)
+ || cb("\n", 1, app_key))
+ return -1;
+ for(ret = 0; ret < ilevel; ret++)
+ cb(" ", 1, app_key);
+ p = scratch;
+ }
+ *p++ = h2c[(*buf >> 4) & 0x0F];
+ *p++ = h2c[*buf & 0x0F];
+ *p++ = ' ';
+ }
+
+ return cb(scratch, p - scratch, app_key);
+}
+
+int
+OCTET_STRING_print_ascii(asn1_TYPE_descriptor_t *td, const void *sptr,
+ int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
+ const OCTET_STRING_t *st = sptr;
+
+ if(st && st->buf) {
+ return cb(st->buf, st->size, app_key);
+ } else {
+ return cb("<absent>", 8, app_key);
+ }
+}
+
+void
+OCTET_STRING_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
+ OCTET_STRING_t *st = sptr;
+ struct _stack *stck = st->_ber_dec_ctx.ptr;
+
+ if(!td || !st)
+ return;
+
+ ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
+
+ if(st->buf) {
+ FREEMEM(st->buf);
+ }
+
+ /*
+ * Remove decode-time stack.
+ */
+ if(stck) {
+ while(stck->tail) {
+ struct _stack_el *sel = stck->tail;
+ stck->tail = sel->prev;
+ FREEMEM(sel);
+ }
+ FREEMEM(stck);
+ }
+
+ if(!contents_only) {
+ FREEMEM(st);
+ }
+}
+
+/*
+ * Conversion routines.
+ */
+int
+OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
+ void *buf;
+
+ if(st == 0 || (str == 0 && len)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Clear the OCTET STRING.
+ */
+ if(str == NULL) {
+ if(st->buf)
+ FREEMEM(st->buf);
+ st->size = 0;
+ return 0;
+ }
+
+ /* Determine the original string size, if not explicitly given */
+ if(len < 0)
+ len = strlen(str);
+
+ /* Allocate and fill the memory */
+ buf = MALLOC(len + 1);
+ if(buf == NULL) {
+ return -1;
+ } else {
+ st->buf = buf;
+ st->size = len;
+ }
+
+ memcpy(buf, str, len);
+ st->buf[st->size] = '\0'; /* Couldn't use memcpy(len+1)! */
+
+ return 0;
+}
+
+OCTET_STRING_t *
+OCTET_STRING_new_fromBuf(const char *str, int len) {
+ OCTET_STRING_t *st;
+
+ st = CALLOC(1, sizeof(*st));
+ if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
+ free(st);
+ st = NULL;
+ }
+
+ return st;
+}
+
diff --git a/skeletons/OCTET_STRING.h b/skeletons/OCTET_STRING.h
new file mode 100644
index 00000000..1aed9a35
--- /dev/null
+++ b/skeletons/OCTET_STRING.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _OCTET_STRING_H_
+#define _OCTET_STRING_H_
+
+#include <constr_TYPE.h>
+
+typedef struct OCTET_STRING {
+ uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */
+ int size; /* Size of the buffer */
+
+ ber_dec_ctx_t _ber_dec_ctx; /* Parsing across buffer boundaries */
+} OCTET_STRING_t;
+
+extern asn1_TYPE_descriptor_t asn1_DEF_OCTET_STRING;
+
+ber_type_decoder_f OCTET_STRING_decode_ber;
+der_type_encoder_f OCTET_STRING_encode_der;
+asn_struct_print_f OCTET_STRING_print;
+asn_struct_print_f OCTET_STRING_print_ascii;
+asn_struct_free_f OCTET_STRING_free;
+
+/***********************************
+ * Some handy conversion routines. *
+ ***********************************/
+
+/*
+ * This function clears the previous value of the OCTET STRING (if any)
+ * and then allocates a new memory and makes s point to the newly allocated
+ * memory. If size = -1, the size of the original string will be determined
+ * using strlen(str).
+ * If str equals to NULL, the function will silently clear the
+ * current contents of the OCTET STRING.
+ * Returns 0 if it was possible to perform operation, -1 otherwise.
+ */
+int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size);
+
+/*
+ * Allocate and fill the new OCTET STRING and return a pointer to the newly
+ * allocated object. NULL is permitted in str: the function will just allocate
+ * empty OCTET STRING.
+ */
+OCTET_STRING_t *OCTET_STRING_new_fromBuf(const char *str, int size);
+
+/* Handy conversion from the C string into the OCTET STRING. */
+#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1);
+#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1);
+
+#endif /* _OCTET_STRING_H_ */
diff --git a/skeletons/ObjectDescriptor.c b/skeletons/ObjectDescriptor.c
new file mode 100644
index 00000000..5a39380c
--- /dev/null
+++ b/skeletons/ObjectDescriptor.c
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <ObjectDescriptor.h>
+
+/*
+ * ObjectDescriptor basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_ObjectDescriptor_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (7 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_ObjectDescriptor = {
+ "ObjectDescriptor",
+ asn_generic_unknown_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print_ascii, /* Treat as ASCII subset (it's not) */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_ObjectDescriptor_tags,
+ sizeof(asn1_DEF_ObjectDescriptor_tags)
+ / sizeof(asn1_DEF_ObjectDescriptor_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
diff --git a/skeletons/ObjectDescriptor.h b/skeletons/ObjectDescriptor.h
new file mode 100644
index 00000000..67addf24
--- /dev/null
+++ b/skeletons/ObjectDescriptor.h
@@ -0,0 +1,15 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _ObjectDescriptor_H_
+#define _ObjectDescriptor_H_
+
+#include <constr_TYPE.h>
+#include <GraphicString.h>
+
+typedef GraphicString_t ObjectDescriptor_t; /* Implemented in terms of. */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_ObjectDescriptor;
+
+#endif /* _ObjectDescriptor_H_ */
diff --git a/skeletons/PrintableString.c b/skeletons/PrintableString.c
new file mode 100644
index 00000000..32ee7da5
--- /dev/null
+++ b/skeletons/PrintableString.c
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <PrintableString.h>
+
+/*
+ * PrintableString basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_PrintableString_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (19 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_PrintableString = {
+ "PrintableString",
+ PrintableString_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print_ascii, /* ASCII subset */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_PrintableString_tags,
+ sizeof(asn1_DEF_PrintableString_tags)
+ / sizeof(asn1_DEF_PrintableString_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
+
+/*
+ * ASN.1:1984 (X.409)
+ */
+static int _PrintableString_alphabet[256] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, /* ' */
+0x41, 0x42, 0x00, 0x43, 0x44, 0x45, 0x46, 0x47, /* ( ) + , - . / */
+0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, /* 0 1 2 3 4 5 6 7 */
+0x3d, 0x3e, 0x48, 0x00, 0x00, 0x49, 0x00, 0x4a, /* 8 9 : = ? */
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A B C D E F G */
+0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* H I J K L M N O */
+0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* P Q R S T U V W */
+0x18, 0x19, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, /* X Y Z */
+0x00, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, /* a b c d e f g */
+0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, /* h i j k l m n o */
+0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, /* p q r s t u v w */
+0x32, 0x33, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, /* x y z */
+};
+
+int
+PrintableString_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ const PrintableString_t *st = sptr;
+
+ if(st && st->buf) {
+ uint8_t *buf = st->buf;
+ uint8_t *end = buf + st->size;
+
+ /*
+ * Check the alphabet of the PrintableString.
+ * ASN.1:1984 (X.409)
+ */
+ for(; buf < end; buf++) {
+ if(!_PrintableString_alphabet[*buf]) {
+ _ASN_ERRLOG("%s: value byte %d "
+ "not in PrintableString alphabet (%d)",
+ td->name,
+ (buf - st->buf) + 1,
+ *buf
+ );
+ return -1;
+ }
+ }
+ } else {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/skeletons/PrintableString.h b/skeletons/PrintableString.h
new file mode 100644
index 00000000..b44a61ec
--- /dev/null
+++ b/skeletons/PrintableString.h
@@ -0,0 +1,17 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _PrintableString_H_
+#define _PrintableString_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t PrintableString_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_PrintableString;
+
+asn_constr_check_f PrintableString_constraint;
+
+#endif /* _PrintableString_H_ */
diff --git a/skeletons/README b/skeletons/README
new file mode 100644
index 00000000..29dbae63
--- /dev/null
+++ b/skeletons/README
@@ -0,0 +1,6 @@
+
+Here are the canonical encoder/decoder algorithms that work with the tables
+constructed by the compiler. The compiler itself does not generate code,
+it just creates those tables and then copies (links) over these files
+which contain generic algorithms.
+
diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c
new file mode 100644
index 00000000..f6572105
--- /dev/null
+++ b/skeletons/RELATIVE-OID.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <RELATIVE-OID.h>
+#include <assert.h>
+#include <errno.h>
+
+/*
+ * RELATIVE-OID basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_RELATIVE_OID_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (13 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_RELATIVE_OID = {
+ "RELATIVE-OID",
+ asn_generic_no_constraint,
+ INTEGER_decode_ber, /* Implemented in terms of INTEGER type */
+ OBJECT_IDENTIFIER_encode_der,
+ RELATIVE_OID_print,
+ INTEGER_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_RELATIVE_OID_tags,
+ sizeof(asn1_DEF_RELATIVE_OID_tags)
+ / sizeof(asn1_DEF_RELATIVE_OID_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ 0 /* Always in primitive form */
+};
+
+int
+RELATIVE_OID_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const RELATIVE_OID_t *st = sptr;
+ int startn;
+ int i;
+
+ if(!st || !st->buf)
+ return cb("<absent>", 8, app_key);
+
+ /* Dump preamble */
+ if(cb("{ ", 2, app_key))
+ return -1;
+
+ for(i = 0, startn = 0; i < st->size; i++) {
+ uint8_t b = st->buf[i];
+ if((b & 0x80)) /* Continuation expected */
+ continue;
+ if(startn && cb(" ", 1, app_key)) /* Separate arcs */
+ return -1;
+ if(OBJECT_IDENTIFIER_print_arc(&st->buf[startn],
+ i - startn + 1, 0, cb, app_key))
+ return -1;
+ startn = i + 1;
+ }
+
+ return cb(" }", 2, app_key);
+}
+
+
+int
+RELATIVE_OID_get_arcs_l(RELATIVE_OID_t *roid,
+ unsigned long *arcs, int arcs_slots) {
+ unsigned long arc_value;
+ int cur_arc = 0;
+ int startn = 0;
+ int i;
+
+ if(!roid || !roid->buf) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for(i = 0; i < roid->size; i++) {
+ uint8_t b = roid->buf[i];
+ if((b & 0x80)) /* Continuation expected */
+ continue;
+
+ if(cur_arc < arcs_slots) {
+ if(OBJECT_IDENTIFIER_get_arc_l(&roid->buf[startn],
+ i - startn + 1, 0, &arc_value))
+ return -1;
+ arcs[cur_arc++] = arc_value;
+ }
+
+ startn = i + 1;
+ }
+
+ return cur_arc;
+}
+
+int
+RELATIVE_OID_set_arcs_l(RELATIVE_OID_t *roid, unsigned long *arcs, int arcs_slots) {
+ uint8_t *buf;
+ uint8_t *bp;
+ int size;
+ int i;
+
+ if(roid == NULL || arcs == NULL || arcs_slots < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Roughly estimate the maximum size necessary to encode these arcs.
+ */
+ size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arcs_slots;
+ bp = buf = MALLOC(size + 1);
+ if(!buf) {
+ /* ENOMEM */
+ return -1;
+ }
+
+ /*
+ * Encode the arcs and refine the encoding size.
+ */
+ size = 0;
+ for(i = 0; i < arcs_slots; i++) {
+ unsigned long value = arcs[i];
+ uint8_t tbuf[sizeof(value) * 2]; /* Conservatively sized */
+ uint8_t *tp = tbuf;
+ int arc_len = 0;
+ int add;
+
+ for(add = 1; value; value >>= 7, add++) {
+ unsigned int b7 = value & 0x7F;
+ *tp++ = 0x80 | b7;
+ if(b7) {
+ arc_len += add;
+ add = 0;
+ }
+ }
+
+ if(arc_len) {
+ tp = &tbuf[arc_len - 1];
+ /* The last octet does not have bit 8 set. */
+ *tbuf &= 0x7f;
+ for(; tp >= tbuf; tp--)
+ *bp++ = *tp;
+ size += arc_len;
+ } else {
+ *bp++ = 0;
+ size++;
+ }
+ }
+
+ /*
+ * Replace buffer.
+ */
+ roid->size = size;
+ bp = roid->buf;
+ roid->buf = buf;
+ if(bp) FREEMEM(bp);
+
+ return 0;
+}
diff --git a/skeletons/RELATIVE-OID.h b/skeletons/RELATIVE-OID.h
new file mode 100644
index 00000000..c0bc680e
--- /dev/null
+++ b/skeletons/RELATIVE-OID.h
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _RELATIVE_OID_H_
+#define _RELATIVE_OID_H_
+
+#include <constr_TYPE.h>
+#include <OBJECT_IDENTIFIER.h>
+
+/* Implemented in terms of OBJECT IDENTIFIER */
+typedef OBJECT_IDENTIFIER_t RELATIVE_OID_t;
+
+extern asn1_TYPE_descriptor_t asn1_DEF_RELATIVE_OID;
+
+asn_struct_print_f RELATIVE_OID_print;
+
+/**********************************
+ * Some handy conversion routines *
+ **********************************/
+
+/* See OBJECT_IDENTIFIER_set_arcs_l() function in OBJECT_IDENTIFIER.h */
+int RELATIVE_OID_set_arcs_l(RELATIVE_OID_t *_roid,
+ unsigned long *arcs, int arcs_slots);
+
+/* See OBJECT_IDENTIFIER_get_arcs_l() function in OBJECT_IDENTIFIER.h */
+int RELATIVE_OID_get_arcs_l(RELATIVE_OID_t *_roid,
+ unsigned long *arcs, int arcs_slots);
+
+#endif /* _RELATIVE_OID_H_ */
diff --git a/skeletons/T61String.c b/skeletons/T61String.c
new file mode 100644
index 00000000..e6dceb78
--- /dev/null
+++ b/skeletons/T61String.c
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <T61String.h>
+
+/*
+ * T61String basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_T61String_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (20 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_T61String = {
+ "T61String",
+ asn_generic_unknown_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print, /* non-ascii string */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_T61String_tags,
+ sizeof(asn1_DEF_T61String_tags)
+ / sizeof(asn1_DEF_T61String_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
diff --git a/skeletons/T61String.h b/skeletons/T61String.h
new file mode 100644
index 00000000..1485577e
--- /dev/null
+++ b/skeletons/T61String.h
@@ -0,0 +1,15 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _T61String_H_
+#define _T61String_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t T61String_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_T61String;
+
+#endif /* _T61String_H_ */
diff --git a/skeletons/TeletexString.c b/skeletons/TeletexString.c
new file mode 100644
index 00000000..1076c8af
--- /dev/null
+++ b/skeletons/TeletexString.c
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <TeletexString.h>
+
+/*
+ * TeletexString basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_TeletexString_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (20 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_TeletexString = {
+ "TeletexString",
+ asn_generic_unknown_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print, /* non-ascii string */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_TeletexString_tags,
+ sizeof(asn1_DEF_TeletexString_tags)
+ / sizeof(asn1_DEF_TeletexString_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
diff --git a/skeletons/TeletexString.h b/skeletons/TeletexString.h
new file mode 100644
index 00000000..6f513581
--- /dev/null
+++ b/skeletons/TeletexString.h
@@ -0,0 +1,15 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _TeletexString_H_
+#define _TeletexString_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t TeletexString_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_TeletexString;
+
+#endif /* _TeletexString_H_ */
diff --git a/skeletons/UTCTime.c b/skeletons/UTCTime.c
new file mode 100644
index 00000000..e2f758ec
--- /dev/null
+++ b/skeletons/UTCTime.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <UTCTime.h>
+#include <GeneralizedTime.h>
+#include <time.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifndef __NO_ASN_TABLE__
+
+/*
+ * UTCTime basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_UTCTime_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (23 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_UTCTime = {
+ "UTCTime",
+ UTCTime_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ UTCTime_print,
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_UTCTime_tags,
+ sizeof(asn1_DEF_UTCTime_tags)
+ / sizeof(asn1_DEF_UTCTime_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
+#endif /* __NO_ASN_TABLE__ */
+
+/*
+ * Check that the time looks like the time.
+ */
+int
+UTCTime_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ const UTCTime_t *st = sptr;
+ time_t tloc;
+
+ errno = EPERM; /* Just an unlikely error code */
+ tloc = asn_UT2time(st, 0);
+ if(tloc == -1 && errno != EPERM) {
+ _ASN_ERRLOG("%s: Invalid time format: %s",
+ td->name, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+UTCTime_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const UTCTime_t *st = sptr;
+
+ if(st && st->buf) {
+ char buf[32];
+ struct tm tm;
+ int ret;
+
+ errno = EPERM;
+ if(asn_UT2time(st, &tm) == -1 && errno != EPERM)
+ return cb("<bad-value>", 11, app_key);
+
+ ret = snprintf(buf, sizeof(buf),
+ "%04d-%02d-%02d %02d:%02d%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ assert(ret > 0 && ret < sizeof(buf));
+ return cb(buf, ret, app_key);
+ } else {
+ return cb("<absent>", 8, app_key);
+ }
+}
+
+time_t
+asn_UT2time(const UTCTime_t *st, struct tm *_tm) {
+ char buf[17+2]; /* "AAMMJJhhmmss+hhmm" = 17, + 2 = 19 */
+ GeneralizedTime_t gt;
+
+ if(!st || !st->buf || st->size < 11 || st->size > (sizeof(buf) - 2)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ gt.buf = buf;
+ gt.size = st->size + 2;
+ memcpy(gt.buf + 2, st->buf, st->size);
+ if(st->buf[0] > 0x35) {
+ /* 19xx */
+ gt.buf[0] = 0x31;
+ gt.buf[1] = 0x39;
+ } else {
+ /* 20xx */
+ gt.buf[0] = 0x32;
+ gt.buf[1] = 0x30;
+ }
+
+ return asn_GT2time(&gt, _tm);
+}
diff --git a/skeletons/UTCTime.h b/skeletons/UTCTime.h
new file mode 100644
index 00000000..1e52388e
--- /dev/null
+++ b/skeletons/UTCTime.h
@@ -0,0 +1,26 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _UTCTime_H_
+#define _UTCTime_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t UTCTime_t; /* Implemented using OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_UTCTime;
+
+asn_constr_check_f UTCTime_constraint;
+asn_struct_print_f UTCTime_print;
+
+/***********************
+ * Some handy helpers. *
+ ***********************/
+
+/* On error returns -1 and errno set to EINVAL */
+struct tm; /* <time.h> */
+time_t asn_UT2time(const UTCTime_t *, struct tm *_optional_tm4fill);
+
+#endif /* _UTCTime_H_ */
diff --git a/skeletons/UTF8String.c b/skeletons/UTF8String.c
new file mode 100644
index 00000000..fdd13d87
--- /dev/null
+++ b/skeletons/UTF8String.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <UTF8String.h>
+
+/*
+ * UTF8String basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_UTF8String_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (12 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_UTF8String = {
+ "UTF8String",
+ UTF8String_constraint, /* Check for invalid codes, etc. */
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ UTF8String_print,
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_UTF8String_tags,
+ sizeof(asn1_DEF_UTF8String_tags)
+ / sizeof(asn1_DEF_UTF8String_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
+static int _UTF8String_h1[16] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x0 ... 0x7 */
+ 0, 0, 0, 0, 2, 2, 3, -1
+};
+static int _UTF8String_h2[16] = {
+ 4, 4, 4, 4, 4, 4, 4, 4, /* 0xF0 .. 0xF7 */
+ 5, 5, 5, 5, 6, 6, -1, -1
+};
+
+int
+UTF8String_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ ssize_t len;
+ len = UTF8String_length(sptr, td->name, app_errlog, app_key);
+ if(len > 0) len = 0;
+ return len;
+}
+
+ssize_t
+UTF8String_length(const UTF8String_t *st, const char *opt_type_name,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+
+ if(st && st->buf) {
+ size_t length = 0;
+ uint8_t *buf = st->buf;
+ uint8_t *end = buf + st->size;
+ int want; /* Number of bytes wanted */
+
+ for(want = 0; buf < end; buf++) {
+ uint8_t ch = *buf;
+ int w = _UTF8String_h1[ch >> 4];
+ if(want) { /* Continuation expected */
+ if(w) {
+ _ASN_ERRLOG("%s: UTF-8 expectation "
+ "failed at byte %d",
+ opt_type_name,
+ (buf - st->buf) + 1);
+ return -1;
+ }
+ want--;
+ } else {
+ switch(w) {
+ case -1: /* Long UTF-8 */
+ w = _UTF8String_h2[ch & 0xF0];
+ if(w != -1)
+ break;
+ /* Fall through */
+ case 0:
+ _ASN_ERRLOG(
+ "%s: UTF-8 expectation"
+ "failed at byte %d",
+ opt_type_name,
+ (buf - st->buf) + 1);
+ return -1;
+ }
+ want = w - 1; /* Expect this much */
+ }
+ if(!want) length++;
+ }
+
+ /* If still want something, then something is wrong */
+ if(want) {
+ _ASN_ERRLOG("%s: truncated UTF-8 sequence",
+ opt_type_name);
+ return -1;
+ }
+
+ return length;
+ } else {
+ _ASN_ERRLOG("%s: value not given", opt_type_name);
+ return -1;
+ }
+}
+
+int
+UTF8String_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const UTF8String_t *st = sptr;
+
+ if(st && st->buf) {
+ return cb(st->buf, st->size, app_key);
+ } else {
+ return cb("<absent>", 8, app_key);
+ }
+}
diff --git a/skeletons/UTF8String.h b/skeletons/UTF8String.h
new file mode 100644
index 00000000..f18bf703
--- /dev/null
+++ b/skeletons/UTF8String.h
@@ -0,0 +1,22 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _UTF8String_H_
+#define _UTF8String_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t UTF8String_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_UTF8String;
+
+asn_constr_check_f UTF8String_constraint;
+asn_struct_print_f UTF8String_print;
+
+/* Returns length of UTF-8 string in characters or -1 if error. */
+ssize_t UTF8String_length(const UTF8String_t *st, const char *opt_type_name,
+ asn_app_consume_bytes_f *app_errlog, void *app_key);
+
+#endif /* _UTF8String_H_ */
diff --git a/skeletons/UniversalString.c b/skeletons/UniversalString.c
new file mode 100644
index 00000000..7d75e079
--- /dev/null
+++ b/skeletons/UniversalString.c
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <UniversalString.h>
+
+/*
+ * UniversalString basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_UniversalString_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (28 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_UniversalString = {
+ "UniversalString",
+ asn_generic_no_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ UniversalString_print, /* Convert into UTF8 and print */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_UniversalString_tags,
+ sizeof(asn1_DEF_UniversalString_tags)
+ / sizeof(asn1_DEF_UniversalString_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
+
+int
+UniversalString_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const UniversalString_t *st = sptr;
+ uint32_t *wchar;
+ uint32_t *wend;
+ char scratch[128]; /* Scratchpad buffer */
+ char *p;
+
+ if(!st || !st->buf) return cb("<absent>", 8, app_key);
+
+ wchar = (uint32_t *)st->buf;
+ wend = (uint32_t *)(st->buf + st->size);
+ for(p = scratch; wchar < wend; wchar++) {
+ uint32_t wc = (((uint8_t *)wchar)[0] << 24)
+ | (((uint8_t *)wchar)[1] << 16)
+ | (((uint8_t *)wchar)[2] << 8)
+ | ((uint8_t *)wchar)[3]; /* 4 bytes */
+ if(sizeof(scratch) - (p - scratch) < 6) {
+ if(cb(scratch, p - scratch, app_key))
+ return -1;
+ p = scratch;
+ }
+ if(wc < 0x80) {
+ *p++ = (char)wc;
+ } else if(wc < 0x800) {
+ *p++ = 0xc0 | ((wc >> 6));
+ *p++ = 0x80 | ((wc & 0x3f));
+ } else if(wc < 0x10000) {
+ *p++ = 0xe0 | ((wc >> 12));
+ *p++ = 0x80 | ((wc >> 6) & 0x3f);
+ *p++ = 0x80 | ((wc & 0x3f));
+ } else if(wc < 0x200000) {
+ *p++ = 0xf0 | ((wc >> 18));
+ *p++ = 0x80 | ((wc >> 12) & 0x3f);
+ *p++ = 0x80 | ((wc >> 6) & 0x3f);
+ *p++ = 0x80 | ((wc & 0x3f));
+ } else if(wc < 0x4000000) {
+ *p++ = 0xf8 | ((wc >> 24));
+ *p++ = 0x80 | ((wc >> 18) & 0x3f);
+ *p++ = 0x80 | ((wc >> 12) & 0x3f);
+ *p++ = 0x80 | ((wc >> 6) & 0x3f);
+ *p++ = 0x80 | ((wc & 0x3f));
+ } else {
+ *p++ = 0xfc | ((wc >> 30) & 0x1);
+ *p++ = 0x80 | ((wc >> 24) & 0x3f);
+ *p++ = 0x80 | ((wc >> 18) & 0x3f);
+ *p++ = 0x80 | ((wc >> 12) & 0x3f);
+ *p++ = 0x80 | ((wc >> 6) & 0x3f);
+ *p++ = 0x80 | ((wc & 0x3f));
+ }
+ }
+
+ return cb(scratch, p - scratch, app_key);
+}
diff --git a/skeletons/UniversalString.h b/skeletons/UniversalString.h
new file mode 100644
index 00000000..cafbc80c
--- /dev/null
+++ b/skeletons/UniversalString.h
@@ -0,0 +1,17 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _UniversalString_H_
+#define _UniversalString_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t UniversalString_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_UniversalString;
+
+asn_struct_print_f UniversalString_print; /* Human-readable output */
+
+#endif /* _UniversalString_H_ */
diff --git a/skeletons/VideotexString.c b/skeletons/VideotexString.c
new file mode 100644
index 00000000..ab92ebd9
--- /dev/null
+++ b/skeletons/VideotexString.c
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <VideotexString.h>
+
+/*
+ * VideotexString basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_VideotexString_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (21 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_VideotexString = {
+ "VideotexString",
+ asn_generic_unknown_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print, /* non-ascii string */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_VideotexString_tags,
+ sizeof(asn1_DEF_VideotexString_tags)
+ / sizeof(asn1_DEF_VideotexString_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
diff --git a/skeletons/VideotexString.h b/skeletons/VideotexString.h
new file mode 100644
index 00000000..4dd7c8e7
--- /dev/null
+++ b/skeletons/VideotexString.h
@@ -0,0 +1,15 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _VideotexString_H_
+#define _VideotexString_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t VideotexString_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_VideotexString;
+
+#endif /* _VideotexString_H_ */
diff --git a/skeletons/VisibleString.c b/skeletons/VisibleString.c
new file mode 100644
index 00000000..af9525f8
--- /dev/null
+++ b/skeletons/VisibleString.c
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <VisibleString.h>
+
+/*
+ * VisibleString basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_VisibleString_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (26 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_VisibleString = {
+ "VisibleString",
+ VisibleString_constraint,
+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */
+ OCTET_STRING_print_ascii, /* ASCII subset */
+ OCTET_STRING_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_VisibleString_tags,
+ sizeof(asn1_DEF_VisibleString_tags)
+ / sizeof(asn1_DEF_VisibleString_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ -1, /* Both ways are fine */
+};
+
+
+/*
+ * ISO646, ISOReg#6
+ */
+static int _VisibleString_alphabet[256] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, /* ! " # $ % & ' */
+0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, /* ( ) * + , - . / */
+0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, /* 0 1 2 3 4 5 6 7 */
+0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* 8 9 : ; < = > ? */
+0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* @ A B C D E F G */
+0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* H I J K L M N O */
+0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, /* P Q R S T U V W */
+0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* X Y Z [ \ ] ^ _ */
+0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, /* ` a b c d e f g */
+0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* h i j k l m n o */
+0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* p q r s t u v w */
+0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x00, /* x y z { | } ~ */
+};
+
+int
+VisibleString_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ const VisibleString_t *st = sptr;
+
+ if(st && st->buf) {
+ uint8_t *buf = st->buf;
+ uint8_t *end = buf + st->size;
+
+ /*
+ * Check the alphabet of the VisibleString.
+ * ISO646, ISOReg#6
+ */
+ for(; buf < end; buf++) {
+ if(!_VisibleString_alphabet[*buf]) {
+ _ASN_ERRLOG("%s: value byte %d "
+ "not in VisibleString alphabet (%d)",
+ td->name,
+ (buf - st->buf) + 1,
+ *buf
+ );
+ return -1;
+ }
+ }
+ } else {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/skeletons/VisibleString.h b/skeletons/VisibleString.h
new file mode 100644
index 00000000..3c1df420
--- /dev/null
+++ b/skeletons/VisibleString.h
@@ -0,0 +1,17 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _VisibleString_H_
+#define _VisibleString_H_
+
+#include <constr_TYPE.h>
+#include <OCTET_STRING.h>
+
+typedef OCTET_STRING_t VisibleString_t; /* Implemented in terms of OCTET STRING */
+
+extern asn1_TYPE_descriptor_t asn1_DEF_VisibleString;
+
+asn_constr_check_f VisibleString_constraint;
+
+#endif /* _VisibleString_H_ */
diff --git a/skeletons/asn_SEQUENCE_OF.c b/skeletons/asn_SEQUENCE_OF.c
new file mode 100644
index 00000000..71f6f0cd
--- /dev/null
+++ b/skeletons/asn_SEQUENCE_OF.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_types.h> /* for MALLOC/REALLOC/FREEMEM */
+#include <asn_SEQUENCE_OF.h>
+
+typedef A_SEQUENCE_OF(void) asn_sequence;
+
+void
+asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free) {
+ asn_sequence *as = asn_sequence_of_x;
+
+ if(as) {
+ void *ptr;
+ int n;
+
+ if(number < 0 || number >= as->count)
+ return; /* Nothing to delete */
+
+ if(_do_free && as->free) {
+ ptr = as->array[number];
+ } else {
+ ptr = 0;
+ }
+
+ /*
+ * Shift all elements to the left to hide the gap.
+ */
+ --as->count;
+ for(n = number; n < as->count; n++)
+ as->array[n] = as->array[n+1];
+
+ /*
+ * Invoke the third-party function only when the state
+ * of the parent structure is consistent.
+ */
+ if(ptr) as->free(ptr);
+ }
+}
+
diff --git a/skeletons/asn_SEQUENCE_OF.h b/skeletons/asn_SEQUENCE_OF.h
new file mode 100644
index 00000000..e9967340
--- /dev/null
+++ b/skeletons/asn_SEQUENCE_OF.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef ASN_SEQUENCE_OF_H
+#define ASN_SEQUENCE_OF_H
+
+#include <asn_SET_OF.h>
+
+/*
+ * SEQUENCE OF is the same as SET OF with a tiny difference:
+ * the delete operation preserves the initial order of elements
+ * and thus MAY operate in non-constant time.
+ */
+#define A_SEQUENCE_OF(type) A_SET_OF(type)
+
+#define ASN_SEQUENCE_ADD(headptr, ptr) \
+ asn_sequence_add((headptr), (ptr))
+
+/***********************************************
+ * Implementation of the SEQUENCE OF structure.
+ */
+
+#define asn_sequence_add asn_set_add
+#define asn_sequence_empty asn_set_empty
+
+/*
+ * Delete the element from the set by its number (base 0).
+ * This is NOT a constant-time operation.
+ * The order of elements is preserved.
+ * If _do_free is given AND the (*free) is initialized, the element
+ * will be freed using the custom (*free) function as well.
+ */
+void asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free);
+
+#endif /* ASN_SEQUENCE_OF_H */
diff --git a/skeletons/asn_SET_OF.c b/skeletons/asn_SET_OF.c
new file mode 100644
index 00000000..dfa99067
--- /dev/null
+++ b/skeletons/asn_SET_OF.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_types.h> /* for MALLOC/REALLOC/FREEMEM */
+#include <asn_SET_OF.h>
+#include <errno.h>
+
+typedef A_SET_OF(void) asn_set;
+
+/*
+ * Add another element into the set.
+ */
+int
+asn_set_add(void *asn_set_of_x, void *ptr) {
+ asn_set *as = asn_set_of_x;
+
+ if(as == 0 || ptr == 0) {
+ errno = EINVAL; /* Invalid arguments */
+ return -1;
+ }
+
+ /*
+ * Make sure there's enough space to insert an element.
+ */
+ if(as->count == as->size) {
+ int _newsize = as->size ? (as->size << 1) : 4;
+ void *_new_arr;
+ _new_arr = REALLOC(as->array, _newsize * sizeof(as->array[0]));
+ if(_new_arr) {
+ as->array = _new_arr;
+ as->size = _newsize;
+ } else {
+ /* ENOMEM */
+ return -1;
+ }
+ }
+
+ as->array[as->count++] = ptr;
+
+ return 0;
+}
+
+void
+asn_set_del(void *asn_set_of_x, int number, int _do_free) {
+ asn_set *as = asn_set_of_x;
+
+ if(as) {
+ void *ptr;
+ if(number < 0 || number >= as->count)
+ return;
+
+ if(_do_free && as->free) {
+ ptr = as->array[number];
+ } else {
+ ptr = 0;
+ }
+
+ as->array[number] = as->array[--as->count];
+
+ /*
+ * Invoke the third-party function only when the state
+ * of the parent structure is consistent.
+ */
+ if(ptr) as->free(ptr);
+ }
+}
+
+/*
+ * Free the contents of the set, do not free the set itself.
+ */
+void
+asn_set_empty(void *asn_set_of_x) {
+ asn_set *as = asn_set_of_x;
+
+ if(as) {
+ if(as->array) {
+ if(as->free) {
+ while(as->count--)
+ as->free(as->array[as->count]);
+ }
+ free(as->array);
+ }
+ as->count = 0;
+ as->size = 0;
+ }
+
+}
+
diff --git a/skeletons/asn_SET_OF.h b/skeletons/asn_SET_OF.h
new file mode 100644
index 00000000..1443a7b8
--- /dev/null
+++ b/skeletons/asn_SET_OF.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef ASN_SET_OF_H
+#define ASN_SET_OF_H
+
+#define A_SET_OF(type) \
+ struct { \
+ type **array; \
+ int count; /* Meaningful size */ \
+ int size; /* Allocated size */ \
+ void (*free)(type *); \
+ }
+
+#define ASN_SET_ADD(headptr, ptr) \
+ asn_set_add((headptr), (ptr))
+
+/*******************************************
+ * Implementation of the SET OF structure.
+ */
+
+/*
+ * Add another structure into the set by its pointer.
+ * RETURN VALUES:
+ * 0 for success and -1/errno for failure.
+ */
+int asn_set_add(void *asn_set_of_x, void *ptr);
+
+/*
+ * Delete the element from the set by its number (base 0).
+ * This is a constant-time operation. The order of elements before the
+ * deleted ones is guaranteed, the order of elements after the deleted
+ * one is NOT guaranteed.
+ * If _do_free is given AND the (*free) is initialized, the element
+ * will be freed using the custom (*free) function as well.
+ */
+void asn_set_del(void *asn_set_of_x, int number, int _do_free);
+
+/*
+ * Empty the contents of the set. Will free the elements, if (*free) is given.
+ * Will NOT free the set itself.
+ */
+void asn_set_empty(void *asn_set_of_x);
+
+#endif /* ASN_SET_OF_H */
diff --git a/skeletons/asn_types.h b/skeletons/asn_types.h
new file mode 100644
index 00000000..6d426673
--- /dev/null
+++ b/skeletons/asn_types.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Miscellaneous system-dependent types.
+ */
+#ifndef _ASN_TYPES_H_
+#define _ASN_TYPES_H_
+
+#include <stdio.h> /* For fprintf() */
+#include <stdlib.h> /* For *alloc(3) */
+#include <string.h> /* For memcpy(3) */
+#include <sys/types.h> /* For size_t */
+#include <stdarg.h> /* For va_start */
+#include <inttypes.h> /* C99 Standard specifies this file, for uintXX_t */
+#include <stddef.h> /* for offsetof and ptrdiff_t */
+
+#ifndef offsetof
+#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0))
+#endif /* offsetof */
+
+#define CALLOC(nmemb, size) calloc(nmemb, size)
+#define MALLOC(size) malloc(size)
+#define REALLOC(oldptr, size) realloc(oldptr, size)
+#define FREEMEM(ptr) free(ptr)
+
+#ifndef MIN /* Suitable for comparing primitive types (integers) */
+#if defined(__GNUC__)
+#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \
+ ((_a)<(_b)?(_a):(_b)); })
+#else /* !__GNUC__ */
+#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */
+#endif /* __GNUC__ */
+#endif /* MIN */
+
+/*
+ * A macro for debugging the ASN.1 internals.
+ * You may enable or override it.
+ */
+#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */
+#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */
+#define ASN_DEBUG(fmt, args...) do { \
+ fprintf(stderr, fmt, ##args); \
+ fprintf(stderr, "\n"); \
+ } while(0)
+#else /* EMIT_ASN_DEBUG */
+#define ASN_DEBUG(fmt, args...) ((void)0) /* Emit a no-op operator */
+#endif /* EMIT_ASN_DEBUG */
+#endif /* ASN_DEBUG */
+
+
+/*
+ * Generic type of an application-defined callback to return various
+ * types of data to the application.
+ * EXPECTED RETURN VALUES:
+ * -1: Failed to consume bytes. Abort the mission.
+ * Other return values indicate success, and ignored.
+ */
+typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size,
+ void *application_specific_key);
+
+#endif /* _ASN_TYPES_H_ */
diff --git a/skeletons/ber_decoder.c b/skeletons/ber_decoder.c
new file mode 100644
index 00000000..135e7910
--- /dev/null
+++ b/skeletons/ber_decoder.c
@@ -0,0 +1,230 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_TYPE.h>
+#include <assert.h>
+
+#define ADVANCE(num_bytes) do { \
+ size_t num = num_bytes; \
+ ptr += num; \
+ size -= num; \
+ consumed_myself += num; \
+ } while(0)
+#define RETURN(_code) do { \
+ ber_dec_rval_t rval; \
+ rval.code = _code; \
+ rval.consumed = consumed_myself; \
+ return rval; \
+ } while(0)
+
+/*
+ * The BER decoder of any type.
+ */
+ber_dec_rval_t
+ber_decode(asn1_TYPE_descriptor_t *type_descriptor,
+ void **struct_ptr, void *ptr, size_t size) {
+
+ /*
+ * Invoke type-specific decoder.
+ */
+ return type_descriptor->ber_decoder(type_descriptor,
+ struct_ptr, /* Pointer to the destination structure */
+ ptr, size, /* Buffer and its size */
+ 0 /* Default tag mode is 0 */
+ );
+}
+
+/*
+ * Check the set of <TL<TL<TL...>>> tags matches the definition.
+ */
+ber_dec_rval_t
+ber_check_tags(asn1_TYPE_descriptor_t *head, ber_dec_ctx_t *ctx,
+ void *ptr, size_t size, int tag_mode,
+ ber_tlv_len_t *last_length, int *opt_tlv_form) {
+ ssize_t consumed_myself = 0;
+ ssize_t tag_len;
+ ssize_t len_len;
+ ber_tlv_tag_t tlv_tag;
+ ber_tlv_len_t tlv_len;
+ ber_tlv_len_t limit_len = -1;
+ int expect_00_terminators = 0;
+ int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */
+ int tagno;
+
+ /*
+ * So what does all this tags_impl_skip stuff mean?
+ * Imagine two types,
+ * A ::= [5] IMPLICIT T
+ * B ::= [2] EXPLICIT T
+ * Where T is defined as
+ * T ::= [4] IMPLICIT SEQUENCE { ... }
+ *
+ * Let's say, we are starting to decode type A, given the
+ * following TLV stream: <5> <0>. What does this mean?
+ * It means that the type A contains type T which is,
+ * in turn, empty.
+ * Remember though, that we are still in A. We cannot
+ * just pass control to the type T decoder. Why? Because
+ * the type T decoder expects <4> <0>, not <5> <0>.
+ * So, we must make sure we are going to receive <5> while
+ * still in A, then pass control to the T decoder, indicating
+ * that the tag <4> was implicitly skipped. The decoder of T
+ * hence will be prepared to treat <4> as valid tag, and decode
+ * it appropriately.
+ */
+
+ /*
+ * We have a list of tags that must occur in the stream:
+ * {A,B,C}
+ * However, it may be indicated that the type is
+ * implicitly tagged in the caller, so it really boils down to the
+ * {I,B,C} or even {I,C}
+ * This is because the implicit tag at above structure may replace
+ * zero or more (or every) tags which follow it. We don't care
+ * about the precise number, as it is already computed for us
+ * by the ASN.1 compiler and placed into head->tags_impl_skip.
+ * So let's suppose the only tag left after implicit tagging is {I}.
+ * Yet, the table we have is {A,B,C} and head->tags_impl_skip=3.
+ * We need to check at least one tag in the loop, so the loop range
+ * is modified so it will be invoked at least one time.
+ */
+ tagno = ctx->step /* Continuing where left previously */
+ + (tag_mode==-1?(head->tags_impl_skip-1):0)
+ + (tag_mode==1?-1:0)
+ ;
+ //assert(head->tags_count >= 1); ?May not be the case for CHOICE!
+ assert(tagno < head->tags_count); /* At least one loop */
+ for((void)tagno; tagno < head->tags_count; tagno++, ctx->step++) {
+
+ /*
+ * Fetch and process T from TLV.
+ */
+ tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
+ ASN_DEBUG("Fetching tag from {%p,%ld} %02X: "
+ "len %ld, tag %s",
+ ptr, (long)size,
+ *(uint8_t *)ptr, (long)tag_len,
+ ber_tlv_tag_string(tlv_tag));
+ switch(tag_len) {
+ case -1: RETURN(RC_FAIL);
+ case 0: RETURN(RC_WMORE);
+ }
+
+ tlv_constr = BER_TLV_CONSTRUCTED(ptr);
+
+ /*
+ * If {I}, don't check anything.
+ * If {I,B,C}, check B and C unless we're at I.
+ */
+ if(tag_mode != 0 && ctx->step == 0) {
+ /*
+ * We don't expect tag to match here.
+ * It's just because we don't know how the tag
+ * is supposed to look like.
+ */
+ } else {
+ assert(tagno >= 0); /* Guaranteed by the code above */
+ if(tlv_tag != head->tags[tagno]) {
+ /*
+ * Unexpected tag. Too bad.
+ */
+ ASN_DEBUG("Expected: %s, expectation failed",
+ ber_tlv_tag_string(head->tags[tagno]));
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * Attention: if there are more tags expected,
+ * ensure that the current tag is presented
+ * in constructed form (it contains other tags!).
+ * If this one is the last one, check that the tag form
+ * matches the one given in descriptor.
+ */
+ if(tagno < (head->tags_count - 1)) {
+ if(tlv_constr == 0) {
+ RETURN(RC_FAIL);
+ }
+ } else {
+ if(head->last_tag_form != tlv_constr
+ && head->last_tag_form != -1) {
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * Fetch and process L from TLV.
+ */
+ len_len = ber_fetch_length(tlv_constr,
+ ptr + tag_len, size - tag_len, &tlv_len);
+ switch(len_len) {
+ case -1: RETURN(RC_FAIL);
+ case 0: RETURN(RC_WMORE);
+ }
+
+ /*
+ * FIXME
+ * As of today, the chain of tags
+ * must either contain several indefinite length TLVs,
+ * or several definite length ones.
+ * No mixing is allowed.
+ */
+ if(tlv_len == -1) {
+ /*
+ * Indefinite length.
+ */
+ if(limit_len == -1) {
+ expect_00_terminators++;
+ } else {
+ ASN_DEBUG("Unexpected indefinite length "
+ "in a chain of definite lengths");
+ RETURN(RC_FAIL);
+ }
+ ADVANCE(tag_len + len_len);
+ continue;
+ } else {
+ if(expect_00_terminators) {
+ ASN_DEBUG("Unexpected definite length "
+ "in a chain of indefinite lengths");
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * Check that multiple TLVs specify ever decreasing length,
+ * which is consistent.
+ */
+ if(limit_len == -1) {
+ limit_len = tlv_len + tag_len + len_len;
+ } else if(limit_len != tlv_len + tag_len + len_len) {
+ /*
+ * Inner TLV specifies length which is inconsistent
+ * with the outer TLV's length value.
+ */
+ ASN_DEBUG("Outer TLV is %d and inner is %d",
+ limit_len, tlv_len);
+ RETURN(RC_FAIL);
+ }
+
+ ADVANCE(tag_len + len_len);
+
+ limit_len -= (tag_len + len_len);
+ if(size > limit_len) {
+ /*
+ * Make sure that we won't consume more bytes
+ * from the large buffer than the inferred limit.
+ */
+ size = limit_len;
+ }
+ }
+
+ if(opt_tlv_form)
+ *opt_tlv_form = tlv_constr;
+ if(expect_00_terminators)
+ *last_length = -expect_00_terminators;
+ else
+ *last_length = tlv_len;
+
+ RETURN(RC_OK);
+}
diff --git a/skeletons/ber_decoder.h b/skeletons/ber_decoder.h
new file mode 100644
index 00000000..8240270a
--- /dev/null
+++ b/skeletons/ber_decoder.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _BER_DECODER_H_
+#define _BER_DECODER_H_
+
+#include <constr_TYPE.h>
+
+struct asn1_TYPE_descriptor_s; /* Forward declaration */
+
+/*
+ * This structure describes the return value common across the
+ * various BER decoders.
+ *
+ * Please note that the number of consumed bytes is ALWAYS meaningful,
+ * even if code!=RC_OK. This is so to indicate the number of successfully
+ * decoded bytes, hence provide a possibility, to fail with more diagnostics
+ * (i.e., print the offending remainder of the buffer).
+ */
+typedef struct ber_dec_rval_s {
+ enum {
+ RC_OK, /* Decoded successfully */
+ RC_WMORE, /* More data expected, call again */
+ RC_FAIL, /* Failure to decode data */
+ } code;
+
+ size_t consumed; /* Number of bytes consumed */
+} ber_dec_rval_t;
+
+/*
+ * A context for decoding BER across buffer boundaries.
+ */
+typedef struct ber_dec_ctx_s {
+ int phase; /* Decoding phase */
+ int step; /* Elementary step of a phase */
+ ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */
+ void *ptr; /* Decoder-specific stuff */
+} ber_dec_ctx_t;
+
+/*
+ * The BER decoder of any type.
+ * This function may be invoked directly from the application.
+ */
+ber_dec_rval_t ber_decode(struct asn1_TYPE_descriptor_s *type_descriptor,
+ void **struct_ptr, /* Pointer to a target structure's pointer */
+ void *buffer, /* Data to be decoded */
+ size_t size /* Size of that buffer */
+ );
+
+/*
+ * Type of generic function which decodes the byte stream into the structure.
+ */
+typedef ber_dec_rval_t (ber_type_decoder_f)(
+ struct asn1_TYPE_descriptor_s *type_descriptor,
+ void **type_structure, void *buf_ptr, size_t size,
+ int tag_mode);
+
+/*******************************
+ * INTERNALLY USEFUL FUNCTIONS *
+ *******************************/
+
+/*
+ * Check that all tags correspond to the type definition (as given in head).
+ * On return, last_length would contain either a non-negative length of the
+ * value part of the last TLV, or the negative number of expected
+ * "end of content" sequences. The number may only be negative if the
+ * head->last_tag_form is non-zero.
+ */
+ber_dec_rval_t ber_check_tags(struct asn1_TYPE_descriptor_s *type_dsc,
+ ber_dec_ctx_t *ctx, /* saved context */
+ void *ptr, size_t size,
+ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */
+ ber_tlv_len_t *last_length,
+ int *opt_tlv_form);
+
+#endif /* _BER_DECODER_H_ */
diff --git a/skeletons/ber_tlv_length.c b/skeletons/ber_tlv_length.c
new file mode 100644
index 00000000..cd08f6ab
--- /dev/null
+++ b/skeletons/ber_tlv_length.c
@@ -0,0 +1,159 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_TYPE.h>
+#include <ber_tlv_length.h>
+#include <ber_tlv_tag.h>
+
+ssize_t
+ber_fetch_length(int _is_constructed, void *bufptr, size_t size,
+ ber_tlv_len_t *len_r) {
+ uint8_t *buf = bufptr;
+ unsigned oct;
+
+ if(size == 0)
+ return 0; /* Want more */
+
+ oct = *(uint8_t *)buf;
+ if((oct & 0x80) == 0) {
+ /*
+ * Short definite length.
+ */
+ *len_r = (oct & 0x7F);
+ return 1;
+ } else {
+ ber_tlv_len_t len;
+ ssize_t skipped;
+
+ if(_is_constructed && oct == 0x80) {
+ *len_r = -1; /* Indefinite length */
+ return 1;
+ }
+
+ if(oct == 0xff) {
+ /* Reserved in standard for future use. */
+ return -1;
+ }
+
+ oct &= 0x7F; /* Leave only the 7 LS bits */
+ for(len = 0, buf++, skipped = 1;
+ oct && (++skipped < size); buf++, oct--) {
+
+ len = (len << 8) | *buf;
+ if(len < 0
+ || (len >> ((8 * sizeof(len)) - 8) && oct > 1)) {
+ /*
+ * Too large length value.
+ */
+ return -1;
+ }
+ }
+
+ if(oct == 0) {
+ *len_r = len;
+ return skipped;
+ }
+
+ return 0; /* Want more */
+ }
+
+}
+
+ssize_t
+ber_skip_length(int _is_constructed, void *ptr, size_t size) {
+ ber_tlv_len_t vlen; /* Length of V in TLV */
+ ssize_t tl; /* Length of L in TLV */
+ ssize_t ll; /* Length of L in TLV */
+ ssize_t skip;
+
+ /*
+ * Determine the size of L in TLV.
+ */
+ ll = ber_fetch_length(_is_constructed, ptr, size, &vlen);
+ if(ll <= 0) return ll;
+
+ /*
+ * Definite length.
+ */
+ if(vlen >= 0) {
+ skip = ll + vlen;
+ if(skip > size)
+ return 0; /* Want more */
+ return skip;
+ }
+
+ /*
+ * Indefinite length!
+ */
+ ASN_DEBUG("Skipping indefinite length");
+ for(skip = ll, ptr += ll, size -= ll;;) {
+ ber_tlv_tag_t tag;
+
+ /* Fetch the tag */
+ tl = ber_fetch_tag(ptr, size, &tag);
+ if(tl <= 0) return tl;
+
+ ll = ber_skip_length(BER_TLV_CONSTRUCTED(ptr),
+ ptr + tl, size - tl);
+ if(ll <= 0) return ll;
+
+ skip += tl + ll;
+
+ /*
+ * This may be the end of the indefinite length structure,
+ * two consecutive 0 octets.
+ * Check if it is true.
+ */
+ if(((uint8_t *)ptr)[0] == 0
+ && ((uint8_t *)ptr)[1] == 0)
+ return skip;
+
+ ptr += tl + ll;
+ size -= tl + ll;
+ }
+
+ /* UNREACHABLE */
+}
+
+ssize_t
+der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) {
+ ssize_t computed_size; /* Size of len encoding */
+ uint8_t *buf = bufp;
+ uint8_t *end;
+ int i;
+
+ if(len <= 127) {
+ /* Encoded in 1 octet */
+ if(size) *buf = len;
+ return 1;
+ }
+
+ /*
+ * Compute the size of the subsequent bytes.
+ */
+ computed_size = sizeof(len); /* assert(sizeof(len)<128), n.p. */
+ for(i = (8*(sizeof(len)-1)); i > 0; i -= 8) {
+ if((len >> i) & 0xFF) break;
+ computed_size--;
+ }
+
+ if(size) {
+ *buf++ = 0x80 | computed_size; /* Length of the encoding */
+ size--;
+ }
+
+ /*
+ * Produce the len encoding, space permitting.
+ */
+ if(size > computed_size)
+ end = buf + computed_size;
+ else
+ end = buf + size;
+ for((void)i /* Reuse bits count */; buf < end; i -= 8, buf++) {
+ *buf = (len >> i) & 0xFF;
+ }
+
+ return computed_size + 1;
+}
+
diff --git a/skeletons/ber_tlv_length.h b/skeletons/ber_tlv_length.h
new file mode 100644
index 00000000..7e5d5f8a
--- /dev/null
+++ b/skeletons/ber_tlv_length.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _BER_TLV_LENGTH_H_
+#define _BER_TLV_LENGTH_H_
+
+typedef ssize_t ber_tlv_len_t;
+
+/*
+ * This function tries to fetch the length of the BER TLV value and place it
+ * in *len_r.
+ * RETURN VALUES:
+ * 0: More data expected than bufptr contains.
+ * -1: Fatal error deciphering length.
+ * >0: Number of bytes used from bufptr.
+ * On return with >0, len_r is constrained as -1..MAX, where -1 mean
+ * that the value is of indefinite length.
+ */
+ssize_t ber_fetch_length(int _is_constructed, void *bufptr, size_t size,
+ ber_tlv_len_t *len_r);
+
+/*
+ * This function expects bufptr to be positioned over L in TLV.
+ * It returns number of bytes occupied by L and V together, suitable
+ * for skipping. The function properly handles indefinite length.
+ * RETURN VALUES:
+ * Standard {-1,0,>0} convention.
+ */
+ssize_t ber_skip_length(int _is_constructed, void *bufptr, size_t size);
+
+/*
+ * This function serializes the length (L from TLV) in DER format.
+ * It always return number of bytes necessary to represent the length,
+ * it is a caller's responsibility to check the return value
+ * against the supplied buffer's size.
+ */
+ssize_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size);
+
+#endif /* _BER_TLV_LENGTH_H_ */
diff --git a/skeletons/ber_tlv_tag.c b/skeletons/ber_tlv_tag.c
new file mode 100644
index 00000000..50c9e69b
--- /dev/null
+++ b/skeletons/ber_tlv_tag.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_TYPE.h>
+#include <ber_tlv_tag.h>
+#include <errno.h>
+
+ssize_t
+ber_fetch_tag(void *ptr, size_t size, ber_tlv_tag_t *tag_r) {
+ ber_tlv_tag_t val;
+ ber_tlv_tag_t tclass;
+ ssize_t skipped;
+
+ if(size == 0)
+ return 0;
+
+ val = *(uint8_t *)ptr;
+ tclass = (val >> 6);
+ if((val &= 31) != 31) {
+ /*
+ * Simple form: everything encoded in a single octet.
+ * Tag Class is encoded using two least significant bits.
+ */
+ *tag_r = (val << 2) | tclass;
+ return 1;
+ }
+
+ /*
+ * Each octet contains 7 bits of useful information.
+ * The MSB is 0 if it is the last octet of the tag.
+ */
+ for(val = 0, ptr++, skipped = 2; skipped < size; ptr++, skipped++) {
+ unsigned oct = *(uint8_t *)ptr;
+ if(oct & 0x80) {
+ val = (val << 7) | (oct & 0x7F);
+ /*
+ * Make sure there are at least 9 bits spare
+ * at the MS side of a value.
+ */
+ if(val >> ((8 * sizeof(val)) - 9)) {
+ /*
+ * We would not be able to accomodate
+ * any more tag bits.
+ */
+ return -1;
+ }
+ } else {
+ *tag_r = (val << 9) | (oct << 2) | tclass;
+ return skipped;
+ }
+ }
+
+ return 0; /* Want more */
+}
+
+
+ssize_t
+ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *f) {
+ char buf[sizeof("[APPLICATION ]") + 32];
+ ssize_t ret;
+
+ ret = ber_tlv_tag_snprint(tag, buf, sizeof(buf));
+ if(ret >= sizeof(buf) || ret < 2) {
+ errno = EPERM;
+ return -1;
+ }
+
+ return fwrite(buf, 1, ret, f);
+}
+
+ssize_t
+ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t size) {
+ char *type = 0;
+ int ret;
+
+ switch(tag & 0x3) {
+ case ASN_TAG_CLASS_UNIVERSAL: type = "UNIVERSAL "; break;
+ case ASN_TAG_CLASS_APPLICATION: type = "APPLICATION "; break;
+ case ASN_TAG_CLASS_CONTEXT: type = ""; break;
+ case ASN_TAG_CLASS_PRIVATE: type = "PRIVATE "; break;
+ }
+
+ ret = snprintf(buf, size, "[%s%u]", type, ((unsigned)tag) >> 2);
+ if(ret <= 0 && size) buf[0] = '\0'; /* against broken libc's */
+
+ return ret;
+}
+
+char *
+ber_tlv_tag_string(ber_tlv_tag_t tag) {
+ static char buf[sizeof("[APPLICATION ]") + 32];
+
+ (void)ber_tlv_tag_snprint(tag, buf, sizeof(buf));
+
+ return buf;
+}
+
+
+ssize_t
+der_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufp, size_t size) {
+ int tclass = BER_TAG_CLASS(tag);
+ ber_tlv_tag_t tval = BER_TAG_VALUE(tag);
+ uint8_t *buf = bufp;
+ uint8_t *end;
+ ssize_t computed_size;
+ int i;
+
+ if(tval <= 30) {
+ /* Encoded in 1 octet */
+ if(size) buf[0] = (tclass << 6) | tval;
+ return 1;
+ } else if(size) {
+ *buf++ = (tclass << 6) | 0x1F;
+ size--;
+ }
+
+ /*
+ * Compute the size of the subsequent bytes.
+ * The routine is written so every floating-point
+ * operation is done at compile time.
+ * Note, there is a subtle problem lurking here,
+ * could you guess where it is? :)
+ * Hint: what happens when ((8*sizeof(tag))%7) == 0?
+ */
+ computed_size = 1 + 8 * sizeof(tag) / 7;
+ for(i = (8*sizeof(tag)) - ((8*sizeof(tag))%7); i >= 7; i -= 7) {
+ if((tval >> i) & 0x7F) break;
+ computed_size--;
+ }
+
+ /*
+ * Fill in the buffer, space permitting.
+ */
+ if(size > computed_size)
+ end = buf + computed_size;
+ else
+ end = buf + size;
+ for((void)i; buf < end; i -= 7, buf++) {
+ *buf = 0x80 | ((tval>>i) & 0x7F);
+ }
+
+ return computed_size + 1;
+}
+
diff --git a/skeletons/ber_tlv_tag.h b/skeletons/ber_tlv_tag.h
new file mode 100644
index 00000000..50419702
--- /dev/null
+++ b/skeletons/ber_tlv_tag.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _BER_TLV_TAG_H_
+#define _BER_TLV_TAG_H_
+
+enum asn_tag_class {
+ ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */
+ ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */
+ ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */
+ ASN_TAG_CLASS_PRIVATE = 3, /* 0b11 */
+};
+typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */
+
+/*
+ * Tag class is encoded together with tag value for optimization purposes.
+ */
+#define BER_TAG_CLASS(tag) ((tag) & 0x3)
+#define BER_TAG_VALUE(tag) ((tag) >> 2)
+#define BER_TLV_CONSTRUCTED(tagptr) (((*(uint8_t *)tagptr) & 0x20)?1:0)
+
+#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2))
+
+/*
+ * Several functions for printing the TAG in the canonical form
+ * (i.e. "[PRIVATE 0]").
+ * Return values correspond to their libc counterparts (if any).
+ */
+ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen);
+ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *);
+char *ber_tlv_tag_string(ber_tlv_tag_t tag);
+
+
+/*
+ * This function tries to fetch the tag from the input stream.
+ * RETURN VALUES:
+ * 0: More data expected than bufptr contains.
+ * -1: Fatal error deciphering tag.
+ * >0: Number of bytes used from bufptr. tag_r will contain the tag.
+ */
+ssize_t ber_fetch_tag(void *bufptr, size_t size, ber_tlv_tag_t *tag_r);
+
+/*
+ * This function serializes the tag (T from TLV) in DER format.
+ * It always return number of bytes necessary to represent the tag,
+ * it is a caller's responsibility to check the return value
+ * against the supplied buffer's size.
+ */
+ssize_t der_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size);
+
+#endif /* _BER_TLV_TAG_H_ */
diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c
new file mode 100644
index 00000000..2cfac3b6
--- /dev/null
+++ b/skeletons/constr_CHOICE.c
@@ -0,0 +1,627 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_CHOICE.h>
+#include <netinet/in.h> /* for ntohl */
+#include <assert.h>
+
+/*
+ * Number of bytes left for this structure.
+ * (ctx->left) indicates the number of bytes _transferred_ for the structure.
+ * (size) contains the number of bytes in the buffer passed.
+ */
+#define LEFT ((size<ctx->left)?size:ctx->left)
+
+/*
+ * If the subprocessor function returns with an indication that it wants
+ * more data, it may well be a fatal decoding problem, because the
+ * size is constrained by the <TLV>'s L, even if the buffer size allows
+ * reading more data.
+ * For example, consider the buffer containing the following TLVs:
+ * <T:5><L:1><V> <T:6>...
+ * The TLV length clearly indicates that one byte is expected in V, but
+ * if the V processor returns with "want more data" even if the buffer
+ * contains way more data than the V processor have seen.
+ */
+#define SIZE_VIOLATION (ctx->left >= 0 && ctx->left <= size)
+
+/*
+ * This macro "eats" the part of the buffer which is definitely "consumed",
+ * i.e. was correctly converted into local representation or rightfully skipped.
+ */
+#define ADVANCE(num_bytes) do { \
+ size_t num = num_bytes; \
+ ptr += num; \
+ size -= num; \
+ if(ctx->left >= 0) \
+ ctx->left -= num; \
+ consumed_myself += num; \
+ } while(0)
+
+/*
+ * Switch to the next phase of parsing.
+ */
+#define NEXT_PHASE(ctx) do { \
+ ctx->phase++; \
+ ctx->step = 0; \
+ } while(0)
+
+/*
+ * Return a standardized complex structure.
+ */
+#define RETURN(_code) do { \
+ rval.code = _code; \
+ rval.consumed = consumed_myself;\
+ return rval; \
+ } while(0)
+
+/*
+ * See the definitions.
+ */
+static inline int _fetch_present_idx(const void *struct_ptr, int off, int size);
+static inline void _set_present_idx(void *sptr, int offset, int size, int pres);
+
+/*
+ * Tags are canonically sorted in the tag to member table.
+ */
+static int
+_search4tag(const void *ap, const void *bp) {
+ const asn1_CHOICE_tag2member_t *a = ap;
+ const asn1_CHOICE_tag2member_t *b = bp;
+ int a_class = BER_TAG_CLASS(a->el_tag);
+ int b_class = BER_TAG_CLASS(b->el_tag);
+
+ if(a_class == b_class) {
+ ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
+ ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
+
+ if(a_value == b_value)
+ return 0;
+ else if(a_value < b_value)
+ return -1;
+ else
+ return 1;
+ } else if(a_class < b_class) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+/*
+ * The decoder of the CHOICE type.
+ */
+ber_dec_rval_t
+CHOICE_decode_ber(asn1_TYPE_descriptor_t *sd,
+ void **struct_ptr, void *ptr, size_t size, int tag_mode) {
+ /*
+ * Bring closer parts of structure description.
+ */
+ asn1_CHOICE_specifics_t *specs = sd->specifics;
+ asn1_CHOICE_element_t *elements = specs->elements;
+
+ /*
+ * Parts of the structure being constructed.
+ */
+ void *st = *struct_ptr; /* Target structure. */
+ ber_dec_ctx_t *ctx; /* Decoder context */
+
+ ber_tlv_tag_t tlv_tag; /* T from TLV */
+ ssize_t tag_len; /* Length of TLV's T */
+ //ber_tlv_len_t tlv_len; /* L from TLV */
+ ber_dec_rval_t rval; /* Return code from subparsers */
+
+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
+
+ ASN_DEBUG("Decoding %s as CHOICE", sd->name);
+
+ /*
+ * Create the target structure if it is not present already.
+ */
+ if(st == 0) {
+ st = *struct_ptr = CALLOC(1, specs->struct_size);
+ if(st == 0) {
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * Restore parsing context.
+ */
+ ctx = (st + specs->ctx_offset);
+
+ /*
+ * Start to parse where left previously
+ */
+ switch(ctx->phase) {
+ case 0:
+ /*
+ * PHASE 0.
+ * Check that the set of tags associated with given structure
+ * perfectly fits our expectations.
+ */
+
+ if(tag_mode || sd->tags_count) {
+ rval = ber_check_tags(sd, ctx, ptr, size,
+ tag_mode, &ctx->left, 0);
+ if(rval.code != RC_OK) {
+ ASN_DEBUG("%s tagging check failed: %d",
+ sd->name, rval.code);
+ consumed_myself += rval.consumed;
+ RETURN(rval.code);
+ }
+
+ if(ctx->left >= 0) {
+ /* ?Substracted below! */
+ ctx->left += rval.consumed;
+ }
+ ADVANCE(rval.consumed);
+ } else {
+ ctx->left = -1;
+ }
+
+ NEXT_PHASE(ctx);
+
+ ASN_DEBUG("Structure consumes %ld bytes, buffer %ld",
+ (long)ctx->left, (long)size);
+
+ /* Fall through */
+ case 1:
+ /*
+ * Fetch the T from TLV.
+ */
+ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
+ ASN_DEBUG("In %s CHOICE tag length %d", sd->name, (int)tag_len);
+ switch(tag_len) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ do {
+ asn1_CHOICE_tag2member_t *t2m;
+ asn1_CHOICE_tag2member_t key;
+
+ key.el_tag = tlv_tag;
+ t2m = bsearch(&key, specs->tag2el, specs->tag2el_count,
+ sizeof(specs->tag2el[0]), _search4tag);
+ if(t2m) {
+ /*
+ * Found the element corresponding to the tag.
+ */
+ NEXT_PHASE(ctx);
+ ctx->step = t2m->el_no;
+ break;
+ } else if(specs->extensible == 0) {
+ ASN_DEBUG("Unexpected tag %s "
+ "in non-extensible CHOICE %s",
+ ber_tlv_tag_string(tlv_tag), sd->name);
+ RETURN(RC_FAIL);
+ } else {
+ /* Skip this tag */
+ ssize_t skip;
+
+ ASN_DEBUG("Skipping unknown tag %s",
+ ber_tlv_tag_string(tlv_tag));
+
+ skip = ber_skip_length(
+ BER_TLV_CONSTRUCTED(ptr),
+ ptr + tag_len, LEFT - tag_len);
+
+ switch(skip) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ ADVANCE(skip + tag_len);
+ RETURN(RC_OK);
+ }
+ } while(0);
+
+ case 2:
+ /*
+ * PHASE 2.
+ * Read in the element.
+ */
+ do {
+ asn1_CHOICE_element_t *elm; /* CHOICE's element */
+ void *memb_ptr; /* Pointer to the member */
+ void *memb_ptr2; /* Pointer to that pointer */
+
+ elm = &elements[ctx->step];
+
+ /*
+ * Compute the position of the member inside a structure,
+ * and also a type of containment (it may be contained
+ * as pointer or using inline inclusion).
+ */
+ if(elm->optional) {
+ /* Optional member, hereby, a simple pointer */
+ memb_ptr2 = (char *)st + elm->memb_offset;
+ } else {
+ /*
+ * A pointer to a pointer
+ * holding the start of the structure
+ */
+ memb_ptr = (char *)st + elm->memb_offset;
+ memb_ptr2 = &memb_ptr;
+ }
+ /*
+ * Invoke the member fetch routine according to member's type
+ */
+ rval = elm->type->ber_decoder(
+ (void *)elm->type,
+ memb_ptr2, ptr, LEFT,
+ elm->tag_mode);
+ switch(rval.code) {
+ case RC_OK:
+ _set_present_idx(st, specs->pres_offset,
+ specs->pres_size, ctx->step + 1);
+ break;
+ case RC_WMORE: /* More data expected */
+ if(!SIZE_VIOLATION) {
+ ADVANCE(rval.consumed);
+ RETURN(RC_WMORE);
+ }
+ RETURN(RC_FAIL);
+ case RC_FAIL: /* Fatal error */
+ RETURN(rval.code);
+ } /* switch(rval) */
+
+ ADVANCE(rval.consumed);
+ } while(0);
+
+ NEXT_PHASE(ctx);
+
+ /* Fall through */
+ case 3:
+ ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d",
+ sd->name, (long)ctx->left, (long)size,
+ tag_mode, sd->tags_count);
+
+ if(ctx->left > 0) {
+ /*
+ * The type must be fully decoded
+ * by the CHOICE member-specific decoder.
+ */
+ RETURN(RC_FAIL);
+ }
+
+ if(ctx->left == -1
+ && !(tag_mode || sd->tags_count)) {
+ /*
+ * This is an untagged CHOICE.
+ * It doesn't contain nothing
+ * except for the member itself, including all its tags.
+ * The decoding is completed.
+ */
+ NEXT_PHASE(ctx);
+ break;
+ }
+
+ /*
+ * Read in the "end of data chunks"'s.
+ */
+ while(ctx->left < 0) {
+ ssize_t tl;
+
+ tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
+ switch(tl) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ /*
+ * Expected <0><0>...
+ */
+ if(((uint8_t *)ptr)[0] == 0) {
+ if(LEFT < 2) {
+ if(SIZE_VIOLATION)
+ RETURN(RC_FAIL);
+ else
+ RETURN(RC_WMORE);
+ } else if(((uint8_t *)ptr)[1] == 0) {
+ /*
+ * Correctly finished with <0><0>.
+ */
+ continue;
+ }
+ } else {
+ ASN_DEBUG("Unexpected continuation in %s",
+ sd->name);
+ RETURN(RC_FAIL);
+ }
+
+ ADVANCE(2);
+ ctx->left++;
+ }
+
+ NEXT_PHASE(ctx);
+ case 4:
+ /* No meaningful work here */
+ break;
+ }
+
+ RETURN(RC_OK);
+}
+
+der_enc_rval_t
+CHOICE_encode_der(asn1_TYPE_descriptor_t *sd,
+ void *struct_ptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn1_CHOICE_specifics_t *specs = sd->specifics;
+ asn1_CHOICE_element_t *elm; /* CHOICE element */
+ der_enc_rval_t erval;
+ void *memb_ptr;
+ size_t computed_size = 0;
+ int present;
+
+ ASN_DEBUG("%s %s as CHOICE",
+ cb?"Encoding":"Estimating", sd->name);
+
+ present = _fetch_present_idx(struct_ptr,
+ specs->pres_offset, specs->pres_size);
+
+ /*
+ * If the structure was not initialized, it cannot be encoded:
+ * can't deduce what to encode in the choice type.
+ */
+ if(present <= 0 || present > specs->elements_count) {
+ if(present == 0 && specs->elements_count == 0) {
+ /* The CHOICE is empty?! */
+ erval.encoded = 0;
+ return erval;
+ }
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = struct_ptr;
+ return erval;
+ }
+
+ /*
+ * Seek over the present member of the structure.
+ */
+ elm = &specs->elements[present-1];
+ if(elm->optional) {
+ memb_ptr = *(void **)((char *)struct_ptr + elm->memb_offset);
+ if(memb_ptr == 0) {
+ erval.encoded = 0;
+ return erval;
+ }
+ } else {
+ memb_ptr = (void *)((char *)struct_ptr + elm->memb_offset);
+ }
+
+ /*
+ * If the CHOICE itself is tagged EXPLICIT:
+ * T ::= [2] EXPLICIT CHOICE { ... }
+ * Then emit the appropriate tags.
+ */
+ if(tag_mode == 1 || sd->tags_count) {
+ /*
+ * For this, we need to pre-compute the member.
+ */
+ ssize_t ret;
+
+ /* Encode member with its tag */
+ erval = elm->type->der_encoder(elm->type, memb_ptr,
+ elm->tag_mode, elm->tag, 0, 0);
+ if(erval.encoded == -1)
+ return erval;
+
+ /* Encode CHOICE with parent or my own tag */
+ ret = der_write_tags(sd, erval.encoded, tag_mode, tag,
+ cb, app_key);
+ if(ret == -1) {
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = struct_ptr;
+ return erval;
+ }
+ computed_size += ret;
+ }
+
+ /*
+ * Encode the single underlying member.
+ */
+ erval = elm->type->der_encoder(elm->type, memb_ptr,
+ elm->tag_mode, elm->tag, cb, app_key);
+ if(erval.encoded == -1)
+ return erval;
+
+ ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)",
+ (long)erval.encoded, (long)computed_size);
+
+ erval.encoded += computed_size;
+
+ return erval;
+}
+
+ber_tlv_tag_t
+CHOICE_outmost_tag(asn1_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) {
+ asn1_CHOICE_specifics_t *specs = td->specifics;
+ int present;
+
+ assert(tag_mode == 0);
+ assert(tag == 0);
+
+ /*
+ * Figure out which CHOICE element is encoded.
+ */
+ present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
+
+ if(present > 0 || present <= specs->elements_count) {
+ asn1_CHOICE_element_t *elm = &specs->elements[present-1];
+ void *memb_ptr;
+
+ if(elm->optional) {
+ memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
+ } else {
+ memb_ptr = (void *)((char *)ptr + elm->memb_offset);
+ }
+
+ return asn1_TYPE_outmost_tag(elm->type, memb_ptr,
+ elm->tag_mode, elm->tag);
+ } else {
+ return -1;
+ }
+}
+
+int
+CHOICE_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ asn1_CHOICE_specifics_t *specs = td->specifics;
+ int present;
+
+ if(!sptr) {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ /*
+ * Figure out which CHOICE element is encoded.
+ */
+ present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
+ if(present > 0 && present <= specs->elements_count) {
+ asn1_CHOICE_element_t *elm = &specs->elements[present-1];
+ const void *memb_ptr;
+
+ if(elm->optional) {
+ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
+ if(!memb_ptr) return 0;
+ } else {
+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
+ }
+
+ return elm->type->check_constraints(elm->type, memb_ptr,
+ app_errlog, app_key);
+ } else {
+ _ASN_ERRLOG("%s: no CHOICE element given", td->name);
+ return -1;
+ }
+}
+
+int
+CHOICE_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn1_CHOICE_specifics_t *specs = td->specifics;
+ int present;
+
+ if(!sptr) return cb("<absent>", 8, app_key);
+
+ /*
+ * Figure out which CHOICE element is encoded.
+ */
+ present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
+
+ /*
+ * Free that element.
+ */
+ if(present > 0 && present <= specs->elements_count) {
+ asn1_CHOICE_element_t *elm = &specs->elements[present-1];
+ const void *memb_ptr;
+
+ if(elm->optional) {
+ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
+ if(!memb_ptr) return cb("<absent>", 8, app_key);
+ } else {
+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
+ }
+
+ /* Print member's name and stuff */
+ if(cb(elm->name, strlen(elm->name), app_key)
+ || cb(": ", 2, app_key))
+ return -1;
+
+ return elm->type->print_struct(elm->type, memb_ptr, ilevel,
+ cb, app_key);
+ } else {
+ return cb("<absent>", 8, app_key);
+ }
+}
+
+void
+CHOICE_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+ asn1_CHOICE_specifics_t *specs = td->specifics;
+ int present;
+
+ if(!td || !ptr)
+ return;
+
+ ASN_DEBUG("Freeing %s as CHOICE", td->name);
+
+ /*
+ * Figure out which CHOICE element is encoded.
+ */
+ present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
+
+ /*
+ * Free that element.
+ */
+ if(present > 0 && present <= specs->elements_count) {
+ asn1_CHOICE_element_t *elm = &specs->elements[present-1];
+ void *memb_ptr;
+
+ if(elm->optional) {
+ memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
+ if(memb_ptr)
+ elm->type->free_struct(elm->type, memb_ptr, 0);
+ } else {
+ memb_ptr = (void *)((char *)ptr + elm->memb_offset);
+ elm->type->free_struct(elm->type, memb_ptr, 1);
+ }
+ }
+
+ if(!contents_only) {
+ FREEMEM(ptr);
+ }
+}
+
+
+/*
+ * The following functions functions offer protection against -fshort-enums,
+ * compatible with little- and big-endian machines.
+ * If assertion is triggered, either disable -fshort-enums, or add an entry
+ * here with the ->pres_size of your target stracture.
+ * Unless the target structure is packed, the ".present" member
+ * is guaranteed to be aligned properly. ASN.1 compiler itself does not
+ * produce packed code.
+ */
+static inline int
+_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) {
+ const void *present_ptr;
+ int present;
+
+ present_ptr = ((const char *)struct_ptr) + pres_offset;
+
+ switch(pres_size) {
+ case sizeof(int): present = *(const int *)present_ptr; break;
+ case sizeof(short): present = *(const short *)present_ptr; break;
+ case sizeof(char): present = *(const char *)present_ptr; break;
+ default:
+ /* ANSI C mandates enum to be equivalent to integer */
+ assert(pres_size != sizeof(int));
+ return 0; /* If not aborted, pass back safe value */
+ }
+
+ return present;
+}
+
+static inline void
+_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) {
+ void *present_ptr;
+ present_ptr = ((char *)struct_ptr) + pres_offset;
+
+ switch(pres_size) {
+ case sizeof(int): *(int *)present_ptr = present; break;
+ case sizeof(short): *(short *)present_ptr = present; break;
+ case sizeof(char): *(char *)present_ptr = present; break;
+ default:
+ /* ANSI C mandates enum to be equivalent to integer */
+ assert(pres_size != sizeof(int));
+ }
+}
diff --git a/skeletons/constr_CHOICE.h b/skeletons/constr_CHOICE.h
new file mode 100644
index 00000000..70766e9d
--- /dev/null
+++ b/skeletons/constr_CHOICE.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _CONSTR_CHOICE_H_
+#define _CONSTR_CHOICE_H_
+
+#include <constr_TYPE.h>
+
+/*
+ * A single element of the CHOICE type.
+ */
+typedef struct asn1_CHOICE_element_s {
+ int memb_offset; /* Offset of the element */
+ int optional; /* Whether the element is optional */
+ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */
+ int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */
+ asn1_TYPE_descriptor_t
+ *type; /* Member type descriptor */
+ char *name; /* ASN.1 identifier of the element */
+} asn1_CHOICE_element_t;
+
+typedef struct asn1_CHOICE_tag2member_s {
+ ber_tlv_tag_t el_tag; /* Outmost tag of the member */
+ int el_no; /* Index of the associated member, base 0 */
+} asn1_CHOICE_tag2member_t;
+
+typedef struct asn1_CHOICE_specifics_s {
+ /*
+ * Target structure description.
+ */
+ int struct_size; /* Size of the target structure. */
+ int ctx_offset; /* Offset of the ber_dec_ctx_t member */
+ int pres_offset; /* Identifier of the present member */
+ int pres_size; /* Size of the identifier (enum) */
+
+ /*
+ * Members of the CHOICE structure.
+ */
+ asn1_CHOICE_element_t *elements;
+ int elements_count;
+
+ /*
+ * Tags to members mapping table.
+ */
+ asn1_CHOICE_tag2member_t *tag2el;
+ int tag2el_count;
+
+ /*
+ * Extensions-related stuff.
+ */
+ int extensible; /* Whether CHOICE is extensible */
+} asn1_CHOICE_specifics_t;
+
+/*
+ * A set specialized functions dealing with the CHOICE type.
+ */
+asn_constr_check_f CHOICE_constraint;
+ber_type_decoder_f CHOICE_decode_ber;
+der_type_encoder_f CHOICE_encode_der;
+asn_outmost_tag_f CHOICE_outmost_tag;
+asn_struct_print_f CHOICE_print;
+asn_struct_free_f CHOICE_free;
+
+#endif /* _CONSTR_CHOICE_H_ */
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
new file mode 100644
index 00000000..6704dd84
--- /dev/null
+++ b/skeletons/constr_SEQUENCE.c
@@ -0,0 +1,588 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_SEQUENCE.h>
+
+/*
+ * Number of bytes left for this structure.
+ * (ctx->left) indicates the number of bytes _transferred_ for the structure.
+ * (size) contains the number of bytes in the buffer passed.
+ */
+#define LEFT ((size<ctx->left)?size:ctx->left)
+
+/*
+ * If the subprocessor function returns with an indication that it wants
+ * more data, it may well be a fatal decoding problem, because the
+ * size is constrained by the <TLV>'s L, even if the buffer size allows
+ * reading more data.
+ * For example, consider the buffer containing the following TLVs:
+ * <T:5><L:1><V> <T:6>...
+ * The TLV length clearly indicates that one byte is expected in V, but
+ * if the V processor returns with "want more data" even if the buffer
+ * contains way more data than the V processor have seen.
+ */
+#define SIZE_VIOLATION (ctx->left >= 0 && ctx->left <= size)
+
+/*
+ * This macro "eats" the part of the buffer which is definitely "consumed",
+ * i.e. was correctly converted into local representation or rightfully skipped.
+ */
+#define ADVANCE(num_bytes) do { \
+ size_t num = num_bytes; \
+ ptr += num; \
+ size -= num; \
+ if(ctx->left >= 0) \
+ ctx->left -= num; \
+ consumed_myself += num; \
+ } while(0)
+
+/*
+ * Switch to the next phase of parsing.
+ */
+#define NEXT_PHASE(ctx) do { \
+ ctx->phase++; \
+ ctx->step = 0; \
+ } while(0)
+#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0)
+
+/*
+ * Return a standardized complex structure.
+ */
+#define RETURN(_code) do { \
+ rval.code = _code; \
+ rval.consumed = consumed_myself;\
+ return rval; \
+ } while(0)
+
+/*
+ * Check whether we are inside the extensions group.
+ */
+#define IN_EXTENSION_GROUP(specs, memb_idx) \
+ ( ((memb_idx) > (specs)->ext_after) \
+ &&((memb_idx) < (specs)->ext_before))
+
+/*
+ * The decoder of the SEQUENCE type.
+ */
+ber_dec_rval_t
+SEQUENCE_decode_ber(asn1_TYPE_descriptor_t *sd,
+ void **struct_ptr, void *ptr, size_t size, int tag_mode) {
+ /*
+ * Bring closer parts of structure description.
+ */
+ asn1_SEQUENCE_specifics_t *specs = sd->specifics;
+ asn1_SEQUENCE_element_t *elements = specs->elements;
+
+ /*
+ * Parts of the structure being constructed.
+ */
+ void *st = *struct_ptr; /* Target structure. */
+ ber_dec_ctx_t *ctx; /* Decoder context */
+
+ ber_tlv_tag_t tlv_tag; /* T from TLV */
+ //ber_tlv_len_t tlv_len; /* L from TLV */
+ ber_dec_rval_t rval; /* Return code from subparsers */
+
+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
+ int edx; /* SEQUENCE element's index */
+
+ ASN_DEBUG("Decoding %s as SEQUENCE", sd->name);
+
+ /*
+ * Create the target structure if it is not present already.
+ */
+ if(st == 0) {
+ st = *struct_ptr = CALLOC(1, specs->struct_size);
+ if(st == 0) {
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * Restore parsing context.
+ */
+ ctx = (st + specs->ctx_offset);
+
+ /*
+ * Start to parse where left previously
+ */
+ switch(ctx->phase) {
+ case 0:
+ /*
+ * PHASE 0.
+ * Check that the set of tags associated with given structure
+ * perfectly fits our expectations.
+ */
+
+ rval = ber_check_tags(sd, ctx, ptr, size,
+ tag_mode, &ctx->left, 0);
+ if(rval.code != RC_OK) {
+ ASN_DEBUG("%s tagging check failed: %d",
+ sd->name, rval.code);
+ consumed_myself += rval.consumed;
+ RETURN(rval.code);
+ }
+
+ if(ctx->left >= 0)
+ ctx->left += rval.consumed; /* ?Substracted below! */
+ ADVANCE(rval.consumed);
+
+ NEXT_PHASE(ctx);
+
+ ASN_DEBUG("Structure consumes %ld bytes, buffer %ld",
+ (long)ctx->left, (long)size);
+
+ /* Fall through */
+ case 1:
+ /*
+ * PHASE 1.
+ * From the place where we've left it previously,
+ * try to decode the next member from the list of
+ * this structure's elements.
+ * (ctx->step) stores the member being processed
+ * between invocations and the microphase {0,1} of parsing
+ * that member:
+ * step = (<member_number> * 2 + <microphase>).
+ */
+ for(edx = (ctx->step >> 1); edx < specs->elements_count;
+ edx++, ctx->step = (ctx->step & ~1) + 2) {
+ void *memb_ptr; /* Pointer to the member */
+ void *memb_ptr2; /* Pointer to that pointer */
+ ssize_t tag_len; /* Length of TLV's T */
+ int opt_edx_end; /* Next non-optional element */
+ int n;
+
+ if(ctx->step & 1)
+ goto microphase2;
+
+ /*
+ * MICROPHASE 1: Synchronize decoding.
+ */
+ ASN_DEBUG("In %s SEQUENCE left %d, edx=%d opt=%d ec=%d",
+ sd->name, (int)ctx->left,
+ edx, elements[edx].optional, specs->elements_count);
+
+ if(ctx->left == 0 /* No more stuff is expected */
+ && (
+ /* Explicit OPTIONAL specification reaches the end */
+ (edx + elements[edx].optional == specs->elements_count)
+ ||
+ /* All extensions are optional */
+ (IN_EXTENSION_GROUP(specs, edx)
+ && specs->ext_before > specs->elements_count)
+ )
+ ) {
+ ASN_DEBUG("End of SEQUENCE %s", sd->name);
+ /*
+ * Found the legitimate end of the structure.
+ */
+ PHASE_OUT(ctx);
+ RETURN(RC_OK);
+ }
+
+ /*
+ * Fetch the T from TLV.
+ */
+ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
+ ASN_DEBUG("In %s SEQUENCE for %d %s next tag length %d",
+ sd->name, edx, elements[edx].name, (int)tag_len);
+ switch(tag_len) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ /*
+ * Find the next available type with this tag.
+ */
+ opt_edx_end = edx + elements[edx].optional + 1;
+ if(opt_edx_end > specs->elements_count)
+ opt_edx_end = specs->elements_count; /* Cap */
+ for(n = edx; n < opt_edx_end; n++) {
+ if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) {
+ /*
+ * Found element corresponding to the tag
+ * being looked at.
+ * Reposition over the right element.
+ */
+ edx = n;
+ ctx->step = 2 * edx; /* Remember! */
+ break;
+ }
+ }
+ if(n == opt_edx_end) {
+ /*
+ * If tag is unknown, it may be either
+ * an unknown (thus, incorrect) tag,
+ * or an extension (...),
+ * or an end of the indefinite-length structure.
+ */
+
+ if(!IN_EXTENSION_GROUP(specs, edx)) {
+ ASN_DEBUG("Unexpected tag %s",
+ ber_tlv_tag_string(tlv_tag));
+ ASN_DEBUG("Expected tag %s%s",
+ ber_tlv_tag_string(elements[edx].tag),
+ elements[edx].optional
+ ?" or alternatives":"");
+ RETURN(RC_FAIL);
+ }
+
+ if(ctx->left < 0
+ && ((uint8_t *)ptr)[0] == 0) {
+ if(LEFT < 2) {
+ if(SIZE_VIOLATION)
+ RETURN(RC_FAIL);
+ else
+ RETURN(RC_WMORE);
+ } else if(((uint8_t *)ptr)[1] == 0) {
+ /*
+ * Yeah, baby! Found the terminator
+ * of the indefinite length structure.
+ */
+ /*
+ * Proceed to the canonical
+ * finalization function.
+ * No advancing is necessary.
+ */
+ goto phase3;
+ }
+ } else {
+ /* Skip this tag */
+ ssize_t skip;
+
+ skip = ber_skip_length(
+ BER_TLV_CONSTRUCTED(ptr),
+ ptr + tag_len, LEFT - tag_len);
+ ASN_DEBUG("Skip length %d in %s",
+ (int)skip, sd->name);
+ switch(skip) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ ADVANCE(skip + tag_len);
+ ctx->step -= 2;
+ edx--;
+ continue; /* Try again with the next tag */
+ }
+ }
+
+ /*
+ * MICROPHASE 2: Invoke the member-specific decoder.
+ */
+ ctx->step |= 1; /* Confirm entering next microphase */
+ microphase2:
+ ASN_DEBUG("Inside SEQUENCE %s MF2", sd->name);
+
+ /*
+ * Compute the position of the member inside a structure,
+ * and also a type of containment (it may be contained
+ * as pointer or using inline inclusion).
+ */
+ if(elements[edx].optional) {
+ /* Optional member, hereby, a simple pointer */
+ memb_ptr2 = (char *)st + elements[edx].memb_offset;
+ } else {
+ /*
+ * A pointer to a pointer
+ * holding the start of the structure
+ */
+ memb_ptr = (char *)st + elements[edx].memb_offset;
+ memb_ptr2 = &memb_ptr;
+ }
+ /*
+ * Invoke the member fetch routine according to member's type
+ */
+ rval = elements[edx].type->ber_decoder(
+ (void *)elements[edx].type,
+ memb_ptr2, ptr, LEFT,
+ elements[edx].tag_mode);
+ ASN_DEBUG("In %s SEQUENCE decoded %d %s in %d bytes code %d",
+ sd->name, edx, elements[edx].type->name,
+ (int)rval.consumed, rval.code);
+ switch(rval.code) {
+ case RC_OK:
+ break;
+ case RC_WMORE: /* More data expected */
+ if(!SIZE_VIOLATION) {
+ ADVANCE(rval.consumed);
+ RETURN(RC_WMORE);
+ }
+ /* Fall through */
+ case RC_FAIL: /* Fatal error */
+ RETURN(RC_FAIL);
+ } /* switch(rval) */
+
+ ADVANCE(rval.consumed);
+ } /* for(all structure members) */
+
+ phase3:
+ ctx->phase = 3;
+ case 3: /* 00 and other tags expected */
+ case 4: /* only 00's expected */
+
+ ASN_DEBUG("SEQUENCE %s Leftover: %ld, size = %ld",
+ sd->name, (long)ctx->left, (long)size);
+
+ /*
+ * Skip everything until the end of the SEQUENCE.
+ */
+ while(ctx->left) {
+ ssize_t tl, ll;
+
+ tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
+ switch(tl) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ /*
+ * If expected <0><0>...
+ */
+ if(ctx->left < 0
+ && ((uint8_t *)ptr)[0] == 0) {
+ if(LEFT < 2) {
+ if(SIZE_VIOLATION)
+ RETURN(RC_FAIL);
+ else
+ RETURN(RC_WMORE);
+ } else if(((uint8_t *)ptr)[1] == 0) {
+ /*
+ * Correctly finished with <0><0>.
+ */
+ ADVANCE(2);
+ ctx->left++;
+ ctx->phase = 4;
+ continue;
+ }
+ }
+
+ if(!IN_EXTENSION_GROUP(specs, specs->elements_count)
+ || ctx->phase == 4) {
+ ASN_DEBUG("Unexpected continuation "
+ "of a non-extensible type "
+ "%s (SEQUENCE): %s",
+ sd->name,
+ ber_tlv_tag_string(tlv_tag));
+ RETURN(RC_FAIL);
+ }
+
+ ll = ber_skip_length(
+ BER_TLV_CONSTRUCTED(ptr),
+ ptr + tl, LEFT - tl);
+ switch(ll) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ ADVANCE(tl + ll);
+ }
+
+ PHASE_OUT(ctx);
+ }
+
+ RETURN(RC_OK);
+}
+
+/*
+ * The DER encoder of the SEQUENCE type.
+ */
+der_enc_rval_t
+SEQUENCE_encode_der(asn1_TYPE_descriptor_t *sd,
+ void *ptr, int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn1_SEQUENCE_specifics_t *specs = sd->specifics;
+ size_t computed_size = 0;
+ der_enc_rval_t erval;
+ ssize_t ret;
+ int edx;
+
+ ASN_DEBUG("%s %s as SEQUENCE",
+ cb?"Encoding":"Estimating", sd->name);
+
+ /*
+ * Gather the length of the underlying members sequence.
+ */
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+ void *memb_ptr;
+ if(elm->optional) {
+ memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
+ if(!memb_ptr) continue;
+ } else {
+ memb_ptr = (void *)((char *)ptr + elm->memb_offset);
+ }
+ erval = elm->type->der_encoder(elm->type, memb_ptr,
+ elm->tag_mode, elm->tag,
+ 0, 0);
+ if(erval.encoded == -1)
+ return erval;
+ computed_size += erval.encoded;
+ ASN_DEBUG("Member %d %s estimated %ld bytes",
+ edx, elm->name, (long)erval.encoded);
+ }
+
+ /*
+ * Encode the TLV for the sequence itself.
+ */
+ ret = der_write_tags(sd, computed_size, tag_mode, tag, cb, app_key);
+ ASN_DEBUG("Wrote tags: %ld (+%ld)", (long)ret, (long)computed_size);
+ if(ret == -1) {
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+ erval.encoded = computed_size + ret;
+
+ if(!cb) return erval;
+
+ /*
+ * Encode all members.
+ */
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+ der_enc_rval_t tmperval;
+ void *memb_ptr;
+
+ if(elm->optional) {
+ memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
+ if(!memb_ptr) continue;
+ } else {
+ memb_ptr = (void *)((char *)ptr + elm->memb_offset);
+ }
+ tmperval = elm->type->der_encoder(elm->type, memb_ptr,
+ elm->tag_mode, elm->tag,
+ cb, app_key);
+ if(tmperval.encoded == -1)
+ return tmperval;
+ computed_size -= tmperval.encoded;
+ ASN_DEBUG("Member %d %s of SEQUENCE %s encoded in %d bytes",
+ edx, elm->name, sd->name, tmperval.encoded);
+ }
+
+ if(computed_size != 0) {
+ /*
+ * Encoded size is not equal to the computed size.
+ */
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ }
+
+ return erval;
+}
+
+int
+SEQUENCE_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn1_SEQUENCE_specifics_t *specs = td->specifics;
+ int edx;
+ int ret;
+
+ if(!sptr) return cb("<absent>", 8, app_key);
+
+ /* Dump preamble */
+ if(cb(td->name, strlen(td->name), app_key)
+ || cb(" ::= {\n", 7, app_key))
+ return -1;
+
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+ const void *memb_ptr;
+
+ if(elm->optional) {
+ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
+ if(!memb_ptr) continue;
+ } else {
+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
+ }
+
+ /* Indentation */
+ for(ret = 0; ret < ilevel; ret++) cb(" ", 1, app_key);
+
+ /* Print the member's name and stuff */
+ if(cb(elm->name, strlen(elm->name), app_key)
+ || cb(": ", 2, app_key))
+ return -1;
+
+ /* Print the member itself */
+ ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 4,
+ cb, app_key);
+ if(ret) return ret;
+
+ /* Print out the terminator */
+ ret = cb("\n", 1, app_key);
+ if(ret) return ret;
+ }
+
+ /* Indentation */
+ for(ret = 0; ret < ilevel - 4; ret++) cb(" ", 1, app_key);
+
+ return cb("}", 1, app_key);
+}
+
+void
+SEQUENCE_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
+ asn1_SEQUENCE_specifics_t *specs = td->specifics;
+ int edx;
+
+ if(!td || !sptr)
+ return;
+
+ ASN_DEBUG("Freeing %s as SEQUENCE", td->name);
+
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+ void *memb_ptr;
+ if(elm->optional) {
+ memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
+ if(memb_ptr)
+ elm->type->free_struct(elm->type, memb_ptr, 0);
+ } else {
+ memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+ elm->type->free_struct(elm->type, memb_ptr, 1);
+ }
+ }
+
+ if(!contents_only) {
+ FREEMEM(sptr);
+ }
+}
+
+int
+SEQUENCE_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ asn1_SEQUENCE_specifics_t *specs = td->specifics;
+ int edx;
+
+ if(!sptr) {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ /*
+ * Iterate over structure members and check their validity.
+ */
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+ const void *memb_ptr;
+
+ if(elm->optional) {
+ memb_ptr = *(const void **)((const char *)sptr + elm->memb_offset);
+ if(!memb_ptr) continue;
+ } else {
+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
+ }
+
+ return elm->type->check_constraints(elm->type, memb_ptr,
+ app_errlog, app_key);
+ }
+
+ return 0;
+}
diff --git a/skeletons/constr_SEQUENCE.h b/skeletons/constr_SEQUENCE.h
new file mode 100644
index 00000000..c15729ca
--- /dev/null
+++ b/skeletons/constr_SEQUENCE.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _CONSTR_SEQUENCE_H_
+#define _CONSTR_SEQUENCE_H_
+
+#include <constr_TYPE.h>
+
+/*
+ * A single element of the SEQUENCE type.
+ */
+typedef struct asn1_SEQUENCE_element_s {
+ int memb_offset; /* Offset of the element */
+ int optional; /* Whether the element is optional */
+ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */
+ int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */
+ asn1_TYPE_descriptor_t
+ *type; /* Member type descriptor */
+ char *name; /* ASN.1 identifier of the element */
+} asn1_SEQUENCE_element_t;
+
+typedef struct asn1_SEQUENCE_specifics_s {
+ /*
+ * Target structure description.
+ */
+ int struct_size; /* Size of the target structure. */
+ int ctx_offset; /* Offset of the ber_dec_ctx_t member */
+
+ /*
+ * Members of the SEQUENCE structure.
+ */
+ asn1_SEQUENCE_element_t *elements;
+ int elements_count;
+
+ /*
+ * Description of an extensions group.
+ */
+ int ext_after; /* Extensions start after this member */
+ int ext_before; /* Extensions stop before this member */
+} asn1_SEQUENCE_specifics_t;
+
+
+/*
+ * A set specialized functions dealing with the SEQUENCE type.
+ */
+asn_constr_check_f SEQUENCE_constraint;
+ber_type_decoder_f SEQUENCE_decode_ber;
+der_type_encoder_f SEQUENCE_encode_der;
+asn_struct_print_f SEQUENCE_print;
+asn_struct_free_f SEQUENCE_free;
+
+#endif /* _CONSTR_SEQUENCE_H_ */
diff --git a/skeletons/constr_SEQUENCE_OF.c b/skeletons/constr_SEQUENCE_OF.c
new file mode 100644
index 00000000..cdddf607
--- /dev/null
+++ b/skeletons/constr_SEQUENCE_OF.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_SEQUENCE_OF.h>
+#include <asn_SEQUENCE_OF.h>
+
+/*
+ * The DER encoder of the SEQUENCE OF type.
+ */
+der_enc_rval_t
+SEQUENCE_OF_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn1_SET_OF_specifics_t *specs = sd->specifics;
+ asn1_SET_OF_element_t *elm = specs->element;
+ A_SEQUENCE_OF(void) *list = ptr;
+ size_t computed_size = 0;
+ ssize_t encoding_size = 0;
+ der_enc_rval_t erval;
+ int edx;
+
+ ASN_DEBUG("Estimating size of SEQUENCE OF %s", sd->name);
+
+ /*
+ * Gather the length of the underlying members sequence.
+ */
+ for(edx = 0; edx < list->count; edx++) {
+ void *memb_ptr = list->array[edx];
+ erval = elm->type->der_encoder(elm->type, memb_ptr,
+ 0, elm->tag,
+ 0, 0);
+ if(erval.encoded == -1)
+ return erval;
+ computed_size += erval.encoded;
+ }
+
+ /*
+ * Encode the TLV for the sequence itself.
+ */
+ encoding_size = der_write_tags(sd, computed_size, tag_mode, tag,
+ cb, app_key);
+ if(encoding_size == -1) {
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+
+ computed_size += encoding_size;
+ if(!cb) {
+ erval.encoded = computed_size;
+ return erval;
+ }
+
+ ASN_DEBUG("Encoding members of SEQUENCE OF %s", sd->name);
+
+ /*
+ * Encode all members.
+ */
+ for(edx = 0; edx < list->count; edx++) {
+ void *memb_ptr = list->array[edx];
+ erval = elm->type->der_encoder(elm->type, memb_ptr,
+ 0, elm->tag,
+ cb, app_key);
+ if(erval.encoded == -1)
+ return erval;
+ encoding_size += erval.encoded;
+ }
+
+ if(computed_size != encoding_size) {
+ /*
+ * Encoded size is not equal to the computed size.
+ */
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ } else {
+ erval.encoded = computed_size;
+ }
+
+ return erval;
+}
+
diff --git a/skeletons/constr_SEQUENCE_OF.h b/skeletons/constr_SEQUENCE_OF.h
new file mode 100644
index 00000000..d2560c6a
--- /dev/null
+++ b/skeletons/constr_SEQUENCE_OF.h
@@ -0,0 +1,21 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _CONSTR_SEQUENCE_OF_H_
+#define _CONSTR_SEQUENCE_OF_H_
+
+#include <constr_TYPE.h>
+#include <constr_SET_OF.h> /* Implemented using SET OF */
+
+/*
+ * A set specialized functions dealing with the SEQUENCE OF type.
+ * Implemented using SET OF.
+ */
+#define SEQUENCE_OF_constraint SET_OF_constraint
+#define SEQUENCE_OF_decode_ber SET_OF_decode_ber
+der_type_encoder_f SEQUENCE_OF_encode_der;
+#define SEQUENCE_OF_print SET_OF_print
+#define SEQUENCE_OF_free SET_OF_free
+
+#endif /* _CONSTR_SET_OF_H_ */
diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c
new file mode 100644
index 00000000..f1df9c1b
--- /dev/null
+++ b/skeletons/constr_SET.c
@@ -0,0 +1,682 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_SET.h>
+#include <netinet/in.h> /* for ntohl() */
+#include <assert.h> /* for assert() */
+
+/*
+ * Number of bytes left for this structure.
+ * (ctx->left) indicates the number of bytes _transferred_ for the structure.
+ * (size) contains the number of bytes in the buffer passed.
+ */
+#define LEFT ((size<ctx->left)?size:ctx->left)
+
+/*
+ * If the subprocessor function returns with an indication that it wants
+ * more data, it may well be a fatal decoding problem, because the
+ * size is constrained by the <TLV>'s L, even if the buffer size allows
+ * reading more data.
+ * For example, consider the buffer containing the following TLVs:
+ * <T:5><L:1><V> <T:6>...
+ * The TLV length clearly indicates that one byte is expected in V, but
+ * if the V processor returns with "want more data" even if the buffer
+ * contains way more data than the V processor have seen.
+ */
+#define SIZE_VIOLATION (ctx->left >= 0 && ctx->left <= size)
+
+/*
+ * This macro "eats" the part of the buffer which is definitely "consumed",
+ * i.e. was correctly converted into local representation or rightfully skipped.
+ */
+#define ADVANCE(num_bytes) do { \
+ size_t num = num_bytes; \
+ ptr += num; \
+ size -= num; \
+ if(ctx->left >= 0) \
+ ctx->left -= num; \
+ consumed_myself += num; \
+ } while(0)
+
+/*
+ * Switch to the next phase of parsing.
+ */
+#define NEXT_PHASE(ctx) do { \
+ ctx->phase++; \
+ ctx->step = 0; \
+ } while(0)
+
+/*
+ * Return a standardized complex structure.
+ */
+#define RETURN(_code) do { \
+ rval.code = _code; \
+ rval.consumed = consumed_myself;\
+ return rval; \
+ } while(0)
+
+/*
+ * Tags are canonically sorted in the tag2element map.
+ */
+static int
+_t2e_cmp(const void *ap, const void *bp) {
+ const asn1_SET_tag2member_t *a = ap;
+ const asn1_SET_tag2member_t *b = bp;
+ int a_class = BER_TAG_CLASS(a->el_tag);
+ int b_class = BER_TAG_CLASS(b->el_tag);
+
+ if(a_class == b_class) {
+ ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
+ ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
+
+ if(a_value == b_value)
+ return 0;
+ else if(a_value < b_value)
+ return -1;
+ else
+ return 1;
+ } else if(a_class < b_class) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+/*
+ * The decoder of the SET type.
+ */
+ber_dec_rval_t
+SET_decode_ber(asn1_TYPE_descriptor_t *sd,
+ void **struct_ptr, void *ptr, size_t size, int tag_mode) {
+ /*
+ * Bring closer parts of structure description.
+ */
+ asn1_SET_specifics_t *specs = sd->specifics;
+ asn1_SET_element_t *elements = specs->elements;
+
+ /*
+ * Parts of the structure being constructed.
+ */
+ void *st = *struct_ptr; /* Target structure. */
+ ber_dec_ctx_t *ctx; /* Decoder context */
+
+ ber_tlv_tag_t tlv_tag; /* T from TLV */
+ //ber_tlv_len_t tlv_len; /* L from TLV */
+ ber_dec_rval_t rval; /* Return code from subparsers */
+
+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
+ int edx; /* SET element's index */
+
+ ASN_DEBUG("Decoding %s as SET", sd->name);
+
+ /*
+ * Create the target structure if it is not present already.
+ */
+ if(st == 0) {
+ st = *struct_ptr = CALLOC(1, specs->struct_size);
+ if(st == 0) {
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * Restore parsing context.
+ */
+ ctx = (st + specs->ctx_offset);
+
+ /*
+ * Start to parse where left previously
+ */
+ switch(ctx->phase) {
+ case 0:
+ /*
+ * PHASE 0.
+ * Check that the set of tags associated with given structure
+ * perfectly fits our expectations.
+ */
+
+ rval = ber_check_tags(sd, ctx, ptr, size,
+ tag_mode, &ctx->left, 0);
+ if(rval.code != RC_OK) {
+ ASN_DEBUG("%s tagging check failed: %d",
+ sd->name, rval.code);
+ consumed_myself += rval.consumed;
+ RETURN(rval.code);
+ }
+
+ if(ctx->left >= 0)
+ ctx->left += rval.consumed; /* ?Substracted below! */
+ ADVANCE(rval.consumed);
+
+ NEXT_PHASE(ctx);
+
+ ASN_DEBUG("Structure advertised %ld bytes, "
+ "buffer contains %ld", (long)ctx->left, (long)size);
+
+ /* Fall through */
+ case 1:
+ /*
+ * PHASE 1.
+ * From the place where we've left it previously,
+ * try to decode the next member from the list of
+ * this structure's elements.
+ * (ctx->step) stores the member being processed
+ * between invocations and the microphase {0,1} of parsing
+ * that member:
+ * step = (2 * <member_number> + <microphase>).
+ * Note, however, that the elements in BER may arrive out of
+ * order, yet DER mandates that they shall arive in the
+ * canonical order of their tags. So, there is a room
+ * for optimization.
+ */
+ for(edx = (ctx->step >> 1); edx < specs->elements_count;
+ ctx->step = (ctx->step & ~1) + 2,
+ edx = (ctx->step >> 1)) {
+ void *memb_ptr; /* Pointer to the member */
+ void *memb_ptr2; /* Pointer to that pointer */
+ ssize_t tag_len; /* Length of TLV's T */
+
+ if(ctx->step & 1)
+ goto microphase2;
+
+ /*
+ * MICROPHASE 1: Synchronize decoding.
+ */
+
+ if(ctx->left == 0)
+ /*
+ * No more things to decode.
+ * Exit out of here and check whether all mandatory
+ * elements have been received (in the next phase).
+ */
+ break;
+
+ /*
+ * Fetch the T from TLV.
+ */
+ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
+ switch(tag_len) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ if(ctx->left < 0 && ((uint8_t *)ptr)[0] == 0) {
+ if(LEFT < 2) {
+ if(SIZE_VIOLATION)
+ RETURN(RC_FAIL);
+ else
+ RETURN(RC_WMORE);
+ } else if(((uint8_t *)ptr)[1] == 0) {
+ /*
+ * Found the terminator of the
+ * indefinite length structure.
+ * Invoke the generic finalization function.
+ */
+ goto phase3;
+ }
+ }
+
+ if(BER_TAGS_EQUAL(tlv_tag, elements[edx].tag)) {
+ /*
+ * The elements seem to go in order.
+ * This is not particularly strange,
+ * but is not strongly anticipated either.
+ */
+ } else {
+ asn1_SET_tag2member_t *t2m;
+ asn1_SET_tag2member_t key;
+
+ key.el_tag = tlv_tag;
+ t2m = bsearch(&key, specs->tag2el, specs->tag2el_count,
+ sizeof(specs->tag2el[0]), _t2e_cmp);
+ if(t2m) {
+ /*
+ * Found the element corresponding to the tag.
+ */
+ edx = t2m->el_no;
+ ctx->step = 2 * edx;
+ } else if(specs->extensible == 0) {
+ ASN_DEBUG("Unexpected tag %s "
+ "in non-extensible SET %s",
+ ber_tlv_tag_string(tlv_tag), sd->name);
+ RETURN(RC_FAIL);
+ } else {
+ /* Skip this tag */
+ ssize_t skip;
+
+ ASN_DEBUG("Skipping unknown tag %s",
+ ber_tlv_tag_string(tlv_tag));
+
+ skip = ber_skip_length(
+ BER_TLV_CONSTRUCTED(ptr),
+ ptr + tag_len, LEFT - tag_len);
+
+ switch(skip) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ ADVANCE(skip + tag_len);
+ ctx->step -= 2;
+ edx--;
+ continue; /* Try again with the next tag */
+ }
+ }
+
+ /*
+ * MICROPHASE 2: Invoke the member-specific decoder.
+ */
+ ctx->step |= 1; /* Confirm entering next microphase */
+ microphase2:
+
+ /*
+ * Check for duplications: must not overwrite
+ * already decoded elements.
+ */
+ if(ASN_SET_ISPRESENT2(st + specs->pres_offset, edx)) {
+ ASN_DEBUG("Duplicate element %d", edx);
+ RETURN(RC_FAIL);
+ }
+
+ /*
+ * Compute the position of the member inside a structure,
+ * and also a type of containment (it may be contained
+ * as pointer or using inline inclusion).
+ */
+ if(elements[edx].optional) {
+ /* Optional member, hereby, a simple pointer */
+ memb_ptr2 = (char *)st + elements[edx].memb_offset;
+ } else {
+ /*
+ * A pointer to a pointer
+ * holding the start of the structure
+ */
+ memb_ptr = (char *)st + elements[edx].memb_offset;
+ memb_ptr2 = &memb_ptr;
+ }
+ /*
+ * Invoke the member fetch routine according to member's type
+ */
+ rval = elements[edx].type->ber_decoder(
+ (void *)elements[edx].type,
+ memb_ptr2, ptr, LEFT,
+ elements[edx].tag_mode);
+ switch(rval.code) {
+ case RC_OK:
+ ASN_SET_MKPRESENT(st + specs->pres_offset, edx);
+ break;
+ case RC_WMORE: /* More data expected */
+ if(!SIZE_VIOLATION) {
+ ADVANCE(rval.consumed);
+ RETURN(RC_WMORE);
+ }
+ /* Fail through */
+ case RC_FAIL: /* Fatal error */
+ RETURN(RC_FAIL);
+ } /* switch(rval) */
+
+ ADVANCE(rval.consumed);
+ } /* for(all structure members) */
+
+ phase3:
+ ctx->phase = 3;
+ /* Fall through */
+ case 3:
+ case 4: /* Only 00 is expected */
+ ASN_DEBUG("SET %s Leftover: %ld, size = %ld",
+ sd->name, (long)ctx->left, (long)size);
+
+ /*
+ * Skip everything until the end of the SET.
+ */
+ while(ctx->left) {
+ ssize_t tl, ll;
+
+ tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
+ switch(tl) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ /*
+ * If expected <0><0>...
+ */
+ if(ctx->left < 0
+ && ((uint8_t *)ptr)[0] == 0) {
+ if(LEFT < 2) {
+ if(SIZE_VIOLATION)
+ RETURN(RC_FAIL);
+ else
+ RETURN(RC_WMORE);
+ } else if(((uint8_t *)ptr)[1] == 0) {
+ /*
+ * Correctly finished with <0><0>.
+ */
+ ADVANCE(2);
+ ctx->left++;
+ ctx->phase = 4;
+ continue;
+ }
+ }
+
+ if(specs->extensible == 0 || ctx->phase == 4) {
+ ASN_DEBUG("Unexpected continuation "
+ "of a non-extensible type %s",
+ sd->name);
+ RETURN(RC_FAIL);
+ }
+
+ ll = ber_skip_length(
+ BER_TLV_CONSTRUCTED(ptr),
+ ptr + tl, LEFT - tl);
+ switch(ll) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ ADVANCE(tl + ll);
+ }
+
+ ctx->phase = 5;
+ case 5:
+ /*
+ * Check that all mandatory elements are present.
+ */
+ for(edx = 0; edx < specs->elements_count;
+ edx += (8 * sizeof(specs->_mandatory_elements[0]))) {
+ unsigned int midx, pres, must;
+
+ midx = edx/(8 * sizeof(specs->_mandatory_elements[0]));
+ pres = ((unsigned int *)(st+specs->pres_offset))[midx];
+ must = ntohl(specs->_mandatory_elements[midx]);
+
+ if((pres & must) == must) {
+ /*
+ * Yes, everything seems to be in place.
+ */
+ } else {
+ ASN_DEBUG("One or more mandatory elements "
+ "of a SET %s %d (%08x.%08x)=%08x "
+ "are not present",
+ sd->name,
+ midx,
+ pres,
+ must,
+ (~(pres & must) & must)
+ );
+ RETURN(RC_FAIL);
+ }
+ }
+
+ NEXT_PHASE(ctx);
+ }
+
+ RETURN(RC_OK);
+}
+
+/*
+ * The DER encoder of the SET type.
+ */
+der_enc_rval_t
+SET_encode_der(asn1_TYPE_descriptor_t *sd,
+ void *ptr, int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn1_SET_specifics_t *specs = sd->specifics;
+ size_t computed_size = 0;
+ der_enc_rval_t my_erval;
+ int t2m_build_own = (specs->tag2el_count != specs->elements_count);
+ asn1_SET_tag2member_t *t2m;
+ int t2m_count;
+ ssize_t ret;
+ int edx;
+
+ /*
+ * Use existing, or build our own tags map.
+ */
+ if(t2m_build_own) {
+ t2m = alloca(specs->elements_count * sizeof(t2m[0]));
+ t2m_count = 0;
+ } else {
+ /*
+ * There is no untagged CHOICE in this SET.
+ * Employ existing table.
+ */
+ t2m = specs->tag2el;
+ t2m_count = specs->tag2el_count;
+ }
+
+ /*
+ * Gather the length of the underlying members sequence.
+ */
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SET_element_t *elm = &specs->elements[edx];
+ der_enc_rval_t erval;
+ void *memb_ptr;
+
+ /*
+ * Compute the length of the encoding of this member.
+ */
+ if(elm->optional) {
+ memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
+ if(!memb_ptr) {
+ if(t2m_build_own) {
+ t2m[t2m_count].el_no = edx;
+ t2m[t2m_count].el_tag = 0;
+ t2m_count++;
+ }
+ continue;
+ }
+ } else {
+ memb_ptr = (void *)((char *)ptr + elm->memb_offset);
+ }
+ erval = elm->type->der_encoder(elm->type, memb_ptr,
+ elm->tag_mode, elm->tag,
+ 0, 0);
+ if(erval.encoded == -1)
+ return erval;
+ computed_size += erval.encoded;
+
+ /*
+ * Remember the outmost tag of this member.
+ */
+ if(t2m_build_own) {
+ t2m[t2m_count].el_no = edx;
+ t2m[t2m_count].el_tag = asn1_TYPE_outmost_tag(
+ elm->type, memb_ptr, elm->tag_mode, elm->tag);
+ t2m_count++;
+ } else {
+ /*
+ * No dynamic sorting is necessary.
+ */
+ }
+ }
+
+ /*
+ * Finalize order of the components.
+ */
+ assert(t2m_count == specs->elements_count);
+ if(t2m_build_own) {
+ /*
+ * Sort the underlying members according to their
+ * canonical tags order. DER encoding mandates it.
+ */
+ qsort(t2m, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp);
+ } else {
+ /*
+ * Tags are already sorted by the compiler.
+ */
+ }
+
+ /*
+ * Encode the TLV for the sequence itself.
+ */
+ ret = der_write_tags(sd, computed_size, tag_mode, tag, cb, app_key);
+ if(ret == -1) {
+ my_erval.encoded = -1;
+ my_erval.failed_type = sd;
+ my_erval.structure_ptr = ptr;
+ return my_erval;
+ }
+ my_erval.encoded = computed_size + ret;
+
+ if(!cb) return my_erval;
+
+ /*
+ * Encode all members.
+ */
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SET_element_t *elm;
+ der_enc_rval_t erval;
+ void *memb_ptr;
+
+ /* Encode according to the tag order */
+ elm = &specs->elements[t2m[edx].el_no];
+
+ if(elm->optional) {
+ memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
+ if(!memb_ptr) continue;
+ } else {
+ memb_ptr = (void *)((char *)ptr + elm->memb_offset);
+ }
+ erval = elm->type->der_encoder(elm->type, memb_ptr,
+ elm->tag_mode, elm->tag,
+ cb, app_key);
+ if(erval.encoded == -1)
+ return erval;
+ computed_size -= erval.encoded;
+ }
+
+ if(computed_size != 0) {
+ /*
+ * Encoded size is not equal to the computed size.
+ */
+ my_erval.encoded = -1;
+ my_erval.failed_type = sd;
+ my_erval.structure_ptr = ptr;
+ }
+
+ return my_erval;
+}
+
+int
+SET_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn1_SET_specifics_t *specs = td->specifics;
+ int edx;
+ int ret;
+
+ if(!sptr) return cb("<absent>", 8, app_key);
+
+ /* Dump preamble */
+ if(cb(td->name, strlen(td->name), app_key)
+ || cb(" ::= {\n", 7, app_key))
+ return -1;
+
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SET_element_t *elm = &specs->elements[edx];
+ const void *memb_ptr;
+
+ if(elm->optional) {
+ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
+ if(!memb_ptr) continue;
+ } else {
+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
+ }
+
+ /* Indentation */
+ for(ret = 0; ret < ilevel; ret++) cb(" ", 1, app_key);
+
+ /* Print the member's name and stuff */
+ if(cb(elm->name, strlen(elm->name), app_key)
+ || cb(": ", 2, app_key))
+ return -1;
+
+ /* Print the member itself */
+ ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 4,
+ cb, app_key);
+ if(ret) return ret;
+
+ ret = cb("\n", 1, app_key);
+ if(ret) return ret;
+ }
+
+ /* Indentation */
+ for(ret = 0; ret < ilevel - 4; ret++) cb(" ", 1, app_key);
+
+ return cb("}", 1, app_key);
+}
+
+void
+SET_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+ asn1_SET_specifics_t *specs = td->specifics;
+ int edx;
+
+ if(!td || !ptr)
+ return;
+
+ ASN_DEBUG("Freeing %s as SET", td->name);
+
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SET_element_t *elm = &specs->elements[edx];
+ void *memb_ptr;
+ if(elm->optional) {
+ memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
+ if(memb_ptr)
+ elm->type->free_struct(elm->type, memb_ptr, 0);
+ } else {
+ memb_ptr = (void *)((char *)ptr + elm->memb_offset);
+ elm->type->free_struct(elm->type, memb_ptr, 1);
+ }
+ }
+
+ if(!contents_only) {
+ FREEMEM(ptr);
+ }
+}
+
+int
+SET_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ asn1_SET_specifics_t *specs = td->specifics;
+ int edx;
+
+ if(!sptr) {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ /*
+ * Iterate over structure members and check their validity.
+ */
+ for(edx = 0; edx < specs->elements_count; edx++) {
+ asn1_SET_element_t *elm = &specs->elements[edx];
+ const void *memb_ptr;
+
+ if(elm->optional) {
+ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
+ if(!memb_ptr) {
+ if(ASN_SET_ISPRESENT2(
+ &(specs->_mandatory_elements), edx)) {
+ _ASN_ERRLOG(
+ "%s: mandatory element "
+ "%s absent",
+ td->name, elm->name);
+ return -1;
+ }
+ continue;
+ }
+ } else {
+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
+ }
+
+ return elm->type->check_constraints(elm->type, memb_ptr,
+ app_errlog, app_key);
+ }
+
+ return 0;
+}
diff --git a/skeletons/constr_SET.h b/skeletons/constr_SET.h
new file mode 100644
index 00000000..c0ac07f5
--- /dev/null
+++ b/skeletons/constr_SET.h
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _CONSTR_SET_H_
+#define _CONSTR_SET_H_
+
+#include <constr_TYPE.h>
+
+/*
+ * Description of a single element of the SET type.
+ */
+typedef struct asn1_SET_element_s {
+ int memb_offset; /* Offset of the element */
+ int optional; /* Whether the element is optional */
+ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */
+ int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */
+ asn1_TYPE_descriptor_t
+ *type; /* Member type descriptor */
+ char *name; /* ASN.1 identifier of the element */
+} asn1_SET_element_t;
+
+/*
+ * Map between the outmost tag of the element and the corresponding
+ * element's index.
+ */
+typedef struct asn1_SET_tag2member_s {
+ ber_tlv_tag_t el_tag; /* Outmost tag of the member */
+ int el_no; /* Index of the associated member, base 0 */
+} asn1_SET_tag2member_t;
+
+typedef struct asn1_SET_specifics_s {
+ /*
+ * Target structure description.
+ */
+ int struct_size; /* Size of the target structure. */
+ int ctx_offset; /* Offset of the ber_dec_ctx_t member */
+ int pres_offset; /* Offset of _presence_map member */
+
+ /*
+ * Members of the SET structure.
+ */
+ asn1_SET_element_t *elements;
+ int elements_count;
+
+ /*
+ * Tags to members mapping table (sorted).
+ */
+ asn1_SET_tag2member_t *tag2el;
+ int tag2el_count;
+
+ /*
+ * Extensions-related stuff.
+ */
+ int extensible; /* Whether SET is extensible */
+ unsigned int *_mandatory_elements; /* Bitmask of mandatory ones */
+} asn1_SET_specifics_t;
+
+/*
+ * A set specialized functions dealing with the SET type.
+ */
+asn_constr_check_f SET_constraint;
+ber_type_decoder_f SET_decode_ber;
+der_type_encoder_f SET_encode_der;
+asn_struct_print_f SET_print;
+asn_struct_free_f SET_free;
+
+/***********************
+ * Some handy helpers. *
+ ***********************/
+
+/*
+ * Figure out whether the SET member indicated by PR_x has already been decoded.
+ * It is very simple bitfield test, despite its visual complexity.
+ */
+#define ASN_SET_ISPRESENT(set_ptr, PR_x) \
+ ASN_SET_ISPRESENT2(&((set_ptr)->_presence_map))
+#define ASN_SET_ISPRESENT2(map_ptr, PR_x) \
+ (((unsigned int *)(map_ptr)) \
+ [(PR_x) / (8 * sizeof(unsigned int))] \
+ & (1 << ((8 * sizeof(unsigned int)) - 1 \
+ - ((PR_x) % (8 * sizeof(unsigned int))))))
+
+#define ASN_SET_MKPRESENT(map_ptr, PR_x) \
+ (((unsigned int *)(map_ptr)) \
+ [(PR_x) / (8 * sizeof(unsigned int))] \
+ |= (1 << ((8 * sizeof(unsigned int)) - 1 \
+ - ((PR_x) % (8 * sizeof(unsigned int))))))
+
+#endif /* _CONSTR_SET_H_ */
diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c
new file mode 100644
index 00000000..9dcf638f
--- /dev/null
+++ b/skeletons/constr_SET_OF.c
@@ -0,0 +1,530 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_SET_OF.h>
+#include <asn_SET_OF.h>
+
+/*
+ * Number of bytes left for this structure.
+ * (ctx->left) indicates the number of bytes _transferred_ for the structure.
+ * (size) contains the number of bytes in the buffer passed.
+ */
+#define LEFT ((size<ctx->left)?size:ctx->left)
+
+/*
+ * If the subprocessor function returns with an indication that it wants
+ * more data, it may well be a fatal decoding problem, because the
+ * size is constrained by the <TLV>'s L, even if the buffer size allows
+ * reading more data.
+ * For example, consider the buffer containing the following TLVs:
+ * <T:5><L:1><V> <T:6>...
+ * The TLV length clearly indicates that one byte is expected in V, but
+ * if the V processor returns with "want more data" even if the buffer
+ * contains way more data than the V processor have seen.
+ */
+#define SIZE_VIOLATION (ctx->left != -1 && ctx->left <= size)
+
+/*
+ * This macro "eats" the part of the buffer which is definitely "consumed",
+ * i.e. was correctly converted into local representation or rightfully skipped.
+ */
+#define ADVANCE(num_bytes) do { \
+ size_t num = num_bytes; \
+ ptr += num; \
+ size -= num; \
+ if(ctx->left >= 0) \
+ ctx->left -= num; \
+ consumed_myself += num; \
+ } while(0)
+
+/*
+ * Switch to the next phase of parsing.
+ */
+#define NEXT_PHASE(ctx) do { \
+ ctx->phase++; \
+ ctx->step = 0; \
+ } while(0)
+#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0)
+
+/*
+ * Return a standardized complex structure.
+ */
+#define RETURN(_code) do { \
+ rval.code = _code; \
+ rval.consumed = consumed_myself;\
+ return rval; \
+ } while(0)
+
+/*
+ * The decoder of the SET OF type.
+ */
+ber_dec_rval_t
+SET_OF_decode_ber(asn1_TYPE_descriptor_t *sd,
+ void **struct_ptr, void *ptr, size_t size, int tag_mode) {
+ /*
+ * Bring closer parts of structure description.
+ */
+ asn1_SET_OF_specifics_t *specs = sd->specifics;
+ asn1_SET_OF_element_t *element = specs->element;
+
+ /*
+ * Parts of the structure being constructed.
+ */
+ void *st = *struct_ptr; /* Target structure. */
+ ber_dec_ctx_t *ctx; /* Decoder context */
+
+ ber_tlv_tag_t tlv_tag; /* T from TLV */
+ //ber_tlv_len_t tlv_len; /* L from TLV */
+ ber_dec_rval_t rval; /* Return code from subparsers */
+
+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
+
+ ASN_DEBUG("Decoding %s as SET OF", sd->name);
+
+ /*
+ * Create the target structure if it is not present already.
+ */
+ if(st == 0) {
+ st = *struct_ptr = CALLOC(1, specs->struct_size);
+ if(st == 0) {
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * Restore parsing context.
+ */
+ ctx = (st + specs->ctx_offset);
+
+ /*
+ * Start to parse where left previously
+ */
+ switch(ctx->phase) {
+ case 0:
+ /*
+ * PHASE 0.
+ * Check that the set of tags associated with given structure
+ * perfectly fits our expectations.
+ */
+
+ rval = ber_check_tags(sd, ctx, ptr, size,
+ tag_mode, &ctx->left, 0);
+ if(rval.code != RC_OK) {
+ ASN_DEBUG("%s tagging check failed: %d",
+ sd->name, rval.code);
+ consumed_myself += rval.consumed;
+ RETURN(rval.code);
+ }
+
+ if(ctx->left >= 0)
+ ctx->left += rval.consumed; /* ?Substracted below! */
+ ADVANCE(rval.consumed);
+
+ ASN_DEBUG("Structure consumes %ld bytes, "
+ "buffer %ld", (long)ctx->left, (long)size);
+
+ NEXT_PHASE(ctx);
+ /* Fall through */
+ case 1:
+ /*
+ * PHASE 1.
+ * From the place where we've left it previously,
+ * try to decode the next item.
+ */
+ for(;; ctx->step = 0) {
+ ssize_t tag_len; /* Length of TLV's T */
+
+ if(ctx->step & 1)
+ goto microphase2;
+
+ /*
+ * MICROPHASE 1: Synchronize decoding.
+ */
+
+ if(ctx->left == 0) {
+ ASN_DEBUG("End of SET OF %s", sd->name);
+ /*
+ * No more things to decode.
+ * Exit out of here.
+ */
+ PHASE_OUT(ctx);
+ RETURN(RC_OK);
+ }
+
+ /*
+ * Fetch the T from TLV.
+ */
+ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
+ switch(tag_len) {
+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
+ /* Fall through */
+ case -1: RETURN(RC_FAIL);
+ }
+
+ if(ctx->left < 0 && ((uint8_t *)ptr)[0] == 0) {
+ if(LEFT < 2) {
+ if(SIZE_VIOLATION)
+ RETURN(RC_FAIL);
+ else
+ RETURN(RC_WMORE);
+ } else if(((uint8_t *)ptr)[1] == 0) {
+ /*
+ * Found the terminator of the
+ * indefinite length structure.
+ */
+ break;
+ }
+ }
+
+ /* Outmost tag may be unknown and cannot be fetched/compared */
+ if(element->tag != -1) {
+ if(BER_TAGS_EQUAL(tlv_tag, element->tag)) {
+ /*
+ * The new list member of expected type has arrived.
+ */
+ } else {
+ ASN_DEBUG("Unexpected tag %s fixed SET OF %s",
+ ber_tlv_tag_string(tlv_tag), sd->name);
+ ASN_DEBUG("%s SET OF has tag %s",
+ sd->name, ber_tlv_tag_string(element->tag));
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * MICROPHASE 2: Invoke the member-specific decoder.
+ */
+ ctx->step |= 1; /* Confirm entering next microphase */
+ microphase2:
+
+ /*
+ * Invoke the member fetch routine according to member's type
+ */
+ rval = element->type->ber_decoder(
+ (void *)element->type,
+ &ctx->ptr, ptr, LEFT, 0);
+ ASN_DEBUG("In %s SET OF %s code %d consumed %d",
+ sd->name, element->type->name,
+ rval.code, (int)rval.consumed);
+ switch(rval.code) {
+ case RC_OK:
+ {
+ A_SET_OF(void) *list = st;
+ if(ASN_SET_ADD(list, ctx->ptr) != 0)
+ RETURN(RC_FAIL);
+ else
+ ctx->ptr = 0;
+ }
+ break;
+ case RC_WMORE: /* More data expected */
+ if(!SIZE_VIOLATION) {
+ ADVANCE(rval.consumed);
+ RETURN(RC_WMORE);
+ }
+ /* Fall through */
+ case RC_FAIL: /* Fatal error */
+ RETURN(RC_FAIL);
+ } /* switch(rval) */
+
+ ADVANCE(rval.consumed);
+ } /* for(all list members) */
+
+ NEXT_PHASE(ctx);
+ case 2:
+ /*
+ * Read in all "end of content" TLVs.
+ */
+ while(ctx->left < 0) {
+ if(LEFT < 2) {
+ if(LEFT > 0 && ((char *)ptr)[0] != 0) {
+ /* Unexpected tag */
+ RETURN(RC_FAIL);
+ } else {
+ RETURN(RC_WMORE);
+ }
+ }
+ if(((char *)ptr)[0] == 0
+ && ((char *)ptr)[1] == 0) {
+ ADVANCE(2);
+ ctx->left++;
+ } else {
+ RETURN(RC_FAIL);
+ }
+ }
+
+ PHASE_OUT(ctx);
+ }
+
+ RETURN(RC_OK);
+}
+
+/*
+ * Internally visible buffer holding a single encoded element.
+ */
+struct _el_buffer {
+ uint8_t *buf;
+ size_t length;
+ size_t size;
+};
+/* Append bytes to the above structure */
+static int _el_addbytes(const void *buffer, size_t size, void *el_buf_ptr) {
+ struct _el_buffer *el_buf = el_buf_ptr;
+
+ if(el_buf->length + size > el_buf->size)
+ return -1;
+
+ memcpy(el_buf->buf + el_buf->length, buffer, size);
+
+ el_buf->length += size;
+ return 0;
+}
+static int _el_buf_cmp(const void *ap, const void *bp) {
+ const struct _el_buffer *a = ap;
+ const struct _el_buffer *b = bp;
+ int ret;
+ size_t common_len;
+
+ if(a->length < b->length)
+ common_len = a->length;
+ else
+ common_len = b->length;
+
+ ret = memcmp(a->buf, b->buf, common_len);
+ if(ret == 0) {
+ if(a->length < b->length)
+ ret = -1;
+ else if(a->length > b->length)
+ ret = 1;
+ }
+
+ return ret;
+}
+
+/*
+ * The DER encoder of the SET OF type.
+ */
+der_enc_rval_t
+SET_OF_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn1_SET_OF_specifics_t *specs = sd->specifics;
+ asn1_SET_OF_element_t *elm = specs->element;
+ asn1_TYPE_descriptor_t *elm_type = elm->type;
+ der_type_encoder_f *der_encoder = elm_type->der_encoder;
+ A_SET_OF(void) *list = ptr;
+ size_t computed_size = 0;
+ ssize_t encoding_size = 0;
+ struct _el_buffer *encoded_els;
+ size_t max_encoded_len = 1;
+ der_enc_rval_t erval;
+ int ret;
+ int edx;
+
+ ASN_DEBUG("Estimating size for SET OF %s", sd->name);
+
+ /*
+ * Gather the length of the underlying members sequence.
+ */
+ for(edx = 0; edx < list->count; edx++) {
+ void *memb_ptr = list->array[edx];
+ erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, 0, 0);
+ if(erval.encoded == -1)
+ return erval;
+ computed_size += erval.encoded;
+
+ /* Compute maximum encoding's size */
+ if(max_encoded_len < erval.encoded)
+ max_encoded_len = erval.encoded;
+ }
+
+ /*
+ * Encode the TLV for the sequence itself.
+ */
+ encoding_size = der_write_tags(sd, computed_size, tag_mode, tag,
+ cb, app_key);
+ if(encoding_size == -1) {
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+ computed_size += encoding_size;
+
+ if(!cb) {
+ erval.encoded = computed_size;
+ return erval;
+ }
+
+ /*
+ * DER mandates dynamic sorting of the SET OF elements
+ * according to their encodings. Build an array of the
+ * encoded elements.
+ */
+ encoded_els = MALLOC(list->count * sizeof(encoded_els[0]));
+ if(encoded_els == NULL) {
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+
+ ASN_DEBUG("Encoding members of %s SET OF", sd->name);
+
+ /*
+ * Encode all members.
+ */
+ for(edx = 0; edx < list->count; edx++) {
+ void *memb_ptr = list->array[edx];
+ struct _el_buffer *encoded_el = &encoded_els[edx];
+
+ /*
+ * Prepare space for encoding.
+ */
+ encoded_el->buf = MALLOC(max_encoded_len);
+ if(encoded_el->buf) {
+ encoded_el->length = 0;
+ encoded_el->size = max_encoded_len;
+ } else {
+ for(edx--; edx >= 0; edx--)
+ FREEMEM(encoded_els[edx].buf);
+ FREEMEM(encoded_els);
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+
+ /*
+ * Encode the member into the prepared space.
+ */
+ erval = der_encoder(elm_type, memb_ptr, 0, elm->tag,
+ _el_addbytes, encoded_el);
+ if(erval.encoded == -1) {
+ for(; edx >= 0; edx--)
+ FREEMEM(encoded_els[edx].buf);
+ FREEMEM(encoded_els);
+ return erval;
+ }
+ encoding_size += erval.encoded;
+ }
+
+ /*
+ * Sort the encoded elements according to their encoding.
+ */
+ qsort(encoded_els, list->count, sizeof(encoded_els[0]), _el_buf_cmp);
+
+ /*
+ * Report encoded elements to the application.
+ * Dispose of temporary sorted members table.
+ */
+ ret = 0;
+ for(edx = 0; edx < list->count; edx++) {
+ struct _el_buffer *encoded_el = &encoded_els[edx];
+ /* Report encoded chunks to the application */
+ if(ret == 0
+ && cb(encoded_el->buf, encoded_el->length, app_key) == -1)
+ ret = -1;
+ FREEMEM(encoded_el->buf);
+ }
+ FREEMEM(encoded_els);
+
+ if(ret || computed_size != encoding_size) {
+ /*
+ * Standard callback failed, or
+ * encoded size is not equal to the computed size.
+ */
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ } else {
+ erval.encoded = computed_size;
+ }
+
+ return erval;
+}
+
+int
+SET_OF_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn1_SET_OF_specifics_t *specs = td->specifics;
+ asn1_SET_OF_element_t *element = specs->element;
+ const A_SET_OF(void) *list = sptr;
+ int ret;
+ int i;
+
+ if(!sptr) return cb("<absent>", 8, app_key);
+
+ /* Dump preamble */
+ if(cb(td->name, strlen(td->name), app_key)
+ || cb(" ::= {\n", 7, app_key))
+ return -1;
+
+ for(i = 0; i < list->count; i++) {
+ const void *memb_ptr = list->array[i];
+ if(!memb_ptr) continue;
+
+ /* Indentation */
+ for(ret = 0; ret < ilevel; ret++) cb(" ", 1, app_key);
+
+ ret = element->type->print_struct(element->type, memb_ptr,
+ ilevel + 4, cb, app_key);
+ if(ret) return ret;
+
+ ret = cb("\n", 1, app_key);
+ if(ret) return ret;
+ }
+
+ /* Indentation */
+ for(ret = 0; ret < ilevel - 4; ret++) cb(" ", 1, app_key);
+
+ return cb("}", 1, app_key);
+}
+
+void
+SET_OF_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+ if(td && ptr) {
+ asn1_SET_OF_specifics_t *specs = td->specifics;
+ asn1_SET_OF_element_t *element = specs->element;
+ A_SET_OF(void) *list = ptr;
+ int i;
+
+ /*
+ * Could not use set_of_empty() because of (*free)
+ * incompatibility.
+ */
+ for(i = 0; i < list->count; i++) {
+ void *memb_ptr = list->array[i];
+ if(memb_ptr)
+ element->type->free_struct(element->type, memb_ptr, 0);
+ }
+ list->count = 0; /* Just in case */
+
+ if(!contents_only) {
+ FREEMEM(ptr);
+ }
+ }
+}
+
+int
+SET_OF_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ asn1_SET_OF_specifics_t *specs = td->specifics;
+ asn1_SET_OF_element_t *element = specs->element;
+ const A_SET_OF(void) *list = sptr;
+ int i;
+
+ if(!sptr) {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ for(i = 0; i < list->count; i++) {
+ const void *memb_ptr = list->array[i];
+ if(!memb_ptr) continue;
+ return element->type->check_constraints(element->type, memb_ptr,
+ app_errlog, app_key);
+ }
+
+ return 0;
+}
diff --git a/skeletons/constr_SET_OF.h b/skeletons/constr_SET_OF.h
new file mode 100644
index 00000000..814774dc
--- /dev/null
+++ b/skeletons/constr_SET_OF.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _CONSTR_SET_OF_H_
+#define _CONSTR_SET_OF_H_
+
+#include <constr_TYPE.h>
+
+typedef struct asn1_SET_OF_element_s {
+ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */
+ asn1_TYPE_descriptor_t
+ *type; /* Member type descriptor */
+} asn1_SET_OF_element_t;
+
+typedef struct asn1_SET_OF_specifics_s {
+ /*
+ * Target structure description.
+ */
+ int struct_size; /* Size of the target structure. */
+ int ctx_offset; /* Offset of the ber_dec_ctx_t member */
+
+ /*
+ * Members of the SET OF list.
+ */
+ asn1_SET_OF_element_t *element;
+} asn1_SET_OF_specifics_t;
+
+/*
+ * A set specialized functions dealing with the SET OF type.
+ */
+asn_constr_check_f SET_OF_constraint;
+ber_type_decoder_f SET_OF_decode_ber;
+der_type_encoder_f SET_OF_encode_der;
+asn_struct_print_f SET_OF_print;
+asn_struct_free_f SET_OF_free;
+
+#endif /* _CONSTR_SET_OF_H_ */
diff --git a/skeletons/constr_TYPE.c b/skeletons/constr_TYPE.c
new file mode 100644
index 00000000..9ab1bdc5
--- /dev/null
+++ b/skeletons/constr_TYPE.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_TYPE.h>
+#include <errno.h>
+
+static asn_app_consume_bytes_f _print2fp;
+
+/*
+ * Return the outmost tag of the type.
+ */
+ber_tlv_tag_t
+asn1_TYPE_outmost_tag(asn1_TYPE_descriptor_t *type_descriptor,
+ const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag) {
+
+ if(tag_mode)
+ return tag;
+
+ if(type_descriptor->tags_count)
+ return type_descriptor->tags[0];
+
+ return type_descriptor->outmost_tag(type_descriptor, struct_ptr, 0, 0);
+}
+
+/*
+ * Print the target language's structure in human readable form.
+ */
+int
+asn_fprint(FILE *stream, asn1_TYPE_descriptor_t *td, const void *struct_ptr) {
+ if(!stream) stream = stdout;
+ if(!td || !struct_ptr) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Invoke type-specific printer */
+ if(td->print_struct(td, struct_ptr, 4, _print2fp, stream))
+ return -1;
+
+ /* Terminate the output */
+ if(_print2fp("\n", 1, stream))
+ return -1;
+
+ return fflush(stream);
+}
+
+/* Dump the data into the specified stdio stream */
+static int
+_print2fp(const void *buffer, size_t size, void *app_key) {
+ FILE *stream = app_key;
+
+ if(fwrite(buffer, 1, size, stream) != size)
+ return -1;
+
+ return 0;
+}
+
diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h
new file mode 100644
index 00000000..c7cfb22b
--- /dev/null
+++ b/skeletons/constr_TYPE.h
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _CONSTR_TYPE_H_
+#define _CONSTR_TYPE_H_
+
+#include <asn_types.h> /* System-dependent types */
+#include <ber_tlv_length.h>
+#include <ber_tlv_tag.h>
+#include <ber_decoder.h>
+#include <der_encoder.h>
+#include <constraints.h>
+
+struct asn1_TYPE_descriptor_s; /* Forward declaration */
+
+/*
+ * Free the structure according to its specification.
+ * If (free_contents_only) is set, the wrapper structure itself (struct_ptr)
+ * will not be freed. (It may be useful in case the structure is allocated
+ * statically or arranged on the stack, yet its elements are allocated
+ * dynamically.)
+ */
+typedef void (asn_struct_free_f)(
+ struct asn1_TYPE_descriptor_s *type_descriptor,
+ void *struct_ptr, int free_contents_only);
+
+/*
+ * Print the structure according to its specification.
+ */
+typedef int (asn_struct_print_f)(
+ struct asn1_TYPE_descriptor_s *type_descriptor,
+ const void *struct_ptr,
+ int level, /* Indentation level */
+ asn_app_consume_bytes_f *callback, void *app_key);
+
+/*
+ * Return the outmost tag of the type.
+ * If the type is untagged CHOICE, the dynamic operation is performed.
+ * NOTE: This function pointer type is only useful internally.
+ * Do not use it in your application.
+ */
+typedef ber_tlv_tag_t (asn_outmost_tag_f)(
+ struct asn1_TYPE_descriptor_s *type_descriptor,
+ const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag);
+/* The instance of the above function type */
+asn_outmost_tag_f asn1_TYPE_outmost_tag;
+
+
+/*
+ * The definitive description of the destination language's structure.
+ */
+typedef struct asn1_TYPE_descriptor_s {
+ char *name; /* A name of the ASN.1 type */
+
+ /*
+ * Generalized functions for dealing with the specific type.
+ * May be directly invoked by applications.
+ */
+ asn_constr_check_f *check_constraints; /* Constraints validator */
+ ber_type_decoder_f *ber_decoder; /* Free-form BER decoder */
+ der_type_encoder_f *der_encoder; /* Canonical DER encoder */
+ asn_struct_print_f *print_struct; /* Human readable output */
+ asn_struct_free_f *free_struct; /* Free the structure */
+
+ /*
+ * Functions used internally. Should not be used by applications.
+ */
+ asn_outmost_tag_f *outmost_tag; /* <optional, internal> */
+
+ /*
+ * Tags that are expected, with some of their vital properties.
+ */
+ ber_tlv_tag_t *tags; /* At least one tag must be specified */
+ int tags_count; /* Number of tags which are expected */
+ int tags_impl_skip; /* Tags to skip in implicit mode */
+ int last_tag_form; /* Acceptable form of the tag (prim, constr) */
+
+ /*
+ * Additional information describing the type, used by appropriate
+ * functions above.
+ */
+ void *specifics;
+} asn1_TYPE_descriptor_t;
+
+/*
+ * This function is a wrapper around (td)->print_struct, which prints out
+ * the contents of the target language's structure (struct_ptr) into the
+ * file pointer (stream) in human readable form.
+ * RETURN VALUES:
+ * 0: The structure is printed.
+ * -1: Problem dumping the structure.
+ */
+int asn_fprint(FILE *stream, /* Destination stream descriptor */
+ asn1_TYPE_descriptor_t *td, /* ASN.1 type descriptor */
+ const void *struct_ptr); /* Structure to be printed */
+
+#endif /* _CONSTR_TYPE_H_ */
diff --git a/skeletons/constraints.c b/skeletons/constraints.c
new file mode 100644
index 00000000..13a1b402
--- /dev/null
+++ b/skeletons/constraints.c
@@ -0,0 +1,111 @@
+#include <constraints.h>
+#include <constr_TYPE.h>
+
+int
+asn_generic_no_constraint(asn1_TYPE_descriptor_t *type_descriptor,
+ const void *struct_ptr, asn_app_consume_bytes_f *cb, void *key) {
+ /* Nothing to check */
+ return 0;
+}
+
+int
+asn_generic_unknown_constraint(asn1_TYPE_descriptor_t *type_descriptor,
+ const void *struct_ptr, asn_app_consume_bytes_f *cb, void *key) {
+ /* Unknown how to check */
+ return 0;
+}
+
+struct __fill_errbuf_arg {
+ char *errbuf;
+ size_t errlen;
+ size_t erroff;
+};
+
+static int
+__fill_errbuf(const void *buffer, size_t size, void *app_key) {
+ struct __fill_errbuf_arg *arg = app_key;
+ size_t avail = arg->errlen - arg->erroff;
+
+ if(avail > size)
+ avail = size + 1;
+
+ switch(avail) {
+ default:
+ memcpy(arg->errbuf + arg->erroff, buffer, avail - 1);
+ arg->erroff += avail - 1;
+ case 1:
+ arg->errbuf[arg->erroff] = '\0';
+ case 0:
+ return 0;
+ }
+
+}
+
+int
+asn_check_constraints(asn1_TYPE_descriptor_t *type_descriptor,
+ const void *struct_ptr, char *errbuf, size_t *errlen) {
+
+ if(errlen) {
+ struct __fill_errbuf_arg arg;
+ int ret;
+
+ arg.errbuf = errbuf;
+ arg.errlen = *errlen;
+ arg.erroff = 0;
+
+ ret = type_descriptor->check_constraints(type_descriptor,
+ struct_ptr, __fill_errbuf, &arg);
+
+ if(ret == -1)
+ *errlen = arg.erroff;
+
+ return ret;
+ } else {
+ return type_descriptor->check_constraints(type_descriptor,
+ struct_ptr, 0, 0);
+ }
+}
+
+void
+_asn_i_log_error(asn_app_consume_bytes_f *cb, void *key, const char *fmt, ...) {
+ char buf[64];
+ char *p;
+ va_list ap;
+ ssize_t ret;
+ size_t len;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ if(ret < 0) {
+ /*
+ * The libc on this system is broken.
+ */
+ ret = sizeof("<broken vsnprintf>") - 1;
+ memcpy(buf, "<broken vsnprintf>", ret + 1);
+ /* Fall through */
+ }
+
+ if(ret < sizeof(buf)) {
+ cb(buf, ret, key);
+ return;
+ }
+
+ /*
+ * More space required to hold the message.
+ */
+ len = ret + 1;
+ p = alloca(len);
+ if(!p) return; /* Can't be though. */
+
+
+ va_start(ap, fmt);
+ ret = vsnprintf(buf, len, fmt, ap);
+ va_end(ap);
+ if(ret < 0 || ret >= len) {
+ ret = sizeof("<broken vsnprintf>") - 1;
+ memcpy(buf, "<broken vsnprintf>", ret + 1);
+ }
+
+ cb(buf, ret, key);
+}
diff --git a/skeletons/constraints.h b/skeletons/constraints.h
new file mode 100644
index 00000000..255b6ae2
--- /dev/null
+++ b/skeletons/constraints.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _ASN1_CONSTRAINTS_VALIDATOR_H_
+#define _ASN1_CONSTRAINTS_VALIDATOR_H_
+
+#include <asn_types.h> /* System-dependent types */
+
+struct asn1_TYPE_descriptor_s; /* Forward declaration */
+
+/*
+ * Validate the structure according to the ASN.1 constraints.
+ * If errbuf and errlen are given, they shall be pointing to the appropriate
+ * buffer space and its length before calling this function. Alternatively,
+ * they could be passed as NULL's. If constraints validation fails,
+ * errlen will contain the actual number of bytes taken from the errbuf
+ * to encode an error message (properly 0-terminated).
+ */
+int
+asn_check_constraints(struct asn1_TYPE_descriptor_s *type_descriptor,
+ const void *struct_ptr, /* Target language's structure */
+ char *errbuf, /* Returned error description */
+ size_t *errlen /* Length of the error description */
+ );
+
+/*
+ * Generic type for constraint checking callback,
+ * associated with every type descriptor.
+ */
+typedef int (asn_constr_check_f)(
+ struct asn1_TYPE_descriptor_s *type_descriptor,
+ const void *struct_ptr,
+ asn_app_consume_bytes_f *optional_app_errlog, /* Log the error */
+ void *optional_app_key /* Opaque key passed to app_errlog */
+ );
+
+/*******************************
+ * INTERNALLY USEFUL FUNCTIONS *
+ *******************************/
+
+asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */
+asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */
+
+/*
+ * Invoke the callback with a complete error message.
+ */
+#define _ASN_ERRLOG(fmt, args...) do { \
+ if(app_errlog) \
+ _asn_i_log_error(app_errlog, \
+ app_key, fmt, ##args); \
+ break; \
+ } while(0);
+void _asn_i_log_error(asn_app_consume_bytes_f *, void *key,
+ const char *fmt, ...) __attribute__ ((format(printf, 3, 4)));
+
+#endif /* _ASN1_CONSTRAINTS_VALIDATOR_H_ */
diff --git a/skeletons/der_encoder.c b/skeletons/der_encoder.c
new file mode 100644
index 00000000..f275f9c1
--- /dev/null
+++ b/skeletons/der_encoder.c
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <constr_TYPE.h>
+#include <assert.h>
+
+static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
+ asn_app_consume_bytes_f *cb, void *app_key, int constructed);
+
+/*
+ * The DER encoder of any type.
+ */
+der_enc_rval_t
+der_encode(asn1_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
+ asn_app_consume_bytes_f *consume_bytes, void *app_key) {
+
+ ASN_DEBUG("DER encoder invoked for %s",
+ type_descriptor->name);
+
+ /*
+ * Invoke type-specific encoder.
+ */
+ return type_descriptor->der_encoder(type_descriptor,
+ struct_ptr, /* Pointer to the destination structure */
+ 0, 0,
+ consume_bytes, app_key);
+}
+
+/*
+ * Write out leading TL[v] sequence according to the type definition.
+ */
+ssize_t
+der_write_tags(asn1_TYPE_descriptor_t *sd,
+ size_t struct_length,
+ int tag_mode,
+ ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */
+ asn_app_consume_bytes_f *cb,
+ void *app_key) {
+ ber_tlv_tag_t *tags; /* Copy of tags stream */
+ int tags_count; /* Number of tags */
+ size_t overall_length;
+ ssize_t *lens;
+ int i;
+
+ if(tag_mode) {
+ /*
+ * Instead of doing shaman dance like we do in ber_check_tags(),
+ * allocate a small array on the stack
+ * and initialize it appropriately.
+ */
+ tags = alloca((sd->tags_count + (tag_mode?1:0))
+ * sizeof(ber_tlv_tag_t));
+ if(tags == NULL) return -1; /* Impossible on i386 */
+ tags_count = sd->tags_count
+ + 1 /* EXPLICIT or IMPLICIT tag is given */
+ - ((tag_mode==-1)?sd->tags_impl_skip:0);
+ /* Copy tags over */
+ tags[0] = tag;
+ for(i = 1; i < tags_count; i++)
+ tags[i] = sd->tags[i - 1 + sd->tags_impl_skip];
+ } else {
+ tags = sd->tags;
+ tags_count = sd->tags_count;
+ }
+
+ /* No tags to write */
+ if(tags_count == 0)
+ return 0;
+
+ lens = alloca(tags_count * sizeof(lens[0]));
+ if(lens == NULL) return -1;
+
+ /*
+ * Array of tags is initialized.
+ * Now, compute the size of the TLV pairs, from right to left.
+ */
+ overall_length = struct_length;
+ for(i = tags_count - 1; i >= 0; --i) {
+ lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
+ if(lens[i] == -1) return -1;
+ overall_length += lens[i];
+ lens[i] = overall_length - lens[i];
+ }
+
+ if(!cb) return overall_length - struct_length;
+
+ ASN_DEBUG("%s %s TL sequence (%d elements)",
+ cb?"Encoding":"Estimating", sd->name, tags_count);
+
+ /*
+ * Encode the TL sequence for real.
+ */
+ for(i = 0; i < tags_count; i++) {
+ ssize_t len;
+ int _constr;
+
+ /* If this one happens to be constructed, do it. */
+ if(i < (tags_count - 1) || sd->last_tag_form == 1)
+ _constr = 1;
+ else _constr = 0;
+
+ len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
+ if(len == -1) return -1;
+ }
+
+ return overall_length - struct_length;
+}
+
+static ssize_t
+der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
+ asn_app_consume_bytes_f *cb, void *app_key,
+ int constructed) {
+ uint8_t buf[32];
+ size_t size = 0;
+ int buf_size = cb?sizeof(buf):0;
+ ssize_t tmp;
+
+ /* Serialize tag (T from TLV) into possibly zero-length buffer */
+ tmp = der_tlv_tag_serialize(tag, buf, buf_size);
+ if(tmp == -1 || tmp > sizeof(buf)) return -1;
+ size += tmp;
+
+ /* Serialize length (L from TLV) into possibly zero-length buffer */
+ tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
+ if(tmp == -1) return -1;
+ size += tmp;
+
+ if(size > sizeof(buf))
+ return -1;
+
+ /*
+ * If callback is specified, invoke it, and check its return value.
+ */
+ if(cb) {
+ if(constructed) *buf |= 0x20;
+ if(cb(buf, size, app_key) == -1) {
+ return -1;
+ }
+ }
+
+ return size;
+}
diff --git a/skeletons/der_encoder.h b/skeletons/der_encoder.h
new file mode 100644
index 00000000..052d9f4c
--- /dev/null
+++ b/skeletons/der_encoder.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _DER_ENCODER_H_
+#define _DER_ENCODER_H_
+
+#include <constr_TYPE.h>
+
+struct asn1_TYPE_descriptor_s; /* Forward declaration */
+
+/*
+ * Type of the return value of the der_encode function.
+ */
+typedef struct der_enc_rval_s {
+ /*
+ * Number of bytes encoded.
+ * -1 indicates failure to encode the structure.
+ * In this case, the members below this one are meaningful.
+ */
+ ssize_t encoded;
+
+ /*
+ * Members meaningful when (encoded == -1), for post-mortem analysis.
+ */
+
+ /* Type which cannot be encoded */
+ struct asn1_TYPE_descriptor_s *failed_type;
+
+ /* Pointer to the structure of that type */
+ void *structure_ptr;
+} der_enc_rval_t;
+
+
+/*
+ * The DER encoder of any type. May be invoked by the application.
+ */
+der_enc_rval_t der_encode(struct asn1_TYPE_descriptor_s *type_descriptor,
+ void *struct_ptr, /* Structure to be encoded */
+ asn_app_consume_bytes_f *consume_bytes_cb,
+ void *app_key /* Arbitrary callback argument */
+ );
+
+/*
+ * Type of the generic DER encoder.
+ */
+typedef der_enc_rval_t (der_type_encoder_f)(
+ struct asn1_TYPE_descriptor_s *type_descriptor,
+ void *struct_ptr, /* Structure to be encoded */
+ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */
+ ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */
+ void *app_key /* Arbitrary callback argument */
+ );
+
+
+/*******************************
+ * INTERNALLY USEFUL FUNCTIONS *
+ *******************************/
+
+/*
+ * Write out leading TL[v] sequence according to the type definition.
+ */
+ssize_t der_write_tags(
+ struct asn1_TYPE_descriptor_s *type_descriptor,
+ size_t struct_length,
+ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */
+ ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *consume_bytes_cb,
+ void *app_key
+ );
+
+#endif /* _DER_ENCODER_H_ */
diff --git a/skeletons/tests/Makefile.am b/skeletons/tests/Makefile.am
new file mode 100644
index 00000000..e620ade6
--- /dev/null
+++ b/skeletons/tests/Makefile.am
@@ -0,0 +1,9 @@
+AM_CPPFLAGS = -I${top_srcdir}/skeletons
+
+check_PROGRAMS = \
+ check-GeneralizedTime \
+ check-UTCTime \
+ check-INTEGER \
+ check-OIDs
+
+TESTS = ${check_PROGRAMS}
diff --git a/skeletons/tests/Makefile.in b/skeletons/tests/Makefile.in
new file mode 100644
index 00000000..779f93a5
--- /dev/null
+++ b/skeletons/tests/Makefile.in
@@ -0,0 +1,411 @@
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+ADD_CFLAGS = @ADD_CFLAGS@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AWK = @AWK@
+CC = @CC@
+CONFIGURE_DEPENDS = @CONFIGURE_DEPENDS@
+CPP = @CPP@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+EXEEXT = @EXEEXT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LEX = @LEX@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PATH = @PATH@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+
+AM_CPPFLAGS = -I${top_srcdir}/skeletons
+
+check_PROGRAMS = \
+ check-GeneralizedTime \
+ check-UTCTime \
+ check-INTEGER \
+ check-OIDs
+
+
+TESTS = ${check_PROGRAMS}
+subdir = skeletons/tests
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+check_PROGRAMS = check-GeneralizedTime$(EXEEXT) check-UTCTime$(EXEEXT) \
+ check-INTEGER$(EXEEXT) check-OIDs$(EXEEXT)
+check_GeneralizedTime_SOURCES = check-GeneralizedTime.c
+check_GeneralizedTime_OBJECTS = check-GeneralizedTime.$(OBJEXT)
+check_GeneralizedTime_LDADD = $(LDADD)
+check_GeneralizedTime_DEPENDENCIES =
+check_GeneralizedTime_LDFLAGS =
+check_INTEGER_SOURCES = check-INTEGER.c
+check_INTEGER_OBJECTS = check-INTEGER.$(OBJEXT)
+check_INTEGER_LDADD = $(LDADD)
+check_INTEGER_DEPENDENCIES =
+check_INTEGER_LDFLAGS =
+check_OIDs_SOURCES = check-OIDs.c
+check_OIDs_OBJECTS = check-OIDs.$(OBJEXT)
+check_OIDs_LDADD = $(LDADD)
+check_OIDs_DEPENDENCIES =
+check_OIDs_LDFLAGS =
+check_UTCTime_SOURCES = check-UTCTime.c
+check_UTCTime_OBJECTS = check-UTCTime.$(OBJEXT)
+check_UTCTime_LDADD = $(LDADD)
+check_UTCTime_DEPENDENCIES =
+check_UTCTime_LDFLAGS =
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/check-GeneralizedTime.Po \
+@AMDEP_TRUE@ $(DEPDIR)/check-INTEGER.Po $(DEPDIR)/check-OIDs.Po \
+@AMDEP_TRUE@ $(DEPDIR)/check-UTCTime.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+ $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+DIST_SOURCES = check-GeneralizedTime.c check-INTEGER.c check-OIDs.c \
+ check-UTCTime.c
+DIST_COMMON = Makefile.am Makefile.in
+SOURCES = check-GeneralizedTime.c check-INTEGER.c check-OIDs.c check-UTCTime.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu skeletons/tests/Makefile
+Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && \
+ CONFIG_HEADERS= CONFIG_LINKS= \
+ CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+
+clean-checkPROGRAMS:
+ -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS)
+check-GeneralizedTime$(EXEEXT): $(check_GeneralizedTime_OBJECTS) $(check_GeneralizedTime_DEPENDENCIES)
+ @rm -f check-GeneralizedTime$(EXEEXT)
+ $(LINK) $(check_GeneralizedTime_LDFLAGS) $(check_GeneralizedTime_OBJECTS) $(check_GeneralizedTime_LDADD) $(LIBS)
+check-INTEGER$(EXEEXT): $(check_INTEGER_OBJECTS) $(check_INTEGER_DEPENDENCIES)
+ @rm -f check-INTEGER$(EXEEXT)
+ $(LINK) $(check_INTEGER_LDFLAGS) $(check_INTEGER_OBJECTS) $(check_INTEGER_LDADD) $(LIBS)
+check-OIDs$(EXEEXT): $(check_OIDs_OBJECTS) $(check_OIDs_DEPENDENCIES)
+ @rm -f check-OIDs$(EXEEXT)
+ $(LINK) $(check_OIDs_LDFLAGS) $(check_OIDs_OBJECTS) $(check_OIDs_LDADD) $(LIBS)
+check-UTCTime$(EXEEXT): $(check_UTCTime_OBJECTS) $(check_UTCTime_DEPENDENCIES)
+ @rm -f check-UTCTime$(EXEEXT)
+ $(LINK) $(check_UTCTime_LDFLAGS) $(check_UTCTime_OBJECTS) $(check_UTCTime_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/check-GeneralizedTime.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/check-INTEGER.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/check-OIDs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/check-UTCTime.Po@am__quote@
+
+distclean-depend:
+ -rm -rf $(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+GTAGS:
+ here=`CDPATH=: && cd $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list='$(TESTS)'; \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *" $$tst "*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ echo "XPASS: $$tst"; \
+ ;; \
+ *) \
+ echo "PASS: $$tst"; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *" $$tst "*) \
+ xfail=`expr $$xfail + 1`; \
+ echo "XFAIL: $$tst"; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ echo "FAIL: $$tst"; \
+ ;; \
+ esac; \
+ fi; \
+ done; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="All $$all tests passed"; \
+ else \
+ banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all tests failed"; \
+ else \
+ banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+ fi; \
+ fi; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"; \
+ test "$$failed" -eq 0; \
+ fi
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ $(mkinstalldirs) "$(distdir)/$$dir"; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+uninstall-am: uninstall-info-am
+
+.PHONY: GTAGS all all-am check check-TESTS check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool distclean \
+ distclean-compile distclean-depend distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am info \
+ info-am install install-am install-data install-data-am \
+ install-exec install-exec-am install-info install-info-am \
+ install-man install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool tags uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/skeletons/tests/check-GeneralizedTime.c b/skeletons/tests/check-GeneralizedTime.c
new file mode 100644
index 00000000..3451cffe
--- /dev/null
+++ b/skeletons/tests/check-GeneralizedTime.c
@@ -0,0 +1,54 @@
+#define __NO_ASN_TABLE__
+#include "../GeneralizedTime.c"
+#include "../constraints.c"
+
+static void
+check(char *time_str, time_t sample) {
+ GeneralizedTime_t gt;
+ struct tm tm;
+ time_t tloc;
+
+ gt.buf = time_str;
+ gt.size = strlen(time_str);
+
+ tloc = asn_GT2time(&gt, &tm);
+ printf("[%s] -> %ld == %ld\n", time_str, (long)tloc, (long)sample);
+ if(tloc != -1)
+ printf("\t%d-%d-%dT%02d:%02d:%02d %ld\n",
+ tm.tm_year + 1900,
+ tm.tm_mon + 1,
+ tm.tm_mday,
+ tm.tm_hour,
+ tm.tm_min,
+ tm.tm_sec,
+ tm.tm_gmtoff
+ );
+ assert(tloc == sample);
+}
+
+int
+main(int ac, char **av) {
+
+ check("200401250", -1);
+ check("2004012509300", -1);
+ check("20040125093000-", -1);
+ check("20040125093007-0", -1);
+ check("20040125093007-080", -1);
+ check("200401250930.01Z", -1);
+
+ check("20040125093007Z", 1075023007);
+ check("20040125093007+00", 1075023007);
+ check("20040125093007.01+0000", 1075023007);
+ check("20040125093007,1+0000", 1075023007);
+ check("20040125093007-0800", 1075051807);
+
+ if(ac > 1) {
+ /* These will be valid only inside PST time zone */
+ check("20040125093007", 1075051807);
+ check("200401250930", 1075051800);
+ check("20040125093000,01", 1075051800);
+ check("20040125093000,1234", 1075051800);
+ }
+
+ return 0;
+}
diff --git a/skeletons/tests/check-INTEGER.c b/skeletons/tests/check-INTEGER.c
new file mode 100644
index 00000000..4053075e
--- /dev/null
+++ b/skeletons/tests/check-INTEGER.c
@@ -0,0 +1,56 @@
+#include "../INTEGER.c"
+#include "../ber_decoder.c"
+#include "../ber_tlv_length.c"
+#include "../ber_tlv_tag.c"
+#include "../der_encoder.c"
+#include "../constraints.c"
+
+static void
+check(uint8_t *buf, int size, long check_long, int check_ret) {
+ INTEGER_t val;
+ int ret;
+ long rlong = 123;
+
+ assert(buf);
+ assert(size >= 0);
+
+ val.buf = buf;
+ val.size = size;
+
+
+ ret = asn1_INTEGER2long(&val, &rlong);
+ printf("Testing (%ld, %d) vs (%ld, %d)\n",
+ rlong, ret, check_long, check_ret);
+ assert(ret == check_ret);
+ if(ret == -1) return;
+ assert(rlong == check_long);
+}
+
+int
+main(int ac, char **av) {
+ uint8_t buf1[] = { 1 };
+ uint8_t buf2[] = { 0xff };
+ uint8_t buf3[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ uint8_t buf4[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 };
+ uint8_t buf5[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+ uint8_t buf6[] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ uint8_t buf7[] = { 0xff, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ uint8_t buf8[] = { 0x7f, 0x7e, 0x7d, 0x7c };
+ uint8_t buf9[] = { 0, 0x7f, 0x7e, 0x7d, 0x7c };
+ uint8_t buf10[] = { 0, 0, 0, 0, 0, 0, 0x7f, 0x7e, 0x7d, 0x7c };
+
+#define CHECK(buf, val, ret) check(buf, sizeof(buf), val, ret)
+
+ CHECK(buf1, 1, 0);
+ CHECK(buf2, -1, 0);
+ CHECK(buf3, -1, 0);
+ CHECK(buf4, -16, 0);
+ CHECK(buf5, 257, 0);
+ CHECK(buf6, 123, -1);
+ CHECK(buf7, 123, -1);
+ CHECK(buf8, 0x7F7E7D7C, 0);
+ CHECK(buf9, 0x7F7E7D7C, 0);
+ CHECK(buf10, 0x7F7E7D7C, 0);
+
+ return 0;
+}
diff --git a/skeletons/tests/check-OIDs.c b/skeletons/tests/check-OIDs.c
new file mode 100644
index 00000000..a97a910a
--- /dev/null
+++ b/skeletons/tests/check-OIDs.c
@@ -0,0 +1,228 @@
+#include "../RELATIVE-OID.c"
+#include "../OBJECT_IDENTIFIER.c"
+#include "../INTEGER.c"
+#include "../ber_decoder.c"
+#include "../ber_tlv_length.c"
+#include "../ber_tlv_tag.c"
+#include "../der_encoder.c"
+#include "../constraints.c"
+
+static int
+_print(const void *buffer, size_t size, void *app_key) {
+ fwrite(buffer, size, 1, stdout);
+ return 0;
+}
+
+static void
+check_OID(uint8_t *buf, size_t len, int *ck_buf, int ck_len) {
+ OBJECT_IDENTIFIER_t *oid;
+ ber_dec_rval_t rval;
+ unsigned long arcs[10];
+ int alen;
+ int i;
+
+ printf("Checking {");
+ for(i = 0; i < len; i++) { printf("%s%02x", i?" ":"", buf[i]); }
+ printf("} against {");
+ for(i = 0; i < ck_len; i++) { printf("%s%d", i?" ":"", ck_buf[i]); }
+ printf("}\n");
+
+ oid = NULL;
+ rval = ber_decode(&asn1_DEF_OBJECT_IDENTIFIER, (void *)&oid, buf, len);
+ assert(rval.code == RC_OK);
+
+ assert(oid->size == len - 2);
+
+ /*
+ * Print the contents for visual debugging.
+ */
+ printf("OBJECT_IDENTIFIER_print() => ");
+ OBJECT_IDENTIFIER_print(&asn1_DEF_OBJECT_IDENTIFIER, oid, 0, _print, 0);
+ printf("\n");
+
+ alen = OBJECT_IDENTIFIER_get_arcs_l(oid,
+ arcs, sizeof(arcs)/sizeof(arcs[0]));
+ assert(alen > 0);
+ assert(alen == ck_len);
+
+ /*
+ * Make sure they are equivalent.
+ */
+ printf("OBJECT_IDENTIFIER_get_arcs() => {");
+ for(i = 0; i < alen; i++) {
+ printf(" %lu", arcs[i]);
+ assert(arcs[i] == ck_buf[i]);
+ }
+ printf(" }\n");
+}
+
+static void
+check_ROID(uint8_t *buf, size_t len, int *ck_buf, int ck_len) {
+ RELATIVE_OID_t *oid;
+ ber_dec_rval_t rval;
+ unsigned long arcs[10];
+ int alen;
+ int i;
+
+ printf("Checking {");
+ for(i = 0; i < len; i++) { printf("%s%02x", i?" ":"", buf[i]); }
+ printf("} against {");
+ for(i = 0; i < ck_len; i++) { printf("%s%d", i?" ":"", ck_buf[i]); }
+ printf("}\n");
+
+ oid = NULL;
+ rval = ber_decode(&asn1_DEF_RELATIVE_OID, (void *)&oid, buf, len);
+ assert(rval.code == RC_OK);
+
+ assert(oid->size == len - 2);
+
+ /*
+ * Print the contents for visual debugging.
+ */
+ printf("RELATIVE_OID_print() => ");
+ RELATIVE_OID_print(&asn1_DEF_RELATIVE_OID, oid, 0, _print, 0);
+ printf("\n");
+
+ alen = RELATIVE_OID_get_arcs_l(oid,
+ arcs, sizeof(arcs)/sizeof(arcs[0]));
+ assert(alen > 0);
+ assert(alen == ck_len);
+
+ /*
+ * Make sure they are equivalent.
+ */
+ printf("RELATIVE_OID_get_arcs() => {");
+ for(i = 0; i < alen; i++) {
+ printf(" %lu", (unsigned long)arcs[i]);
+ assert(arcs[i] == ck_buf[i]);
+ }
+ printf(" }\n");
+}
+
+/*
+ * Encode the specified array of arcs as RELATIVE-OID, decode it and compare.
+ */
+static void
+check_REGEN(int *arcs, int acount) {
+ static RELATIVE_OID_t oid;
+ unsigned long tmp_arcs[10];
+ int tmp_alen = 10;
+ int alen;
+ int ret;
+ int i;
+
+ printf("Encoding {");
+ for(i = 0; i < acount; i++) {
+ printf(" %u", arcs[i]);
+ }
+ printf(" }\n");
+
+ ret = RELATIVE_OID_set_arcs_l(&oid, (unsigned long *)arcs, acount);
+ assert(ret == 0);
+
+ alen = RELATIVE_OID_get_arcs_l(&oid, tmp_arcs, tmp_alen);
+ assert(alen >= 0);
+ assert(alen < tmp_alen);
+
+ printf("Encoded {");
+ for(i = 0; i < alen; i++) {
+ printf(" %lu", tmp_arcs[i]);
+ assert(arcs[i] == tmp_arcs[i]);
+ }
+ printf(" }\n");
+}
+
+/*
+ * Encode the specified array of arcs as OBJECT IDENTIFIER,
+ * decode it and compare.
+ */
+static void
+check_REGEN_OID(int *arcs, int acount) {
+ static OBJECT_IDENTIFIER_t oid;
+ unsigned long tmp_arcs[10];
+ int tmp_alen = 10;
+ int alen;
+ int ret;
+ int i;
+
+ printf("Encoding {");
+ for(i = 0; i < acount; i++) {
+ printf(" %u", arcs[i]);
+ }
+ printf(" }\n");
+
+ ret = OBJECT_IDENTIFIER_set_arcs_l(&oid, (unsigned long *)arcs, acount);
+ assert(ret == 0);
+
+ alen = OBJECT_IDENTIFIER_get_arcs_l(&oid, tmp_arcs, tmp_alen);
+ assert(alen >= 0);
+ assert(alen < tmp_alen);
+
+ printf("Encoded {");
+ for(i = 0; i < alen; i++) {
+ printf(" %lu", tmp_arcs[i]);
+ assert(arcs[i] == tmp_arcs[i]);
+ }
+ printf(" }\n");
+}
+
+#define CHECK_OID(n) check_OID(buf ## n, sizeof(buf ## n), \
+ buf ## n ## _check, \
+ sizeof(buf ## n ## _check)/sizeof(buf ## n ## _check[0]))
+#define CHECK_ROID(n) check_ROID(buf ## n, sizeof(buf ## n), \
+ buf ## n ## _check, \
+ sizeof(buf ## n ## _check)/sizeof(buf ## n ## _check[0]))
+#define CHECK_REGEN(n) check_REGEN(buf ## n ## _check, \
+ sizeof(buf ## n ## _check)/sizeof(buf ## n ## _check[0]))
+#define CHECK_REGEN_OID(n) check_REGEN_OID(buf ## n ## _check, \
+ sizeof(buf ## n ## _check)/sizeof(buf ## n ## _check[0]))
+
+int
+main(int ac, char **av) {
+ /* {joint-iso-itu-t 100 3} */
+ uint8_t buf1[] = {
+ 0x06, /* OBJECT IDENTIFIER */
+ 0x03, /* Length */
+ 0x81, 0x34, 0x03
+ };
+ int buf1_check[] = { 2, 100, 3 };
+
+ /* {8571 3 2} */
+ uint8_t buf2[] = {
+ 0x0D, /* RELATIVE-OID */
+ 0x04, /* Length */
+ 0xC2, 0x7B, 0x03, 0x02
+ };
+ int buf2_check[] = { 8571, 3, 2 };
+
+ int buf3_check[] = { 0 };
+ int buf4_check[] = { 1 };
+ int buf5_check[] = { 80, 40 };
+ int buf6_check[] = { 127 };
+ int buf7_check[] = { 128 };
+ int buf8_check[] = { 65535, 65536 };
+ int buf9_check[] = { 100000, 0x20000, 1234, 256, 127, 128 };
+ int buf10_check[] = { 0, 0xffffffff, 0xff00ff00, 0 };
+ int buf11_check[] = { 0, 1, 2 };
+ int buf12_check[] = { 1, 38, 3 };
+ int buf13_check[] = { 0, 0, 0xf000 };
+
+
+ CHECK_OID(1); /* buf1, buf1_check */
+ CHECK_ROID(2); /* buf2, buf2_check */
+
+ CHECK_REGEN(3); /* Regenerate RELATIVE-OID */
+ CHECK_REGEN(4);
+ CHECK_REGEN(5);
+ CHECK_REGEN(6);
+ CHECK_REGEN(7);
+ CHECK_REGEN(8);
+ CHECK_REGEN(9);
+ CHECK_REGEN(10);
+ CHECK_REGEN_OID(1); /* Regenerate OBJECT IDENTIFIER */
+ CHECK_REGEN_OID(11);
+ CHECK_REGEN_OID(12);
+ CHECK_REGEN_OID(13);
+
+ return 0;
+}
diff --git a/skeletons/tests/check-UTCTime.c b/skeletons/tests/check-UTCTime.c
new file mode 100644
index 00000000..7522140e
--- /dev/null
+++ b/skeletons/tests/check-UTCTime.c
@@ -0,0 +1,54 @@
+#define __NO_ASN_TABLE__
+#include "../UTCTime.c"
+#define __NO_ASSERT_H__
+#include "../GeneralizedTime.c"
+#include "../constraints.c"
+
+static void
+check(char *time_str, time_t sample) {
+ UTCTime_t gt;
+ struct tm tm;
+ time_t tloc;
+
+ gt.buf = time_str;
+ gt.size = strlen(time_str);
+
+ tloc = asn_UT2time(&gt, &tm);
+ printf("[%s] -> %ld == %ld\n", time_str, (long)tloc, (long)sample);
+ if(tloc != -1)
+ printf("\t%d-%d-%dT%02d:%02d:%02d %ld\n",
+ tm.tm_year + 1900,
+ tm.tm_mon + 1,
+ tm.tm_mday,
+ tm.tm_hour,
+ tm.tm_min,
+ tm.tm_sec,
+ tm.tm_gmtoff
+ );
+ assert(tloc == sample);
+}
+
+int
+main(int ac, char **av) {
+
+ check("0401250", -1);
+ check("0401250930", -1); /* "Z" or "(+|-)hhmm" required */
+ check("04012509300", -1);
+ check("040125093000-", -1);
+ check("040125093007-0", -1);
+ check("040125093007-080", -1);
+ check("0401250930.01Z", -1);
+
+ check("040125093007Z", 1075023007);
+ check("040125093007+00", 1075023007);
+ check("040125093007-0800", 1075051807);
+
+ if(ac > 1) {
+ /* These will be valid only inside PST time zone */
+ check("040125093007", 1075051807);
+ check("040125093000,01", 1075051800);
+ check("040125093000,1234", 1075051800);
+ }
+
+ return 0;
+}