aboutsummaryrefslogtreecommitdiffstats
path: root/lib/asn1/c_src/asn1_erl_nif.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asn1/c_src/asn1_erl_nif.c')
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c432
1 files changed, 329 insertions, 103 deletions
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c
index 58314e23c2..9c9f83bc2a 100644
--- a/lib/asn1/c_src/asn1_erl_nif.c
+++ b/lib/asn1/c_src/asn1_erl_nif.c
@@ -46,10 +46,6 @@
#define ASN1_PRIMITIVE 0
#define ASN1_CONSTRUCTED 0x20
-#define ASN1_COMPLETE 1
-#define ASN1_BER_TLV_DECODE 2
-#define ASN1_BER_TLV_PARTIAL_DECODE 3
-
#define ASN1_NOVALUE 0
#define ASN1_SKIPPED 0
@@ -61,38 +57,55 @@
#define INVMASK(X,M) (X & (M ^ 0xff))
#define MASK(X,M) (X & M)
-int complete(ErlNifBinary *, unsigned char *, int );
+/* PER COMPLETE */
+int per_complete(ErlNifBinary *, unsigned char *, int);
-int insert_octets(int, unsigned char **, unsigned char **, int *);
+int per_insert_octets(int, unsigned char **, unsigned char **, int *);
-int insert_octets_except_unused(int, unsigned char **, unsigned char **, int *,
- int);
+int per_insert_octets_except_unused(int, unsigned char **, unsigned char **,
+ int *, int);
-int insert_octets_as_bits_exact_len(int, int, unsigned char **,
+int per_insert_octets_as_bits_exact_len(int, int, unsigned char **,
unsigned char **, int *);
-int insert_octets_as_bits(int, unsigned char **, unsigned char **, int *);
+int per_insert_octets_as_bits(int, unsigned char **, unsigned char **, int *);
-int pad_bits(int, unsigned char **, int *);
+int per_pad_bits(int, unsigned char **, int *);
-int insert_least_sign_bits(int, unsigned char, unsigned char **, int *);
+int per_insert_least_sign_bits(int, unsigned char, unsigned char **, int *);
-int insert_most_sign_bits(int, unsigned char, unsigned char **, int *);
+int per_insert_most_sign_bits(int, unsigned char, unsigned char **, int *);
-int insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *);
+int per_insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *);
-int insert_octets_unaligned(int, unsigned char **, unsigned char **, int);
+int per_insert_octets_unaligned(int, unsigned char **, unsigned char **, int);
-int realloc_memory(ErlNifBinary *, int, unsigned char **);
+int per_realloc_memory(ErlNifBinary *, int, unsigned char **);
-int decode_begin(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int,
+/* BER DECODE */
+int ber_decode_begin(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int,
unsigned int *);
-int decode(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int *, int);
+int ber_decode(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int *, int);
+
+int ber_decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *);
+
+int ber_decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int,
+ int);
+
+/* BER ENCODE */
+typedef struct ber_encode_mem_chunk mem_chunk_t;
+
+int ber_encode(ErlNifEnv *, ERL_NIF_TERM , mem_chunk_t **, unsigned int *);
-int decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *);
+void ber_free_chunks(mem_chunk_t *chunk);
+mem_chunk_t *ber_new_chunk(unsigned int length);
+int ber_check_memory(mem_chunk_t **curr, unsigned int needed);
-int decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int, int);
+int ber_encode_tag(ErlNifEnv *, ERL_NIF_TERM , unsigned int ,
+ mem_chunk_t **, unsigned int *);
+
+int ber_encode_length(size_t , mem_chunk_t **, unsigned int *);
/*
*
@@ -101,7 +114,8 @@ int decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int, int);
*
*/
-int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
+int per_complete(ErlNifBinary *out_binary, unsigned char *in_buf,
+ int in_buf_len) {
int counter = in_buf_len;
/* counter keeps track of number of bytes left in the
input buffer */
@@ -175,7 +189,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
no_bits = (int) *(++in_ptr);
val = *(++in_ptr);
counter -= 2;
- if ((ret = insert_least_sign_bits(no_bits, val, &ptr, &unused))
+ if ((ret = per_insert_least_sign_bits(no_bits, val, &ptr, &unused))
== ASN1_ERROR
)
return ASN1_ERROR;
@@ -189,8 +203,8 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
no_bytes = (int) *(++in_ptr);
counter -= (no_bytes + 1);
if ((counter < 0)
- || (ret = insert_octets(no_bytes, &in_ptr, &ptr, &unused))
- == ASN1_ERROR
+ || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr,
+ &unused)) == ASN1_ERROR
)
return ASN1_ERROR;
buf_space -= ret;
@@ -205,8 +219,8 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
no_bytes = no_bytes | (int) *(++in_ptr);
counter -= (2 + no_bytes);
if ((counter < 0)
- || (ret = insert_octets(no_bytes, &in_ptr, &ptr, &unused))
- == ASN1_ERROR
+ || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr,
+ &unused)) == ASN1_ERROR
)
return ASN1_ERROR;
buf_space -= ret;
@@ -222,7 +236,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
counter -= (2 + no_bytes);
ret = -4711;
if ((counter < 0)
- || (ret = insert_octets_except_unused(no_bytes, &in_ptr,
+ || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr,
&ptr, &unused, in_unused)) == ASN1_ERROR
)
return ASN1_ERROR;
@@ -241,7 +255,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
no_bytes = no_bytes | (int) *(++in_ptr);
counter -= (3 + no_bytes);
if ((counter < 0)
- || (ret = insert_octets_except_unused(no_bytes, &in_ptr,
+ || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr,
&ptr, &unused, in_unused)) == ASN1_ERROR
)
return ASN1_ERROR;
@@ -273,15 +287,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
/* Have to allocate more memory */
buf_size += needed;
buf_space += needed;
- if (realloc_memory(out_binary, buf_size, &ptr)
- == ASN1_ERROR
- )
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
return ASN1_ERROR;
}
counter -= (2 + no_bytes);
if ((counter < 0)
- || (ret = insert_octets_as_bits_exact_len(desired_len,
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
)
return ASN1_ERROR;
@@ -302,15 +315,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
/* Have to allocate more memory */
buf_size += needed;
buf_space += needed;
- if (realloc_memory(out_binary, buf_size, &ptr)
- == ASN1_ERROR
- )
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
return ASN1_ERROR;
}
counter -= (3 + no_bytes);
if ((counter < 0)
- || (ret = insert_octets_as_bits_exact_len(desired_len,
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
)
return ASN1_ERROR;
@@ -331,15 +343,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
/* Have to allocate more memory */
buf_size += needed;
buf_space += needed;
- if (realloc_memory(out_binary, buf_size, &ptr)
- == ASN1_ERROR
- )
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
return ASN1_ERROR;
}
counter -= (3 + no_bytes);
if ((counter < 0)
- || (ret = insert_octets_as_bits_exact_len(desired_len,
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
)
return ASN1_ERROR;
@@ -362,15 +373,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
/* Have to allocate more memory */
buf_size += needed;
buf_space += needed;
- if (realloc_memory(out_binary, buf_size, &ptr)
- == ASN1_ERROR
- )
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
return ASN1_ERROR;
}
counter -= (4 + no_bytes);
if ((counter < 0)
- || (ret = insert_octets_as_bits_exact_len(desired_len,
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
)
return ASN1_ERROR;
@@ -392,16 +402,15 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
/* Have to allocate more memory */
buf_size += needed;
buf_space += needed;
- if (realloc_memory(out_binary, buf_size, &ptr)
- == ASN1_ERROR
- )
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
return ASN1_ERROR;
}
counter -= (2 + no_bytes);
if ((counter < 0)
- || (ret = insert_bits_as_bits(desired_len, no_bytes,
+ || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
&in_ptr, &ptr, &unused)) == ASN1_ERROR
)
return ASN1_ERROR;
@@ -422,15 +431,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
/* Have to allocate more memory */
buf_size += needed;
buf_space += needed;
- if (realloc_memory(out_binary, buf_size, &ptr)
- == ASN1_ERROR
- )
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
return ASN1_ERROR;
}
counter -= (3 + no_bytes);
if ((counter < 0)
- || (ret = insert_bits_as_bits(desired_len, no_bytes,
+ || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
&in_ptr, &ptr, &unused)) == ASN1_ERROR
)
return ASN1_ERROR;
@@ -453,15 +461,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
/* Have to allocate more memory */
buf_size += needed;
buf_space += needed;
- if (realloc_memory(out_binary, buf_size, &ptr)
- == ASN1_ERROR
- )
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
return ASN1_ERROR;
}
counter -= (4 + no_bytes);
if ((counter < 0)
- || (ret = insert_bits_as_bits(desired_len, no_bytes,
+ || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
&in_ptr, &ptr, &unused)) == ASN1_ERROR
)
return ASN1_ERROR;
@@ -483,7 +490,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) {
}
}
-int realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) {
+int per_realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) {
int i = *ptr - binary->data;
@@ -496,7 +503,7 @@ int realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) {
return ASN1_OK;
}
-int insert_most_sign_bits(int no_bits, unsigned char val,
+int per_insert_most_sign_bits(int no_bits, unsigned char val,
unsigned char **output_ptr, int *unused) {
unsigned char *ptr = *output_ptr;
@@ -517,7 +524,7 @@ int insert_most_sign_bits(int no_bits, unsigned char val,
return ASN1_OK;
}
-int insert_least_sign_bits(int no_bits, unsigned char val,
+int per_insert_least_sign_bits(int no_bits, unsigned char val,
unsigned char **output_ptr, int *unused) {
unsigned char *ptr = *output_ptr;
int ret = 0;
@@ -543,10 +550,10 @@ int insert_least_sign_bits(int no_bits, unsigned char val,
return ret;
}
-/* pad_bits adds no_bits bits in the buffer that output_ptr
+/* per_pad_bits adds no_bits bits in the buffer that output_ptr
points at.
*/
-int pad_bits(int no_bits, unsigned char **output_ptr, int *unused) {
+int per_pad_bits(int no_bits, unsigned char **output_ptr, int *unused) {
unsigned char *ptr = *output_ptr;
int ret = 0;
@@ -569,37 +576,37 @@ int pad_bits(int no_bits, unsigned char **output_ptr, int *unused) {
The unused parameter tells how many bits that are not set in the
actual byte in the output buffer. If desired_no is more bits than the
input buffer has in no_bytes bytes, then zero bits is padded.*/
-int insert_bits_as_bits(int desired_no, int no_bytes, unsigned char **input_ptr,
- unsigned char **output_ptr, int *unused) {
+int per_insert_bits_as_bits(int desired_no, int no_bytes,
+ unsigned char **input_ptr, unsigned char **output_ptr, int *unused) {
unsigned char *in_ptr = *input_ptr;
unsigned char val;
int no_bits, ret, ret2;
if (desired_no == (no_bytes * 8)) {
- if (insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
+ if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
== ASN1_ERROR
)
return ASN1_ERROR;
ret = no_bytes;
} else if (desired_no < (no_bytes * 8)) {
- /* printf("insert_bits_as_bits 1\n\r"); */
- if (insert_octets_unaligned(desired_no / 8, &in_ptr, output_ptr,
+ /* printf("per_insert_bits_as_bits 1\n\r"); */
+ if (per_insert_octets_unaligned(desired_no / 8, &in_ptr, output_ptr,
*unused) == ASN1_ERROR
)
return ASN1_ERROR;
- /* printf("insert_bits_as_bits 2\n\r"); */
+ /* printf("per_insert_bits_as_bits 2\n\r"); */
val = *++in_ptr;
/* printf("val = %d\n\r",(int)val); */
no_bits = desired_no % 8;
/* printf("no_bits = %d\n\r",no_bits); */
- insert_most_sign_bits(no_bits, val, output_ptr, unused);
+ per_insert_most_sign_bits(no_bits, val, output_ptr, unused);
ret = CEIL(desired_no,8);
} else {
- if (insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
+ if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
== ASN1_ERROR
)
return ASN1_ERROR;
- ret2 = pad_bits(desired_no - (no_bytes * 8), output_ptr, unused);
+ ret2 = per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused);
/* printf("ret2 = %d\n\r",ret2); */
ret = CEIL(desired_no,8);
/* printf("ret = %d\n\r",ret); */
@@ -609,30 +616,30 @@ int insert_bits_as_bits(int desired_no, int no_bytes, unsigned char **input_ptr,
return ret;
}
-/* insert_octets_as_bits_exact_len */
-int insert_octets_as_bits_exact_len(int desired_len, int in_buff_len,
+/* per_insert_octets_as_bits_exact_len */
+int per_insert_octets_as_bits_exact_len(int desired_len, int in_buff_len,
unsigned char **in_ptr, unsigned char **ptr, int *unused) {
int ret = 0;
int ret2 = 0;
if (desired_len == in_buff_len) {
- if ((ret = insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
+ if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
== ASN1_ERROR
)
return ASN1_ERROR;
} else if (desired_len > in_buff_len) {
- if ((ret = insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
+ if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
== ASN1_ERROR
)
return ASN1_ERROR;
/* now pad with zero bits */
/* printf("~npad_bits: called with %d bits padding~n~n~r",desired_len - in_buff_len); */
- if ((ret2 = pad_bits(desired_len - in_buff_len, ptr, unused))
+ if ((ret2 = per_pad_bits(desired_len - in_buff_len, ptr, unused))
== ASN1_ERROR
)
return ASN1_ERROR;
} else {/* desired_len < no_bits */
- if ((ret = insert_octets_as_bits(desired_len, in_ptr, ptr, unused))
+ if ((ret = per_insert_octets_as_bits(desired_len, in_ptr, ptr, unused))
== ASN1_ERROR
)
return ASN1_ERROR;
@@ -648,7 +655,7 @@ int insert_octets_as_bits_exact_len(int desired_len, int in_buff_len,
otherwise the function returns ASN1_ERROR. The output buffer is concatenated
without alignment.
*/
-int insert_octets_as_bits(int no_bytes, unsigned char **input_ptr,
+int per_insert_octets_as_bits(int no_bytes, unsigned char **input_ptr,
unsigned char **output_ptr, int *unused) {
unsigned char *in_ptr = *input_ptr;
unsigned char *ptr = *output_ptr;
@@ -688,7 +695,7 @@ int insert_octets_as_bits(int no_bytes, unsigned char **input_ptr,
into the output buffer, *output_ptr. Before the first byte is
inserted the input buffer is aligned.
*/
-int insert_octets(int no_bytes, unsigned char **input_ptr,
+int per_insert_octets(int no_bytes, unsigned char **input_ptr,
unsigned char **output_ptr, int *unused) {
unsigned char *in_ptr = *input_ptr;
unsigned char *ptr = *output_ptr;
@@ -710,10 +717,10 @@ int insert_octets(int no_bytes, unsigned char **input_ptr,
return (ret + no_bytes);
}
-/* insert_octets_unaligned inserts bytes from the input buffer, *input_ptr,
+/* per_insert_octets_unaligned inserts bytes from the input buffer, *input_ptr,
into the output buffer, *output_ptr.No alignment is done.
*/
-int insert_octets_unaligned(int no_bytes, unsigned char **input_ptr,
+int per_insert_octets_unaligned(int no_bytes, unsigned char **input_ptr,
unsigned char **output_ptr, int unused) {
unsigned char *in_ptr = *input_ptr;
unsigned char *ptr = *output_ptr;
@@ -737,7 +744,7 @@ int insert_octets_unaligned(int no_bytes, unsigned char **input_ptr,
return no_bytes;
}
-int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr,
+int per_insert_octets_except_unused(int no_bytes, unsigned char **input_ptr,
unsigned char **output_ptr, int *unused, int in_unused) {
unsigned char *in_ptr = *input_ptr;
unsigned char *ptr = *output_ptr;
@@ -745,12 +752,12 @@ int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr,
int ret = 0;
if (in_unused == 0) {
- if ((ret = insert_octets_unaligned(no_bytes, &in_ptr, &ptr, *unused))
+ if ((ret = per_insert_octets_unaligned(no_bytes, &in_ptr, &ptr, *unused))
== ASN1_ERROR
)
return ASN1_ERROR;
} else {
- if ((ret = insert_octets_unaligned(no_bytes - 1, &in_ptr, &ptr, *unused))
+ if ((ret = per_insert_octets_unaligned(no_bytes - 1, &in_ptr, &ptr, *unused))
!= ASN1_ERROR) {
val = (int) *(++in_ptr);
no_bits = 8 - in_unused;
@@ -789,7 +796,7 @@ int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr,
/*
* int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
- int in_buf_len, unsigned int *err_pos)
+ int in_buf_len, unsigned int *err_pos)
* term is a pointer to the term which is to be returned to erlang
* in_buf is a pointer into the buffer of incoming bytes.
* in_buf_len is the length of the incoming buffer.
@@ -830,16 +837,16 @@ int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr,
* is the empty binary.
* If some error occured during the decoding of the in_buf an error is returned.
*/
-int decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
+int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
int in_buf_len, unsigned int *err_pos) {
int maybe_ret;
int ib_index = 0;
unsigned char *rest_data;
ERL_NIF_TERM decoded_term, rest;
- if ((maybe_ret = decode(env, &decoded_term, in_buf, &ib_index, in_buf_len))
- <= ASN1_ERROR)
- {
+ if ((maybe_ret = ber_decode(env, &decoded_term, in_buf, &ib_index,
+ in_buf_len)) <= ASN1_ERROR)
+ {
*err_pos = ib_index;
return maybe_ret;
};
@@ -855,7 +862,7 @@ int decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
return ASN1_OK;
}
-int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
+int ber_decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
int *ib_index, int in_buf_len) {
int maybe_ret;
int form;
@@ -865,7 +872,7 @@ int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
if ((*ib_index + 2) > in_buf_len)
return ASN1_VALUE_ERROR;
/* "{{TagNo," */
- if ((form = decode_tag(env, &tag, in_buf, in_buf_len, ib_index))
+ if ((form = ber_decode_tag(env, &tag, in_buf, in_buf_len, ib_index))
<= ASN1_ERROR
)
return form; /* 5 bytes */
@@ -875,7 +882,7 @@ int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
/* buffer must hold at least one byte (0 as length and nothing as
value) */
/* "{{TagNo,Value}," */
- if ((maybe_ret = decode_value(env, &value, in_buf, ib_index, form,
+ if ((maybe_ret = ber_decode_value(env, &value, in_buf, ib_index, form,
in_buf_len)) <= ASN1_ERROR
)
return maybe_ret; /* at least 5 bytes */
@@ -887,7 +894,7 @@ int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
* decode_tag decodes the BER encoded tag in in_buf and creates an
* nif term tag
*/
-int decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf,
+int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf,
int in_buf_len, int *ib_index) {
int tag_no, tmp_tag, form;
@@ -930,11 +937,11 @@ int decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf,
}
/*
- * decode_value decodes the BER encoded length and value fields in the
+ * ber_decode_value decodes the BER encoded length and value fields in the
* in_buf and puts the value part in the decode_buf as an Erlang
* nif term into value
*/
-int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf,
+int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf,
int *ib_index, int form, int in_buf_len) {
int maybe_ret;
unsigned int len = 0;
@@ -970,7 +977,7 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf,
if (*ib_index >= in_buf_len)
return ASN1_INDEF_LEN_ERROR;
- if ((maybe_ret = decode(env, &term, in_buf, ib_index, in_buf_len))
+ if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index, in_buf_len))
<= ASN1_ERROR
)
return maybe_ret;
@@ -986,9 +993,9 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf,
curr_head = enif_make_list(env, 0);
while (*ib_index < end_index) {
- if ((maybe_ret = decode(env, &term, in_buf, ib_index, in_buf_len))
- <= ASN1_ERROR
- )
+ if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index,
+ in_buf_len)) <= ASN1_ERROR
+ )
return maybe_ret;
curr_head = enif_make_list_cell(env, term, curr_head);
}
@@ -1003,6 +1010,187 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf,
return ASN1_OK;
}
+struct ber_encode_mem_chunk {
+ mem_chunk_t *next;
+ int length;
+ char *top;
+ char *curr;
+};
+
+int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, unsigned int *count) {
+
+ const ERL_NIF_TERM *tv;
+ unsigned int form;
+ int arity;
+
+ if (!enif_get_tuple(env, term, &arity, &tv))
+ return ASN1_ERROR;
+
+ form = enif_is_list(env, tv[1]) ? ASN1_CONSTRUCTED : ASN1_PRIMITIVE;
+
+ switch (form) {
+ case ASN1_PRIMITIVE: {
+ ErlNifBinary value;
+ if (!enif_inspect_binary(env, tv[1], &value))
+ return ASN1_ERROR;
+
+ if (ber_check_memory(curr, value.size))
+ return ASN1_ERROR;
+ memcpy((*curr)->curr - value.size + 1, value.data, value.size);
+ (*curr)->curr -= value.size;
+ *count += value.size;
+
+ if (ber_encode_length(value.size, curr, count))
+ return ASN1_ERROR;
+
+ break;
+ }
+ case ASN1_CONSTRUCTED: {
+ ERL_NIF_TERM head, tail;
+ unsigned int tmp_cnt;
+
+ if(!enif_make_reverse_list(env, tv[1], &head))
+ return ASN1_ERROR;
+
+ if (!enif_get_list_cell(env, head, &head, &tail)) {
+ if (enif_is_empty_list(env, tv[1])) {
+ *((*curr)->curr) = 0;
+ (*curr)->curr -= 1;
+ (*count)++;
+ break;
+ } else
+ return ASN1_ERROR;
+ }
+
+ do {
+ tmp_cnt = 0;
+ if (ber_encode(env, head, curr, &tmp_cnt)) {
+ return ASN1_ERROR;
+ }
+ *count += tmp_cnt;
+ } while (enif_get_list_cell(env, tail, &head, &tail));
+
+ if (ber_check_memory(curr, *count)) {
+ return ASN1_ERROR;
+ }
+
+ if (ber_encode_length(*count, curr, count)) {
+ return ASN1_ERROR;
+ }
+
+ break;
+ }
+ }
+
+ // We need atleast 5 bytes to encode the next tlv
+ if (ber_check_memory(curr, 3))
+ return ASN1_ERROR;
+
+ if (ber_encode_tag(env, tv[0], form, curr, count))
+ return ASN1_ERROR;
+
+ return ASN1_OK;
+}
+
+int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form,
+ mem_chunk_t **curr, unsigned int *count) {
+ unsigned int class_tag_no, head_tag;
+ if (!enif_get_uint(env, tag, &class_tag_no))
+ return ASN1_ERROR;
+
+ head_tag = form | ((class_tag_no & 0x30000) >> 10);
+ class_tag_no = class_tag_no & 0xFFFF;
+
+ if (class_tag_no <= 30) {
+ *(*curr)->curr = head_tag | class_tag_no;
+ (*curr)->curr -= 1;
+ (*count)++;
+ return ASN1_OK;
+ } else {
+ *(*curr)->curr = class_tag_no & 127;
+ class_tag_no = class_tag_no >> 7;
+ (*curr)->curr -= 1;
+ (*count)++;
+
+ while (class_tag_no > 0) {
+ *(*curr)->curr = (class_tag_no & 127) | 0x80;
+ class_tag_no >>= 7;
+ (*curr)->curr -= 1;
+ (*count)++;
+ }
+
+ *(*curr)->curr = head_tag | 0x1F;
+ (*curr)->curr -= 1;
+ (*count)++;
+
+ return ASN1_OK;
+ }
+}
+
+int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) {
+ if (size < 128) {
+ if (ber_check_memory(curr, 1u))
+ return ASN1_ERROR;
+ *(*curr)->curr = size;
+ (*curr)->curr -= 1;
+ (*count)++;
+ } else {
+ int chunks = size / 256 + 1;
+ if (ber_check_memory(curr, chunks + 1))
+ return ASN1_ERROR;
+
+ while (size > 0)
+ {
+ *(*curr)->curr = size & 0xFF;
+ size >>= 8;
+ (*curr)->curr -= 1;
+ (*count)++;
+ }
+
+ *(*curr)->curr = chunks | 0x80;
+ (*curr)->curr -= 1;
+ (*count)++;
+ }
+ return ASN1_OK;
+}
+
+mem_chunk_t *ber_new_chunk(unsigned int length) {
+ mem_chunk_t *new = enif_alloc(sizeof(mem_chunk_t));
+ if (new == NULL)
+ return NULL;
+ new->next = NULL;
+ new->top = enif_alloc(sizeof(char) * length);
+ if (new->top == NULL) {
+ free(new);
+ return NULL;
+ }
+ new->curr = new->top + length - 1;
+ new->length = length;
+ return new;
+}
+
+void ber_free_chunks(mem_chunk_t *chunk) {
+ mem_chunk_t *curr, *next = chunk;
+ while (next != NULL) {
+ curr = next;
+ next = curr->next;
+ enif_free(curr->top);
+ enif_free(curr);
+ }
+}
+
+int ber_check_memory(mem_chunk_t **curr, unsigned int needed) {
+ mem_chunk_t *new;
+ if ((*curr)->curr-needed >= (*curr)->top)
+ return ASN1_OK;
+
+ if ((new = ber_new_chunk((*curr)->length > needed ? (*curr)->length * 2 : (*curr)->length + needed)) == NULL)
+ return ASN1_ERROR;
+ new->next = *curr;
+ *curr = new;
+ return ASN1_OK;
+}
+
static ERL_NIF_TERM encode_per_complete(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM err_code;
@@ -1018,11 +1206,11 @@ static ERL_NIF_TERM encode_per_complete(ErlNifEnv* env, int argc,
if (in_binary.size == 0)
return enif_make_binary(env, &out_binary);
- if ((complete_len = complete(&out_binary, in_binary.data, in_binary.size))
- <= ASN1_ERROR) {
+ if ((complete_len = per_complete(&out_binary, in_binary.data,
+ in_binary.size)) <= ASN1_ERROR) {
enif_release_binary(&out_binary);
if (complete_len == ASN1_ERROR
- )
+ )
err_code = enif_make_uint(env, '1');
else
err_code = enif_make_uint(env, 0);
@@ -1043,7 +1231,7 @@ static ERL_NIF_TERM decode_ber_tlv(ErlNifEnv* env, int argc,
if (!enif_inspect_iolist_as_binary(env, argv[0], &in_binary))
return enif_make_badarg(env);
- if ((return_code = decode_begin(env, &return_term, in_binary.data,
+ if ((return_code = ber_decode_begin(env, &return_term, in_binary.data,
in_binary.size, &err_pos)) != ASN1_OK
)
return enif_make_tuple2(env, enif_make_atom(env,"error"), enif_make_tuple2(env,
@@ -1051,6 +1239,43 @@ static ERL_NIF_TERM decode_ber_tlv(ErlNifEnv* env, int argc,
return return_term;
}
+static ERL_NIF_TERM encode_ber_tlv(ErlNifEnv* env, int argc,
+ const ERL_NIF_TERM argv[]) {
+ ErlNifBinary out_binary;
+ unsigned int length = 0, pos = 0;
+ int encode_err;
+ mem_chunk_t *curr, *top;
+ ERL_NIF_TERM err_code;
+
+ curr = ber_new_chunk(40);
+
+ if ((encode_err = ber_encode(env, argv[0], &curr, &length))
+ <= ASN1_ERROR) {
+ ber_free_chunks(curr);
+ err_code = enif_make_int(env, encode_err);
+ return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code);
+ }
+
+ if (!enif_alloc_binary(length, &out_binary)) {
+ ber_free_chunks(curr);
+ return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env,"oom"));
+ }
+
+ top = curr;
+
+ while (curr != NULL) {
+ length = curr->length - (curr->curr-curr->top) -1;
+ if (length > 0)
+ memcpy(out_binary.data + pos, curr->curr+1, length);
+ pos += length;
+ curr = curr->next;
+ }
+
+ ber_free_chunks(top);
+
+ return enif_make_binary(env, &out_binary);
+}
+
static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) {
int i;
return enif_get_int(env, load_info, &i) && i == 1;
@@ -1074,6 +1299,7 @@ static void unload(ErlNifEnv* env, void* priv_data) {
}
static ErlNifFunc nif_funcs[] = { { "encode_per_complete", 1,
- encode_per_complete }, { "decode_ber_tlv", 1, decode_ber_tlv } };
+ encode_per_complete }, { "decode_ber_tlv", 1, decode_ber_tlv }, {
+ "encode_ber_tlv", 1, encode_ber_tlv } };
ERL_NIF_INIT(asn1rt_nif, nif_funcs, load, NULL, upgrade, unload)