diff options
Diffstat (limited to 'lib/asn1/c_src/asn1_erl_nif.c')
-rw-r--r-- | lib/asn1/c_src/asn1_erl_nif.c | 432 |
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) |