From dab9296e05c7b1ffa4e12a270c41741adb1da383 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 22 Jul 2011 16:56:21 +0200 Subject: Create a nif for ber encode --- lib/asn1/c_src/asn1_erl_nif.c | 384 +++++++++++++++++++++++++++---------- lib/asn1/src/asn1rt_ber_bin_v2.erl | 22 ++- lib/asn1/src/asn1rt_nif.erl | 8 +- 3 files changed, 303 insertions(+), 111 deletions(-) (limited to 'lib/asn1') diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c index 58314e23c2..eacbade196 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,52 @@ #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 */ +int ber_encode(ErlNifEnv *, ERL_NIF_TERM , ErlNifBinary *, + unsigned char **, unsigned int *); -int decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *); +int ber_check_memory(ErlNifBinary *, unsigned char **, unsigned int *, unsigned int); -int decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int, int); +int ber_encode_tag(ErlNifEnv *, ERL_NIF_TERM , unsigned int , + unsigned char **, unsigned int *); + +int ber_encode_length(size_t , ErlNifBinary *, unsigned char **, unsigned int *); /* * @@ -101,7 +111,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 +186,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 +200,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 +216,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 +233,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 +252,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 +284,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 +312,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 +340,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 +370,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 +399,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 +428,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 +458,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 +487,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 +500,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 +521,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 +547,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 +573,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 +613,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 +652,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 +692,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 +714,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 +741,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 +749,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 +793,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 +834,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 +859,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 +869,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 +879,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 +891,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 +934,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 +974,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 +990,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 +1007,150 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, return ASN1_OK; } +int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, ErlNifBinary *out_binary, + unsigned char **curr, unsigned int *unused) { + + 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; + + // We need atleast 5 bytes to encode the next tlv, so we double the memory available if not enough is available + if (ber_check_memory(out_binary, curr, unused, 5)) + return ASN1_ERROR; + + if (ber_encode_tag(env, tv[0], form, curr, unused)) + return ASN1_ERROR; + + if (form == ASN1_PRIMITIVE) { + ErlNifBinary value; + if (!enif_inspect_binary(env, tv[1], &value)) + return ASN1_ERROR; + if (ber_encode_length(value.size, out_binary, curr, unused)) + return ASN1_ERROR; + if(ber_check_memory(out_binary, curr, unused, value.size)) + return ASN1_ERROR; + memcpy(*curr, value.data, value.size); + *curr += value.size; + *unused -= value.size; + } else { + ErlNifBinary tmp_bin; + unsigned char *tmp_curr; + unsigned int tmp_unused = 40; + ERL_NIF_TERM head, tail; + + if (!enif_get_list_cell(env, tv[1], &head, &tail)) { + if (enif_is_empty_list(env, tv[1])) { + **curr = 0; + ++*curr; + --*unused; + return ASN1_OK; + } else + return ASN1_ERROR; + } + + if (!enif_alloc_binary(40, &tmp_bin)) + return ASN1_ERROR; + + tmp_curr = tmp_bin.data; + + do { + if (ber_encode(env, head, &tmp_bin, &tmp_curr, &tmp_unused)) { + enif_release_binary(&tmp_bin); + return ASN1_ERROR; + } + } while (enif_get_list_cell(env, tail, &head, &tail)); + + if (ber_encode_length(tmp_bin.size - tmp_unused, out_binary, curr, + unused)) { + enif_release_binary(&tmp_bin); + return ASN1_ERROR; + } + + if (ber_check_memory(out_binary, curr, unused, + tmp_bin.size - tmp_unused)) { + enif_release_binary(&tmp_bin); + return ASN1_ERROR; + } + + memcpy(*curr, tmp_bin.data, tmp_bin.size - tmp_unused); + *curr += tmp_bin.size - tmp_unused; + *unused -= tmp_bin.size - tmp_unused; + enif_release_binary(&tmp_bin); + } + + return ASN1_OK; +} + +int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form, + unsigned char **curr, unsigned int *unused) { + unsigned int class_tag_no; + if (!enif_get_uint(env, tag, &class_tag_no)) + return ASN1_ERROR; + + **curr = form | ((class_tag_no & 196608) >> 10); + class_tag_no = class_tag_no & 65535; + + if (class_tag_no <= 30) { + **curr |= class_tag_no; + ++*curr; --*unused; + return ASN1_OK; + } else { + **curr |= 31; + ++*curr; --*unused; + while (class_tag_no > 127) { + **curr = (class_tag_no & 127) | 128; + class_tag_no = class_tag_no >> 7; + ++*curr; + --*unused; + } + **curr = class_tag_no; + ++*curr; + --*unused; + return ASN1_OK; + } +} + +int ber_encode_length(size_t size, ErlNifBinary *out_binary, unsigned char **curr, unsigned int *unused) { + if (size < 128) { + if (ber_check_memory(out_binary, curr, unused, 1u)) + return ASN1_ERROR; + **curr = size; + ++*curr; + --*unused; + } else { + int chunks = size / 256 + 1; + if (ber_check_memory(out_binary, curr, unused, chunks + 1)) + return ASN1_ERROR; + **curr = chunks + 128; + ++*curr; + --*unused; + while (chunks > 0) + { + **curr = ((size >> (8*(chunks-1)))) & 255; + ++*curr; + --*unused; + chunks--; + } + } + return ASN1_OK; +} + +int ber_check_memory(ErlNifBinary *bin, unsigned char **curr, unsigned int *unused,unsigned int needed) { + int incr; + if (*unused >= needed) + return ASN1_OK; + incr = bin->size > needed ? bin->size : needed; + if (per_realloc_memory(bin, bin->size + incr, curr)) + return ASN1_ERROR; + *unused += incr; + 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 +1166,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 +1191,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 +1199,35 @@ 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; + int complete_len; + unsigned int unused = 40; + unsigned char *curr; + ERL_NIF_TERM err_code; + + if (!enif_alloc_binary(unused, &out_binary)) + return enif_make_atom(env, "alloc_binary_failed"); + + curr = out_binary.data; + + if ((complete_len = ber_encode(env, argv[0], &out_binary, &curr, &unused)) + <= 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); + return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code); + } + + if (unused != 0) + enif_realloc_binary(&out_binary, out_binary.size - unused); + + 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 +1251,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) diff --git a/lib/asn1/src/asn1rt_ber_bin_v2.erl b/lib/asn1/src/asn1rt_ber_bin_v2.erl index 4c75b5918f..4797263ca7 100644 --- a/lib/asn1/src/asn1rt_ber_bin_v2.erl +++ b/lib/asn1/src/asn1rt_ber_bin_v2.erl @@ -128,15 +128,25 @@ % encode(Tlv) -> % encode_constructed(Tlv). +encode(Tlv) when is_binary(Tlv) -> + Tlv; encode([Tlv]) -> encode(Tlv); -encode({TlvTag,TlvVal}) when is_list(TlvVal) -> +encode(Tlv) -> + case is_nif_loadable() of + true -> + asn1rt_nif:encode_ber_tlv(Tlv); + false -> + encode_erl(Tlv) + end. + +encode_erl([Tlv]) -> + encode_erl(Tlv); +encode_erl({TlvTag,TlvVal}) when is_list(TlvVal) -> %% constructed form of value encode_tlv(TlvTag,TlvVal,?CONSTRUCTED); -encode({TlvTag,TlvVal}) -> - encode_tlv(TlvTag,TlvVal,?PRIMITIVE); -encode(Bin) when is_binary(Bin) -> - Bin. +encode_erl({TlvTag,TlvVal}) -> + encode_tlv(TlvTag,TlvVal,?PRIMITIVE). encode_tlv(TlvTag,TlvVal,Form) -> Tag = encode_tlv_tag(TlvTag,Form), @@ -155,7 +165,7 @@ encode_tlv_val(Bin) -> {Bin,size(Bin)}. encode_tlv_list([Tlv|Tlvs],Acc) -> - EncTlv = encode(Tlv), + EncTlv = encode_erl(Tlv), encode_tlv_list(Tlvs,[EncTlv|Acc]); encode_tlv_list([],Acc) -> Bin=list_to_binary(lists:reverse(Acc)), diff --git a/lib/asn1/src/asn1rt_nif.erl b/lib/asn1/src/asn1rt_nif.erl index 8580c70e6b..de1fb94816 100644 --- a/lib/asn1/src/asn1rt_nif.erl +++ b/lib/asn1/src/asn1rt_nif.erl @@ -22,7 +22,8 @@ %% Nif interface for asn1 -export([encode_per_complete/1, - decode_ber_tlv/1]). + decode_ber_tlv/1, + encode_ber_tlv/1]). -on_load(load_nif/0). @@ -76,8 +77,11 @@ load_nif() -> Status end. -encode_per_complete(_Binary) -> +encode_per_complete(_TagValueList) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). decode_ber_tlv(_Binary) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). + +encode_ber_tlv(_TagValueList) -> + erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). -- cgit v1.2.3