diff options
74 files changed, 2344 insertions, 1247 deletions
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index a547191d6d..86575ccb9b 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -240,6 +240,10 @@ do { \ sys_memcpy((void *) (IP), (void *) &aui__, sizeof(struct au_init)); \ } while (0) +#if ERTS_ALC_DEFAULT_ACUL \ + || ERTS_ALC_DEFAULT_ACUL_LL_ALLOC \ + || ERTS_ALC_DEFAULT_ACUL_EHEAP_ALLOC + static ERTS_INLINE void set_default_acul(struct au_init *ip, int acul) { @@ -249,6 +253,8 @@ set_default_acul(struct au_init *ip, int acul) ip->init.util.acul = acul; } +#endif + static void set_default_sl_alloc_opts(struct au_init *ip) { diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index 095ad24387..7e3b3c707d 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -397,6 +397,7 @@ type POLLSET_UPDREQ SHORT_LIVED SYSTEM pollset_update_req type POLL_FDS LONG_LIVED SYSTEM poll_fds type POLL_RES_EVS LONG_LIVED SYSTEM poll_result_events type FD_STATUS LONG_LIVED SYSTEM fd_status +type SELECT_FDS LONG_LIVED SYSTEM select_fds +if unix diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index b19e603a5f..bf8a37c71b 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -1753,7 +1753,8 @@ handle_delayed_dealloc(Allctr_t *allctr, if (IS_FREE_LAST_MBC_BLK(blk)) { /* * A multiblock carrier that previously has been migrated away - * from us and now is back to be deallocated... + * from us and now is back to be deallocated. For more info + * see schedule_dealloc_carrier(). * * Note that we cannot use FBLK_TO_MBC(blk) since it * data has been overwritten by the queue. @@ -1761,6 +1762,12 @@ handle_delayed_dealloc(Allctr_t *allctr, Carrier_t *crr = FIRST_BLK_TO_MBC(allctr, blk); ERTS_ALC_CPOOL_ASSERT(ERTS_ALC_IS_CPOOL_ENABLED(allctr)); ERTS_ALC_CPOOL_ASSERT(allctr == crr->cpool.orig_allctr); + ERTS_ALC_CPOOL_ASSERT(((erts_aint_t) allctr) + != (erts_smp_atomic_read_nob(&crr->allctr) + & ~FLG_MASK)); + + erts_smp_atomic_set_nob(&crr->allctr, ((erts_aint_t) allctr)); + schedule_dealloc_carrier(allctr, crr); } else { @@ -3001,7 +3008,7 @@ check_pending_dealloc_carrier(Allctr_t *allctr, static void schedule_dealloc_carrier(Allctr_t *allctr, Carrier_t *crr) { - Allctr_t *used_allctr; + Allctr_t *orig_allctr; int check_pending_dealloc; erts_aint_t max_size; @@ -3010,25 +3017,37 @@ schedule_dealloc_carrier(Allctr_t *allctr, Carrier_t *crr) return; } - used_allctr = crr->cpool.orig_allctr; + orig_allctr = crr->cpool.orig_allctr; - if (allctr != used_allctr) { + if (allctr != orig_allctr) { Block_t *blk = MBC_TO_FIRST_BLK(allctr, crr); - int cinit = used_allctr->dd.ix - allctr->dd.ix; + int cinit = orig_allctr->dd.ix - allctr->dd.ix; /* - * Receiver will recognize that this is a carrier to - * deallocate since the block is an mbc block that - * is free and last in carrier... + * We send the carrier to its origin for deallocation. + * This in order: + * - not to complicate things for the thread specific + * instances of mseg_alloc, and + * - to ensure that we always only reuse empty carriers + * originating from our own thread specific mseg_alloc + * instance which is beneficial on NUMA systems. + * + * The receiver will recognize that this is a carrier to + * deallocate (and not a block which is the common case) + * since the block is an mbc block that is free and last + * in the carrier. */ ERTS_ALC_CPOOL_ASSERT(IS_FREE_LAST_MBC_BLK(blk)); ERTS_ALC_CPOOL_ASSERT(IS_MBC_FIRST_ABLK(allctr, blk)); ERTS_ALC_CPOOL_ASSERT(crr == FBLK_TO_MBC(blk)); - ERTS_ALC_CPOOL_ASSERT(crr == FIRST_BLK_TO_MBC(used_allctr, blk)); + ERTS_ALC_CPOOL_ASSERT(crr == FIRST_BLK_TO_MBC(allctr, blk)); + ERTS_ALC_CPOOL_ASSERT(((erts_aint_t) allctr) + == (erts_smp_atomic_read_nob(&crr->allctr) + & ~FLG_MASK)); - if (ddq_enqueue(&used_allctr->dd.q, BLK2UMEM(blk), cinit)) - erts_alloc_notify_delayed_dealloc(used_allctr->ix); + if (ddq_enqueue(&orig_allctr->dd.q, BLK2UMEM(blk), cinit)) + erts_alloc_notify_delayed_dealloc(orig_allctr->ix); return; } diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c index 8da135b2c8..f7b5f25eac 100644 --- a/erts/emulator/beam/erl_ptab.c +++ b/erts/emulator/beam/erl_ptab.c @@ -1435,7 +1435,7 @@ erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next) aid_ix = max_ix; else aid_ix--; - ASSERT((aid_ix & max_ix) == (((Uint32) erts_atomic32_read_nob(&ptab->vola.tile.fid_ix)) & max_ix)); + ASSERT((aid_ix & max_ix) == (((Uint32) erts_smp_atomic32_read_nob(&ptab->vola.tile.fid_ix)) & max_ix)); #endif } diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 01e130bd64..c1e66b59af 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -4842,7 +4842,7 @@ erts_stale_drv_select(Eterm port, if (drv_port == ERTS_INVALID_ERL_DRV_PORT) { Port *prt = erts_port_lookup_raw(port); if (prt) - drv_port = ERTS_Port2ErlDrvPort(port); + drv_port = ERTS_Port2ErlDrvPort(prt); else drv_port = ERTS_INVALID_ERL_DRV_PORT; } diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index a523d67158..7d292a304a 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -40,6 +40,13 @@ # include "config.h" #endif +#if defined(__DARWIN__) || defined(__APPLE__) && defined(__MACH__) +/* Setting _DARWIN_UNLIMITED_SELECT before including sys/select.h enables + * the version of select() that does not place a limit on the fd_set. + */ +# define _DARWIN_UNLIMITED_SELECT +#endif + #ifndef WANT_NONBLOCKING # define WANT_NONBLOCKING #endif @@ -90,6 +97,52 @@ #define HARD_DEBUG #endif +#ifdef _DARWIN_UNLIMITED_SELECT +typedef struct { + size_t sz; + fd_set* ptr; +}ERTS_fd_set; +# define ERTS_FD_CLR(fd, fds) FD_CLR((fd), (fds)->ptr) +# define ERTS_FD_SET(fd, fds) FD_SET((fd), (fds)->ptr) +# define ERTS_FD_ISSET(fd,fds) FD_ISSET((fd), (fds)->ptr) +# define ERTS_FD_ZERO(fds) memset((fds)->ptr, 0, (fds)->sz) +# define ERTS_FD_SIZE(n) ((((n)+NFDBITS-1)/NFDBITS)*sizeof(fd_mask)) + +static void ERTS_FD_COPY(ERTS_fd_set *src, ERTS_fd_set *dst) +{ + if (dst->sz != src->sz) { + dst->ptr = dst->ptr + ? erts_realloc(ERTS_ALC_T_SELECT_FDS, dst->ptr, src->sz) + : erts_alloc(ERTS_ALC_T_SELECT_FDS, src->sz); + dst->sz = src->sz; + } + memcpy(dst->ptr, src->ptr, src->sz); +} + +static ERTS_INLINE +int ERTS_SELECT(int nfds, ERTS_fd_set *readfds, ERTS_fd_set *writefds, + ERTS_fd_set *exceptfds, struct timeval *timeout) +{ + ASSERT(!readfds || readfds->sz >= nfds); + ASSERT(!writefds || writefds->sz >= nfds); + ASSERT(!exceptfds); + return select(nfds, + (readfds ? readfds->ptr : NULL ), + (writefds ? writefds->ptr : NULL), + NULL, + timeout); +} + +#else /* !_DARWIN_UNLIMITED_SELECT */ +# define ERTS_fd_set fd_set +# define ERTS_FD_CLR FD_CLR +# define ERTS_FD_ISSET FD_ISSET +# define ERTS_FD_SET FD_SET +# define ERTS_FD_ZERO FD_ZERO +# define ERTS_FD_COPY(src,dst) (*(dst) = *(src)) +# define ERTS_SELECT select +#endif + #define ERTS_POLL_USE_BATCH_UPDATE_POLLSET (ERTS_POLL_USE_DEVPOLL \ || ERTS_POLL_USE_KQUEUE) #define ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE \ @@ -244,10 +297,10 @@ struct ErtsPollSet_ { #if ERTS_POLL_USE_FALLBACK int no_select_fds; #endif - fd_set input_fds; - fd_set res_input_fds; - fd_set output_fds; - fd_set res_output_fds; + ERTS_fd_set input_fds; + ERTS_fd_set res_input_fds; + ERTS_fd_set output_fds; + ERTS_fd_set res_output_fds; #endif #if ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE ErtsPollSetUpdateRequestsBlock update_requests; @@ -624,6 +677,33 @@ grow_poll_fds(ErtsPollSet ps, int min_ix) } #endif +#ifdef _DARWIN_UNLIMITED_SELECT +static void +grow_select_fds(int fd, ERTS_fd_set* fds) +{ + int new_len = ERTS_POLL_EXPORT(erts_poll_get_table_len)(fd + 1); + if (new_len > max_fds) + new_len = max_fds; + new_len = ERTS_FD_SIZE(new_len); + fds->ptr = fds->sz + ? erts_realloc(ERTS_ALC_T_SELECT_FDS, fds->ptr, new_len) + : erts_alloc(ERTS_ALC_T_SELECT_FDS, new_len); + memset((char*)fds->ptr + fds->sz, 0, new_len - fds->sz); + fds->sz = new_len; +} +static ERTS_INLINE void +ensure_select_fds(int fd, ERTS_fd_set* in, ERTS_fd_set* out) +{ + ASSERT(in->sz == out->sz); + if (ERTS_FD_SIZE(fd+1) > in->sz) { + grow_select_fds(fd, in); + grow_select_fds(fd, out); + } +} +#else +# define ensure_select_fds(fd, in, out) do {} while(0) +#endif /* _DARWIN_UNLIMITED_SELECT */ + static void grow_fds_status(ErtsPollSet ps, int min_fd) { @@ -1290,22 +1370,23 @@ static int update_pollset(ErtsPollSet ps, int fd) #elif ERTS_POLL_USE_SELECT /* --- select ------------------------------ */ { ErtsPollEvents events = ps->fds_status[fd].events; + ensure_select_fds(fd, &ps->input_fds, &ps->output_fds); if ((ERTS_POLL_EV_IN & events) != (ERTS_POLL_EV_IN & ps->fds_status[fd].used_events)) { if (ERTS_POLL_EV_IN & events) { - FD_SET(fd, &ps->input_fds); + ERTS_FD_SET(fd, &ps->input_fds); } else { - FD_CLR(fd, &ps->input_fds); + ERTS_FD_CLR(fd, &ps->input_fds); } } if ((ERTS_POLL_EV_OUT & events) != (ERTS_POLL_EV_OUT & ps->fds_status[fd].used_events)) { if (ERTS_POLL_EV_OUT & events) { - FD_SET(fd, &ps->output_fds); + ERTS_FD_SET(fd, &ps->output_fds); } else { - FD_CLR(fd, &ps->output_fds); + ERTS_FD_CLR(fd, &ps->output_fds); } } @@ -1789,7 +1870,7 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res, while (fd < end_fd && res < max_res) { pr[res].events = (ErtsPollEvents) 0; - if (FD_ISSET(fd, &ps->res_input_fds)) { + if (ERTS_FD_ISSET(fd, &ps->res_input_fds)) { #if ERTS_POLL_USE_FALLBACK if (fd == ps->kp_fd) { res += get_kp_results(ps, &pr[res], max_res-res); @@ -1805,7 +1886,7 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res, #endif pr[res].events |= ERTS_POLL_EV_IN; } - if (FD_ISSET(fd, &ps->res_output_fds)) + if (ERTS_FD_ISSET(fd, &ps->res_output_fds)) pr[res].events |= ERTS_POLL_EV_OUT; if (pr[res].events) { pr[res].fd = fd; @@ -1832,24 +1913,23 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res, while (fd < end_fd && res < max_res) { if (ps->fds_status[fd].events) { int sres; - fd_set *iset = NULL; - fd_set *oset = NULL; + ERTS_fd_set *iset = NULL; + ERTS_fd_set *oset = NULL; if (ps->fds_status[fd].events & ERTS_POLL_EV_IN) { iset = &ps->res_input_fds; - FD_ZERO(iset); - FD_SET(fd, iset); + ERTS_FD_ZERO(iset); + ERTS_FD_SET(fd, iset); } if (ps->fds_status[fd].events & ERTS_POLL_EV_OUT) { oset = &ps->res_output_fds; - FD_ZERO(oset); - FD_SET(fd, oset); - + ERTS_FD_ZERO(oset); + ERTS_FD_SET(fd, oset); } do { /* Initiate 'tv' each time; select() may modify it */ SysTimeval tv = {0, 0}; - sres = select(ps->max_fd+1, iset, oset, NULL, &tv); + sres = ERTS_SELECT(ps->max_fd+1, iset, oset, NULL, &tv); } while (sres < 0 && errno == EINTR); if (sres < 0) { #if ERTS_POLL_USE_FALLBACK @@ -1873,7 +1953,7 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res, } else if (sres > 0) { pr[res].fd = fd; - if (iset && FD_ISSET(fd, iset)) { + if (iset && ERTS_FD_ISSET(fd, iset)) { #if ERTS_POLL_USE_FALLBACK if (fd == ps->kp_fd) { res += get_kp_results(ps, @@ -1891,7 +1971,7 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res, #endif pr[res].events |= ERTS_POLL_EV_IN; } - if (oset && FD_ISSET(fd, oset)) { + if (oset && ERTS_FD_ISSET(fd, oset)) { pr[res].events |= ERTS_POLL_EV_OUT; } ASSERT(pr[res].events); @@ -1992,14 +2072,14 @@ check_fd_events(ErtsPollSet ps, SysTimeval *tv, int max_res) #elif ERTS_POLL_USE_SELECT /* --- select ------------------------------ */ SysTimeval to = *tv; - ps->res_input_fds = ps->input_fds; - ps->res_output_fds = ps->output_fds; - + ERTS_FD_COPY(&ps->input_fds, &ps->res_input_fds); + ERTS_FD_COPY(&ps->output_fds, &ps->res_output_fds); + #ifdef ERTS_SMP if (to.tv_sec || to.tv_usec) erts_thr_progress_prepare_wait(NULL); #endif - res = select(ps->max_fd + 1, + res = ERTS_SELECT(ps->max_fd + 1, &ps->res_input_fds, &ps->res_output_fds, NULL, @@ -2027,7 +2107,7 @@ check_fd_events(ErtsPollSet ps, SysTimeval *tv, int max_res) ERTS_POLLSET_LOCK(ps); handle_update_requests(ps); ERTS_POLLSET_UNLOCK(ps); - res = select(ps->max_fd + 1, + res = ERTS_SELECT(ps->max_fd + 1, &ps->res_input_fds, &ps->res_output_fds, NULL, @@ -2233,7 +2313,8 @@ ERTS_POLL_EXPORT(erts_poll_init)(void) max_fds = OPEN_MAX; #endif -#if ERTS_POLL_USE_SELECT && defined(FD_SETSIZE) +#if ERTS_POLL_USE_SELECT && defined(FD_SETSIZE) && \ + !defined(_DARWIN_UNLIMITED_SELECT) if (max_fds > FD_SETSIZE) max_fds = FD_SETSIZE; #endif @@ -2301,10 +2382,21 @@ ERTS_POLL_EXPORT(erts_poll_create_pollset)(void) #if ERTS_POLL_USE_FALLBACK ps->no_select_fds = 0; #endif - FD_ZERO(&ps->input_fds); - FD_ZERO(&ps->res_input_fds); - FD_ZERO(&ps->output_fds); - FD_ZERO(&ps->res_output_fds); +#ifdef _DARWIN_UNLIMITED_SELECT + ps->input_fds.sz = 0; + ps->input_fds.ptr = NULL; + ps->res_input_fds.sz = 0; + ps->res_input_fds.ptr = NULL; + ps->output_fds.sz = 0; + ps->output_fds.ptr = NULL; + ps->res_output_fds.sz = 0; + ps->res_output_fds.ptr = NULL; +#else + ERTS_FD_ZERO(&ps->input_fds); + ERTS_FD_ZERO(&ps->res_input_fds); + ERTS_FD_ZERO(&ps->output_fds); + ERTS_FD_ZERO(&ps->res_output_fds); +#endif #endif #if ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE ps->update_requests.next = NULL; @@ -2382,6 +2474,16 @@ ERTS_POLL_EXPORT(erts_poll_destroy_pollset)(ErtsPollSet ps) if (ps->poll_fds) erts_free(ERTS_ALC_T_POLL_FDS, (void *) ps->poll_fds); #elif ERTS_POLL_USE_SELECT +#ifdef _DARWIN_UNLIMITED_SELECT + if (ps->input_fds.ptr) + erts_free(ERTS_ALC_T_SELECT_FDS, (void *) ps->input_fds.ptr); + if (ps->res_input_fds.ptr) + erts_free(ERTS_ALC_T_SELECT_FDS, (void *) ps->res_input_fds.ptr); + if (ps->output_fds.ptr) + erts_free(ERTS_ALC_T_SELECT_FDS, (void *) ps->output_fds.ptr); + if (ps->res_output_fds.ptr) + erts_free(ERTS_ALC_T_SELECT_FDS, (void *) ps->res_output_fds.ptr); +#endif #endif #if ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE { @@ -2445,6 +2547,10 @@ ERTS_POLL_EXPORT(erts_poll_info)(ErtsPollSet ps, ErtsPollInfo *pip) #if ERTS_POLL_USE_POLL size += ps->poll_fds_len*sizeof(struct pollfd); #elif ERTS_POLL_USE_SELECT +#ifdef _DARWIN_UNLIMITED_SELECT + size += ps->input_fds.sz + ps->res_input_fds.sz + + ps->output_fds.sz + ps->res_output_fds.sz; +#endif #endif #if ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl index e467e844b3..ced8b41c4b 100644 --- a/erts/emulator/test/port_SUITE.erl +++ b/erts/emulator/test/port_SUITE.erl @@ -628,7 +628,7 @@ iter_max_ports(Config) when is_list(Config) -> iter_max_ports_test(Config) -> - Dog = test_server:timetrap(test_server:minutes(20)), + Dog = test_server:timetrap(test_server:minutes(30)), PortTest = port_test(Config), Command = lists:concat([PortTest, " -h0 -q"]), Iters = case os:type() of diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex d977b237be..cdc13a656d 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 34785ff2a9..e016a50c4c 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -3554,8 +3554,8 @@ sched_wall_time(Ref, N, Acc) -> {Ref, SWT} -> sched_wall_time(Ref, N-1, [SWT|Acc]) end. --spec erlang:gather_gc_info_result(Ref) -> [{number(),number(),0}] when - Ref :: reference(). +-spec erlang:gather_gc_info_result(Ref) -> + {number(),number(),0} when Ref :: reference(). gather_gc_info_result(Ref) when erlang:is_reference(Ref) -> gc_info(Ref, erlang:system_info(schedulers), {0,0}). diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl index efb55cf015..d279e9697f 100644 --- a/lib/asn1/src/asn1ct_constructed_per.erl +++ b/lib/asn1/src/asn1ct_constructed_per.erl @@ -354,8 +354,7 @@ gen_dec_constructed_imm_2(Typename, CompList, %% we don't return named lists any more Cnames = mkcnamelist(CompList), demit({"Result = "}), %dbg %% return value as record - RecordName = lists:concat([get_record_name_prefix(), - asn1ct_gen:list2rname(Typename)]), + RecordName = record_name(Typename), case Typename of ['EXTERNAL'] -> emit({" OldFormat={'",RecordName, @@ -377,6 +376,29 @@ gen_dec_constructed_imm_2(Typename, CompList, end, emit({{curr,bytes},"}"}). +%% record_name([TypeName]) -> RecordNameString +%% Construct a record name for the constructed type, ignoring any +%% fake sequences that are used to represent an extension addition +%% group. Such fake sequences never appear as a top type, and their +%% name always start with "ExtAddGroup". + +record_name(Typename0) -> + [TopType|Typename1] = lists:reverse(Typename0), + Typename = filter_ext_add_groups(Typename1, [TopType]), + lists:concat([get_record_name_prefix(), + asn1ct_gen:list2rname(Typename)]). + +filter_ext_add_groups([H|T], Acc) when is_atom(H) -> + case atom_to_list(H) of + "ExtAddGroup"++_ -> + filter_ext_add_groups(T, Acc); + _ -> + filter_ext_add_groups(T, [H|Acc]) + end; +filter_ext_add_groups([H|T], Acc) -> + filter_ext_add_groups(T, [H|Acc]); +filter_ext_add_groups([], Acc) -> Acc. + textual_order([#'ComponentType'{textual_order=undefined}|_],TermList) -> TermList; textual_order(CompList,TermList) when is_list(CompList) -> diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index 30c9ab9365..69d9d51bf1 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -250,7 +250,8 @@ emit_enc_enumerated_case(Erules, C, EnumName, Count) -> enc_ext_and_val(per, E, F, Args) -> [E|apply(asn1ct_eval_per, F, Args)]; enc_ext_and_val(uper, E, F, Args) -> - <<E:1,(apply(asn1ct_eval_uper, F, Args))/bitstring>>. + Bs = list_to_bitstring([apply(asn1ct_eval_uper, F, Args)]), + <<E:1,Bs/bitstring>>. %% Object code generating for encoding and decoding diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index c6803a0f96..bf362db843 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -86,7 +86,7 @@ per_dec_enumerated(BaseNamedList, NamedListExt0, Aligned) -> bit_case(Base, Ext). per_dec_extension_map(Aligned) -> - Len = {add,per_dec_normally_small_number(Aligned),1}, + Len = per_dec_normally_small_length(Aligned), {get_bits,Len,[1,bitstring]}. per_dec_integer(Constraint0, Aligned) -> @@ -240,6 +240,11 @@ per_dec_normally_small_number(Aligned) -> Unlimited = per_decode_semi_constrained(0, Aligned), bit_case(Small, Unlimited). +per_dec_normally_small_length(Aligned) -> + Small = {add,{get_bits,6,[1]},1}, + Unlimited = decode_unconstrained_length(false, Aligned), + bit_case(Small, Unlimited). + per_decode_semi_constrained(Lb, Aligned) -> add_lb(Lb, {get_bits,decode_unconstrained_length(false, Aligned),[8]}). diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl index 6be493320c..f00b23a8b2 100644 --- a/lib/asn1/test/asn1_SUITE.erl +++ b/lib/asn1/test/asn1_SUITE.erl @@ -454,10 +454,13 @@ testSeqDefault(Config, Rule, Opts) -> testSeqExtension(Config) -> test(Config, fun testSeqExtension/3). testSeqExtension(Config, Rule, Opts) -> - asn1_test_lib:compile_all(["External", "SeqExtension"], Config, + asn1_test_lib:compile_all(["External", + "SeqExtension", + "SeqExtension2"], + Config, [Rule|Opts]), DataDir = ?config(data_dir, Config), - testSeqExtension:main(DataDir, [Rule|Opts]). + testSeqExtension:main(Rule, DataDir, [Rule|Opts]). testSeqExternal(Config) -> test(Config, fun testSeqExternal/3). testSeqExternal(Config, Rule, Opts) -> diff --git a/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1 b/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1 index 3a727e46bb..8dc5f3d7e1 100644 --- a/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1 +++ b/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1 @@ -31,5 +31,25 @@ Seq ::= SEQUENCE { i INTEGER } +EnumExtBig ::= ENUMERATED { + base, + ..., + e00,e01,e02,e03,e04,e05,e06,e07,e08,e09,e0a,e0b,e0c,e0d,e0e,e0f, + e10,e11,e12,e13,e14,e15,e16,e17,e18,e19,e1a,e1b,e1c,e1d,e1e,e1f, + e20,e21,e22,e23,e24,e25,e26,e27,e28,e29,e2a,e2b,e2c,e2d,e2e,e2f, + e30,e31,e32,e33,e34,e35,e36,e37,e38,e39,e3a,e3b,e3c,e3d,e3e,e3f, + e40,e41,e42,e43,e44,e45,e46,e47,e48,e49,e4a,e4b,e4c,e4d,e4e,e4f, + e50,e51,e52,e53,e54,e55,e56,e57,e58,e59,e5a,e5b,e5c,e5d,e5e,e5f, + e60,e61,e62,e63,e64,e65,e66,e67,e68,e69,e6a,e6b,e6c,e6d,e6e,e6f, + e70,e71,e72,e73,e74,e75,e76,e77,e78,e79,e7a,e7b,e7c,e7d,e7e,e7f, + e80 +} + +SeqBig ::= SEQUENCE { + b BOOLEAN, + e EnumExtBig, + i INTEGER +} + END diff --git a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn index b07dcd8baa..0e905d8839 100644 --- a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn +++ b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn @@ -118,4 +118,23 @@ AC-BarringConfig ::= SEQUENCE { ac-BarringForSpecialAC BIT STRING (SIZE(5)) } +InlinedSeq ::= SEQUENCE { + ..., + [[ + s SEQUENCE { + a INTEGER, + b BOOLEAN + } + ]] +} + +-- 'ExtAddGroup1' is used internally to represent fake sequences for +-- extension addition groups. Make sure that a real sequence with that +-- name at the top-level doesn't cause a problem. + +ExtAddGroup1 ::= SEQUENCE { + x INTEGER, + y INTEGER +} + END diff --git a/lib/asn1/test/asn1_SUITE_data/SeqExtension2.asn1 b/lib/asn1/test/asn1_SUITE_data/SeqExtension2.asn1 new file mode 100644 index 0000000000..44900d9d39 --- /dev/null +++ b/lib/asn1/test/asn1_SUITE_data/SeqExtension2.asn1 @@ -0,0 +1,208 @@ +SeqExtension2 DEFINITIONS AUTOMATIC TAGS ::= +BEGIN + +SeqExt66 ::= SEQUENCE { + ..., + i0 INTEGER (0..127) OPTIONAL, + i1 INTEGER (0..127) OPTIONAL, + i2 INTEGER (0..127) OPTIONAL, + i3 INTEGER (0..127) OPTIONAL, + i4 INTEGER (0..127) OPTIONAL, + i5 INTEGER (0..127) OPTIONAL, + i6 INTEGER (0..127) OPTIONAL, + i7 INTEGER (0..127) OPTIONAL, + i8 INTEGER (0..127) OPTIONAL, + i9 INTEGER (0..127) OPTIONAL, + i10 INTEGER (0..127) OPTIONAL, + i11 INTEGER (0..127) OPTIONAL, + i12 INTEGER (0..127) OPTIONAL, + i13 INTEGER (0..127) OPTIONAL, + i14 INTEGER (0..127) OPTIONAL, + i15 INTEGER (0..127) OPTIONAL, + i16 INTEGER (0..127) OPTIONAL, + i17 INTEGER (0..127) OPTIONAL, + i18 INTEGER (0..127) OPTIONAL, + i19 INTEGER (0..127) OPTIONAL, + i20 INTEGER (0..127) OPTIONAL, + i21 INTEGER (0..127) OPTIONAL, + i22 INTEGER (0..127) OPTIONAL, + i23 INTEGER (0..127) OPTIONAL, + i24 INTEGER (0..127) OPTIONAL, + i25 INTEGER (0..127) OPTIONAL, + i26 INTEGER (0..127) OPTIONAL, + i27 INTEGER (0..127) OPTIONAL, + i28 INTEGER (0..127) OPTIONAL, + i29 INTEGER (0..127) OPTIONAL, + i30 INTEGER (0..127) OPTIONAL, + i31 INTEGER (0..127) OPTIONAL, + i32 INTEGER (0..127) OPTIONAL, + i33 INTEGER (0..127) OPTIONAL, + i34 INTEGER (0..127) OPTIONAL, + i35 INTEGER (0..127) OPTIONAL, + i36 INTEGER (0..127) OPTIONAL, + i37 INTEGER (0..127) OPTIONAL, + i38 INTEGER (0..127) OPTIONAL, + i39 INTEGER (0..127) OPTIONAL, + i40 INTEGER (0..127) OPTIONAL, + i41 INTEGER (0..127) OPTIONAL, + i42 INTEGER (0..127) OPTIONAL, + i43 INTEGER (0..127) OPTIONAL, + i44 INTEGER (0..127) OPTIONAL, + i45 INTEGER (0..127) OPTIONAL, + i46 INTEGER (0..127) OPTIONAL, + i47 INTEGER (0..127) OPTIONAL, + i48 INTEGER (0..127) OPTIONAL, + i49 INTEGER (0..127) OPTIONAL, + i50 INTEGER (0..127) OPTIONAL, + i51 INTEGER (0..127) OPTIONAL, + i52 INTEGER (0..127) OPTIONAL, + i53 INTEGER (0..127) OPTIONAL, + i54 INTEGER (0..127) OPTIONAL, + i55 INTEGER (0..127) OPTIONAL, + i56 INTEGER (0..127) OPTIONAL, + i57 INTEGER (0..127) OPTIONAL, + i58 INTEGER (0..127) OPTIONAL, + i59 INTEGER (0..127) OPTIONAL, + i60 INTEGER (0..127) OPTIONAL, + i61 INTEGER (0..127) OPTIONAL, + i62 INTEGER (0..127) OPTIONAL, + i63 INTEGER (0..127) OPTIONAL, + i64 INTEGER (0..127) OPTIONAL, + i65 INTEGER (0..127) OPTIONAL +} + +SeqExt130 ::= SEQUENCE { + ..., + i0 INTEGER (0..255) OPTIONAL, + i1 INTEGER (0..255) OPTIONAL, + i2 INTEGER (0..255) OPTIONAL, + i3 INTEGER (0..255) OPTIONAL, + i4 INTEGER (0..255) OPTIONAL, + i5 INTEGER (0..255) OPTIONAL, + i6 INTEGER (0..255) OPTIONAL, + i7 INTEGER (0..255) OPTIONAL, + i8 INTEGER (0..255) OPTIONAL, + i9 INTEGER (0..255) OPTIONAL, + i10 INTEGER (0..255) OPTIONAL, + i11 INTEGER (0..255) OPTIONAL, + i12 INTEGER (0..255) OPTIONAL, + i13 INTEGER (0..255) OPTIONAL, + i14 INTEGER (0..255) OPTIONAL, + i15 INTEGER (0..255) OPTIONAL, + i16 INTEGER (0..255) OPTIONAL, + i17 INTEGER (0..255) OPTIONAL, + i18 INTEGER (0..255) OPTIONAL, + i19 INTEGER (0..255) OPTIONAL, + i20 INTEGER (0..255) OPTIONAL, + i21 INTEGER (0..255) OPTIONAL, + i22 INTEGER (0..255) OPTIONAL, + i23 INTEGER (0..255) OPTIONAL, + i24 INTEGER (0..255) OPTIONAL, + i25 INTEGER (0..255) OPTIONAL, + i26 INTEGER (0..255) OPTIONAL, + i27 INTEGER (0..255) OPTIONAL, + i28 INTEGER (0..255) OPTIONAL, + i29 INTEGER (0..255) OPTIONAL, + i30 INTEGER (0..255) OPTIONAL, + i31 INTEGER (0..255) OPTIONAL, + i32 INTEGER (0..255) OPTIONAL, + i33 INTEGER (0..255) OPTIONAL, + i34 INTEGER (0..255) OPTIONAL, + i35 INTEGER (0..255) OPTIONAL, + i36 INTEGER (0..255) OPTIONAL, + i37 INTEGER (0..255) OPTIONAL, + i38 INTEGER (0..255) OPTIONAL, + i39 INTEGER (0..255) OPTIONAL, + i40 INTEGER (0..255) OPTIONAL, + i41 INTEGER (0..255) OPTIONAL, + i42 INTEGER (0..255) OPTIONAL, + i43 INTEGER (0..255) OPTIONAL, + i44 INTEGER (0..255) OPTIONAL, + i45 INTEGER (0..255) OPTIONAL, + i46 INTEGER (0..255) OPTIONAL, + i47 INTEGER (0..255) OPTIONAL, + i48 INTEGER (0..255) OPTIONAL, + i49 INTEGER (0..255) OPTIONAL, + i50 INTEGER (0..255) OPTIONAL, + i51 INTEGER (0..255) OPTIONAL, + i52 INTEGER (0..255) OPTIONAL, + i53 INTEGER (0..255) OPTIONAL, + i54 INTEGER (0..255) OPTIONAL, + i55 INTEGER (0..255) OPTIONAL, + i56 INTEGER (0..255) OPTIONAL, + i57 INTEGER (0..255) OPTIONAL, + i58 INTEGER (0..255) OPTIONAL, + i59 INTEGER (0..255) OPTIONAL, + i60 INTEGER (0..255) OPTIONAL, + i61 INTEGER (0..255) OPTIONAL, + i62 INTEGER (0..255) OPTIONAL, + i63 INTEGER (0..255) OPTIONAL, + i64 INTEGER (0..255) OPTIONAL, + i65 INTEGER (0..255) OPTIONAL, + i66 INTEGER (0..255) OPTIONAL, + i67 INTEGER (0..255) OPTIONAL, + i68 INTEGER (0..255) OPTIONAL, + i69 INTEGER (0..255) OPTIONAL, + i70 INTEGER (0..255) OPTIONAL, + i71 INTEGER (0..255) OPTIONAL, + i72 INTEGER (0..255) OPTIONAL, + i73 INTEGER (0..255) OPTIONAL, + i74 INTEGER (0..255) OPTIONAL, + i75 INTEGER (0..255) OPTIONAL, + i76 INTEGER (0..255) OPTIONAL, + i77 INTEGER (0..255) OPTIONAL, + i78 INTEGER (0..255) OPTIONAL, + i79 INTEGER (0..255) OPTIONAL, + i80 INTEGER (0..255) OPTIONAL, + i81 INTEGER (0..255) OPTIONAL, + i82 INTEGER (0..255) OPTIONAL, + i83 INTEGER (0..255) OPTIONAL, + i84 INTEGER (0..255) OPTIONAL, + i85 INTEGER (0..255) OPTIONAL, + i86 INTEGER (0..255) OPTIONAL, + i87 INTEGER (0..255) OPTIONAL, + i88 INTEGER (0..255) OPTIONAL, + i89 INTEGER (0..255) OPTIONAL, + i90 INTEGER (0..255) OPTIONAL, + i91 INTEGER (0..255) OPTIONAL, + i92 INTEGER (0..255) OPTIONAL, + i93 INTEGER (0..255) OPTIONAL, + i94 INTEGER (0..255) OPTIONAL, + i95 INTEGER (0..255) OPTIONAL, + i96 INTEGER (0..255) OPTIONAL, + i97 INTEGER (0..255) OPTIONAL, + i98 INTEGER (0..255) OPTIONAL, + i99 INTEGER (0..255) OPTIONAL, + i100 INTEGER (0..255) OPTIONAL, + i101 INTEGER (0..255) OPTIONAL, + i102 INTEGER (0..255) OPTIONAL, + i103 INTEGER (0..255) OPTIONAL, + i104 INTEGER (0..255) OPTIONAL, + i105 INTEGER (0..255) OPTIONAL, + i106 INTEGER (0..255) OPTIONAL, + i107 INTEGER (0..255) OPTIONAL, + i108 INTEGER (0..255) OPTIONAL, + i109 INTEGER (0..255) OPTIONAL, + i110 INTEGER (0..255) OPTIONAL, + i111 INTEGER (0..255) OPTIONAL, + i112 INTEGER (0..255) OPTIONAL, + i113 INTEGER (0..255) OPTIONAL, + i114 INTEGER (0..255) OPTIONAL, + i115 INTEGER (0..255) OPTIONAL, + i116 INTEGER (0..255) OPTIONAL, + i117 INTEGER (0..255) OPTIONAL, + i118 INTEGER (0..255) OPTIONAL, + i119 INTEGER (0..255) OPTIONAL, + i120 INTEGER (0..255) OPTIONAL, + i121 INTEGER (0..255) OPTIONAL, + i122 INTEGER (0..255) OPTIONAL, + i123 INTEGER (0..255) OPTIONAL, + i124 INTEGER (0..255) OPTIONAL, + i125 INTEGER (0..255) OPTIONAL, + i126 INTEGER (0..255) OPTIONAL, + i127 INTEGER (0..255) OPTIONAL, + i128 INTEGER (0..255) OPTIONAL, + i129 INTEGER (0..255) OPTIONAL +} + +END diff --git a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl index 00e4c707dd..8e21e6ca84 100644 --- a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl +++ b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl @@ -34,6 +34,9 @@ run(Erule) -> run3(), run3(Erule), + roundtrip('InlinedSeq', #'InlinedSeq'{s=#'InlinedSeq_s'{a=42,b=true}}), + roundtrip('ExtAddGroup1', #'ExtAddGroup1'{x=42,y=1023}), + ok. %% From X.691 (07/2002) A.4. diff --git a/lib/asn1/test/asn1_test_lib.erl b/lib/asn1/test/asn1_test_lib.erl index b839dfcf2a..7d7364e2a4 100644 --- a/lib/asn1/test/asn1_test_lib.erl +++ b/lib/asn1/test/asn1_test_lib.erl @@ -22,6 +22,7 @@ -export([compile/3]). -export([compile_all/3]). -export([compile_erlang/3]). +-export([hex_to_bin/1]). -export([ticket_7407_compile/2,ticket_7407_code/1, ticket_7678/2, ticket_7708/2, ticket_7763/1, ticket_7876/3]). @@ -61,6 +62,13 @@ compile_erlang(Mod, Config, Options) -> {ok, M} = compile:file(filename:join(DataDir, Mod), [report,{i,CaseDir},{outdir,CaseDir}|Options]). +hex_to_bin(S) -> + << <<(hex2num(C)):4>> || C <- S, C =/= $\s >>. + +%%% +%%% Internal functions. +%%% + should_load(File, Options) -> case lists:member(abs, Options) of true -> @@ -79,6 +87,10 @@ strip_extension(File, Ext) when Ext == ".asn"; Ext == ".set"; Ext == ".asn1"-> strip_extension(File, _Ext) -> File. +hex2num(C) when $0 =< C, C =< $9 -> C - $0; +hex2num(C) when $A =< C, C =< $F -> C - $A + 10; +hex2num(C) when $a =< C, C =< $f -> C - $a + 10. + ticket_7407_compile(Config,Option) -> ?line DataDir = ?config(data_dir,Config), diff --git a/lib/asn1/test/testConstraints.erl b/lib/asn1/test/testConstraints.erl index e825302629..14e508d2b5 100644 --- a/lib/asn1/test/testConstraints.erl +++ b/lib/asn1/test/testConstraints.erl @@ -126,19 +126,29 @@ int_constraints(Rules) -> %%========================================================== roundtrip('SemiConstrained', 100), + v_roundtrip(Rules, 'SemiConstrained', 100+128), roundtrip('SemiConstrained', 397249742397243), + roundtrip('SemiConstrained', 100 + 1 bsl 128*8), + roundtrip('SemiConstrained', 100 + 1 bsl 256*8), + roundtrip('NegSemiConstrained', -128), + v_roundtrip(Rules, 'NegSemiConstrained', 0), roundtrip('NegSemiConstrained', -1), roundtrip('NegSemiConstrained', 500), roundtrip('SemiConstrainedExt', -65536), roundtrip('SemiConstrainedExt', 0), roundtrip('SemiConstrainedExt', 42), + v_roundtrip(Rules, 'SemiConstrainedExt', 42+128), roundtrip('SemiConstrainedExt', 100), roundtrip('SemiConstrainedExt', 47777789), + roundtrip('SemiConstrainedExt', 42 + 1 bsl 128*8), + roundtrip('SemiConstrainedExt', 42 + 1 bsl 256*8), + roundtrip('NegSemiConstrainedExt', -1023), roundtrip('NegSemiConstrainedExt', -128), roundtrip('NegSemiConstrainedExt', -1), + v_roundtrip(Rules, 'NegSemiConstrainedExt', 0), roundtrip('NegSemiConstrainedExt', 500), %%========================================================== @@ -174,6 +184,21 @@ int_constraints(Rules) -> ok. +%% PER: Ensure that if the lower bound is Lb, Lb+16#80 is encoded +%% in two bytes as 16#0180. (Not in three bytes as 16#010080.) +v(ber, 'SemiConstrained', 100+128) -> "020200E4"; +v(per, 'SemiConstrained', 100+128) -> "0180"; +v(uper, 'SemiConstrained', 100+128) -> "0180"; +v(ber, 'NegSemiConstrained', 0) -> "020100"; +v(per, 'NegSemiConstrained', 0) -> "0180"; +v(uper, 'NegSemiConstrained', 0) -> "0180"; +v(ber, 'SemiConstrainedExt', 42+128) -> "020200AA"; +v(per, 'SemiConstrainedExt', 42+128) -> "000180"; +v(uper, 'SemiConstrainedExt', 42+128) -> "00C000"; +v(ber, 'NegSemiConstrainedExt', 0) -> "020100"; +v(per, 'NegSemiConstrainedExt', 0) -> "000180"; +v(uper, 'NegSemiConstrainedExt', 0) -> "00C000". + shorter_ext(per, "a") -> <<16#80,16#01,16#61>>; shorter_ext(uper, "a") -> <<16#80,16#E1>>; shorter_ext(ber, _) -> none. @@ -183,13 +208,17 @@ refed_NNL_name(_Erule) -> ?line {error,_Reason} = asn1_wrapper:encode('Constraints','AnotherThing',fred3). +v_roundtrip(Erule, Type, Value) -> + Encoded = asn1_test_lib:hex_to_bin(v(Erule, Type, Value)), + Encoded = roundtrip('Constraints', Type, Value). + roundtrip(Type, Value) -> roundtrip('Constraints', Type, Value). roundtrip(Module, Type, Value) -> {ok,Encoded} = Module:encode(Type, Value), {ok,Value} = Module:decode(Type, Encoded), - ok. + Encoded. roundtrip_enc(Type, Value, Enc) -> Module = 'Constraints', diff --git a/lib/asn1/test/testEnumExt.erl b/lib/asn1/test/testEnumExt.erl index 8840ed6d2f..8779f3b83b 100644 --- a/lib/asn1/test/testEnumExt.erl +++ b/lib/asn1/test/testEnumExt.erl @@ -38,7 +38,7 @@ main(Rule) when Rule =:= per; Rule =:= uper -> %% ENUMERATED no extensionmark B64 = <<64>>, B64 = roundtrip('Noext', red), - common(); + common(Rule); main(ber) -> io:format("main(ber)~n",[]), %% ENUMERATED with extensionmark (value is in root set) @@ -56,18 +56,38 @@ main(ber) -> roundtrip('Globalstate', preop), roundtrip('Globalstate', com), - common(). + common(ber). -common() -> +common(Erule) -> roundtrip('Seq', {'Seq',blue,42}), roundtrip('Seq', {'Seq',red,42}), roundtrip('Seq', {'Seq',green,42}), roundtrip('Seq', {'Seq',orange,47}), roundtrip('Seq', {'Seq',black,4711}), roundtrip('Seq', {'Seq',magenta,4712}), + + [begin + S = io_lib:format("e~2.016.0b", [I]), + E = list_to_atom(lists:flatten(S)), + roundtrip('SeqBig', {'SeqBig',true,E,9357}) + end || I <- lists:seq(0, 128)], + + v_roundtrip(Erule, 'SeqBig', {'SeqBig',true,e40,9357}), + v_roundtrip(Erule, 'SeqBig', {'SeqBig',true,e80,9357}), ok. roundtrip(Type, Value) -> {ok,Encoded} = 'EnumExt':encode(Type, Value), {ok,Value} = 'EnumExt':decode(Type, Encoded), Encoded. + +v_roundtrip(Erule, Type, Value) -> + Encoded = roundtrip(Type, Value), + Encoded = asn1_test_lib:hex_to_bin(v(Erule, Value)). + +v(ber, {'SeqBig',true,e40,9357}) -> "300A8001 FF810141 8202248D"; +v(ber, {'SeqBig',true,e80,9357}) -> "300B8001 FF810200 81820224 8D"; +v(per, {'SeqBig',true,e40,9357}) -> "E0014002 248D"; +v(per, {'SeqBig',true,e80,9357}) -> "E0018002 248D"; +v(uper, {'SeqBig',true,e40,9357}) -> "E0280044 91A0"; +v(uper, {'SeqBig',true,e80,9357}) -> "E0300044 91A0". diff --git a/lib/asn1/test/testSeqExtension.erl b/lib/asn1/test/testSeqExtension.erl index 1128d9a7c3..724f485fa0 100644 --- a/lib/asn1/test/testSeqExtension.erl +++ b/lib/asn1/test/testSeqExtension.erl @@ -20,7 +20,7 @@ -module(testSeqExtension). -include("External.hrl"). --export([main/2]). +-export([main/3]). -include_lib("test_server/include/test_server.hrl"). @@ -32,7 +32,7 @@ -record('SeqExt6',{i1,i2,i3,i4,i5,i6,i7}). -record('SuperSeq',{s1,s2,s3,s4,s5,s6,i}). -main(DataDir, Opts) -> +main(Erule, DataDir, Opts) -> roundtrip('SeqExt1', #'SeqExt1'{}), roundtrip('SeqExt2', #'SeqExt2'{bool=true,int=99}), @@ -92,9 +92,38 @@ main(DataDir, Opts) -> s5={'SeqExt5'}, s6={'SeqExt6',531,601,999,777,11953}, i=BigInt} = DecodedSuperSeq, + + + %% Test more than 64 extensions. + roundtrip2('SeqExt66', + list_to_tuple(['SeqExt66'|lists:seq(0, 65)])), + v_roundtrip2(Erule, 'SeqExt66', + list_to_tuple(['SeqExt66'| + lists:duplicate(65, asn1_NOVALUE)++[125]])), + roundtrip2('SeqExt130', + list_to_tuple(['SeqExt130'|lists:seq(0, 129)])), + v_roundtrip2(Erule, 'SeqExt130', + list_to_tuple(['SeqExt130'| + lists:duplicate(129, asn1_NOVALUE)++[199]])), ok. roundtrip(Type, Value) -> {ok,Encoded} = 'SeqExtension':encode(Type, Value), {ok,Value} = 'SeqExtension':decode(Type, Encoded), ok. + +v_roundtrip2(Erule, Type, Value) -> + Encoded = asn1_test_lib:hex_to_bin(v(Erule, Type)), + Encoded = roundtrip2(Type, Value). + +roundtrip2(Type, Value) -> + {ok,Encoded} = 'SeqExtension2':encode(Type, Value), + {ok,Value} = 'SeqExtension2':decode(Type, Encoded), + Encoded. + +v(ber, 'SeqExt66') -> "30049F41 017D"; +v(per, 'SeqExt66') -> "C0420000 00000000 00004001 FA"; +v(uper, 'SeqExt66') -> "D0800000 00000000 00101FA0"; +v(ber, 'SeqExt130') -> "30069F81 010200C7"; +v(per, 'SeqExt130') -> "C0808200 00000000 00000000 00000000 00000040 01C7"; +v(uper, 'SeqExt130') -> "E0208000 00000000 00000000 00000000 0000101C 70". diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 98ebb21f29..00abeb9990 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -142,6 +142,19 @@ (s)[3] = (char)((i) & 0xff);\ } +/* This shall correspond to the similar macro in crypto.erl */ +/* Current value is: erlang:system_info(context_reductions) * 10 */ +#define MAX_BYTES_TO_NIF 20000 + +#define CONSUME_REDS(NifEnv, Ibin) \ +do { \ + int _cost = ((Ibin).size * 100) / MAX_BYTES_TO_NIF;\ + if (_cost) { \ + (void) enif_consume_timeslice((NifEnv), \ + (_cost > 100) ? 100 : _cost); \ + } \ + } while (0) + /* NIF interface declarations */ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info); @@ -208,7 +221,7 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -338,7 +351,7 @@ static ErlNifFunc nif_funcs[] = { {"dss_verify_nif", 4, dss_verify_nif}, {"rsa_verify_nif", 4, rsa_verify_nif}, {"aes_cbc_crypt", 4, aes_cbc_crypt}, - {"exor", 2, exor}, + {"do_exor", 2, do_exor}, {"rc4_encrypt", 2, rc4_encrypt}, {"rc4_set_key", 1, rc4_set_key}, {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state}, @@ -778,6 +791,7 @@ static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } MD5((unsigned char *) ibin.data, ibin.size, enif_make_new_binary(env,MD5_LEN, &ret)); + CONSUME_REDS(env,ibin); return ret; } static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -799,6 +813,7 @@ static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv new_ctx = (MD5_CTX*) enif_make_new_binary(env,MD5_CTX_LEN, &ret); memcpy(new_ctx, ctx_bin.data, MD5_CTX_LEN); MD5_Update(new_ctx, data_bin.data, data_bin.size); + CONSUME_REDS(env,data_bin); return ret; } static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -820,10 +835,11 @@ static ERL_NIF_TERM ripemd160(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ ERL_NIF_TERM ret; if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { - return enif_make_badarg(env); + return enif_make_badarg(env); } RIPEMD160((unsigned char *) ibin.data, ibin.size, - enif_make_new_binary(env,RIPEMD160_LEN, &ret)); + enif_make_new_binary(env,RIPEMD160_LEN, &ret)); + CONSUME_REDS(env,ibin); return ret; } static ERL_NIF_TERM ripemd160_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -838,13 +854,14 @@ static ERL_NIF_TERM ripemd160_update(ErlNifEnv* env, int argc, const ERL_NIF_TER ErlNifBinary ctx_bin, data_bin; ERL_NIF_TERM ret; if (!enif_inspect_binary(env, argv[0], &ctx_bin) - || ctx_bin.size != RIPEMD160_CTX_LEN - || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { - return enif_make_badarg(env); + || ctx_bin.size != RIPEMD160_CTX_LEN + || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { + return enif_make_badarg(env); } new_ctx = (RIPEMD160_CTX*) enif_make_new_binary(env,RIPEMD160_CTX_LEN, &ret); memcpy(new_ctx, ctx_bin.data, RIPEMD160_CTX_LEN); RIPEMD160_Update(new_ctx, data_bin.data, data_bin.size); + CONSUME_REDS(env, data_bin); return ret; } static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -853,7 +870,7 @@ static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM RIPEMD160_CTX ctx_clone; ERL_NIF_TERM ret; if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != RIPEMD160_CTX_LEN) { - return enif_make_badarg(env); + return enif_make_badarg(env); } memcpy(&ctx_clone, ctx_bin.data, RIPEMD160_CTX_LEN); /* writable */ RIPEMD160_Final(enif_make_new_binary(env, RIPEMD160_LEN, &ret), &ctx_clone); @@ -871,6 +888,7 @@ static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } SHA1((unsigned char *) ibin.data, ibin.size, enif_make_new_binary(env,SHA_LEN, &ret)); + CONSUME_REDS(env,ibin); return ret; } static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -891,6 +909,7 @@ static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv new_ctx = (SHA_CTX*) enif_make_new_binary(env,SHA_CTX_LEN, &ret); memcpy(new_ctx, ctx_bin.data, SHA_CTX_LEN); SHA1_Update(new_ctx, data_bin.data, data_bin.size); + CONSUME_REDS(env,data_bin); return ret; } static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -917,6 +936,7 @@ static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv } SHA224((unsigned char *) ibin.data, ibin.size, enif_make_new_binary(env,SHA224_LEN, &ret)); + CONSUME_REDS(env,ibin); return ret; #else return atom_notsup; @@ -945,6 +965,7 @@ static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret); memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX)); SHA224_Update(new_ctx, data_bin.data, data_bin.size); + CONSUME_REDS(env,data_bin); return ret; #else return atom_notsup; @@ -978,6 +999,7 @@ static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv } SHA256((unsigned char *) ibin.data, ibin.size, enif_make_new_binary(env,SHA256_LEN, &ret)); + CONSUME_REDS(env,ibin); return ret; #else return atom_notsup; @@ -1006,6 +1028,7 @@ static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret); memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX)); SHA256_Update(new_ctx, data_bin.data, data_bin.size); + CONSUME_REDS(env,data_bin); return ret; #else return atom_notsup; @@ -1039,6 +1062,7 @@ static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv } SHA384((unsigned char *) ibin.data, ibin.size, enif_make_new_binary(env,SHA384_LEN, &ret)); + CONSUME_REDS(env,ibin); return ret; #else return atom_notsup; @@ -1067,6 +1091,7 @@ static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret); memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX)); SHA384_Update(new_ctx, data_bin.data, data_bin.size); + CONSUME_REDS(env,data_bin); return ret; #else return atom_notsup; @@ -1100,6 +1125,7 @@ static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv } SHA512((unsigned char *) ibin.data, ibin.size, enif_make_new_binary(env,SHA512_LEN, &ret)); + CONSUME_REDS(env,ibin); return ret; #else return atom_notsup; @@ -1128,6 +1154,7 @@ static ERL_NIF_TERM sha512_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret); memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX)); SHA512_Update(new_ctx, data_bin.data, data_bin.size); + CONSUME_REDS(env,data_bin); return ret; #else return atom_notsup; @@ -1161,6 +1188,7 @@ static ERL_NIF_TERM md4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } MD4((unsigned char *) ibin.data, ibin.size, enif_make_new_binary(env,MD4_LEN, &ret)); + CONSUME_REDS(env,ibin); return ret; } static ERL_NIF_TERM md4_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -1181,6 +1209,7 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv new_ctx = (MD4_CTX*) enif_make_new_binary(env,MD4_CTX_LEN, &ret); memcpy(new_ctx, ctx_bin.data, MD4_CTX_LEN); MD4_Update(new_ctx, data_bin.data, data_bin.size); + CONSUME_REDS(env,data_bin); return ret; } static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -1210,6 +1239,7 @@ static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ } hmac_md5(key.data, key.size, data.data, data.size, hmacbuf); memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz); + CONSUME_REDS(env,data); return ret; } @@ -1228,6 +1258,7 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ hmac_sha1(key.data, key.size, data.data, data.size, hmacbuf); memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz); + CONSUME_REDS(env,data); return ret; } @@ -1247,6 +1278,7 @@ static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM hmac_sha224(key.data, key.size, data.data, data.size, hmacbuf); memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz); + CONSUME_REDS(env,data); return ret; #else return atom_notsup; @@ -1269,6 +1301,7 @@ static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM hmac_sha256(key.data, key.size, data.data, data.size, hmacbuf); memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz); + CONSUME_REDS(env,data); return ret; #else return atom_notsup; @@ -1291,6 +1324,7 @@ static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM hmac_sha384(key.data, key.size, data.data, data.size, hmacbuf); memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz); + CONSUME_REDS(env,data); return ret; #else return atom_notsup; @@ -1314,6 +1348,7 @@ static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM hmac_sha512(key.data, key.size, data.data, data.size, hmacbuf); memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz); + CONSUME_REDS(env,data); return ret; #else return atom_notsup; @@ -1371,6 +1406,7 @@ static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg ctx_buf = enif_make_new_binary(env, sizeof(HMAC_CTX), &ret); memcpy(ctx_buf, context.data, context.size); HMAC_Update((HMAC_CTX *)ctx_buf, data.data, data.size); + CONSUME_REDS(env,data); return ret; } @@ -1427,6 +1463,7 @@ static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a DES_set_key((const_DES_cblock*)key.data, &schedule); DES_ncbc_encrypt(text.data, enif_make_new_binary(env, text.size, &ret), text.size, &schedule, &ivec_clone, (argv[3] == atom_true)); + CONSUME_REDS(env,text); return ret; } @@ -1446,6 +1483,7 @@ static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a DES_set_key((const_DES_cblock*)key.data, &schedule); DES_cfb_encrypt(text.data, enif_make_new_binary(env, text.size, &ret), 8, text.size, &schedule, &ivec_clone, (argv[3] == atom_true)); + CONSUME_REDS(env,text); return ret; } @@ -1462,6 +1500,7 @@ static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a DES_ecb_encrypt((const_DES_cblock*)text.data, (DES_cblock*)enif_make_new_binary(env, 8, &ret), &schedule, (argv[2] == atom_true)); + CONSUME_REDS(env,text); return ret; } @@ -1488,6 +1527,7 @@ static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T DES_ede3_cbc_encrypt(text.data, enif_make_new_binary(env,text.size,&ret), text.size, &schedule1, &schedule2, &schedule3, &ivec_clone, (argv[5] == atom_true)); + CONSUME_REDS(env,text); return ret; } @@ -1514,6 +1554,7 @@ static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_N DES_ede3_cfb_encrypt(text.data, enif_make_new_binary(env,text.size,&ret), 8, text.size, &schedule1, &schedule2, &schedule3, &ivec_clone, (argv[5] == atom_true)); + CONSUME_REDS(env,text); return ret; #else return atom_notsup; @@ -1540,6 +1581,7 @@ static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE enif_make_new_binary(env, text.size, &ret), text.size, &aes_key, ivec_clone, &new_ivlen, (argv[3] == atom_true)); + CONSUME_REDS(env,text); return ret; } @@ -1565,6 +1607,7 @@ static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM AES_ctr128_encrypt((unsigned char *) text.data, enif_make_new_binary(env, text.size, &ret), text.size, &aes_key, ivec_clone, ecount_buf, &num); + CONSUME_REDS(env,text); /* To do an incremental {en|de}cryption, the state to to keep between calls must include ivec_clone, ecount_buf and num. */ @@ -1608,6 +1651,7 @@ static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_N num2_term = enif_make_uint(env, num); new_state_term = enif_make_tuple4(env, state_term[0], ivec2_term, ecount2_term, num2_term); ret = enif_make_tuple2(env, new_state_term, cipher_term); + CONSUME_REDS(env,text_bin); return ret; } @@ -2055,10 +2099,11 @@ static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a ret_ptr = enif_make_new_binary(env, data_bin.size, &ret); memcpy(ivec, ivec_bin.data, 16); /* writable copy */ AES_cbc_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i); + CONSUME_REDS(env,data_bin); return ret; } -static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Data1, Data2) */ ErlNifBinary d1, d2; unsigned char* ret_ptr; @@ -2075,6 +2120,7 @@ static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) for (i=0; i<d1.size; i++) { ret_ptr[i] = d1.data[i] ^ d2.data[i]; } + CONSUME_REDS(env,d1); return ret; } @@ -2091,6 +2137,7 @@ static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg RC4_set_key(&rc4_key, key.size, key.data); RC4(&rc4_key, data.size, data.data, enif_make_new_binary(env, data.size, &ret)); + CONSUME_REDS(env,data); return ret; } @@ -2123,7 +2170,7 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N memcpy(rc4_key, state.data, sizeof(RC4_KEY)); RC4(rc4_key, data.size, data.data, enif_make_new_binary(env, data.size, &new_data)); - + CONSUME_REDS(env,data); return enif_make_tuple2(env,new_state,new_data); } @@ -2150,6 +2197,7 @@ static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a data_bin.size, &rc2_key, iv_copy, (argv[3] == atom_true)); + CONSUME_REDS(env,data_bin); return ret; } @@ -2781,6 +2829,7 @@ static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM BF_cfb64_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret), data_bin.size, &bf_key, bf_tkey, &bf_n, (argv[3] == atom_true ? BF_ENCRYPT : BF_DECRYPT)); + CONSUME_REDS(env,data_bin); return ret; } @@ -2804,6 +2853,7 @@ static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar BF_cbc_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret), data_bin.size, &bf_key, bf_tkey, (argv[3] == atom_true ? BF_ENCRYPT : BF_DECRYPT)); + CONSUME_REDS(env,data_bin); return ret; } @@ -2821,6 +2871,7 @@ static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar BF_set_key(&bf_key, key_bin.size, key_bin.data); BF_ecb_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret), &bf_key, (argv[2] == atom_true ? BF_ENCRYPT : BF_DECRYPT)); + CONSUME_REDS(env,data_bin); return ret; } @@ -2843,6 +2894,7 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N memcpy(bf_tkey, ivec_bin.data, 8); BF_ofb64_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret), data_bin.size, &bf_key, bf_tkey, &bf_n); + CONSUME_REDS(env,data_bin); return ret; } diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 2df407018e..99d167bfa9 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -208,7 +208,7 @@ </type> <desc> <p>Computes the shared secret from the private key and the other party's public key. - See also <seealso marker="public_key:public_key#compute_key/2">public_key:compute_key/2</seealso> + See also <seealso marker="public_key:public_key#compute_key-2">public_key:compute_key/2</seealso> </p> </desc> </func> @@ -240,7 +240,7 @@ </type> <desc> <p>Generates public keys of type <c>Type</c>. - See also <seealso marker="public_key:public_key#generate_key/1">public_key:generate_key/1</seealso> + See also <seealso marker="public_key:public_key#generate_key-1">public_key:generate_key/1</seealso> </p> </desc> </func> @@ -269,7 +269,7 @@ <desc> <p>Initializes the context for streaming hash operations. <c>Type</c> determines which digest to use. The returned context should be used as argument - to <seealso marker="#hash_update/2">hash_update</seealso>.</p> + to <seealso marker="#hash_update-2">hash_update</seealso>.</p> <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c> is not supported by the underlying OpenSSL implementation.</p> </desc> @@ -283,10 +283,10 @@ </type> <desc> <p>Updates the digest represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c> - must have been generated using <seealso marker="#hash_init/1">hash_init</seealso> + must have been generated using <seealso marker="#hash_init-1">hash_init</seealso> or a previous call to this function. <c>Data</c> can be any length. <c>NewContext</c> must be passed into the next call to <c>hash_update</c> - or <seealso marker="#hash_final/1">hash_final</seealso>.</p> + or <seealso marker="#hash_final-1">hash_final</seealso>.</p> </desc> </func> <func> @@ -297,7 +297,7 @@ </type> <desc> <p>Finalizes the hash operation referenced by <c>Context</c> returned - from a previous call to <seealso marker="#hash_update/2">hash_update</seealso>. + from a previous call to <seealso marker="#hash_update-2">hash_update</seealso>. The size of <c>Digest</c> is determined by the type of hash function used to generate it.</p> </desc> @@ -346,10 +346,10 @@ <desc> <p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c> must have been generated using an HMAC init function (such as - <seealso marker="#hmac_init/2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c> + <seealso marker="#hmac_init-2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c> must be passed into the next call to <c>hmac_update</c> - or to one of the functions <seealso marker="#hmac_final/1">hmac_final</seealso> and - <seealso marker="#hmac_final_n/1">hmac_final_n</seealso> + or to one of the functions <seealso marker="#hmac_final-1">hmac_final</seealso> and + <seealso marker="#hmac_final_n-2">hmac_final_n</seealso> </p> </desc> @@ -447,36 +447,36 @@ <v>PlainText = binary()</v> </type> <desc> - <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with - <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>) - using the <c>PrivateKey</c> and returns the - message. The <c>Padding</c> is the padding mode that was - used to encrypt the data, - see <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>. - See also <seealso marker="public_key:public_key#decrypt_private/2">public_key:decrypt_private/[2,3]</seealso> + <p>Decrypts the <c>ChipherText</c>, encrypted with + <seealso marker="#public_encrypt-4">public_encrypt/4</seealso> (or equivalent function) + using the <c>PrivateKey</c>, and returns the + plaintext (message digest). This is a low level signature verification operation + used for instance by older versions of the SSL protocol. + See also <seealso marker="public_key:public_key#decrypt_private-2">public_key:decrypt_private/[2,3]</seealso> </p> </desc> </func> - + <func> <name>private_encrypt(Type, PlainText, PrivateKey, Padding) -> ChipherText</name> - <fsummary>Encrypts Msg using the private Key.</fsummary> + <fsummary>Encrypts PlainText using the private Key.</fsummary> <type> <v>Type = rsa</v> <v>PlainText = binary()</v> + <d> The size of the <c>PlainText</c> must be less + than <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is + used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> is + used, where N is public modulus of the RSA key.</d> <v>PrivateKey = rsa_private()</v> <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v> <v>ChipherText = binary()</v> </type> <desc> <p>Encrypts the <c>PlainText</c> using the <c>PrivateKey</c> - and returns the cipher. The <c>Padding</c> decides what padding mode is used, - <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most - used mode. - The size of the <c>Msg</c> must be less than <c>byte_size(N)-11</c> if - <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> - is used, where N is public modulus of the RSA key. - See also <seealso marker="public_key:public_key#encrypt_private/2">public_key:encrypt_private/[2,3]</seealso> + and returns the ciphertext. This is a low level signature operation + used for instance by older versions of the SSL protocol. See + also <seealso + marker="public_key:public_key#encrypt_private-2">public_key:encrypt_private/[2,3]</seealso> </p> </desc> </func> @@ -491,42 +491,35 @@ <v>PlainText = binary()</v> </type> <desc> - <p>Decrypts the <c>ChipherText</c> (encrypted with - <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>) - using the <c>PrivateKey</c> and returns the - message. The <c>Padding</c> is the padding mode that was - used to encrypt the data, - see <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>. - See also <seealso marker="public_key:public_key#decrypt_public/2">public_key:decrypt_public/[2,3]</seealso> + <p>Decrypts the <c>ChipherText</c>, encrypted with + <seealso marker="#private_encrypt-4">private_encrypt/4</seealso>(or equivalent function) + using the <c>PrivateKey</c>, and returns the + plaintext (message digest). This is a low level signature verification operation + used for instance by older versions of the SSL protocol. + See also <seealso marker="public_key:public_key#decrypt_public-2">public_key:decrypt_public/[2,3]</seealso> </p> </desc> </func> <func> <name>public_encrypt(Type, PlainText, PublicKey, Padding) -> ChipherText</name> - <fsummary>Encrypts Msg using the public Key.</fsummary> + <fsummary>Encrypts PlainText using the public Key.</fsummary> <type> <v>Type = rsa</v> <v>PlainText = binary()</v> + <d> The size of the <c>PlainText</c> must be less + than <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is + used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> is + used, where N is public modulus of the RSA key.</d> <v>PublicKey = rsa_public()</v> <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v> <v>ChipherText = binary()</v> </type> <desc> - <p>Encrypts the <c>PlainText</c> (usually a session key) using - the <c>PublicKey</c> and returns the <c>CipherText</c>. The - <c>Padding</c> decides what padding mode is used, - <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most - used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as - defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding - parameter. This mode is recommended for all new - applications. The size of the <c>Msg</c> must be less than - <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is - used, <c>byte_size(N)-41</c> if - <c>rsa_pkcs1_oaep_padding</c> is used and - <c>byte_size(N)</c> if <c>rsa_no_padding</c> is used, where N is public modulus of the RSA key. - See also <seealso - marker="public_key:public_key#encrypt_public/2">public_key:encrypt_public/[2,3]</seealso> + <p>Encrypts the <c>PlainText</c> (message digest) using the <c>PublicKey</c> + and returns the <c>CipherText</c>. This is a low level signature operation + used for instance by older versions of the SSL protocol. See also <seealso + marker="public_key:public_key#encrypt_public-2">public_key:encrypt_public/[2,3]</seealso> </p> </desc> </func> @@ -563,9 +556,9 @@ <type> <v>Algorithm = rsa | dss | ecdsa </v> <v>Msg = binary() | {digest,binary()}</v> - <d>The msg is either the binary "plain text" data to be - signed or it is the hashed value of "plain text" i.e. the - digest.</d> + <d>The msg is either the binary "cleartext" data to be + signed or it is the hashed value of "cleartext" i.e. the + digest (plaintext).</d> <v>DigestType = digest_type()</v> <v>Key = rsa_private() | dss_private() | [ecdh_private(),ecdh_params()]</v> </type> @@ -573,7 +566,7 @@ <p>Creates a digital signature.</p> <p>Algorithm <c>dss</c> can only be used together with digest type <c>sha</c>.</p> - See also <seealso marker="public_key:public_key#sign/3">public_key:sign/3</seealso> + See also <seealso marker="public_key:public_key#sign-3">public_key:sign/3</seealso> </desc> </func> @@ -617,8 +610,8 @@ </type> <desc> <p>Initializes the state for use in RC4 stream encryption - <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and - <seealso marker="#stream_decrypt/2">stream_decrypt</seealso></p> + <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and + <seealso marker="#stream_decrypt-2">stream_decrypt</seealso></p> </desc> </func> @@ -635,8 +628,8 @@ <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR). <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with - <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and - <seealso marker="#stream_decrypt/2">stream_decrypt</seealso>.</p> + <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and + <seealso marker="#stream_decrypt-2">stream_decrypt</seealso>.</p> </desc> </func> @@ -650,7 +643,7 @@ <desc> <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3. <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using - <seealso marker="#stream_init/2">stream_init</seealso>. + <seealso marker="#stream_init-2">stream_init</seealso>. <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p> </desc> </func> @@ -665,7 +658,7 @@ <desc> <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3. <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using - <seealso marker="#stream_init/2">stream_init</seealso>. + <seealso marker="#stream_init-2">stream_init</seealso>. <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p> </desc> </func> @@ -692,8 +685,8 @@ <type> <v> Algorithm = rsa | dss | ecdsa </v> <v>Msg = binary() | {digest,binary()}</v> - <d>The msg is either the binary "plain text" data - or it is the hashed value of "plain text" i.e. the digest.</d> + <d>The msg is either the binary "cleartext" data + or it is the hashed value of "cleartext" i.e. the digest (plaintext).</d> <v>DigestType = digest_type()</v> <v>Signature = binary()</v> <v>Key = rsa_public() | dss_public() | [ecdh_public(),ecdh_params()]</v> @@ -703,7 +696,7 @@ <p>Algorithm <c>dss</c> can only be used together with digest type <c>sha</c>.</p> - See also <seealso marker="public_key:public_key#sign/3">public_key:verify/3</seealso> + See also <seealso marker="public_key:public_key#verify-4">public_key:verify/4</seealso> </desc> </func> diff --git a/lib/crypto/src/crypto.appup.src b/lib/crypto/src/crypto.appup.src index b39ef734eb..5b4ce5acee 100644 --- a/lib/crypto/src/crypto.appup.src +++ b/lib/crypto/src/crypto.appup.src @@ -1,7 +1,8 @@ +%% -*- erlang -*- %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -17,6 +18,11 @@ %% %CopyrightEnd% %% {"%VSN%", - [], - [] -}. + [ + {<<"2\\.*">>, [{restart_application, crypto}]} + {<<"1\\.*">>, [{restart_application, crypto}]} + ], + [ + {<<"2\\.*">>, [{restart_application, crypto}]} + {<<"1\\.*">>, [{restart_application, crypto}]} + ]}. diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index e042545094..a093b45410 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -35,7 +35,6 @@ -export([private_encrypt/4, public_decrypt/4]). -export([dh_generate_parameters/2, dh_check/1]). %% Testing see - %% DEPRECATED %% Replaced by hash_* -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). @@ -165,60 +164,8 @@ -export([info/0]). -deprecated({info, 0, next_major_release}). --define(FUNC_LIST, [hash, hash_init, hash_update, hash_final, - hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, - %% deprecated - md4, md4_init, md4_update, md4_final, - md5, md5_init, md5_update, md5_final, - sha, sha_init, sha_update, sha_final, - md5_mac, md5_mac_96, - sha_mac, sha_mac_96, - %% - block_encrypt, block_decrypt, - %% deprecated - des_cbc_encrypt, des_cbc_decrypt, - des_cfb_encrypt, des_cfb_decrypt, - des_ecb_encrypt, des_ecb_decrypt, - des3_cbc_encrypt, des3_cbc_decrypt, - des3_cfb_encrypt, des3_cfb_decrypt, - aes_cfb_128_encrypt, aes_cfb_128_decrypt, - rc2_cbc_encrypt, rc2_cbc_decrypt, - rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, - aes_cbc_128_encrypt, aes_cbc_128_decrypt, - aes_cbc_256_encrypt, aes_cbc_256_decrypt, - blowfish_cbc_encrypt, blowfish_cbc_decrypt, - blowfish_cfb64_encrypt, blowfish_cfb64_decrypt, - blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt, - %% - rand_bytes, - strong_rand_bytes, - rand_uniform, - mod_pow, - exor, - %% deprecated - mod_exp,strong_rand_mpint,erlint, mpint, - %% - sign, verify, generate_key, compute_key, - %% deprecated - dss_verify,dss_sign, - rsa_verify,rsa_sign, - rsa_public_encrypt,rsa_private_decrypt, - rsa_private_encrypt,rsa_public_decrypt, - dh_generate_key, dh_compute_key, - %% - stream_init, stream_encrypt, stream_decrypt, - %% deprecated - rc4_encrypt, rc4_set_key, rc4_encrypt_with_state, - aes_ctr_encrypt, aes_ctr_decrypt, - aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, - %% - next_iv, - %% deprecated - aes_cbc_ivec, - des_cbc_ivec, des_cfb_ivec, - info, - %% - info_lib, supports]). +%% This should correspond to the similar macro in crypto.c +-define(MAX_BYTES_TO_NIF, 20000). %% Current value is: erlang:system_info(context_reductions) * 10 -type mpint() :: binary(). -type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'. @@ -235,76 +182,27 @@ %%-type ec_curve() :: ec_named_curve() | ec_curve_spec(). %%-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}. --define(nif_stub,nif_stub_error(?LINE)). - -on_load(on_load/0). - -define(CRYPTO_NIF_VSN,201). -on_load() -> - LibBaseName = "crypto", - PrivDir = code:priv_dir(crypto), - LibName = case erlang:system_info(build_type) of - opt -> - LibBaseName; - Type -> - LibTypeName = LibBaseName ++ "." ++ atom_to_list(Type), - case (filelib:wildcard( - filename:join( - [PrivDir, - "lib", - LibTypeName ++ "*"])) /= []) orelse - (filelib:wildcard( - filename:join( - [PrivDir, - "lib", - erlang:system_info(system_architecture), - LibTypeName ++ "*"])) /= []) of - true -> LibTypeName; - false -> LibBaseName - end - end, - Lib = filename:join([PrivDir, "lib", LibName]), - Status = case erlang:load_nif(Lib, {?CRYPTO_NIF_VSN,Lib}) of - ok -> ok; - {error, {load_failed, _}}=Error1 -> - ArchLibDir = - filename:join([PrivDir, "lib", - erlang:system_info(system_architecture)]), - Candidate = - filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])), - case Candidate of - [] -> Error1; - _ -> - ArchLib = filename:join([ArchLibDir, LibName]), - erlang:load_nif(ArchLib, {?CRYPTO_NIF_VSN,ArchLib}) - end; - Error1 -> Error1 - end, - case Status of - ok -> ok; - {error, {E, Str}} -> - error_logger:error_msg("Unable to load crypto library. Failed with error:~n\"~p, ~s\"~n" - "OpenSSL might not be installed on this system.~n",[E,Str]), - Status - end. - +-define(nif_stub,nif_stub_error(?LINE)). nif_stub_error(Line) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). +%%-------------------------------------------------------------------- +%%% API +%%-------------------------------------------------------------------- +%% Crypto app version history: +%% (no version): Driver implementation +%% 2.0 : NIF implementation, requires OTP R14 +version() -> ?CRYPTO_VSN. + start() -> application:start(crypto). stop() -> application:stop(crypto). -info() -> - ?FUNC_LIST. - -info_lib() -> ?nif_stub. - -algorithms() -> ?nif_stub. - supports()-> Algs = algorithms(), PubKeyAlgs = @@ -316,32 +214,20 @@ supports()-> end, [{hashs, Algs -- [ec]}, {ciphers, [des_cbc, des_cfb, des3_cbc, des3_cbf, des_ede3, blowfish_cbc, - blowfish_cfb64, blowfish_ofb64, blowfish_ecb, aes_cbc128, aes_cfb128, aes_cbc256, rc2_cbc, aes_ctr, rc4 + blowfish_cfb64, blowfish_ofb64, blowfish_ecb, aes_cbc128, aes_cfb128, + aes_cbc256, rc2_cbc, aes_ctr, rc4 ]}, PubKeyAlgs ]. -%% Crypto app version history: -%% (no version): Driver implementation -%% 2.0 : NIF implementation, requires OTP R14 -version() -> ?CRYPTO_VSN. - -%% Below Key and Data are binaries or IO-lists. IVec is a binary. -%% Output is always a binary. Context is a binary. - -%% -%% MESSAGE DIGESTS -%% +info_lib() -> ?nif_stub. -spec hash(_, iodata()) -> binary(). -hash(md5, Data) -> md5(Data); -hash(md4, Data) -> md4(Data); -hash(sha, Data) -> sha(Data); -hash(ripemd160, Data) -> ripemd160(Data); -hash(sha224, Data) -> sha224(Data); -hash(sha256, Data) -> sha256(Data); -hash(sha384, Data) -> sha384(Data); -hash(sha512, Data) -> sha512(Data). + +hash(Hash, Data0) -> + Data = iolist_to_binary(Data0), + MaxByts = max_bytes(), + hash(Hash, Data, erlang:byte_size(Data), MaxByts, initial). -spec hash_init('md5'|'md4'|'ripemd160'| 'sha'|'sha224'|'sha256'|'sha384'|'sha512') -> any(). @@ -357,14 +243,10 @@ hash_init(sha512) -> {sha512, sha512_init()}. -spec hash_update(_, iodata()) -> any(). -hash_update({md5,Context}, Data) -> {md5, md5_update(Context,Data)}; -hash_update({md4,Context}, Data) -> {md4, md4_update(Context,Data)}; -hash_update({sha,Context}, Data) -> {sha, sha_update(Context,Data)}; -hash_update({ripemd160,Context}, Data) -> {ripemd160, ripemd160_update(Context,Data)}; -hash_update({sha224,Context}, Data) -> {sha224, sha224_update(Context,Data)}; -hash_update({sha256,Context}, Data) -> {sha256, sha256_update(Context,Data)}; -hash_update({sha384,Context}, Data) -> {sha384, sha384_update(Context,Data)}; -hash_update({sha512,Context}, Data) -> {sha512, sha512_update(Context,Data)}. +hash_update(State, Data0) -> + Data = iolist_to_binary(Data0), + MaxBytes = max_bytes(), + hash_update(State, Data, erlang:byte_size(Data), MaxBytes). -spec hash_final(_) -> binary(). @@ -377,6 +259,457 @@ hash_final({sha256,Context}) -> sha256_final(Context); hash_final({sha384,Context}) -> sha384_final(Context); hash_final({sha512,Context}) -> sha512_final(Context). + +-spec hmac(_, iodata(), iodata()) -> binary(). +-spec hmac(_, iodata(), iodata(), integer()) -> binary(). +-spec hmac_init(atom(), iodata()) -> binary(). +-spec hmac_update(binary(), iodata()) -> binary(). +-spec hmac_final(binary()) -> binary(). +-spec hmac_final_n(binary(), integer()) -> binary(). + +hmac(Type, Key, Data0) -> + Data = iolist_to_binary(Data0), + hmac(Type, Key, Data, undefined, erlang:byte_size(Data), max_bytes(), initial). +hmac(Type, Key, Data0, MacSize) -> + Data = iolist_to_binary(Data0), + hmac(Type, Key, Data, MacSize, erlang:byte_size(Data), max_bytes(), initial). + + +hmac_init(_Type, _Key) -> ?nif_stub. + +hmac_update(State, Data0) -> + Data = iolist_to_binary(Data0), + hmac_update(State, Data, erlang:byte_size(Data), max_bytes()). +hmac_final(_Context) -> ? nif_stub. +hmac_final_n(_Context, _HashLen) -> ? nif_stub. + +%% Ecrypt/decrypt %%% + +-spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | + blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc, + Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). + +block_encrypt(des_cbc, Key, Ivec, Data) -> + des_cbc_encrypt(Key, Ivec, Data); +block_encrypt(des_cfb, Key, Ivec, Data) -> + des_cfb_encrypt(Key, Ivec, Data); +block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> + des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> + des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> + des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(blowfish_cbc, Key, Ivec, Data) -> + blowfish_cbc_encrypt(Key, Ivec, Data); +block_encrypt(blowfish_cfb64, Key, Ivec, Data) -> + blowfish_cfb64_encrypt(Key, Ivec, Data); +block_encrypt(blowfish_ofb64, Key, Ivec, Data) -> + blowfish_ofb64_encrypt(Key, Ivec, Data); +block_encrypt(aes_cbc128, Key, Ivec, Data) -> + aes_cbc_128_encrypt(Key, Ivec, Data); +block_encrypt(aes_cbc256, Key, Ivec, Data) -> + aes_cbc_256_encrypt(Key, Ivec, Data); +block_encrypt(aes_cfb128, Key, Ivec, Data) -> + aes_cfb_128_encrypt(Key, Ivec, Data); +block_encrypt(rc2_cbc, Key, Ivec, Data) -> + rc2_cbc_encrypt(Key, Ivec, Data). + +-spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | + blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc, + Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). + +block_decrypt(des_cbc, Key, Ivec, Data) -> + des_cbc_decrypt(Key, Ivec, Data); +block_decrypt(des_cfb, Key, Ivec, Data) -> + des_cfb_decrypt(Key, Ivec, Data); +block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> + des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> + des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> + des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(blowfish_cbc, Key, Ivec, Data) -> + blowfish_cbc_decrypt(Key, Ivec, Data); +block_decrypt(blowfish_cfb64, Key, Ivec, Data) -> + blowfish_cfb64_decrypt(Key, Ivec, Data); +block_decrypt(blowfish_ofb64, Key, Ivec, Data) -> + blowfish_ofb64_decrypt(Key, Ivec, Data); +block_decrypt(aes_cbc128, Key, Ivec, Data) -> + aes_cbc_128_decrypt(Key, Ivec, Data); +block_decrypt(aes_cbc256, Key, Ivec, Data) -> + aes_cbc_256_decrypt(Key, Ivec, Data); +block_decrypt(aes_cfb128, Key, Ivec, Data) -> + aes_cfb_128_decrypt(Key, Ivec, Data); +block_decrypt(rc2_cbc, Key, Ivec, Data) -> + rc2_cbc_decrypt(Key, Ivec, Data). + +-spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). + +block_encrypt(des_ecb, Key, Data) -> + des_ecb_encrypt(Key, Data); +block_encrypt(blowfish_ecb, Key, Data) -> + blowfish_ecb_encrypt(Key, Data). + +-spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). + +block_decrypt(des_ecb, Key, Data) -> + des_ecb_decrypt(Key, Data); +block_decrypt(blowfish_ecb, Key, Data) -> + blowfish_ecb_decrypt(Key, Data). + +-spec next_iv(des_cbc | des3_cbc | aes_cbc, Data::iodata()) -> binary(). + +next_iv(des_cbc, Data) -> + des_cbc_ivec(Data); +next_iv(des3_cbc, Data) -> + des_cbc_ivec(Data); +next_iv(aes_cbc, Data) -> + aes_cbc_ivec(Data). + +-spec next_iv(des_cfb, Data::iodata(), Ivec::binary()) -> binary(). + +next_iv(des_cfb, Data, Ivec) -> + des_cfb_ivec(Ivec, Data); +next_iv(Type, Data, _Ivec) -> + next_iv(Type, Data). + +stream_init(aes_ctr, Key, Ivec) -> + {aes_ctr, aes_ctr_stream_init(Key, Ivec)}. +stream_init(rc4, Key) -> + {rc4, rc4_set_key(Key)}. + +stream_encrypt(State, Data0) -> + Data = iolist_to_binary(Data0), + MaxByts = max_bytes(), + stream_crypt(fun do_stream_encrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []). + +stream_decrypt(State, Data0) -> + Data = iolist_to_binary(Data0), + MaxByts = max_bytes(), + stream_crypt(fun do_stream_decrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []). + +%% +%% RAND - pseudo random numbers using RN_ functions in crypto lib +%% +-spec rand_bytes(non_neg_integer()) -> binary(). +-spec strong_rand_bytes(non_neg_integer()) -> binary(). +-spec rand_uniform(crypto_integer(), crypto_integer()) -> + crypto_integer(). + +rand_bytes(_Bytes) -> ?nif_stub. + +strong_rand_bytes(Bytes) -> + case strong_rand_bytes_nif(Bytes) of + false -> erlang:error(low_entropy); + Bin -> Bin + end. +strong_rand_bytes_nif(_Bytes) -> ?nif_stub. + +rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub. + + +rand_uniform(From,To) when is_binary(From), is_binary(To) -> + case rand_uniform_nif(From,To) of + <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 -> + <<(Len + 1):32/integer, 0, MSB, Rest/binary>>; + Whatever -> + Whatever + end; +rand_uniform(From,To) when is_integer(From),is_integer(To) -> + if From < 0 -> + rand_uniform_pos(0, To - From) + From; + true -> + rand_uniform_pos(From, To) + end. + +rand_uniform_pos(From,To) when From < To -> + BinFrom = mpint(From), + BinTo = mpint(To), + case rand_uniform(BinFrom, BinTo) of + Result when is_binary(Result) -> + erlint(Result); + Other -> + Other + end; +rand_uniform_pos(_,_) -> + error(badarg). + +rand_uniform_nif(_From,_To) -> ?nif_stub. + + +-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error. +mod_pow(Base, Exponent, Prime) -> + case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of + <<0>> -> error; + R -> R + end. +verify(dss, none, Data, Signature, Key) when is_binary(Data) -> + verify(dss, sha, {digest, Data}, Signature, Key); +verify(Alg, Type, Data, Signature, Key) when is_binary(Data) -> + verify(Alg, Type, {digest, hash(Type, Data)}, Signature, Key); +verify(dss, Type, Data, Signature, Key) -> + dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key)); +verify(rsa, Type, DataOrDigest, Signature, Key) -> + case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of + notsup -> erlang:error(notsup); + Bool -> Bool + end; +verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) -> + case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key(Curve, undefined, Key)) of + notsup -> erlang:error(notsup); + Bool -> Bool + end. +sign(dss, none, Data, Key) when is_binary(Data) -> + sign(dss, sha, {digest, Data}, Key); +sign(Alg, Type, Data, Key) when is_binary(Data) -> + sign(Alg, Type, {digest, hash(Type, Data)}, Key); +sign(rsa, Type, DataOrDigest, Key) -> + case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of + error -> erlang:error(badkey, [Type,DataOrDigest,Key]); + Sign -> Sign + end; +sign(dss, Type, DataOrDigest, Key) -> + case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of + error -> erlang:error(badkey, [DataOrDigest, Key]); + Sign -> Sign + end; +sign(ecdsa, Type, DataOrDigest, [Key, Curve]) -> + case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key(Curve, Key, undefined)) of + error -> erlang:error(badkey, [Type,DataOrDigest,Key]); + Sign -> Sign + end. + +-spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) -> + binary(). +-spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). +-spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). +-spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). + +public_encrypt(rsa, BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +%% Binary, Key = [E,N,D] +private_decrypt(rsa, BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + + +%% Binary, Key = [E,N,D] +private_encrypt(rsa, BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +%% Binary, Key = [E,N] +public_decrypt(rsa, BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +%% +%% XOR - xor to iolists and return a binary +%% NB doesn't check that they are the same size, just concatenates +%% them and sends them to the driver +%% +-spec exor(iodata(), iodata()) -> binary(). + +exor(Bin1, Bin2) -> + Data1 = iolist_to_binary(Bin1), + Data2 = iolist_to_binary(Bin2), + MaxBytes = max_bytes(), + exor(Data1, Data2, erlang:byte_size(Data1), MaxBytes, []). + +generate_key(Type, Params) -> + generate_key(Type, Params, undefined). + +generate_key(dh, DHParameters, PrivateKey) -> + dh_generate_key_nif(ensure_int_as_bin(PrivateKey), + map_ensure_int_as_bin(DHParameters), 0); + +generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg) + when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) -> + Private = case PrivArg of + undefined -> random_bytes(32); + _ -> ensure_int_as_bin(PrivArg) + end, + host_srp_gen_key(Private, Verifier, Generator, Prime, Version); + +generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg) + when is_binary(Generator), is_binary(Prime), is_atom(Version) -> + Private = case PrivateArg of + undefined -> random_bytes(32); + _ -> PrivateArg + end, + user_srp_gen_key(Private, Generator, Prime); + +generate_key(ecdh, Curve, undefined) -> + ec_key_to_term_nif(ec_key_generate(Curve)). + + +compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) -> + case dh_compute_key_nif(ensure_int_as_bin(OthersPublicKey), + ensure_int_as_bin(MyPrivateKey), + map_ensure_int_as_bin(DHParameters)) of + error -> erlang:error(computation_failed, + [OthersPublicKey,MyPrivateKey,DHParameters]); + Ret -> Ret + end; + +compute_key(srp, HostPublic, {UserPublic, UserPrivate}, + {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when + is_binary(Prime), + is_binary(Generator), + is_atom(Version) -> + HostPubBin = ensure_int_as_bin(HostPublic), + Multiplier = srp_multiplier(Version, Generator, Prime), + Scrambler = case ScramblerArg of + [] -> srp_scrambler(Version, ensure_int_as_bin(UserPublic), + HostPubBin, Prime); + [S] -> S + end, + srp_user_secret_nif(ensure_int_as_bin(UserPrivate), Scrambler, HostPubBin, + Multiplier, Generator, DerivedKey, Prime); + +compute_key(srp, UserPublic, {HostPublic, HostPrivate}, + {host,[Verifier, Prime, Version | ScramblerArg]}) when + is_binary(Verifier), + is_binary(Prime), + is_atom(Version) -> + UserPubBin = ensure_int_as_bin(UserPublic), + Scrambler = case ScramblerArg of + [] -> srp_scrambler(Version, UserPubBin, ensure_int_as_bin(HostPublic), Prime); + [S] -> S + end, + srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler, + UserPubBin, Prime); + +compute_key(ecdh, Others, My, Curve) -> + ecdh_compute_key_nif(ensure_int_as_bin(Others), + term_to_ec_key(Curve,My,undefined)). + + +random_bytes(N) -> + try strong_rand_bytes(N) of + RandBytes -> + RandBytes + catch + error:low_entropy -> + rand_bytes(N) + end. + +%%-------------------------------------------------------------------- +%%% On load +%%-------------------------------------------------------------------- + +on_load() -> + LibBaseName = "crypto", + PrivDir = code:priv_dir(crypto), + LibName = case erlang:system_info(build_type) of + opt -> + LibBaseName; + Type -> + LibTypeName = LibBaseName ++ "." ++ atom_to_list(Type), + case (filelib:wildcard( + filename:join( + [PrivDir, + "lib", + LibTypeName ++ "*"])) /= []) orelse + (filelib:wildcard( + filename:join( + [PrivDir, + "lib", + erlang:system_info(system_architecture), + LibTypeName ++ "*"])) /= []) of + true -> LibTypeName; + false -> LibBaseName + end + end, + Lib = filename:join([PrivDir, "lib", LibName]), + Status = case erlang:load_nif(Lib, {?CRYPTO_NIF_VSN,Lib}) of + ok -> ok; + {error, {load_failed, _}}=Error1 -> + ArchLibDir = + filename:join([PrivDir, "lib", + erlang:system_info(system_architecture)]), + Candidate = + filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])), + case Candidate of + [] -> Error1; + _ -> + ArchLib = filename:join([ArchLibDir, LibName]), + erlang:load_nif(ArchLib, {?CRYPTO_NIF_VSN,ArchLib}) + end; + Error1 -> Error1 + end, + case Status of + ok -> ok; + {error, {E, Str}} -> + error_logger:error_msg("Unable to load crypto library. Failed with error:~n\"~p, ~s\"~n" + "OpenSSL might not be installed on this system.~n",[E,Str]), + Status + end. +%%-------------------------------------------------------------------- +%%% Internal functions (some internal API functions are part of the deprecated API) +%%-------------------------------------------------------------------- +max_bytes() -> + ?MAX_BYTES_TO_NIF. + +%% HASH -------------------------------------------------------------------- +hash(Hash, Data, Size, Max, initial) when Size =< Max -> + do_hash(Hash, Data); +hash(State0, Data, Size, Max, continue) when Size =< Max -> + State = do_hash_update(State0, Data), + hash_final(State); +hash(Hash, Data, _Size, Max, initial) -> + <<Increment:Max/binary, Rest/binary>> = Data, + State0 = hash_init(Hash), + State = do_hash_update(State0, Increment), + hash(State, Rest, erlang:byte_size(Rest), max_bytes(), continue); +hash(State0, Data, _Size, MaxByts, continue) -> + <<Increment:MaxByts/binary, Rest/binary>> = Data, + State = do_hash_update(State0, Increment), + hash(State, Rest, erlang:byte_size(Rest), max_bytes(), continue). + +do_hash(md5, Data) -> md5(Data); +do_hash(md4, Data) -> md4(Data); +do_hash(sha, Data) -> sha(Data); +do_hash(ripemd160, Data) -> ripemd160(Data); +do_hash(sha224, Data) -> sha224(Data); +do_hash(sha256, Data) -> sha256(Data); +do_hash(sha384, Data) -> sha384(Data); +do_hash(sha512, Data) -> sha512(Data). + +hash_update(State, Data, Size, MaxBytes) when Size =< MaxBytes -> + do_hash_update(State, Data); +hash_update(State0, Data, _, MaxBytes) -> + <<Increment:MaxBytes/binary, Rest/binary>> = Data, + State = do_hash_update(State0, Increment), + hash_update(State, Rest, erlang:byte_size(Rest), MaxBytes). + +do_hash_update({md5,Context}, Data) -> {md5, md5_update(Context,Data)}; +do_hash_update({md4,Context}, Data) -> {md4, md4_update(Context,Data)}; +do_hash_update({sha,Context}, Data) -> {sha, sha_update(Context,Data)}; +do_hash_update({ripemd160,Context}, Data) -> {ripemd160, ripemd160_update(Context,Data)}; +do_hash_update({sha224,Context}, Data) -> {sha224, sha224_update(Context,Data)}; +do_hash_update({sha256,Context}, Data) -> {sha256, sha256_update(Context,Data)}; +do_hash_update({sha384,Context}, Data) -> {sha384, sha384_update(Context,Data)}; +do_hash_update({sha512,Context}, Data) -> {sha512, sha512_update(Context,Data)}. + + %% %% MD5 %% @@ -567,40 +900,56 @@ sha512_init_nif() -> ?nif_stub. sha512_update_nif(_Context, _Data) -> ?nif_stub. sha512_final_nif(_Context) -> ?nif_stub. -%% -%% MESSAGE AUTHENTICATION CODES -%% - -%% -%% HMAC (multiple hash options) -%% +%% HMAC -------------------------------------------------------------------- --spec hmac(_, iodata(), iodata()) -> binary(). --spec hmac(_, iodata(), iodata(), integer()) -> binary(). --spec hmac_init(atom(), iodata()) -> binary(). --spec hmac_update(binary(), iodata()) -> binary(). --spec hmac_final(binary()) -> binary(). --spec hmac_final_n(binary(), integer()) -> binary(). - -hmac(md5, Key, Data) -> md5_mac(Key, Data); -hmac(sha, Key, Data) -> sha_mac(Key, Data); -hmac(sha224, Key, Data) -> sha224_mac(Key, Data); -hmac(sha256, Key, Data) -> sha256_mac(Key, Data); -hmac(sha384, Key, Data) -> sha384_mac(Key, Data); -hmac(sha512, Key, Data) -> sha512_mac(Key, Data). - -hmac(md5, Key, Data, Size) -> md5_mac_n(Key, Data, Size); -hmac(sha, Key, Data, Size) -> sha_mac_n(Key, Data, Size); -hmac(sha224, Key, Data, Size) -> sha224_mac(Key, Data, Size); -hmac(sha256, Key, Data, Size) -> sha256_mac(Key, Data, Size); -hmac(sha384, Key, Data, Size) -> sha384_mac(Key, Data, Size); -hmac(sha512, Key, Data, Size) -> sha512_mac(Key, Data, Size). +hmac(Type, Key, Data, MacSize, Size, MaxBytes, initial) when Size =< MaxBytes -> + case MacSize of + undefined -> + do_hmac(Type, Key, Data); + _ -> + do_hmac(Type, Key, Data, MacSize) + end; +hmac(Type, Key, Data, MacSize, _, MaxBytes, initial) -> + <<Increment:MaxBytes/binary, Rest/binary>> = Data, + State0 = hmac_init(Type, Key), + State = hmac_update(State0, Increment), + hmac(State, Rest, MacSize, erlang:byte_size(Rest), max_bytes(), continue). +hmac(State0, Data, MacSize, Size, MaxBytes, continue) when Size =< MaxBytes -> + State = hmac_update(State0, Data), + case MacSize of + undefined -> + hmac_final(State); + _ -> + hmac_final_n(State, MacSize) + end; +hmac(State0, Data, MacSize, _Size, MaxBytes, continue) -> + <<Increment:MaxBytes/binary, Rest/binary>> = Data, + State = hmac_update(State0, Increment), + hmac(State, Rest, MacSize, erlang:byte_size(Rest), max_bytes(), continue). + +hmac_update(State, Data, Size, MaxBytes) when Size =< MaxBytes -> + do_hmac_update(State, Data); +hmac_update(State0, Data, _, MaxBytes) -> + <<Increment:MaxBytes/binary, Rest/binary>> = Data, + State = do_hmac_update(State0, Increment), + hmac_update(State, Rest, erlang:byte_size(Rest), MaxBytes). + +do_hmac(md5, Key, Data) -> md5_mac(Key, Data); +do_hmac(sha, Key, Data) -> sha_mac(Key, Data); +do_hmac(sha224, Key, Data) -> sha224_mac(Key, Data); +do_hmac(sha256, Key, Data) -> sha256_mac(Key, Data); +do_hmac(sha384, Key, Data) -> sha384_mac(Key, Data); +do_hmac(sha512, Key, Data) -> sha512_mac(Key, Data). + +do_hmac(md5, Key, Data, Size) -> md5_mac_n(Key, Data, Size); +do_hmac(sha, Key, Data, Size) -> sha_mac_n(Key, Data, Size); +do_hmac(sha224, Key, Data, Size) -> sha224_mac(Key, Data, Size); +do_hmac(sha256, Key, Data, Size) -> sha256_mac(Key, Data, Size); +do_hmac(sha384, Key, Data, Size) -> sha384_mac(Key, Data, Size); +do_hmac(sha512, Key, Data, Size) -> sha512_mac(Key, Data, Size). + +do_hmac_update(_Context, _Data) -> ? nif_stub. -hmac_init(_Type, _Key) -> ?nif_stub. -hmac_update(_Context, _Data) -> ? nif_stub. -hmac_final(_Context) -> ? nif_stub. -hmac_final_n(_Context, _HashLen) -> ? nif_stub. - %% %% MD5_MAC %% @@ -696,172 +1045,7 @@ sha512_mac(Key, Data, MacSz) -> sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. - -%% Ecrypt/decrypt %%% - --spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | - blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc, - Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). - -block_encrypt(des_cbc, Key, Ivec, Data) -> - des_cbc_encrypt(Key, Ivec, Data); -block_encrypt(des_cfb, Key, Ivec, Data) -> - des_cfb_encrypt(Key, Ivec, Data); -block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> - des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); -block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> - des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data); -block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> - des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); -block_encrypt(blowfish_cbc, Key, Ivec, Data) -> - blowfish_cbc_encrypt(Key, Ivec, Data); -block_encrypt(blowfish_cfb64, Key, Ivec, Data) -> - blowfish_cfb64_encrypt(Key, Ivec, Data); -block_encrypt(blowfish_ofb64, Key, Ivec, Data) -> - blowfish_ofb64_encrypt(Key, Ivec, Data); -block_encrypt(aes_cbc128, Key, Ivec, Data) -> - aes_cbc_128_encrypt(Key, Ivec, Data); -block_encrypt(aes_cbc256, Key, Ivec, Data) -> - aes_cbc_256_encrypt(Key, Ivec, Data); -block_encrypt(aes_cfb128, Key, Ivec, Data) -> - aes_cfb_128_encrypt(Key, Ivec, Data); -block_encrypt(rc2_cbc, Key, Ivec, Data) -> - rc2_cbc_encrypt(Key, Ivec, Data). - --spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | - blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc, - Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). - -block_decrypt(des_cbc, Key, Ivec, Data) -> - des_cbc_decrypt(Key, Ivec, Data); -block_decrypt(des_cfb, Key, Ivec, Data) -> - des_cfb_decrypt(Key, Ivec, Data); -block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> - des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); -block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> - des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data); -block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> - des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); -block_decrypt(blowfish_cbc, Key, Ivec, Data) -> - blowfish_cbc_decrypt(Key, Ivec, Data); -block_decrypt(blowfish_cfb64, Key, Ivec, Data) -> - blowfish_cfb64_decrypt(Key, Ivec, Data); -block_decrypt(blowfish_ofb64, Key, Ivec, Data) -> - blowfish_ofb64_decrypt(Key, Ivec, Data); -block_decrypt(aes_cbc128, Key, Ivec, Data) -> - aes_cbc_128_decrypt(Key, Ivec, Data); -block_decrypt(aes_cbc256, Key, Ivec, Data) -> - aes_cbc_256_decrypt(Key, Ivec, Data); -block_decrypt(aes_cfb128, Key, Ivec, Data) -> - aes_cfb_128_decrypt(Key, Ivec, Data); -block_decrypt(rc2_cbc, Key, Ivec, Data) -> - rc2_cbc_decrypt(Key, Ivec, Data). - --spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). - -block_encrypt(des_ecb, Key, Data) -> - des_ecb_encrypt(Key, Data); -block_encrypt(blowfish_ecb, Key, Data) -> - blowfish_ecb_encrypt(Key, Data). - --spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). - -block_decrypt(des_ecb, Key, Data) -> - des_ecb_decrypt(Key, Data); -block_decrypt(blowfish_ecb, Key, Data) -> - blowfish_ecb_decrypt(Key, Data). - --spec next_iv(des_cbc | des3_cbc | aes_cbc, Data::iodata()) -> binary(). - -next_iv(des_cbc, Data) -> - des_cbc_ivec(Data); -next_iv(des3_cbc, Data) -> - des_cbc_ivec(Data); -next_iv(aes_cbc, Data) -> - aes_cbc_ivec(Data). - --spec next_iv(des_cfb, Data::iodata(), Ivec::binary()) -> binary(). - -next_iv(des_cfb, Data, Ivec) -> - des_cfb_ivec(Ivec, Data); -next_iv(Type, Data, _Ivec) -> - next_iv(Type, Data). - -stream_init(aes_ctr, Key, Ivec) -> - {aes_ctr, aes_ctr_stream_init(Key, Ivec)}. -stream_init(rc4, Key) -> - {rc4, rc4_set_key(Key)}. -stream_encrypt({aes_ctr, State0}, Data) -> - {State, Cipher} = aes_ctr_stream_encrypt(State0, Data), - {{aes_ctr, State}, Cipher}; -stream_encrypt({rc4, State0}, Data) -> - {State, Cipher} = rc4_encrypt_with_state(State0, Data), - {{rc4, State}, Cipher}. -stream_decrypt({aes_ctr, State0}, Data) -> - {State, Text} = aes_ctr_stream_decrypt(State0, Data), - {{aes_ctr, State}, Text}; -stream_decrypt({rc4, State0}, Data) -> - {State, Text} = rc4_encrypt_with_state (State0, Data), - {{rc4, State}, Text}. - -%% -%% CRYPTO FUNCTIONS -%% - -%% -%% DES - in cipher block chaining mode (CBC) -%% --spec des_cbc_encrypt(iodata(), binary(), iodata()) -> binary(). --spec des_cbc_decrypt(iodata(), binary(), iodata()) -> binary(). - -des_cbc_encrypt(Key, IVec, Data) -> - des_cbc_crypt(Key, IVec, Data, true). - -des_cbc_decrypt(Key, IVec, Data) -> - des_cbc_crypt(Key, IVec, Data, false). - -des_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. - -%% -%% dec_cbc_ivec(Data) -> binary() -%% -%% Returns the IVec to be used in the next iteration of -%% des_cbc_[encrypt|decrypt]. -%% --spec des_cbc_ivec(iodata()) -> binary(). - -des_cbc_ivec(Data) when is_binary(Data) -> - {_, IVec} = split_binary(Data, size(Data) - 8), - IVec; -des_cbc_ivec(Data) when is_list(Data) -> - des_cbc_ivec(list_to_binary(Data)). - -%% -%% DES - in 8-bits cipher feedback mode (CFB) -%% --spec des_cfb_encrypt(iodata(), binary(), iodata()) -> binary(). --spec des_cfb_decrypt(iodata(), binary(), iodata()) -> binary(). - -des_cfb_encrypt(Key, IVec, Data) -> - des_cfb_crypt(Key, IVec, Data, true). - -des_cfb_decrypt(Key, IVec, Data) -> - des_cfb_crypt(Key, IVec, Data, false). - -des_cfb_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. - -%% -%% dec_cfb_ivec(IVec, Data) -> binary() -%% -%% Returns the IVec to be used in the next iteration of -%% des_cfb_[encrypt|decrypt]. -%% --spec des_cfb_ivec(iodata(), iodata()) -> binary(). - -des_cfb_ivec(IVec, Data) -> - IVecAndData = list_to_binary([IVec, Data]), - {_, NewIVec} = split_binary(IVecAndData, byte_size(IVecAndData) - 8), - NewIVec. +%% CIPHERS -------------------------------------------------------------------- %% %% DES - in electronic codebook mode (ECB) @@ -973,292 +1157,63 @@ aes_cfb_128_decrypt(Key, IVec, Data) -> aes_cfb_128_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. -%% -%% RAND - pseudo random numbers using RN_ functions in crypto lib %% --spec rand_bytes(non_neg_integer()) -> binary(). --spec strong_rand_bytes(non_neg_integer()) -> binary(). --spec rand_uniform(crypto_integer(), crypto_integer()) -> - crypto_integer(). --spec strong_rand_mpint(Bits::non_neg_integer(), - Top::-1..1, - Bottom::0..1) -> binary(). - -rand_bytes(_Bytes) -> ?nif_stub. - -strong_rand_bytes(Bytes) -> - case strong_rand_bytes_nif(Bytes) of - false -> erlang:error(low_entropy); - Bin -> Bin - end. -strong_rand_bytes_nif(_Bytes) -> ?nif_stub. - -rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub. - -strong_rand_mpint(Bits, Top, Bottom) -> - case strong_rand_mpint_nif(Bits,Top,Bottom) of - false -> erlang:error(low_entropy); - Bin -> Bin - end. -strong_rand_mpint_nif(_Bits, _Top, _Bottom) -> ?nif_stub. - +%% DES - in cipher block chaining mode (CBC) +%% +-spec des_cbc_encrypt(iodata(), binary(), iodata()) -> binary(). +-spec des_cbc_decrypt(iodata(), binary(), iodata()) -> binary(). -rand_uniform(From,To) when is_binary(From), is_binary(To) -> - case rand_uniform_nif(From,To) of - <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 -> - <<(Len + 1):32/integer, 0, MSB, Rest/binary>>; - Whatever -> - Whatever - end; -rand_uniform(From,To) when is_integer(From),is_integer(To) -> - if From < 0 -> - rand_uniform_pos(0, To - From) + From; - true -> - rand_uniform_pos(From, To) - end. +des_cbc_encrypt(Key, IVec, Data) -> + des_cbc_crypt(Key, IVec, Data, true). -rand_uniform_pos(From,To) when From < To -> - BinFrom = mpint(From), - BinTo = mpint(To), - case rand_uniform(BinFrom, BinTo) of - Result when is_binary(Result) -> - erlint(Result); - Other -> - Other - end; -rand_uniform_pos(_,_) -> - error(badarg). +des_cbc_decrypt(Key, IVec, Data) -> + des_cbc_crypt(Key, IVec, Data, false). -rand_uniform_nif(_From,_To) -> ?nif_stub. +des_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. %% -%% mod_exp - utility for rsa generation and SRP +%% dec_cbc_ivec(Data) -> binary() %% -mod_exp(Base, Exponent, Modulo) - when is_integer(Base), is_integer(Exponent), is_integer(Modulo) -> - bin_to_int(mod_exp_nif(int_to_bin(Base), int_to_bin(Exponent), int_to_bin(Modulo), 0)); - -mod_exp(Base, Exponent, Modulo) -> - mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4). - --spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error. -mod_pow(Base, Exponent, Prime) -> - case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of - <<0>> -> error; - R -> R - end. - +%% Returns the IVec to be used in the next iteration of +%% des_cbc_[encrypt|decrypt]. +%% +-spec des_cbc_ivec(iodata()) -> binary(). -mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub. +des_cbc_ivec(Data) when is_binary(Data) -> + {_, IVec} = split_binary(Data, size(Data) - 8), + IVec; +des_cbc_ivec(Data) when is_list(Data) -> + des_cbc_ivec(list_to_binary(Data)). %% -%% DSS, RSA - verify +%% DES - in 8-bits cipher feedback mode (CFB) %% --spec dss_verify(data_or_digest(), binary(), [binary()]) -> boolean(). --spec dss_verify(dss_digest_type(), data_or_digest(), binary(), [binary()]) -> boolean(). --spec rsa_verify(data_or_digest(), binary(), [binary()]) -> boolean(). --spec rsa_verify(rsa_digest_type(), data_or_digest(), binary(), [binary()]) -> - boolean(). - -%% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey -dss_verify(Data,Signature,Key) -> - dss_verify(sha, Data, Signature, Key). - -dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none -> - verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key)); -dss_verify(Type,Digest,Signature,Key) -> - verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)). - -% Key = [E,N] E=PublicExponent N=PublicModulus -rsa_verify(Data,Signature,Key) -> - rsa_verify(sha, Data,Signature,Key). -rsa_verify(Type, Data, Signature, Key) when is_binary(Data) -> - verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key)); -rsa_verify(Type, Digest, Signature, Key) -> - verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)). - - -verify(dss, Type, Data, Signature, Key) -> - dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key)); - -verify(rsa, Type, DataOrDigest, Signature, Key) -> - case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of - notsup -> erlang:error(notsup); - Bool -> Bool - end; -verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) -> - case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key(Curve, undefined, Key)) of - notsup -> erlang:error(notsup); - Bool -> Bool - end. +-spec des_cfb_encrypt(iodata(), binary(), iodata()) -> binary(). +-spec des_cfb_decrypt(iodata(), binary(), iodata()) -> binary(). +des_cfb_encrypt(Key, IVec, Data) -> + des_cfb_crypt(Key, IVec, Data, true). -dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. -rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. -ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub. +des_cfb_decrypt(Key, IVec, Data) -> + des_cfb_crypt(Key, IVec, Data, false). +des_cfb_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. %% -%% DSS, RSA - sign +%% dec_cfb_ivec(IVec, Data) -> binary() %% -%% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey --spec dss_sign(data_or_digest(), [binary()]) -> binary(). --spec dss_sign(dss_digest_type(), data_or_digest(), [binary()]) -> binary(). --spec rsa_sign(data_or_digest(), [binary()]) -> binary(). --spec rsa_sign(rsa_digest_type(), data_or_digest(), [binary()]) -> binary(). - -dss_sign(DataOrDigest,Key) -> - dss_sign(sha,DataOrDigest,Key). -dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none -> - sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); -dss_sign(Type, Digest, Key) -> - sign(dss, Type, Digest, map_mpint_to_bin(Key)). - - -%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent -rsa_sign(DataOrDigest,Key) -> - rsa_sign(sha, DataOrDigest, Key). - -rsa_sign(Type, Data, Key) when is_binary(Data) -> - sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); -rsa_sign(Type, Digest, Key) -> - sign(rsa, Type, Digest, map_mpint_to_bin(Key)). - -map_mpint_to_bin(List) -> - lists:map(fun(E) -> mpint_to_bin(E) end, List ). - -map_ensure_int_as_bin([H|_]=List) when is_integer(H) -> - lists:map(fun(E) -> int_to_bin(E) end, List); -map_ensure_int_as_bin(List) -> - List. - -ensure_int_as_bin(Int) when is_integer(Int) -> - int_to_bin(Int); -ensure_int_as_bin(Bin) -> - Bin. - -map_to_norm_bin([H|_]=List) when is_integer(H) -> - lists:map(fun(E) -> int_to_bin(E) end, List); -map_to_norm_bin(List) -> - lists:map(fun(E) -> mpint_to_bin(E) end, List). - - -sign(rsa, Type, DataOrDigest, Key) -> - case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of - error -> erlang:error(badkey, [Type,DataOrDigest,Key]); - Sign -> Sign - end; -sign(dss, Type, DataOrDigest, Key) -> - case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of - error -> erlang:error(badkey, [DataOrDigest, Key]); - Sign -> Sign - end; -sign(ecdsa, Type, DataOrDigest, [Key, Curve]) -> - case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key(Curve, Key, undefined)) of - error -> erlang:error(badkey, [Type,DataOrDigest,Key]); - Sign -> Sign - end. - -rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. -dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. -ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. - - - - --spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) -> - binary(). --spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> - binary(). --spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> - binary(). --spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> - binary(). - -public_encrypt(rsa, BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of - error -> - erlang:error(encrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - -%% Binary, Key = [E,N,D] -private_decrypt(rsa, BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of - error -> - erlang:error(decrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - - -%% Binary, Key = [E,N,D] -private_encrypt(rsa, BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of - error -> - erlang:error(encrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - -%% Binary, Key = [E,N] -public_decrypt(rsa, BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of - error -> - erlang:error(decrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - - +%% Returns the IVec to be used in the next iteration of +%% des_cfb_[encrypt|decrypt]. %% -%% rsa_public_encrypt -%% rsa_private_decrypt --type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. - --spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) -> - binary(). --spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> - binary(). --spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) -> - binary(). --spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> - binary(). -%% Binary, Key = [E,N] -rsa_public_encrypt(BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of - error -> - erlang:error(encrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - -rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. +-spec des_cfb_ivec(iodata(), iodata()) -> binary(). -%% Binary, Key = [E,N,D] -rsa_private_decrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of - error -> - erlang:error(decrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. +des_cfb_ivec(IVec, Data) -> + IVecAndData = list_to_binary([IVec, Data]), + {_, NewIVec} = split_binary(IVecAndData, byte_size(IVecAndData) - 8), + NewIVec. -rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. - -%% Binary, Key = [E,N,D] -rsa_private_encrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of - error -> - erlang:error(encrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - -%% Binary, Key = [E,N] -rsa_public_decrypt(BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of - error -> - erlang:error(decrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - %% %% AES - with 128 or 256 bit key in cipher block chaining mode (CBC) %% @@ -1298,6 +1253,33 @@ aes_cbc_ivec(Data) when is_binary(Data) -> aes_cbc_ivec(Data) when is_list(Data) -> aes_cbc_ivec(list_to_binary(Data)). + +%% Stream ciphers -------------------------------------------------------------------- + +stream_crypt(Fun, State, Data, Size, MaxByts, []) when Size =< MaxByts -> + Fun(State, Data); +stream_crypt(Fun, State0, Data, Size, MaxByts, Acc) when Size =< MaxByts -> + {State, Cipher} = Fun(State0, Data), + {State, list_to_binary(lists:reverse([Cipher | Acc]))}; +stream_crypt(Fun, State0, Data, _, MaxByts, Acc) -> + <<Increment:MaxByts/binary, Rest/binary>> = Data, + {State, CipherText} = Fun(State0, Increment), + stream_crypt(Fun, State, Rest, erlang:byte_size(Rest), MaxByts, [CipherText | Acc]). + +do_stream_encrypt({aes_ctr, State0}, Data) -> + {State, Cipher} = aes_ctr_stream_encrypt(State0, Data), + {{aes_ctr, State}, Cipher}; +do_stream_encrypt({rc4, State0}, Data) -> + {State, Cipher} = rc4_encrypt_with_state(State0, Data), + {{rc4, State}, Cipher}. + +do_stream_decrypt({aes_ctr, State0}, Data) -> + {State, Text} = aes_ctr_stream_decrypt(State0, Data), + {{aes_ctr, State}, Text}; +do_stream_decrypt({rc4, State0}, Data) -> + {State, Text} = rc4_encrypt_with_state(State0, Data), + {{rc4, State}, Text}. + %% %% AES - in counter mode (CTR) %% @@ -1305,7 +1287,7 @@ aes_cbc_ivec(Data) when is_list(Data) -> binary(). -spec aes_ctr_decrypt(iodata(), binary(), iodata()) -> binary(). - + aes_ctr_encrypt(_Key, _IVec, _Data) -> ?nif_stub. aes_ctr_decrypt(_Key, _IVec, _Cipher) -> ?nif_stub. @@ -1326,15 +1308,6 @@ aes_ctr_stream_encrypt({_Key, _IVec, _ECount, _Num}=_State, _Data) -> ?nif_stub. aes_ctr_stream_decrypt({_Key, _IVec, _ECount, _Num}=_State, _Cipher) -> ?nif_stub. %% -%% XOR - xor to iolists and return a binary -%% NB doesn't check that they are the same size, just concatenates -%% them and sends them to the driver -%% --spec exor(iodata(), iodata()) -> binary(). - -exor(_A, _B) -> ?nif_stub. - -%% %% RC4 - symmetric stream cipher %% -spec rc4_encrypt(iodata(), iodata()) -> binary(). @@ -1363,7 +1336,76 @@ rc2_40_cbc_encrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 -> rc2_40_cbc_decrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 -> rc2_cbc_crypt(Key,IVec,Data,false). -%% + +%% Secure remote password ------------------------------------------------------------------- + +user_srp_gen_key(Private, Generator, Prime) -> + case mod_pow(Generator, Private, Prime) of + error -> + error; + Public -> + {Public, Private} + end. + +host_srp_gen_key(Private, Verifier, Generator, Prime, Version) -> + Multiplier = srp_multiplier(Version, Generator, Prime), + case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of + error -> + error; + Public -> + {Public, Private} + end. + +srp_multiplier('6a', Generator, Prime) -> + %% k = SHA1(N | PAD(g)) from http://srp.stanford.edu/design.html + C0 = sha_init(), + C1 = sha_update(C0, Prime), + C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)), + sha_final(C2); +srp_multiplier('6', _, _) -> + <<3/integer>>; +srp_multiplier('3', _, _) -> + <<1/integer>>. + +srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'-> + %% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html + PadLength = erlang:byte_size(Prime), + C0 = sha_init(), + C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)), + C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)), + sha_final(C2); +srp_scrambler('3', _, HostPublic, _Prime) -> + %% The parameter u is a 32-bit unsigned integer which takes its value + %% from the first 32 bits of the SHA1 hash of B, MSB first. + <<U:32/bits, _/binary>> = sha(HostPublic), + U. + +srp_pad_length(Width, Length) -> + (Width - Length rem Width) rem Width. + +srp_pad_to(Width, Binary) -> + case srp_pad_length(Width, size(Binary)) of + 0 -> Binary; + N -> << 0:(N*8), Binary/binary>> + end. + +srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub. + +srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub. + +srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub. + + +%% Digital signatures -------------------------------------------------------------------- +rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. + +dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. +rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. +ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub. + +%% Public Keys -------------------------------------------------------------------- %% DH Diffie-Hellman functions %% @@ -1412,80 +1454,10 @@ dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) -> dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub. -generate_key(Type, Params) -> - generate_key(Type, Params, undefined). - -generate_key(dh, DHParameters, PrivateKey) -> - dh_generate_key_nif(ensure_int_as_bin(PrivateKey), - map_ensure_int_as_bin(DHParameters), 0); - -generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg) - when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) -> - Private = case PrivArg of - undefined -> random_bytes(32); - _ -> ensure_int_as_bin(PrivArg) - end, - host_srp_gen_key(Private, Verifier, Generator, Prime, Version); - -generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg) - when is_binary(Generator), is_binary(Prime), is_atom(Version) -> - Private = case PrivateArg of - undefined -> random_bytes(32); - _ -> PrivateArg - end, - user_srp_gen_key(Private, Generator, Prime); - -generate_key(ecdh, Curve, undefined) -> - ec_key_to_term_nif(ec_key_generate(Curve)). - - ec_key_generate(_Key) -> ?nif_stub. - -compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) -> - case dh_compute_key_nif(ensure_int_as_bin(OthersPublicKey), - ensure_int_as_bin(MyPrivateKey), - map_ensure_int_as_bin(DHParameters)) of - error -> erlang:error(computation_failed, - [OthersPublicKey,MyPrivateKey,DHParameters]); - Ret -> Ret - end; - -compute_key(srp, HostPublic, {UserPublic, UserPrivate}, - {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when - is_binary(Prime), - is_binary(Generator), - is_atom(Version) -> - HostPubBin = ensure_int_as_bin(HostPublic), - Multiplier = srp_multiplier(Version, Generator, Prime), - Scrambler = case ScramblerArg of - [] -> srp_scrambler(Version, ensure_int_as_bin(UserPublic), - HostPubBin, Prime); - [S] -> S - end, - srp_user_secret_nif(ensure_int_as_bin(UserPrivate), Scrambler, HostPubBin, - Multiplier, Generator, DerivedKey, Prime); - -compute_key(srp, UserPublic, {HostPublic, HostPrivate}, - {host,[Verifier, Prime, Version | ScramblerArg]}) when - is_binary(Verifier), - is_binary(Prime), - is_atom(Version) -> - UserPubBin = ensure_int_as_bin(UserPublic), - Scrambler = case ScramblerArg of - [] -> srp_scrambler(Version, UserPubBin, ensure_int_as_bin(HostPublic), Prime); - [S] -> S - end, - srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler, - UserPubBin, Prime); - -compute_key(ecdh, Others, My, Curve) -> - ecdh_compute_key_nif(ensure_int_as_bin(Others), - term_to_ec_key(Curve,My,undefined)). - ecdh_compute_key_nif(_Others, _My) -> ?nif_stub. - %% %% EC %% @@ -1511,65 +1483,181 @@ term_to_ec_key(Curve, PrivKey, PubKey) -> term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. +%% MISC -------------------------------------------------------------------- + +exor(Data1, Data2, Size, MaxByts, []) when Size =< MaxByts -> + do_exor(Data1, Data2); +exor(Data1, Data2, Size, MaxByts, Acc) when Size =< MaxByts -> + Result = do_exor(Data1, Data2), + list_to_binary(lists:reverse([Result | Acc])); +exor(Data1, Data2, _Size, MaxByts, Acc) -> + <<Increment1:MaxByts/binary, Rest1/binary>> = Data1, + <<Increment2:MaxByts/binary, Rest2/binary>> = Data2, + Result = do_exor(Increment1, Increment2), + exor(Rest1, Rest2, erlang:byte_size(Rest1), MaxByts, [Result | Acc]). + +do_exor(_A, _B) -> ?nif_stub. -%% LOCAL FUNCTIONS +algorithms() -> ?nif_stub. + +int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []); +int_to_bin(X) -> int_to_bin_pos(X, []). + +int_to_bin_pos(0,Ds=[_|_]) -> + list_to_binary(Ds); +int_to_bin_pos(X,Ds) -> + int_to_bin_pos(X bsr 8, [(X band 255)|Ds]). + +int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 -> + list_to_binary(Ds); +int_to_bin_neg(X,Ds) -> + int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). + +bytes_to_integer(Bin) -> + bin_to_int(Bin). + +bin_to_int(Bin) when is_binary(Bin) -> + Bits = bit_size(Bin), + <<Integer:Bits/integer>> = Bin, + Integer; +bin_to_int(undefined) -> + undefined. + +map_ensure_int_as_bin([H|_]=List) when is_integer(H) -> + lists:map(fun(E) -> int_to_bin(E) end, List); +map_ensure_int_as_bin(List) -> + List. + +ensure_int_as_bin(Int) when is_integer(Int) -> + int_to_bin(Int); +ensure_int_as_bin(Bin) -> + Bin. + +map_to_norm_bin([H|_]=List) when is_integer(H) -> + lists:map(fun(E) -> int_to_bin(E) end, List); +map_to_norm_bin(List) -> + lists:map(fun(E) -> mpint_to_bin(E) end, List). + +%%-------------------------------------------------------------------- +%%% Deprecated +%%-------------------------------------------------------------------- %% +%% rsa_public_encrypt +%% rsa_private_decrypt +-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. -user_srp_gen_key(Private, Generator, Prime) -> - case mod_pow(Generator, Private, Prime) of +-spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) -> + binary(). +-spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> + binary(). +-spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) -> + binary(). +-spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> + binary(). + +%% Binary, Key = [E,N] +rsa_public_encrypt(BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of error -> - error; - Public -> - {Public, Private} + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign end. -host_srp_gen_key(Private, Verifier, Generator, Prime, Version) -> - Multiplier = srp_multiplier(Version, Generator, Prime), - case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of - error -> - error; - Public -> - {Public, Private} - end. +rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. -srp_multiplier('6a', Generator, Prime) -> - %% k = SHA1(N | PAD(g)) from http://srp.stanford.edu/design.html - C0 = sha_init(), - C1 = sha_update(C0, Prime), - C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)), - sha_final(C2); -srp_multiplier('6', _, _) -> - <<3/integer>>; -srp_multiplier('3', _, _) -> - <<1/integer>>. +%% Binary, Key = [E,N,D] +rsa_private_decrypt(BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. -srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'-> - %% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html - PadLength = erlang:byte_size(Prime), - C0 = sha_init(), - C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)), - C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)), - sha_final(C2); -srp_scrambler('3', _, HostPublic, _Prime) -> - %% The parameter u is a 32-bit unsigned integer which takes its value - %% from the first 32 bits of the SHA1 hash of B, MSB first. - <<U:32/bits, _/binary>> = sha(HostPublic), - U. +rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. -srp_pad_length(Width, Length) -> - (Width - Length rem Width) rem Width. -srp_pad_to(Width, Binary) -> - case srp_pad_length(Width, size(Binary)) of - 0 -> Binary; - N -> << 0:(N*8), Binary/binary>> +%% Binary, Key = [E,N,D] +rsa_private_encrypt(BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign end. -srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub. +%% Binary, Key = [E,N] +rsa_public_decrypt(BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. -srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub. +map_mpint_to_bin(List) -> + lists:map(fun(E) -> mpint_to_bin(E) end, List ). + +%% +%% DSS, RSA - sign +%% +%% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey +-spec dss_sign(data_or_digest(), [binary()]) -> binary(). +-spec dss_sign(dss_digest_type(), data_or_digest(), [binary()]) -> binary(). +-spec rsa_sign(data_or_digest(), [binary()]) -> binary(). +-spec rsa_sign(rsa_digest_type(), data_or_digest(), [binary()]) -> binary(). + +dss_sign(DataOrDigest,Key) -> + dss_sign(sha,DataOrDigest,Key). +dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none -> + sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); +dss_sign(Type, Digest, Key) -> + sign(dss, Type, Digest, map_mpint_to_bin(Key)). + + +%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent +rsa_sign(DataOrDigest,Key) -> + rsa_sign(sha, DataOrDigest, Key). + +rsa_sign(Type, Data, Key) when is_binary(Data) -> + sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); +rsa_sign(Type, Digest, Key) -> + sign(rsa, Type, Digest, map_mpint_to_bin(Key)). + +%% +%% DSS, RSA - verify +%% +-spec dss_verify(data_or_digest(), binary(), [binary()]) -> boolean(). +-spec dss_verify(dss_digest_type(), data_or_digest(), binary(), [binary()]) -> boolean(). +-spec rsa_verify(data_or_digest(), binary(), [binary()]) -> boolean(). +-spec rsa_verify(rsa_digest_type(), data_or_digest(), binary(), [binary()]) -> + boolean(). + +%% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey +dss_verify(Data,Signature,Key) -> + dss_verify(sha, Data, Signature, Key). + +dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none -> + verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key)); +dss_verify(Type,Digest,Signature,Key) -> + verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)). + +% Key = [E,N] E=PublicExponent N=PublicModulus +rsa_verify(Data,Signature,Key) -> + rsa_verify(sha, Data,Signature,Key). +rsa_verify(Type, Data, Signature, Key) when is_binary(Data) -> + verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key)); +rsa_verify(Type, Digest, Signature, Key) -> + verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)). + +-spec strong_rand_mpint(Bits::non_neg_integer(), + Top::-1..1, + Bottom::0..1) -> binary(). + +strong_rand_mpint(Bits, Top, Bottom) -> + case strong_rand_mpint_nif(Bits,Top,Bottom) of + false -> erlang:error(low_entropy); + Bin -> Bin + end. +strong_rand_mpint_nif(_Bits, _Top, _Bottom) -> ?nif_stub. -srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub. %% large integer in a binary with 32bit length %% MP representaion (SSH2) @@ -1594,32 +1682,6 @@ mpint_pos(X) -> <<?UINT32(Sz), Bin/binary>> end. -int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []); -int_to_bin(X) -> int_to_bin_pos(X, []). - -%%int_to_bin_pos(X) when X >= 0 -> -%% int_to_bin_pos(X, []). - -int_to_bin_pos(0,Ds=[_|_]) -> - list_to_binary(Ds); -int_to_bin_pos(X,Ds) -> - int_to_bin_pos(X bsr 8, [(X band 255)|Ds]). - -int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 -> - list_to_binary(Ds); -int_to_bin_neg(X,Ds) -> - int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). - -bytes_to_integer(Bin) -> - bin_to_int(Bin). - -bin_to_int(Bin) when is_binary(Bin) -> - Bits = bit_size(Bin), - <<Integer:Bits/integer>> = Bin, - Integer; -bin_to_int(undefined) -> - undefined. - %% int from integer in a binary with 32bit length erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) -> Bits= MPIntSize * 8, @@ -1629,11 +1691,71 @@ erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) -> mpint_to_bin(<<Len:32, Bin:Len/binary>>) -> Bin. -random_bytes(N) -> - try strong_rand_bytes(N) of - RandBytes -> - RandBytes - catch - error:low_entropy -> - rand_bytes(N) - end. +%% +%% mod_exp - utility for rsa generation and SRP +%% +mod_exp(Base, Exponent, Modulo) + when is_integer(Base), is_integer(Exponent), is_integer(Modulo) -> + bin_to_int(mod_exp_nif(int_to_bin(Base), int_to_bin(Exponent), int_to_bin(Modulo), 0)); + +mod_exp(Base, Exponent, Modulo) -> + mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4). + +mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub. + +-define(FUNC_LIST, [hash, hash_init, hash_update, hash_final, + hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, + %% deprecated + md4, md4_init, md4_update, md4_final, + md5, md5_init, md5_update, md5_final, + sha, sha_init, sha_update, sha_final, + md5_mac, md5_mac_96, + sha_mac, sha_mac_96, + %% + block_encrypt, block_decrypt, + %% deprecated + des_cbc_encrypt, des_cbc_decrypt, + des_cfb_encrypt, des_cfb_decrypt, + des_ecb_encrypt, des_ecb_decrypt, + des3_cbc_encrypt, des3_cbc_decrypt, + des3_cfb_encrypt, des3_cfb_decrypt, + aes_cfb_128_encrypt, aes_cfb_128_decrypt, + rc2_cbc_encrypt, rc2_cbc_decrypt, + rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, + aes_cbc_128_encrypt, aes_cbc_128_decrypt, + aes_cbc_256_encrypt, aes_cbc_256_decrypt, + blowfish_cbc_encrypt, blowfish_cbc_decrypt, + blowfish_cfb64_encrypt, blowfish_cfb64_decrypt, + blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt, + %% + rand_bytes, + strong_rand_bytes, + rand_uniform, + mod_pow, + exor, + %% deprecated + mod_exp,strong_rand_mpint,erlint, mpint, + %% + sign, verify, generate_key, compute_key, + %% deprecated + dss_verify,dss_sign, + rsa_verify,rsa_sign, + rsa_public_encrypt,rsa_private_decrypt, + rsa_private_encrypt,rsa_public_decrypt, + dh_generate_key, dh_compute_key, + %% + stream_init, stream_encrypt, stream_decrypt, + %% deprecated + rc4_encrypt, rc4_set_key, rc4_encrypt_with_state, + aes_ctr_encrypt, aes_ctr_decrypt, + aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, + %% + next_iv, + %% deprecated + aes_cbc_ivec, + des_cbc_ivec, des_cfb_ivec, + info, + %% + info_lib, supports]). +info() -> + ?FUNC_LIST. diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index b3bb5dbd17..58aaa78d28 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -212,16 +212,8 @@ mod_pow(Config) when is_list(Config) -> exor() -> [{doc, "Test the exor function"}]. exor(Config) when is_list(Config) -> - B = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>, - Z1 = zero_bin(B), - Z1 = crypto:exor(B, B), - B1 = crypto:rand_bytes(100), - B2 = crypto:rand_bytes(100), - Z2 = zero_bin(B1), - Z2 = crypto:exor(B1, B1), - Z2 = crypto:exor(B2, B2), - R = xor_bytes(B1, B2), - R = crypto:exor(B1, B2). + do_exor(<<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>), + do_exor(term_to_binary(lists:seq(1, 1000000))). %%-------------------------------------------------------------------- rand_uniform() -> [{doc, "rand_uniform and random_bytes testing"}]. @@ -229,10 +221,10 @@ rand_uniform(Config) when is_list(Config) -> rand_uniform_aux_test(10), 10 = byte_size(crypto:rand_bytes(10)), 10 = byte_size(crypto:strong_rand_bytes(10)). + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- - hash(_, [], []) -> ok; hash(Type, [Msg | RestMsg], [Digest| RestDigest]) -> @@ -491,7 +483,7 @@ do_block_iolistify({Type, Key, IV, PlainText}) -> iolistify(<<"Test With Truncation">>)-> %% Do not iolistify as it spoils this special case <<"Test With Truncation">>; -iolistify(Msg)-> +iolistify(Msg) when is_binary(Msg) -> Length = erlang:byte_size(Msg), Split = Length div 2, List0 = binary_to_list(Msg), @@ -500,7 +492,9 @@ iolistify(Msg)-> [[Element], List1, List2]; {List1, List2}-> [List1, List2] - end. + end; +iolistify(Msg) -> + iolistify(list_to_binary(Msg)). des_iolistify(Msg) -> des_iolist(erlang:byte_size(Msg) div 8, Msg, []). @@ -540,6 +534,17 @@ ipow(A, B, M, Prod) -> ipow(A1, B1, M, (A*Prod) rem M) end. +do_exor(B) -> + Z1 = zero_bin(B), + Z1 = crypto:exor(B, B), + B1 = crypto:rand_bytes(100), + B2 = crypto:rand_bytes(100), + Z2 = zero_bin(B1), + Z2 = crypto:exor(B1, B1), + Z2 = crypto:exor(B2, B2), + R = xor_bytes(B1, B2), + R = crypto:exor(B1, B2). + zero_bin(N) when is_integer(N) -> N8 = N * 8, <<0:N8/integer>>; @@ -586,20 +591,20 @@ group_config(md4 = Type, Config) -> group_config(md5 = Type, Config) -> Msgs = rfc_1321_msgs(), Digests = rfc_1321_md5_digests(), - Keys = rfc_2202_md5_keys(), - Data = rfc_2202_msgs(), - Hmac = rfc_2202_hmac_md5(), + Keys = rfc_2202_md5_keys() ++ [long_hmac_key(md5)], + Data = rfc_2202_msgs() ++ [long_msg()], + Hmac = rfc_2202_hmac_md5() ++ [long_hmac(md5)], [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; group_config(ripemd160 = Type, Config) -> Msgs = ripemd160_msgs(), Digests = ripemd160_digests(), [{hash, {Type, Msgs, Digests}} | Config]; group_config(sha = Type, Config) -> - Msgs = [rfc_4634_test1(), rfc_4634_test2_1()], - Digests = rfc_4634_sha_digests(), - Keys = rfc_2202_sha_keys(), - Data = rfc_2202_msgs(), - Hmac = rfc_2202_hmac_sha(), + Msgs = [rfc_4634_test1(), rfc_4634_test2_1(),long_msg()], + Digests = rfc_4634_sha_digests() ++ [long_sha_digest()], + Keys = rfc_2202_sha_keys() ++ [long_hmac_key(sha)], + Data = rfc_2202_msgs() ++ [long_msg()], + Hmac = rfc_2202_hmac_sha() ++ [long_hmac(sha)], [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; group_config(sha224 = Type, Config) -> Msgs = [rfc_4634_test1(), rfc_4634_test2_1()], @@ -609,25 +614,25 @@ group_config(sha224 = Type, Config) -> Hmac = rfc4231_hmac_sha224(), [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; group_config(sha256 = Type, Config) -> - Msgs = [rfc_4634_test1(), rfc_4634_test2_1()], - Digests = rfc_4634_sha256_digests(), - Keys = rfc_4231_keys(), - Data = rfc_4231_msgs(), - Hmac = rfc4231_hmac_sha256(), + Msgs = [rfc_4634_test1(), rfc_4634_test2_1(), long_msg()], + Digests = rfc_4634_sha256_digests() ++ [long_sha256_digest()], + Keys = rfc_4231_keys() ++ [long_hmac_key(sha256)], + Data = rfc_4231_msgs() ++ [long_msg()], + Hmac = rfc4231_hmac_sha256() ++ [long_hmac(sha256)], [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; group_config(sha384 = Type, Config) -> - Msgs = [rfc_4634_test1(), rfc_4634_test2()], - Digests = rfc_4634_sha384_digests(), - Keys = rfc_4231_keys(), - Data = rfc_4231_msgs(), - Hmac = rfc4231_hmac_sha384(), + Msgs = [rfc_4634_test1(), rfc_4634_test2(), long_msg()], + Digests = rfc_4634_sha384_digests() ++ [long_sha384_digest()], + Keys = rfc_4231_keys() ++ [long_hmac_key(sha384)], + Data = rfc_4231_msgs() ++ [long_msg()], + Hmac = rfc4231_hmac_sha384() ++ [long_hmac(sha384)], [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; group_config(sha512 = Type, Config) -> - Msgs = [rfc_4634_test1(), rfc_4634_test2()], - Digests = rfc_4634_sha512_digests(), - Keys = rfc_4231_keys(), - Data = rfc_4231_msgs(), - Hmac = rfc4231_hmac_sha512(), + Msgs = [rfc_4634_test1(), rfc_4634_test2(), long_msg()], + Digests = rfc_4634_sha512_digests() ++ [long_sha512_digest()], + Keys = rfc_4231_keys() ++ [long_hmac_key(sha512)], + Data = rfc_4231_msgs() ++ [long_msg()], + Hmac = rfc4231_hmac_sha512() ++ [long_hmac(sha512)], [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; group_config(rsa = Type, Config) -> Msg = rsa_plain(), @@ -789,6 +794,23 @@ rfc_4634_sha512_digests() -> "454D4423643CE80E2A9AC94FA54CA49F"), hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA17299AEADB6889018501D289E4900F7E4331B99DEC4B5433AC7D329EEB6DD26545E96E55B874BE909")]. +long_msg() -> + lists:duplicate(1000000, $a). + +long_sha_digest() -> + hexstr2bin("34aa973c" "d4c4daa4" "f61eeb2b" "dbad2731" "6534016f"). + +long_sha256_digest() -> + hexstr2bin("cdc76e5c" "9914fb92" "81a1c7e2" "84d73e67" "f1809a48" "a497200e" "046d39cc" "c7112cd0"). + +long_sha384_digest() -> + hexstr2bin("9d0e1809716474cb" "086e834e310a4a1c" "ed149e9c00f24852" "7972cec5704c2a5b" + "07b8b3dc38ecc4eb" "ae97ddd87f3d8985"). + +long_sha512_digest() -> + hexstr2bin("e718483d0ce76964" "4e2e42c7bc15b463" "8e1f98b13b204428" "5632a803afa973eb" + "de0ff244877ea60a" "4cb0432ce577c31b" "eb009c5c2c49aa2e" "4eadb217ad8cc09b"). + ripemd160_msgs() -> [<<"">>, <<"a">>, @@ -852,6 +874,35 @@ hmac_key(_) -> hmac_inc(_) -> [<<"Sampl">>, <<"e #1">>]. +%% https://www.cosic.esat.kuleuven.be/nessie/testvectors/ +long_hmac_key(Type) when Type == sha384; + Type == sha512 -> + hexstr2bin("00112233445566778899AABBCCDDEEFF" + "0123456789ABCDEF0011223344556677" + "8899AABBCCDDEEFF0123456789ABCDEF" + "00112233445566778899AABBCCDDEEFF"); +long_hmac_key(_) -> + hexstr2bin("0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF"). +long_hmac(md5) -> + hexstr2bin("82FDDA30202CB6ACC6F24D4F8A50EB7A"); +long_hmac(sha) -> + hexstr2bin("61D1D0B6459860755FDA892938C23DD401E54A7E"); +long_hmac(sha256) -> + hexstr2bin("50008B8DC7ED3926936347FDC1A01E9D" + "5220C6CC4B038B482C0F28A4CD88CA37"); +long_hmac(sha384) -> + hexstr2bin("C1EB08DAFA015833D3FC6B29A387558B" + "3F6FA1524AA1A8EB64798D5A76A39D6E" + "A1465525342E060EE996277B4FFCDDC9"); +long_hmac(sha512) -> + hexstr2bin("D116BF471AAE1264854F1906025E846A" + "61618A965FCA30B695220EA2D6E547E3" + "F3B5A4B54E6778928C26D5D3D810498E" + "8DF86CB3CC1E9F66A00419B13B6B0C9A"). + rfc_2202_hmac_md5() -> [ hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d"), @@ -1193,7 +1244,8 @@ blowfish_ofb64() -> rc4() -> [{rc4, <<"apaapa">>, <<"Yo baby yo">>}, - {rc4, <<"apaapa">>, list_to_binary(lists:seq(0, 255))} + {rc4, <<"apaapa">>, list_to_binary(lists:seq(0, 255))}, + {rc4, <<"apaapa">>, lists:duplicate(1000000, $a)} ]. aes_ctr() -> @@ -1237,7 +1289,11 @@ aes_ctr() -> hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")}, {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"), - hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")} + hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}, + + {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), + lists:duplicate(1000000, $a)} ]. rsa_plain() -> diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk index 2a0cb57aa9..d5d7c8a128 100644 --- a/lib/crypto/vsn.mk +++ b/lib/crypto/vsn.mk @@ -1 +1 @@ -CRYPTO_VSN = 2.3 +CRYPTO_VSN = 3.0 diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index d847990694..3c9aebc6af 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -1,5 +1,7 @@ <?xml version="1.0" encoding="latin1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd" [ + <!ENTITY spawn_opt + '<seealso marker="erts:erlang#spawn_opt-2">erlang:spawn_opt/2</seealso>'> <!ENTITY nodes '<seealso marker="erts:erlang#nodes-0">erlang:nodes/0</seealso>'> <!ENTITY make_ref @@ -871,6 +873,17 @@ of a single Diameter node across multiple Erlang nodes.</p> </note> </item> +<tag><c>{spawn_opt, [term()]}</c></tag> +<item> +<p> +An options list passed to &spawn_opt; when spawning a process for an +incoming Diameter request, unless the transport in question +specifies another value.</p> + +<p> +Defaults to the empty list.</p> +</item> + <tag><c>{use_shared_peers, boolean() | [node()] | evaluable()}</c></tag> <item> <p> @@ -1161,6 +1174,17 @@ Defaults to 30000 for a connecting transport and 60000 for a listening transport.</p> </item> +<marker id="spawn_opt"/> +<tag><c>{spawn_opt, [term()]}</c></tag> +<item> +<p> +An options list passed to &spawn_opt; when spawning a process for an +incoming Diameter request.</p> + +<p> +Defaults to the list configured on the service if not specified.</p> +</item> + <marker id="transport_config"/> <tag><c>{transport_config, term()}</c></tag> <tag><c>{transport_config, term(), &dict_Unsigned32; | infinity}</c></tag> diff --git a/lib/diameter/doc/src/diameter_sctp.xml b/lib/diameter/doc/src/diameter_sctp.xml index df140b16b9..5fe14b1ef6 100644 --- a/lib/diameter/doc/src/diameter_sctp.xml +++ b/lib/diameter/doc/src/diameter_sctp.xml @@ -70,10 +70,15 @@ and implements the behaviour documented in <v>Type = connect | accept</v> <v>Ref = &mod_transport_ref;</v> <v>Svc = #diameter_service{}</v> -<v>Opt = {raddr, &ip_address;} | {rport, integer()} | term()</v> +<v>Opt = OwnOpt | SctpOpt</v> <v>Pid = pid()</v> <v>LAddr = &ip_address;</v> <v>Reason = term()</v> +<v>OwnOpt = {raddr, &ip_address;} + | {rport, integer()} + | {accept, Match}</v> +<v>SctpOpt = term()</v> +<v>Match = &ip_address; | string() | [Match]</v> </type> <desc> @@ -85,9 +90,20 @@ Options <c>raddr</c> and <c>rport</c> specify the remote address and port for a connecting transport and not valid for a listening transport: the former is required while latter defaults to 3868 if unspecified. -More than one <c>raddr</c> option can be specified, in which case the +Mupltiple <c>raddr</c> options can be specified, in which case the connecting transport in question attempts each in sequence until -an association is established. +an association is established.</p> + +<p> +Option <c>accept</c> specifies remote addresses for a listening +transport and is not valid for a connecting transport. +If specified, a remote address that does not match one of the +specified addresses causes the association to be aborted. +Multiple <c>accept</c> options can be specified. +A string-valued <c>Match</c> that does not parse as an address is +interpreted as a regular expression.</p> + +<p> Remaining options are any accepted by &gen_sctp_open1;, with the exception of options <c>mode</c>, <c>binary</c>, <c>list</c>, <c>active</c> and <c>sctp_events</c>. diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml index 8e509aa829..ce4d6cfd0f 100644 --- a/lib/diameter/doc/src/diameter_tcp.xml +++ b/lib/diameter/doc/src/diameter_tcp.xml @@ -96,10 +96,12 @@ before configuring TLS capability on diameter transports.</p> <v>Reason = term()</v> <v>OwnOpt = {raddr, &ip_address;} | {rport, integer()} + | {accept, Match} | {port, integer()} | {fragment_timer, infinity | 0..16#FFFFFFFF}</v> <v>SslOpt = {ssl_options, true | list()}</v> <v>TcpOpt = term()</v> +<v>Match = &ip_address; | string() | [Match]</v> </type> <desc> @@ -109,7 +111,18 @@ The start function required by &man_transport;.</p> <p> Options <c>raddr</c> and <c>rport</c> specify the remote address and port for a connecting transport and are not valid for a listening -transport. +transport.</p> + +<p> +Option <c>accept</c> specifies remote addresses for a listening +transport and is not valid for a connecting transport. +If specified, a remote address that does not match one of the +specified addresses causes the connection to be aborted. +Multiple <c>accept</c> options can be specified. +A string-valued <c>Match</c> that does not parse as an address is +interpreted as a regular expression.</p> + +<p> Option <c>ssl_options</c> must be specified for a transport that should support TLS: a value of <c>true</c> results in a TLS handshake immediately upon connection establishment while diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index 57730cad61..77200cc7d0 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -306,7 +306,8 @@ call(SvcName, App, Message) -> | {restrict_connections, restriction()} | {sequence, sequence() | evaluable()} | {share_peers, remotes()} - | {use_shared_peers, remotes()}. + | {use_shared_peers, remotes()} + | {spawn_opt, list()}. -type application_opt() :: {alias, app_alias()} @@ -345,6 +346,7 @@ call(SvcName, App, Message) -> | {reconnect_timer, 'Unsigned32'()} | {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}} | {watchdog_config, [{okay|suspect, non_neg_integer()}]} + | {spawn_opt, list()} | {private, any()}. %% Predicate passed to remove_transport/2 diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 2a145c874b..fc5c284bf2 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -549,6 +549,9 @@ opt({watchdog_timer, Tmo}) -> opt({watchdog_config, L}) -> is_list(L) andalso lists:all(fun wdopt/1, L); +opt({spawn_opt, Opts}) -> + is_list(Opts); + %% Options that we can't validate. opt({K, _}) when K == transport_config; @@ -632,7 +635,8 @@ make_config(SvcName, Opts) -> {false, use_shared_peers}, {false, monitor}, {?NOMASK, sequence}, - {nodes, restrict_connections}]), + {nodes, restrict_connections}, + {[], spawn_opt}]), #service{name = SvcName, rec = #diameter_service{applications = Apps, @@ -647,6 +651,9 @@ make_opts(Opts, Defs) -> [{K, opt(K,V)} || {K,V} <- Known]. +opt(spawn_opt, L) -> + is_list(L); + opt(K, false = B) when K /= sequence -> B; diff --git a/lib/diameter/src/base/diameter_peer.erl b/lib/diameter/src/base/diameter_peer.erl index 0d2efd4d1f..e5d4b28766 100644 --- a/lib/diameter/src/base/diameter_peer.erl +++ b/lib/diameter/src/base/diameter_peer.erl @@ -25,7 +25,8 @@ -export([recv/2, up/1, up/2, - up/3]). + up/3, + match/2]). %% ... and the stack. -export([start/1, @@ -63,16 +64,16 @@ -define(DEFAULT_TCFG, []). -define(DEFAULT_TTMO, infinity). -%%% --------------------------------------------------------------------------- -%%% # notify/3 -%%% --------------------------------------------------------------------------- +%% --------------------------------------------------------------------------- +%% # notify/3 +%% --------------------------------------------------------------------------- notify(Nodes, SvcName, T) -> rpc:abcast(Nodes, ?SERVER, {notify, SvcName, T}). -%%% --------------------------------------------------------------------------- -%%% # start/1 -%%% --------------------------------------------------------------------------- +%% --------------------------------------------------------------------------- +%% # start/1 +%% --------------------------------------------------------------------------- -spec start({T, [Opt], #diameter_service{}}) -> {TPid, [Addr], Tmo, Data} @@ -180,9 +181,34 @@ start(T, [M|Ms], Cfg, Svc, Tmo, Rest, Errs) -> start(Mod, Args) -> apply(Mod, start, Args). -%%% --------------------------------------------------------------------------- -%%% # up/1-3 -%%% --------------------------------------------------------------------------- +%% --------------------------------------------------------------------------- +%% # match/2 +%% --------------------------------------------------------------------------- + +match(Addrs, Matches) + when is_list(Addrs) -> + lists:all(fun(A) -> match1(A, Matches) end, Addrs). + +match1(Addr, Matches) + when not is_integer(hd(Matches)) -> + lists:any(fun(M) -> match1(Addr, M) end, Matches); + +match1(Addr, Match) -> + match(Addr, addr(Match), Match). + +match(Addr, {ok, A}, _) -> + Addr == A; +match(Addr, {error, _}, RE) -> + match == re:run(inet_parse:ntoa(Addr), RE, [{capture, none}]). + +addr([_|_] = A) -> + inet_parse:address(A); +addr(A) -> + {ok, A}. + +%% --------------------------------------------------------------------------- +%% # up/1-3 +%% --------------------------------------------------------------------------- up(Pid) -> %% accepting transport ifc_send(Pid, {self(), connected}). @@ -193,16 +219,16 @@ up(Pid, Remote) -> %% connecting transport up(Pid, Remote, LAddrs) -> %% connecting transport ifc_send(Pid, {self(), connected, Remote, LAddrs}). -%%% --------------------------------------------------------------------------- -%%% # recv/2 -%%% --------------------------------------------------------------------------- +%% --------------------------------------------------------------------------- +%% # recv/2 +%% --------------------------------------------------------------------------- recv(Pid, Pkt) -> ifc_send(Pid, {recv, Pkt}). -%%% --------------------------------------------------------------------------- -%%% # send/2 -%%% --------------------------------------------------------------------------- +%% --------------------------------------------------------------------------- +%% # send/2 +%% --------------------------------------------------------------------------- send(Pid, #diameter_packet{transport_data = undefined, bin = Bin}) -> @@ -211,16 +237,16 @@ send(Pid, #diameter_packet{transport_data = undefined, send(Pid, Pkt) -> ifc_send(Pid, {send, Pkt}). -%%% --------------------------------------------------------------------------- -%%% # close/1 -%%% --------------------------------------------------------------------------- +%% --------------------------------------------------------------------------- +%% # close/1 +%% --------------------------------------------------------------------------- close(Pid) -> ifc_send(Pid, {close, self()}). -%%% --------------------------------------------------------------------------- -%%% # abort/1 -%%% --------------------------------------------------------------------------- +%% --------------------------------------------------------------------------- +%% # abort/1 +%% --------------------------------------------------------------------------- abort(Pid) -> exit(Pid, shutdown). @@ -241,16 +267,16 @@ state() -> uptime() -> call(uptime). -%%% ---------------------------------------------------------- -%%% # init(Role) -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # init(Role) +%% ---------------------------------------------------------- init([]) -> {ok, #state{}}. -%%% ---------------------------------------------------------- -%%% # handle_call(Request, From, State) -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # handle_call(Request, From, State) +%% ---------------------------------------------------------- handle_call(state, _, State) -> {reply, State, State}; @@ -262,17 +288,17 @@ handle_call(Req, From, State) -> ?UNEXPECTED([Req, From]), {reply, nok, State}. -%%% ---------------------------------------------------------- -%%% # handle_cast(Request, State) -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # handle_cast(Request, State) +%% ---------------------------------------------------------- handle_cast(Msg, State) -> ?UNEXPECTED([Msg]), {noreply, State}. -%%% ---------------------------------------------------------- -%%% # handle_info(Request, State) -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # handle_info(Request, State) +%% ---------------------------------------------------------- %% Remote service is distributing a message. handle_info({notify, SvcName, T}, S) -> diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 112e83476d..9dd8aafc61 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -770,10 +770,8 @@ start(Ref, Type, Opts, #state{watchdogT = WatchdogT, = Svc = merge_service(Opts, Svc0), {_,_} = Mask = proplists:get_value(sequence, SvcOpts), - Pid = s(Type, Ref, {diameter_traffic:make_recvdata([SvcName, - PeerT, - Apps, - Mask]), + RecvData = diameter_traffic:make_recvdata([SvcName, PeerT, Apps, Mask]), + Pid = s(Type, Ref, {{spawn_opts([Opts, SvcOpts]), RecvData}, Opts, SvcOpts, Svc}), @@ -787,6 +785,12 @@ start(Ref, Type, Opts, #state{watchdogT = WatchdogT, %% record so that each watchdog may get a different record. This %% record is what is passed back into application callbacks. +spawn_opts(Optss) -> + SpawnOpts = get_value(spawn_opt, Optss, []), + [T || T <- SpawnOpts, + T /= link, + T /= monitor]. + s(Type, Ref, T) -> {_MRef, Pid} = diameter_watchdog:start({Type, Ref}, T), Pid. @@ -986,6 +990,18 @@ keyfind([Key | Rest], Pos, L) -> T end. +%% get_value/3 + +get_value(_, [], Def) -> + Def; +get_value(Key, [L | Rest], Def) -> + case lists:keyfind(Key, 1, L) of + {_,V} -> + V; + _ -> + get_value(Key, Rest, Def) + end. + %% find_outgoing_app/2 find_outgoing_app(Alias, Apps) -> diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index b2c5955501..8b6f026b34 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -48,6 +48,7 @@ -define(BASE, ?DIAMETER_DICT_COMMON). %% Note: the RFC 3588 dictionary -define(DEFAULT_TIMEOUT, 5000). %% for outgoing requests +-define(DEFAULT_SPAWN_OPTS, []). %% Table containing outgoing requests for which a reply has yet to be %% received. @@ -153,13 +154,8 @@ receive_message(TPid, Pkt, Dict0, RecvData) RecvData). %% Incoming request ... -recv(true, false, TPid, Pkt, Dict0, RecvData) -> - try - spawn(fun() -> recv_request(TPid, Pkt, Dict0, RecvData) end) - catch - error: system_limit = E -> %% discard - ?LOG({error, E}, now()) - end; +recv(true, false, TPid, Pkt, Dict0, T) -> + spawn_request(TPid, Pkt, Dict0, T); %% ... answer to known request ... recv(false, #request{ref = Ref, handler = Pid} = Req, _, Pkt, Dict0, _) -> @@ -177,6 +173,21 @@ recv(false, #request{ref = Ref, handler = Pid} = Req, _, Pkt, Dict0, _) -> recv(false, false, _, _, _, _) -> ok. +%% spawn_request/4 + +spawn_request(TPid, Pkt, Dict0, {Opts, RecvData}) -> + spawn_request(TPid, Pkt, Dict0, Opts, RecvData); +spawn_request(TPid, Pkt, Dict0, RecvData) -> + spawn_request(TPid, Pkt, Dict0, ?DEFAULT_SPAWN_OPTS, RecvData). + +spawn_request(TPid, Pkt, Dict0, Opts, RecvData) -> + try + spawn_opt(fun() -> recv_request(TPid, Pkt, Dict0, RecvData) end, Opts) + catch + error: system_limit = E -> %% discard + ?LOG({error, E}, now()) + end. + %% --------------------------------------------------------------------------- %% recv_request/4 %% --------------------------------------------------------------------------- diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl index 8b8c2a6694..49a530b4eb 100644 --- a/lib/diameter/src/transport/diameter_sctp.erl +++ b/lib/diameter/src/transport/diameter_sctp.erl @@ -42,6 +42,9 @@ -export([ports/0, ports/1]). +-export_type([listen_option/0, + connect_option/0]). + -include_lib("kernel/include/inet_sctp.hrl"). -include_lib("diameter/include/diameter.hrl"). @@ -54,6 +57,9 @@ %% The default port for a listener. -define(DEFAULT_PORT, 3868). %% RFC 3588, ch 2.1 +%% Remote addresses to accept connections from. +-define(DEFAULT_ACCEPT, []). %% any + %% How long a listener with no associations lives before offing %% itself. -define(LISTENER_TIMEOUT, 30000). @@ -62,6 +68,17 @@ %% association establishment. -define(ACCEPT_TIMEOUT, 5000). +-type connect_option() :: {raddr, inet:ip_address()} + | {rport, inet:port_number()} + | gen_sctp:open_option(). + +-type match() :: inet:ip_address() + | string() + | [match()]. + +-type listen_option() :: {accept, match()} + | gen_sctp:open_option(). + -type uint() :: non_neg_integer(). %% Accepting/connecting transport process state. @@ -69,7 +86,7 @@ {parent :: pid(), mode :: {accept, pid()} | accept - | {connect, {list(inet:ip_address()), uint(), list()}} + | {connect, {[inet:ip_address()], uint(), list()}} %% {RAs, RP, Errors} | connect, socket :: gen_sctp:sctp_socket(), @@ -86,7 +103,8 @@ tmap = ets:new(?MODULE, []) :: ets:tid(), %% {MRef, Pid|AssocId}, {AssocId, Pid} pending = {0, ets:new(?MODULE, [ordered_set])}, - tref :: reference()}). + tref :: reference(), + accept :: [match()]}). %% Field tmap is used to map an incoming message or event to the %% relevent transport process. Field pending implements a queue of %% transport processes to which an association has been assigned (at @@ -102,6 +120,13 @@ %% # start/3 %% --------------------------------------------------------------------------- +-spec start({accept, Ref}, #diameter_service{}, [listen_option()]) + -> {ok, pid(), [inet:ip_address()]} + when Ref :: diameter:transport_ref(); + ({connect, Ref}, #diameter_service{}, [connect_option()]) + -> {ok, pid(), [inet:ip_address()]} + when Ref :: diameter:transport_ref(). + start(T, #diameter_service{capabilities = Caps}, Opts) when is_list(Opts) -> diameter_sctp_sup:start(), %% start supervisors on demand @@ -169,12 +194,14 @@ init(T) -> %% A process owning a listening socket. i({listen, Ref, {Opts, Addrs}}) -> - {LAs, Sock} = AS = open(Addrs, Opts, ?DEFAULT_PORT), + {[Matches], Rest} = proplists:split(Opts, [accept]), + {LAs, Sock} = AS = open(Addrs, Rest, ?DEFAULT_PORT), proc_lib:init_ack({ok, self(), LAs}), ok = gen_sctp:listen(Sock, true), true = diameter_reg:add_new({?MODULE, listener, {Ref, AS}}), start_timer(#listener{ref = Ref, - socket = Sock}); + socket = Sock, + accept = accept(Matches)}); %% A connecting transport. i({connect, Pid, Opts, Addrs, Ref}) -> @@ -311,6 +338,9 @@ handle_call({{accept, Ref}, Pid}, _, #listener{ref = Ref, {TPid, NewS} = accept(Ref, Pid, S), {reply, {ok, TPid}, NewS#listener{count = N+1}}; +handle_call(T, From, {listener,_,_,_,_,_,_} = S) -> % started in old code + handle_call(T, From, upgrade(S)); + handle_call(_, _, State) -> {reply, nok, State}. @@ -329,7 +359,10 @@ handle_info(T, #transport{} = S) -> {noreply, #transport{} = t(T,S)}; handle_info(T, #listener{} = S) -> - {noreply, #listener{} = l(T,S)}. + {noreply, #listener{} = l(T,S)}; + +handle_info(T, {listener,_,_,_,_,_,_} = S) -> % started in old code + handle_info(T, upgrade(S)). %% --------------------------------------------------------------------------- %% # code_change/3 @@ -363,6 +396,9 @@ terminate(_, #listener{socket = Sock}) -> %% --------------------------------------------------------------------------- +upgrade(S) -> + #listener{} = erlang:append_element(S, ?DEFAULT_ACCEPT). + putr(Key, Val) -> put({?MODULE, Key}, Val). @@ -386,7 +422,7 @@ l({sctp, Sock, _RA, _RP, Data} = Msg, #listener{socket = Sock} = S) -> try find(Id, Data, S) of {TPid, NewS} -> - TPid ! {peeloff, peeloff(Sock, Id, TPid), Msg}, + TPid ! {peeloff, peeloff(Sock, Id, TPid), Msg, S#listener.accept}, NewS; false -> S @@ -460,11 +496,14 @@ t(T,S) -> %% transition/2 %% Listening process is transfering ownership of an association. -transition({peeloff, Sock, {sctp, LSock, _RA, _RP, _Data} = Msg}, +transition({peeloff, Sock, {sctp, LSock, _RA, _RP, _Data} = Msg, Matches}, #transport{mode = {accept, _}, socket = LSock} = S) -> + ok = accept_peer(Sock, Matches), transition(Msg, S#transport{socket = Sock}); +transition({peeloff = T, _Sock, _Msg} = T, #transport{} = S) ->% from old code + transition(erlang:append_element(T, ?DEFAULT_ACCEPT), S); %% Incoming message. transition({sctp, _Sock, _RA, _RP, Data}, #transport{socket = Sock} = S) -> @@ -510,6 +549,27 @@ transition({resolve_port, Pid}, #transport{socket = Sock}) %% Crash on anything unexpected. +ok({ok, T}) -> + T; +ok(T) -> + x(T). + +%% accept_peer/2 + +accept_peer(_, []) -> + ok; + +accept_peer(Sock, Matches) -> + {RAddrs, _} = ok(inet:peername(Sock)), + diameter_peer:match(RAddrs, Matches) + orelse x({accept, RAddrs, Matches}), + ok. + +%% accept/1 + +accept(Opts) -> + [[M] || {accept, M} <- Opts]. + %% accept/3 %% %% Start a new transport process or use one that's already been diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl index cbbba714ac..4d1b8bec51 100644 --- a/lib/diameter/src/transport/diameter_tcp.erl +++ b/lib/diameter/src/transport/diameter_tcp.erl @@ -42,6 +42,9 @@ -export([ports/0, ports/1]). +-export_type([connect_option/0, + listen_option/0]). + -include_lib("diameter/include/diameter.hrl"). %% Keys into process dictionary. @@ -80,6 +83,25 @@ -type frag() :: {length(), size(), binary(), list(binary())} | binary(). +-type connect_option() :: {raddr, inet:ip_address()} + | {rport, pos_integer()} + | {ssl_options, true | [ssl:connect_option()]} + | option() + | ssl:connect_option() + | gen_tcp:connect_option(). + +-type match() :: inet:ip_address() + | string() + | [match()]. + +-type listen_option() :: {accept, match()} + | {ssl_options, true | [ssl:listen_option()]} + | ssl:listen_option() + | gen_tcp:listen_option(). + +-type option() :: {port, non_neg_integer()} + | {fragment_timer, 0..16#FFFFFFFF}. + %% Accepting/connecting transport process state. -record(transport, {socket :: inet:socket() | ssl:sslsocket(), %% accept/connect socket @@ -100,18 +122,14 @@ %% # start/3 %% --------------------------------------------------------------------------- --spec start({accept, Ref}, Svc, [Opt]) +-spec start({accept, Ref}, #diameter_service{}, [listen_option()]) -> {ok, pid(), [inet:ip_address()]} - when Ref :: diameter:transport_ref(), - Svc :: #diameter_service{}, - Opt :: diameter:transport_opt(); - ({connect, Ref}, Svc, [Opt]) + when Ref :: diameter:transport_ref(); + ({connect, Ref}, #diameter_service{}, [connect_option()]) -> {ok, pid(), [inet:ip_address()]} | {ok, pid()} - when Ref :: diameter:transport_ref(), - Svc :: #diameter_service{}, - Opt :: diameter:transport_opt(). - + when Ref :: diameter:transport_ref(). + start({T, Ref}, #diameter_service{capabilities = Caps}, Opts) -> diameter_tcp_sup:start(), %% start tcp supervisors on demand {Mod, Rest} = split(Opts), @@ -225,10 +243,10 @@ laddr([], Mod, Sock) -> Addr; laddr([{ip, Addr}], _, _) -> Addr. - + own(Opts) -> - {Own, Rest} = proplists:split(Opts, [fragment_timer]), - {lists:append(Own), Rest}. + {[Own], Rest} = proplists:split(Opts, [fragment_timer]), + {Own, Rest}. ssl(Opts) -> {[SslOpts], Rest} = proplists:split(Opts, [ssl_options]), @@ -257,9 +275,11 @@ init(Type, Ref, Mod, Pid, _, Opts, Addrs) -> %% init/6 init(accept = T, Ref, Mod, Pid, Opts, Addrs) -> - {LAddr, LSock} = listener(Ref, {Mod, Opts, Addrs}), + {[Matches], Rest} = proplists:split(Opts, [accept]), + {LAddr, LSock} = listener(Ref, {Mod, Rest, Addrs}), proc_lib:init_ack({ok, self(), [LAddr]}), Sock = ok(accept(Mod, LSock)), + ok = accept_peer(Mod, Sock, accept(Matches)), publish(Mod, T, Ref, Sock), diameter_peer:up(Pid), Sock; @@ -282,7 +302,7 @@ init_rc([]) -> up(Pid, Remote, [{ip, _Addr}], _, _) -> diameter_peer:up(Pid, Remote); -up(Pid, Remote, [], Mod, Sock) -> +up(Pid, Remote, [], Mod, Sock) -> {Addr, _Port} = ok(sockname(Mod, Sock)), diameter_peer:up(Pid, Remote, [Addr]). @@ -298,6 +318,22 @@ ok(No) -> x(Reason) -> exit({shutdown, Reason}). +%% accept_peer/3 + +accept_peer(_Mod, _Sock, []) -> + ok; + +accept_peer(Mod, Sock, Matches) -> + {RAddr, _} = ok(peername(Mod, Sock)), + diameter_peer:match([RAddr], Matches) + orelse x({accept, RAddr, Matches}), + ok. + +%% accept/1 + +accept(Opts) -> + [[M] || {accept, M} <- Opts]. + %% listener/2 listener(LRef, T) -> diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 38bdf55af8..a97c54fc04 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -171,7 +171,8 @@ {'Product-Name', "OTP/diameter"}, {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]}, - {restrict_connections, false} + {restrict_connections, false}, + {spawn_opt, [{min_heap_size, 5000}]} | [{application, [{dictionary, D}, {module, ?MODULE}, {answer_errors, callback}]} @@ -321,6 +322,7 @@ add_transports(Config) -> LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx/2}, + {spawn_opt, [{min_heap_size, 8096}]}, {applications, apps(rfc3588)}]), Cs = [?util:connect(?CLIENT, tcp, diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index aa489fef5f..92c72c84e7 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -336,7 +336,7 @@ opts(Prot, T) -> {transport_config, [{ip, ?ADDR}, {port, 0} | opts(T)]}]. opts(listen) -> - []; + [{accept, M} || M <- [{256,0,0,1}, ["256.0.0.1", ["^.+$"]]]]; opts(PortNr) -> [{raddr, ?ADDR}, {rport, PortNr}]. diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk index 9287e105df..6f08d380ca 100644 --- a/lib/erl_interface/vsn.mk +++ b/lib/erl_interface/vsn.mk @@ -1 +1 @@ -EI_VSN = 3.7.12 +EI_VSN = 3.7.13 diff --git a/lib/et/vsn.mk b/lib/et/vsn.mk index 99532ee3f3..40cdc2b298 100644 --- a/lib/et/vsn.mk +++ b/lib/et/vsn.mk @@ -1 +1 @@ -ET_VSN = 1.4.4.3 +ET_VSN = 1.4.4.4 diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index aada1252ad..3ea530a366 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2012. All Rights Reserved. +%% Copyright Ericsson AB 1997-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -947,21 +947,34 @@ gethostbyname_self(Name, Type) when is_atom(Name) -> gethostbyname_self(Name, Type) when is_list(Name), Type =:= inet; is_list(Name), Type =:= inet6 -> - case inet_db:gethostname() of - Name -> - {ok,make_hostent(Name, - [translate_ip(loopback, Type)], - [], Type)}; - Self -> + N = inet_db:tolower(Name), + Self = inet_db:gethostname(), + %% + %% This is the final fallback that pretends /etc/hosts has got + %% a line for the hostname on the loopback address. + %% Lookups into /etc/hosts are case insensitive and return + %% what is in the file. Therefore the letter case may differ between + %% the returned hostent record and the hostname that was asked for. + %% + case inet_db:tolower(Self) of + N -> + {ok, + make_hostent( + Self, [translate_ip(loopback, Type)], [], Type)}; + _ -> case inet_db:res_option(domain) of - "" -> {error,nxdomain}; + "" -> + {error,nxdomain}; Domain -> - case lists:append([Self,".",Domain]) of - Name -> - {ok,make_hostent(Name, - [translate_ip(loopback, Type)], - [], Type)}; - _ -> {error,nxdomain} + FQDN = lists:append([Self,".",Domain]), + case inet_db:tolower(FQDN) of + N -> + {ok, + make_hostent( + FQDN, + [translate_ip(loopback, Type)], [], Type)}; + _ -> + {error,nxdomain} end end end; diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl index d4749b9756..a7679c531b 100644 --- a/lib/kernel/src/inet_db.erl +++ b/lib/kernel/src/inet_db.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -845,7 +845,8 @@ init([]) -> process_flag(trap_exit, true), Db = ets:new(inet_db, [public, named_table]), reset_db(Db), - Cache = ets:new(inet_cache, [public, bag, {keypos,2}, named_table]), + CacheOpts = [public, bag, {keypos,#dns_rr.domain}, named_table], + Cache = ets:new(inet_cache, CacheOpts), BynameOpts = [protected, bag, named_table, {keypos,1}], ByaddrOpts = [protected, bag, named_table, {keypos,3}], HostsByname = ets:new(inet_hosts_byname, BynameOpts), @@ -901,15 +902,21 @@ reset_db(Db) -> handle_call(Request, From, #state{db=Db}=State) -> case Request of {load_hosts_file,IPNmAs} when is_list(IPNmAs) -> - NIPs = lists:flatten([ [{N,if tuple_size(IP) =:= 4 -> inet; - tuple_size(IP) =:= 8 -> inet6 - end,IP} || N <- [Nm|As]] - || {IP,Nm,As} <- IPNmAs]), + NIPs = + lists:flatten( + [ [{N, + if tuple_size(IP) =:= 4 -> inet; + tuple_size(IP) =:= 8 -> inet6 + end,IP} || N <- [Nm|As]] + || {IP,Nm,As} <- IPNmAs]), Byname = State#state.hosts_file_byname, Byaddr = State#state.hosts_file_byaddr, ets:delete_all_objects(Byname), ets:delete_all_objects(Byaddr), - ets:insert(Byname, NIPs), + %% Byname has lowercased names while Byaddr keep the name casing. + %% This is to be able to reconstruct the original + %% /etc/hosts entry. + ets:insert(Byname, [{tolower(N),Type,IP} || {N,Type,IP} <- NIPs]), ets:insert(Byaddr, NIPs), {reply, ok, State}; @@ -938,16 +945,14 @@ handle_call(Request, From, #state{db=Db}=State) -> {reply, ok, State}; {add_rr, RR} when is_record(RR, dns_rr) -> - RR1 = lower_rr(RR), - ?dbg("add_rr: ~p~n", [RR1]), - do_add_rr(RR1, Db, State), + ?dbg("add_rr: ~p~n", [RR]), + do_add_rr(RR, Db, State), {reply, ok, State}; {del_rr, RR} when is_record(RR, dns_rr) -> - RR1 = lower_rr(RR), %% note. del_rr will handle wildcards !!! Cache = State#state.cache, - ets:match_delete(Cache, RR1), + ets:match_delete(Cache, RR), {reply, ok, State}; {lookup_rr, Domain, Class, Type} -> @@ -1225,15 +1230,18 @@ handle_set_file(ParseFun, Bin, From, State) -> handle_rc_list(Opts, From, State) end. +%% Byname has lowercased names while Byaddr keep the name casing. +%% This is to be able to reconstruct the original /etc/hosts entry. + do_add_host(Byname, Byaddr, Names, Type, IP) -> do_del_host(Byname, Byaddr, IP), - NIPs = [{tolower(N),Type,IP} || N <- Names], - ets:insert(Byname, NIPs), - ets:insert(Byaddr, NIPs), + ets:insert(Byname, [{tolower(N),Type,IP} || N <- Names]), + ets:insert(Byaddr, [{N,Type,IP} || N <- Names]), ok. do_del_host(Byname, Byaddr, IP) -> - [ets:delete_object(Byname, NIP) || NIP <- ets:lookup(Byaddr, IP)], + [ets:delete_object(Byname, {tolower(Name),Type,Addr}) || + {Name,Type,Addr} <- ets:lookup(Byaddr, IP)], ets:delete(Byaddr, IP), ok. @@ -1369,7 +1377,7 @@ times() -> %% lookup and remove old entries do_lookup_rr(Domain, Class, Type) -> - match_rr(#dns_rr{domain = tolower(Domain), class = Class,type = Type, + match_rr(#dns_rr{domain = Domain, class = Class,type = Type, cnt = '_', tm = '_', ttl = '_', bm = '_', func = '_', data = '_'}). @@ -1393,23 +1401,20 @@ filter_rr([], _Time) -> []. %% -%% Lower case the domain name before storage -%% -lower_rr(RR) -> - Dn = RR#dns_rr.domain, - if is_list(Dn) -> - RR#dns_rr { domain = tolower(Dn) }; - true -> RR - end. - +%% Case fold upper-case to lower-case according to RFC 4343 +%% "Domain Name System (DNS) Case Insensitivity Clarification". %% -%% Map upper-case to lower-case %% NOTE: this code is in kernel and we don't want to relay -%% to much on stdlib +%% to much on stdlib. Furthermore string:to_lower/1 +%% does not follow RFC 4343. %% tolower([]) -> []; -tolower([C|Cs]) when C >= $A, C =< $Z -> [(C-$A)+$a|tolower(Cs)]; -tolower([C|Cs]) -> [C|tolower(Cs)]. +tolower([C|Cs]) when is_integer(C) -> + if C >= $A, C =< $Z -> + [(C-$A)+$a|tolower(Cs)]; + true -> + [C|tolower(Cs)] + end. dn_ip6_int(A,B,C,D,E,F,G,H) -> dnib(H) ++ dnib(G) ++ dnib(F) ++ dnib(E) ++ diff --git a/lib/kernel/src/inet_hosts.erl b/lib/kernel/src/inet_hosts.erl index df1d4fc0be..6e9719b4aa 100644 --- a/lib/kernel/src/inet_hosts.erl +++ b/lib/kernel/src/inet_hosts.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -38,9 +38,12 @@ gethostbyname(_) -> {error, formerr}. gethostbyname(Name, Type) when is_list(Name), is_atom(Type) -> - case gethostbyname(Name, Type, inet_hosts_byname, inet_hosts_byaddr) of + %% Byname has lowercased names while Byaddr keep the name casing. + %% This is to be able to reconstruct the original /etc/hosts entry. + N = inet_db:tolower(Name), + case gethostbyname(N, Type, inet_hosts_byname, inet_hosts_byaddr) of false -> - case gethostbyname(Name, Type, + case gethostbyname(N, Type, inet_hosts_file_byname, inet_hosts_file_byaddr) of false -> {error,nxdomain}; diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl index 59ba408d7a..94a9f7c64d 100644 --- a/lib/kernel/src/inet_res.erl +++ b/lib/kernel/src/inet_res.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -181,8 +181,8 @@ lookup(Name, Class, Type, Opts, Timeout) -> lookup_filter({ok,#dns_rec{anlist=Answers}}, Class, Type) -> [A#dns_rr.data || A <- Answers, - A#dns_rr.class =:= Class, - A#dns_rr.type =:= Type]; + Class =:= any orelse A#dns_rr.class =:= Class, + Type =:= any orelse A#dns_rr.type =:= Type]; lookup_filter({error,_}, _, _) -> []. %% -------------------------------------------------------------------------- diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 1f7724d0dc..62ba95e1a3 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -183,80 +183,74 @@ t_gethostbyname(Config) when is_list(Config) -> h_addr_list = [IP]}, ?line HEntF_ = HEntF, ?line check_elems([{HEnt#hostent.h_aliases,[[],Aliases]}]), + %% + ?line FullNameU = toupper(FullName), + ?line {ok,HEntU} = inet:gethostbyname(FullNameU), + ?line FullNameU = toupper(HEntU#hostent.h_name), + ?line #hostent{ + h_addrtype = inet, + h_length = 4, + h_addr_list = [IP]} = HEntU, + ?line check_elems( + [{[toupper(H) || H <- HEntU#hostent.h_aliases], + [[],[toupper(A) || A <- Aliases]]}]), ?line {DName, _DFullName, _DIPStr, _DIP, _, _, _} = ct:get_config(test_dummy_host), ?line {error,nxdomain} = inet:gethostbyname(DName), - ?line {error,nxdomain} = inet:gethostbyname(IP_46_Str). + ?line {error,nxdomain} = inet:gethostbyname(IP_46_Str), + ok. t_gethostbyname_v6() -> required(v6). t_gethostbyname_v6(doc) -> "Test the inet:gethostbyname/1 inet6 function."; t_gethostbyname_v6(suite) -> []; t_gethostbyname_v6(Config) when is_list(Config) -> - ?line {Name, _, _, _,Aliases,IP_46_Str,IP_46} = - ct:get_config(test_host_ipv4_only), + {Name, FullName, IPStr, IP, Aliases} = + ct:get_config(test_host_ipv6_only), - case {inet:gethostbyname(IP_46_Str, inet6), - inet:gethostbyname(Name, inet6)} of - {{ok,HEnt46},{ok,_}} -> - ?line HEnt46_ = HEnt46#hostent{h_name = IP_46_Str, - h_addrtype = inet6, - h_length = 16, - h_addr_list = [IP_46]}, - ?line HEnt46_ = HEnt46, - ?line check_elems([{HEnt46#hostent.h_aliases,[[],Aliases]}]), - - ?line {Name6, FullName6, IPStr6, IP6, Aliases6} = - ct:get_config(test_host_ipv6_only), - ?line {ok,_} = inet:gethostbyname(IPStr6, inet6), - ?line {ok,HEnt6} = inet:gethostbyname(Name6, inet6), - ?line {ok,HEnt6} = inet:gethostbyname(list_to_atom(Name6), inet6), - ?line case HEnt6#hostent.h_addr_list of - [IP6] -> % ipv6 ok - ?line HEnt6_ = HEnt6#hostent{h_addrtype = inet6, - h_length = 16, - h_addr_list = [IP6]}, - ?line HEnt6_ = HEnt6, - ?line check_elems([{HEnt6#hostent.h_name,[Name6,FullName6]}, - {HEnt6#hostent.h_aliases,[[],Aliases6]}]); - _ -> % ipv4 compatible addr - ?line {ok,HEnt4} = inet:gethostbyname(Name6, inet), - ?line [IP4] = HEnt4#hostent.h_addr_list, - ?line {ok,IP46_2} = - inet_parse:ipv6_address("::ffff:"++inet_parse:ntoa(IP4)), - ?line HEnt6_ = HEnt6#hostent{h_addrtype = inet6, - h_length = 16, - h_addr_list = [IP46_2]}, - ?line HEnt6_ = HEnt6, - ?line check_elems([{HEnt6#hostent.h_name,[Name6,FullName6]}]) - end, - - ?line {ok,HEntF6} = inet:gethostbyname(FullName6, inet6), - ?line case HEntF6#hostent.h_addr_list of - [IP6] -> % ipv6 ok - ?line HEntF6_ = HEntF6#hostent{h_name = FullName6, - h_addrtype = inet6, - h_length = 16, - h_addr_list = [IP6]}, - ?line HEntF6_ = HEntF6, - ?line check_elems([{HEntF6#hostent.h_aliases,[[],Aliases6]}]); - _ -> % ipv4 compatible addr - ?line {ok,HEntF4} = inet:gethostbyname(FullName6, inet), - ?line [IPF4] = HEntF4#hostent.h_addr_list, - ?line {ok,IPF46_2} = - inet_parse:ipv6_address("::ffff:"++inet_parse:ntoa(IPF4)), - ?line HEntF6_ = HEntF6#hostent{h_addrtype = inet6, - h_length = 16, - h_addr_list = [IPF46_2]}, - ?line HEntF6_ = HEntF6, - ?line check_elems([{HEntF6#hostent.h_name,[Name6,FullName6]}]) - end, - - ?line {DName6, _DFullName6, _DIPStr6, _DIP6, _} = - ct:get_config(test_dummy_ipv6_host), - ?line {error,nxdomain} = inet:gethostbyname(DName6, inet6), - ok; - {_,_} -> + case inet:gethostbyname(Name, inet6) of + {ok,HEnt} -> + {ok,_} = inet:gethostbyname(IPStr, inet6), + {ok,HEnt} = inet:gethostbyname(list_to_atom(Name), inet6), + case HEnt#hostent.h_addr_list of + [IP] -> % IPv6 address + #hostent{h_addrtype = inet6, + h_length = 16} = HEnt, + check_elems( + [{HEnt#hostent.h_name,[Name,FullName]}, + {HEnt#hostent.h_aliases,[[],Aliases]}]); + [IP46] -> % IPv4 compatible address + {ok,HEnt4} = inet:gethostbyname(Name, inet), + #hostent{h_addrtype = inet, + h_length = 4, + h_addr_list = [IP4]} = HEnt4, + {ok,IP46} = + inet_parse:ipv6_address( + "::ffff:" ++ inet_parse:ntoa(IP4)), + check_elems( + [{HEnt#hostent.h_name,[Name,FullName]}]) + end, + + {ok,HEntF} = inet:gethostbyname(FullName, inet6), + case HEntF#hostent.h_addr_list of + [IP] -> % IPv6 address + #hostent{h_name = FullName, + h_addrtype = inet6, + h_length = 16} = HEntF, + check_elems( + [{HEnt#hostent.h_aliases,[[],Aliases]}]); + [IP46F] -> % IPv4 compatible address + {ok,HEnt4F} = inet:gethostbyname(FullName, inet), + #hostent{h_addrtype = inet, + h_length = 4, + h_addr_list = [IP4F]} = HEnt4F, + {ok,IP46F} = + inet_parse:ipv6_address( + "::ffff:" ++ inet_parse:ntoa(IP4F)), + check_elems( + [{HEntF#hostent.h_name,[Name,FullName]}]) + end; + _ -> {skip, "IPv6 is not supported on this host"} end. @@ -290,47 +284,35 @@ t_getaddr(Config) when is_list(Config) -> ?line {error,nxdomain} = inet:getaddr(DName, inet), ?line {error,nxdomain} = inet:getaddr(DFullName, inet), ?line {ok,DIP} = inet:getaddr(DIPStr, inet), - ?line {ok,DIP} = inet:getaddr(DIP, inet). + ?line {ok,DIP} = inet:getaddr(DIP, inet), + ok. t_getaddr_v6() -> required(v4) ++ required(v6). t_getaddr_v6(doc) -> "Test the inet:getaddr/2 function."; t_getaddr_v6(suite) -> []; t_getaddr_v6(Config) when is_list(Config) -> - ?line {Name,FullName,IPStr,_IP,_,IP_46_Str,IP46} = - ct:get_config(test_host_ipv4_only), - case {inet:getaddr(IP_46_Str, inet6),inet:getaddr(Name, inet6)} of - {{ok,IP46},{ok,V4Addr}} when V4Addr /= {0,0,0,0,0,0,0,1} -> - %% Since we suceeded in parsing an IPv6 address string and - %% look up the name, this computer fully supports IPv6. - ?line {ok,IP46} = inet:getaddr(IP46, inet6), - ?line {ok,IP46} = inet:getaddr(Name, inet6), - ?line {ok,IP46} = inet:getaddr(FullName, inet6), - ?line {ok,IP46} = inet:getaddr(IPStr, inet6), -%% ?line IP4toIP6 = inet:getaddr(IPStr, inet6), -%% ?line case IP4toIP6 of -%% {ok,IP46} -> -%% ?line ok; -%% {error,nxdomain} -> -%% ?line false = -%% lists:member(native, -%% inet_db:res_option(lookup)) -%% end, - ?line {Name6, FullName6, IPStr6, IP6, _} = - ct:get_config(test_host_ipv6_only), - ?line {ok,_} = inet:getaddr(list_to_atom(Name6), inet6), - ?line {ok,_} = inet:getaddr(Name6, inet6), - ?line {ok,_} = inet:getaddr(FullName6, inet6), - ?line {ok,IP6} = inet:getaddr(IP6, inet6), - ?line {ok,IP6} = inet:getaddr(IPStr6, inet6), - - ?line {DName6, DFullName6, DIPStr6, DIP6, _} = + {Name,FullName,IPStr,IP,_} = + ct:get_config(test_host_ipv6_only), + + case inet:getaddr(Name, inet6) of + {ok,Addr} -> + IP = Addr, + {ok,IP} = inet:getaddr(toupper(Name), inet6), + {ok,IP} = inet:getaddr(list_to_atom(Name), inet6), + {ok,IP} = inet:getaddr(list_to_atom(toupper(Name)), inet6), + {ok,IP} = inet:getaddr(FullName, inet6), + {ok,IP} = inet:getaddr(toupper(FullName), inet6), + {ok,IP} = inet:getaddr(IP, inet6), + {ok,IP} = inet:getaddr(IPStr, inet6), + %% + {DName,DFullName,DIPStr,DIP,_} = ct:get_config(test_dummy_ipv6_host), - ?line {error,nxdomain} = inet:getaddr(DName6, inet6), - ?line {error,nxdomain} = inet:getaddr(DFullName6, inet6), - ?line {ok,DIP6} = inet:getaddr(DIPStr6, inet6), - ?line {ok,DIP6} = inet:getaddr(DIP6, inet6), + {error,nxdomain} = inet:getaddr(DName, inet6), + {error,nxdomain} = inet:getaddr(DFullName, inet6), + {ok,DIP} = inet:getaddr(DIPStr, inet6), + {ok,DIP} = inet:getaddr(DIP, inet6), ok; - {_,_} -> + _ -> {skip, "IPv6 is not supported on this host"} end. @@ -608,8 +590,12 @@ t_parse_address(Func, [String|L]) -> t_parse_address(Func, L). parse_strict_address(Config) when is_list(Config) -> - {ok, Ipv4} = inet:parse_strict_address("127.0.0.1"), - {ok, Ipv6} = inet:parse_strict_address("c11:0c22:5c33:c440:55c0:c66c:77:0088"). + {ok, {127,0,0,1}} = + inet:parse_strict_address("127.0.0.1"), + {ok, {3089,3106,23603,50240,21952,50796,119,136}} = + inet:parse_strict_address("c11:0c22:5c33:c440:55c0:c66c:77:0088"), + {ok, {3089,3106,23603,50240,0,0,119,136}} = + inet:parse_strict_address("c11:0c22:5c33:c440::077:0088"). t_gethostnative(suite) ->[]; t_gethostnative(doc) ->[]; @@ -1102,3 +1088,14 @@ ip_member({127,_,_,_}, [{127,_,_,_}|_]) -> true; ip_member(K, [K|_]) -> true; ip_member(K, [_|T]) -> ip_member(K, T); ip_member(_, []) -> false. + +%% Case fold to upper case according to RFC 4343 +%% +toupper([C|Cs]) when is_integer(C) -> + if $a =< C, C =< $z -> + [(C - $a + $A)|toupper(Cs)]; + true -> + [C|toupper(Cs)] + end; +toupper([]) -> + []. diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl index f3ba28e4f9..1bc93e3138 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2011. All Rights Reserved. +%% Copyright Ericsson AB 2009-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -282,6 +282,7 @@ basic(doc) -> basic(Config) when is_list(Config) -> NS = ns(Config), Name = "ns.otptest", + NameC = caseflip(Name), IP = {127,0,0,254}, %% %% nslookup @@ -292,6 +293,17 @@ basic(Config) when is_list(Config) -> Bin1 = inet_dns:encode(Msg1), %%io:format("Bin1 = ~w~n", [Bin1]), {ok,Msg1} = inet_dns:decode(Bin1), + %% Now with scrambled case + {ok,Msg1b} = inet_res:nslookup(NameC, in, a, [NS]), + io:format("~p~n", [Msg1b]), + [RR1b] = inet_dns:msg(Msg1b, anlist), + IP = inet_dns:rr(RR1b, data), + Bin1b = inet_dns:encode(Msg1b), + %%io:format("Bin1b = ~w~n", [Bin1b]), + {ok,Msg1b} = inet_dns:decode(Bin1b), + true = + (tolower(inet_dns:rr(RR1, domain)) + =:= tolower(inet_dns:rr(RR1b, domain))), %% %% resolve {ok,Msg2} = inet_res:resolve(Name, in, a, [{nameservers,[NS]},verbose]), @@ -301,15 +313,29 @@ basic(Config) when is_list(Config) -> Bin2 = inet_dns:encode(Msg2), %%io:format("Bin2 = ~w~n", [Bin2]), {ok,Msg2} = inet_dns:decode(Bin2), + %% Now with scrambled case + {ok,Msg2b} = inet_res:resolve(NameC, in, a, [{nameservers,[NS]},verbose]), + io:format("~p~n", [Msg2b]), + [RR2b] = inet_dns:msg(Msg2b, anlist), + IP = inet_dns:rr(RR2b, data), + Bin2b = inet_dns:encode(Msg2b), + %%io:format("Bin2b = ~w~n", [Bin2b]), + {ok,Msg2b} = inet_dns:decode(Bin2b), + true = + (tolower(inet_dns:rr(RR2, domain)) + =:= tolower(inet_dns:rr(RR2b, domain))), %% %% lookup [IP] = inet_res:lookup(Name, in, a, [{nameservers,[NS]},verbose]), + [IP] = inet_res:lookup(NameC, in, a, [{nameservers,[NS]},verbose]), %% %% gethostbyname {ok,#hostent{h_addr_list=[IP]}} = inet_res:gethostbyname(Name), + {ok,#hostent{h_addr_list=[IP]}} = inet_res:gethostbyname(NameC), %% %% getbyname {ok,#hostent{h_addr_list=[IP]}} = inet_res:getbyname(Name, a), + {ok,#hostent{h_addr_list=[IP]}} = inet_res:getbyname(NameC, a), ok. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -317,63 +343,115 @@ basic(Config) when is_list(Config) -> resolve(doc) -> ["Lookup different records using resolve/2..4"]; resolve(Config) when is_list(Config) -> + Class = in, NS = ns(Config), Domain = "otptest", RDomain4 = "0.0.127.in-addr.arpa", RDomain6 = "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa", Name = "resolve."++Domain, - L = [{in,a,Name,[{127,0,0,28}],undefined}, - {in,aaaa,Name,[{0,0,0,0,0,0,32512,28}],undefined}, - {in,cname,"cname."++Name,[Name],undefined}, - {in,a,"cname."++Name,[Name,{127,0,0,28}],undefined}, - {in,ns,"ns."++Name,[],[Name]}, - {in,soa,Domain,[],[{"ns.otptest","lsa.otptest",1,60,10,300,30}]}, + L = [{a,Name,[{a,{127,0,0,28}}],undefined}, + {aaaa,Name,[{aaaa,{0,0,0,0,0,0,32512,28}}],undefined}, + {cname,"cname."++Name,[{cname,Name}],undefined}, + {a,"cname."++Name,[{cname,Name},{a,{127,0,0,28}}],undefined}, + {ns,"ns."++Name,[],[{ns,Name}]}, + {soa,Domain,[],[{soa,{"ns.otptest","lsa.otptest",1,60,10,300,30}}]}, %% WKS: protocol TCP (6), services (bits) TELNET (23) and SMTP (25) - {in,wks,"wks."++Name,[{{127,0,0,28},6,<<0,0,1,64>>}],undefined}, - {in,ptr,"28."++RDomain4,[Name],undefined}, - {in,ptr,"c.1.0.0.0.0.f.7."++RDomain6,[Name],undefined}, - {in,hinfo,Name,[{"BEAM","Erlang/OTP"}],undefined}, - {in,mx,RDomain4,[{10,"mx."++Domain}],undefined}, - {in,srv,"_srv._tcp."++Name,[{10,3,4711,Name}],undefined}, - {in,naptr,"naptr."++Name, - [{10,5,"s","http","","_srv._tcp."++Name}],undefined}, - {in,txt,"txt."++Name, - [["Hej ","du ","glade "],["ta ","en ","spade!"]],undefined}, - {in,mb,"mb."++Name,["mx."++Name],undefined}, - {in,mg,"mg."++Name,["lsa."++Domain],undefined}, - {in,mr,"mr."++Name,["lsa."++Domain],undefined}, - {in,minfo,"minfo."++Name, - [{"minfo-owner."++Name,"minfo-bounce."++Name}],undefined}, - {in,any,"cname."++Name,[Name],undefined}, - {in,any,Name,[{127,0,0,28}, - {0,0,0,0,0,0,32512,28}, - {"BEAM","Erlang/OTP"}],undefined} + {wks,"wks."++Name,[{wks,{{127,0,0,28},6,<<0,0,1,64>>}}],undefined}, + {ptr,"28."++RDomain4,[{ptr,Name}],undefined}, + {ptr,"c.1.0.0.0.0.f.7."++RDomain6,[{ptr,Name}],undefined}, + {hinfo,Name,[{hinfo,{"BEAM","Erlang/OTP"}}],undefined}, + {mx,RDomain4,[{mx,{10,"mx."++Domain}}],undefined}, + {srv,"_srv._tcp."++Name,[{srv,{10,3,4711,Name}}],undefined}, + {naptr,"naptr."++Name, + [{naptr,{10,5,"s","http","","_srv._tcp."++Name}}], + undefined}, + {txt,"txt."++Name, + [{txt,["Hej ","du ","glade "]},{txt,["ta ","en ","spade!"]}], + undefined}, + {mb,"mb."++Name,[{mb,"mx."++Name}],undefined}, + {mg,"mg."++Name,[{mg,"Lsa."++Domain}],undefined}, + {mr,"mr."++Name,[{mr,"LSA."++Domain}],undefined}, + {minfo,"minfo."++Name, + [{minfo,{"minfo-OWNER."++Name,"MinfoBounce."++Name}}], + undefined}, + {any,"cname."++Name,[{cname,Name}],undefined}, + {any,Name, + [{a,{127,0,0,28}}, + {aaaa,{0,0,0,0,0,0,32512,28}}, + {hinfo,{"BEAM","Erlang/OTP"}}], + undefined} ], - resolve([{edns,false},{nameservers,[NS]}], L), - resolve([{edns,0},{nameservers,[NS]}], L). - -resolve(_Opts, []) -> ok; -resolve(Opts, [{Class,Type,Name,Answers,Authority}=Q|Qs]) -> + resolve(Class, [{edns,0},{nameservers,[NS]}], L), + resolve(Class, [{edns,false},{nameservers,[NS]}], L), + %% Again, to see ensure the cache does not mess things up + resolve(Class, [{edns,0},{nameservers,[NS]}], L), + resolve(Class, [{edns,false},{nameservers,[NS]}], L). + +resolve(_Class, _Opts, []) -> + ok; +resolve(Class, Opts, [{Type,Nm,Answers,Authority}=Q|Qs]) -> io:format("Query: ~p~nOptions: ~p~n", [Q,Opts]), - {ok,Msg} = inet_res:resolve(Name, Class, Type, Opts), + {Name,NameC} = + case erlang:phash2(Q) band 4 of + 0 -> + {Nm,caseflip(Nm)}; + _ -> + {caseflip(Nm),Nm} + end, AnList = if Answers =/= undefined -> - lists:sort(Answers); + normalize_answers(Answers); true -> undefined end, NsList = if Authority =/= undefined -> - lists:sort(Authority); + normalize_answers(Authority); true -> undefined end, - case {lists:sort - ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, anlist)]), - lists:sort - ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, nslist)])} of + {ok,Msg} = inet_res:resolve(Name, Class, Type, Opts), + check_msg(Class, Type, Msg, AnList, NsList), + {ok,MsgC} = inet_res:resolve(NameC, Class, Type, Opts), + check_msg(Class, Type, MsgC, AnList, NsList), + resolve(Class, Opts, Qs). + + + +normalize_answers(AnList) -> + lists:sort([normalize_answer(Answer) || Answer <- AnList]). + +normalize_answer({soa,{NS,HM,Ser,Ref,Ret,Exp,Min}}) -> + {tolower(NS),tolower_email(HM),Ser,Ref,Ret,Exp,Min}; +normalize_answer({mx,{Prio,DN}}) -> + {Prio,tolower(DN)}; +normalize_answer({srv,{Prio,Weight,Port,DN}}) -> + {Prio,Weight,Port,tolower(DN)}; +normalize_answer({naptr,{Order,Pref,Flags,Service,RE,Repl}}) -> + {Order,Pref,Flags,Service,RE,tolower(Repl)}; +normalize_answer({minfo,{RespM,ErrM}}) -> + {tolower_email(RespM),tolower_email(ErrM)}; +normalize_answer({T,MN}) when T =:= mg; T =:= mr -> + tolower_email(MN); +normalize_answer({T,DN}) when T =:= cname; T =:= ns; T =:= ptr; T =:= mb -> + tolower(DN); +normalize_answer(Answer) -> + Answer. + +check_msg(Class, Type, Msg, AnList, NsList) -> + io:format("check_msg Type: ~p, Msg: ~p~n.", [Type,Msg]), + case {normalize_answers( + [begin + Class = inet_dns:rr(RR, class), + {inet_dns:rr(RR, type),inet_dns:rr(RR, data)} + end || RR <- inet_dns:msg(Msg, anlist)]), + normalize_answers( + [begin + Class = inet_dns:rr(RR, class), + {inet_dns:rr(RR, type),inet_dns:rr(RR, data)} + end || RR <- inet_dns:msg(Msg, nslist)])} of {AnList,NsList} -> ok; {NsList,AnList} when Type =:= ns -> @@ -389,7 +467,7 @@ resolve(Opts, [{Class,Type,Name,Answers,Authority}=Q|Qs]) -> end, Buf = inet_dns:encode(Msg), {ok,Msg} = inet_dns:decode(Buf), - resolve(Opts, Qs). + ok. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -497,6 +575,7 @@ files_monitor(Config) when is_list(Config) -> do_files_monitor(Config) -> Dir = ?config(priv_dir, Config), {ok,Hostname} = inet:gethostname(), + io:format("Hostname = ~p.~n", [Hostname]), FQDN = case inet_db:res_option(domain) of "" -> @@ -504,11 +583,13 @@ do_files_monitor(Config) -> _ -> Hostname++"."++inet_db:res_option(domain) end, + io:format("FQDN = ~p.~n", [FQDN]), HostsFile = filename:join(Dir, "files_monitor_hosts"), ResolvConf = filename:join(Dir, "files_monitor_resolv.conf"), ok = inet_db:res_option(resolv_conf, ResolvConf), ok = inet_db:res_option(hosts_file, HostsFile), [] = inet_db:res_option(search), + %% The inet function will use its final fallback to find this host {ok,#hostent{h_name = Hostname, h_addrtype = inet, h_length = 4, @@ -521,6 +602,7 @@ do_files_monitor(Config) -> {error,nxdomain} = inet_res:gethostbyname(FQDN), {ok,{127,0,0,10}} = inet:getaddr("mx.otptest", inet), {ok,{0,0,0,0,0,0,32512,28}} = inet:getaddr("resolve.otptest", inet6), + %% The inet function will use its final fallback to find this host {ok,#hostent{h_name = Hostname, h_addrtype = inet6, h_length = 16, @@ -603,3 +685,41 @@ ipv4_to_ipv6() -> inet_SUITE:ipv4_to_ipv6(). ipv4_to_ipv6(Config) -> inet_SUITE:ipv4_to_ipv6(Config). host_and_addr() -> inet_SUITE:host_and_addr(). host_and_addr(Config) -> inet_SUITE:host_and_addr(Config). + + + +%% Case flip helper + +caseflip([C|Cs]) when is_integer(C), $a =< C, C =< $z -> + [(C - $a + $A)|caseflip_skip(Cs)]; +caseflip([C|Cs]) when is_integer(C), $A =< C, C =< $Z -> + [(C - $A + $a)|caseflip_skip(Cs)]; +caseflip([C|Cs]) -> + [C|caseflip(Cs)]; +caseflip([]) -> + []. + +caseflip_skip([C|Cs]) when is_integer(C), $a =< C, C =< $z -> + [C|caseflip(Cs)]; +caseflip_skip([C|Cs]) when is_integer(C), $A =< C, C =< $Z -> + [C|caseflip(Cs)]; +caseflip_skip([C|Cs]) -> + [C|caseflip_skip(Cs)]; +caseflip_skip([]) -> + []. + +tolower_email([$.|Cs]) -> + [$.|tolower(Cs)]; +tolower_email([C|Cs]) -> + [C|tolower_email(Cs)]. + +%% Case fold to lower case according to RFC 4343 +%% +tolower([C|Cs]) when is_integer(C) -> + if $A =< C, C =< $Z -> + [(C - $A + $a)|tolower(Cs)]; + true -> + [C|tolower(Cs)] + end; +tolower([]) -> + []. diff --git a/lib/kernel/test/inet_res_SUITE_data/otptest/named_inc.conf b/lib/kernel/test/inet_res_SUITE_data/otptest/named_inc.conf index 0b01b25204..2d68f6e59c 100644 --- a/lib/kernel/test/inet_res_SUITE_data/otptest/named_inc.conf +++ b/lib/kernel/test/inet_res_SUITE_data/otptest/named_inc.conf @@ -2,11 +2,11 @@ zone "." in { type master; file "root.zone"; }; -zone "0.0.127.in-addr.arpa" in { +zone "0.0.127.in-addr.arpa." in { type master; file "0.0.127.in-addr.arpa.zone"; }; -zone "0.0.0.0.f.7.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" in { +zone "0.0.0.0.f.7.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa." in { type master; file "0.0.0.0.f.7.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.zone"; -};
\ No newline at end of file +}; diff --git a/lib/kernel/test/inet_res_SUITE_data/otptest/root.zone b/lib/kernel/test/inet_res_SUITE_data/otptest/root.zone index 11cba18d45..5a56eac95c 100644 --- a/lib/kernel/test/inet_res_SUITE_data/otptest/root.zone +++ b/lib/kernel/test/inet_res_SUITE_data/otptest/root.zone @@ -43,8 +43,8 @@ naptr.resolve.otptest IN NAPTR 10 5 "S" "HTTP" "" _srv._tcp.resolve.otptest txt.resolve.otptest IN TXT "Hej " "du " "glade " txt.resolve.otptest IN TXT "ta " "en " "spade!" mb.resolve.otptest IN MB mx.resolve.otptest -mg.resolve.otptest IN MG lsa.otptest -mr.resolve.otptest IN MR lsa.otptest -minfo.resolve.otptest IN MINFO minfo-owner.resolve.otptest minfo-bounce.resolve.otptest +mg.resolve.otptest IN MG Lsa.otptest +mr.resolve.otptest IN MR LSA.otptest +minfo.resolve.otptest IN MINFO minfo-OWNER.resolve.otptest MinfoBounce.resolve.otptest ns.otptest IN A 127.0.0.254 diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl index 415c69d508..8f78dc55e8 100644 --- a/lib/mnesia/src/mnesia_subscr.erl +++ b/lib/mnesia/src/mnesia_subscr.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -447,8 +447,12 @@ deactivate(ClientPid, What, Var, SubscrTab) -> {'EXIT', _} -> unlink(ClientPid) end, - del_subscr(Var, What, ClientPid), - {ok, node()}. + try + del_subscr(Var, What, ClientPid), + {ok, node()} + catch _:_ -> + {error, badarg} + end. del_subscr(subscribers, _What, Pid) -> mnesia_lib:del(subscribers, Pid); diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl index 0df245b75d..db23a39943 100644 --- a/lib/mnesia/test/mnesia_evil_coverage_test.erl +++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl @@ -1985,6 +1985,10 @@ subscribe_standard(Config) when is_list(Config)-> ?match({atomic, ok}, mnesia:create_table(Tab, Def)), %% Check system events + ?match({error, {badarg, foo}}, mnesia:unsubscribe(foo)), + ?match({error, badarg}, mnesia:unsubscribe({table, foo})), + ?match(_, mnesia:unsubscribe(activity)), + ?match({ok, N1}, mnesia:subscribe(system)), ?match({ok, N1}, mnesia:subscribe(activity)), diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl index 3273bc4d40..d57f976d1f 100644 --- a/lib/mnesia/test/mnesia_isolation_test.erl +++ b/lib/mnesia/test/mnesia_isolation_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -613,11 +613,11 @@ unbound2(Config) when is_list(Config) -> ?match_receive({B, continuing}), %% B should now be in lock queue. - A ! continue, - ?match_receive({A, {atomic, ok}}), - ?match_receive({B, {atomic, [{ul,{key,{17,42}},val}]}}), + A ! continue, + ?match_multi_receive([{A, {atomic, ok}}, + {B, {atomic, [{ul,{key,{17,42}},val}]}}]), ok. - + receiver() -> receive {_Pid, begin_trans} -> diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk index 7d6c5484a7..e3acea0258 100644 --- a/lib/os_mon/vsn.mk +++ b/lib/os_mon/vsn.mk @@ -1 +1 @@ -OS_MON_VSN = 2.2.11 +OS_MON_VSN = 2.2.12 diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 10c95a39ac..bce6d58682 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -43,7 +43,8 @@ <title>public_key</title> <list type="bulleted"> - <item>public_key requires the crypto application.</item> + <item>public_key requires the crypto and asn1 applications, the latter since R16 (hopefully the runtime dependency on asn1 will + be removed again in the future).</item> <item>Supports <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url> - Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile </item> @@ -154,8 +155,8 @@ <funcs> <func> - <name> compute_key(OthersKey, MyKey)-></name> - <name> compute_key(OthersKey, MyKey, Params)-></name> + <name>compute_key(OthersKey, MyKey)-></name> + <name>compute_key(OthersKey, MyKey, Params)-></name> <fsummary> Compute shared secret</fsummary> <type> <v>OthersKey = #'ECPoint'{} | binary(), MyKey = #'ECPrivateKey'{} | binary()</v> @@ -176,7 +177,8 @@ <v>Options = public_crypt_options()</v> </type> <desc> - <p>Public key decryption using the private key.</p> + <p>Public key decryption using the private key. See also <seealso + marker="crypto:crypto#private_decrypt/4">crypto:private_decrypt/4</seealso></p> </desc> </func> @@ -190,7 +192,8 @@ <v>Options = public_crypt_options()</v> </type> <desc> - <p> Public key decryption using the public key.</p> + <p> Public key decryption using the public key. See also <seealso + marker="crypto:crypto#public_decrypt/4">crypto:public_decrypt/4</seealso></p> </desc> </func> @@ -304,7 +307,9 @@ <v>Key = rsa_private_key()</v> </type> <desc> - <p> Public key encryption using the private key.</p> + <p> Public key encryption using the private key. + See also <seealso + marker="crypto:crypto#private_encrypt/4">crypto:private_encrypt/4</seealso></p> </desc> </func> @@ -316,7 +321,8 @@ <v>Key = rsa_public_key()</v> </type> <desc> - <p> Public key encryption using the public key.</p> + <p> Public key encryption using the public key. See also <seealso + marker="crypto:crypto#public_encrypt/4">crypto:public_encrypt/4</seealso></p> </desc> </func> diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src index 9f0677606d..736a778a4b 100644 --- a/lib/public_key/src/public_key.app.src +++ b/lib/public_key/src/public_key.app.src @@ -11,7 +11,7 @@ 'OTP-PUB-KEY', 'PKCS-FRAME' ]}, - {applications, [crypto, kernel, stdlib]}, + {applications, [asn1, crypto, kernel, stdlib]}, {registered, []}, {env, []} ] diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 3eea6f6ec4..cdbfe6e07c 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -252,8 +252,7 @@ decrypt_private(CipherText, Key) -> decrypt_private(CipherText, Key, []). decrypt_private(CipherText, - #'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D} = Key, + #'RSAPrivateKey'{} = Key, Options) when is_binary(CipherText), is_list(Options) -> diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl index c490493e13..9180fa968b 100644 --- a/lib/public_key/test/pkits_SUITE.erl +++ b/lib/public_key/test/pkits_SUITE.erl @@ -113,12 +113,14 @@ groups() -> init_per_suite(Config) -> try crypto:start() of ok -> + application:start(asn1), crypto_support_check(Config) catch _:_ -> {skip, "Crypto did not start"} end. end_per_suite(_Config) -> + application:stop(asn1), application:stop(crypto). %%-------------------------------------------------------------------- diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 5a64140c67..f2596e3d85 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -58,12 +58,14 @@ groups() -> init_per_suite(Config) -> try crypto:start() of ok -> + application:start(asn1), Config catch _:_ -> {skip, "Crypto did not start"} end. end_per_suite(_Config) -> + application:stop(asn1), application:stop(crypto). %%------------------------------------------------------------------- diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index bd20a5546b..b820f24d2a 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 0.18 +PUBLIC_KEY_VSN = 0.19 diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 3a7aa79d16..7d5478c3f6 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -41,11 +41,13 @@ %%-------------------------------------------------------------------- start() -> application:start(crypto), + application:start(asn1), application:start(public_key), application:start(ssh). start(Type) -> application:start(crypto, Type), + application:start(asn1), application:start(public_key, Type), application:start(ssh, Type). diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 75c17b14db..0c1e47311d 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -214,8 +214,8 @@ prf(Socket, Secret, Label, Seed, WantedLength) -> clear_pem_cache() -> tls:clear_pem_cache(). -format_error(Reason) when is_list(Reason) -> - tls:format_error(Reason). +format_error(Error) -> + tls:format_error(Error). random_bytes(N) -> tls:random_bytes(N). diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 898b421dff..ec5d793d65 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -1190,14 +1190,16 @@ hash_size(md5) -> 16; hash_size(sha) -> 20; -hash_size(sha224) -> - 28; +%% Uncomment when adding cipher suite that needs it +%% hash_size(sha224) -> +%% 28; hash_size(sha256) -> 32; hash_size(sha384) -> - 48; -hash_size(sha512) -> - 64. + 48. +%% Uncomment when adding cipher suite that needs it +%% hash_size(sha512) -> +%% 64. %% RFC 5246: 6.2.3.2. CBC Block Cipher %% diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 1b06e351cf..7af4a68461 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -104,7 +104,6 @@ connection_init(Trustedcerts, Role) -> %%-------------------------------------------------------------------- cache_pem_file(File, DbHandle) -> MD5 = crypto:hash(md5, File), - MD5 = crypto:md5(File), case ssl_pkix_db:lookup_cached_pem(DbHandle, MD5) of [{Content,_}] -> {ok, Content}; diff --git a/lib/ssl/src/tls.erl b/lib/ssl/src/tls.erl index fcecf8196f..bb02695c12 100644 --- a/lib/ssl/src/tls.erl +++ b/lib/ssl/src/tls.erl @@ -94,11 +94,13 @@ %%-------------------------------------------------------------------- start() -> application:start(crypto), + application:start(asn1), application:start(public_key), application:start(ssl). start(Type) -> application:start(crypto, Type), + application:start(asn1), application:start(public_key, Type), application:start(ssl, Type). diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 6a0461e805..246fecf34a 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -673,8 +673,7 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey}, #state{negotiated_version = Version, - diffie_hellman_params = #'DHParameter'{prime = P, - base = G} = Params, + diffie_hellman_params = #'DHParameter'{} = Params, diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) -> case dh_master_secret(Params, ClientPublicDhKey, ServerDhPrivateKey, State0) of #state{} = State1 -> diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl index fea75736f7..51fd2e1dc9 100644 --- a/lib/ssl/src/tls_handshake.erl +++ b/lib/ssl/src/tls_handshake.erl @@ -866,7 +866,7 @@ handle_ecc_point_fmt_extension(undefined) -> handle_ecc_point_fmt_extension(_) -> #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}. -handle_ecc_curves_extension(Version, undefined) -> +handle_ecc_curves_extension(_Version, undefined) -> undefined; handle_ecc_curves_extension(Version, _) -> #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}. diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index fed590f0ef..b5cf6d1212 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -190,8 +190,7 @@ init_per_suite(Config0) -> catch crypto:stop(), try crypto:start() of ok -> - application:start(public_key), - + ssl:start(), %% make rsa certs using oppenssl Result = (catch make_certs:all(?config(data_dir, Config0), diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl index 4e095dc184..f76c55f670 100644 --- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -80,8 +80,7 @@ init_per_suite(Config0) -> catch crypto:stop(), try crypto:start() of ok -> - application:start(public_key), - application:start(ssl), + ssl:start(), %% make rsa certs using oppenssl Result = (catch make_certs:all(?config(data_dir, Config0), diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl index 7b271c4d5d..30c0a67a36 100644 --- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl @@ -69,7 +69,6 @@ init_per_suite(Config) -> catch crypto:stop(), try crypto:start() of ok -> - application:start(public_key), ssl:start(), Result = (catch make_certs:all(?config(data_dir, Config), diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 5a374e234d..36f7af784d 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -139,7 +139,7 @@ init_per_suite(Config) -> catch crypto:stop(), try crypto:start() of ok -> - application:start(public_key), + ssl:start(), Result = (catch make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config))), diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl index 5f5166391f..f95eae51b7 100644 --- a/lib/ssl/test/ssl_payload_SUITE.erl +++ b/lib/ssl/test/ssl_payload_SUITE.erl @@ -71,7 +71,6 @@ init_per_suite(Config) -> catch crypto:stop(), try crypto:start() of ok -> - application:start(public_key), ssl:start(), make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config)), ssl_test_lib:cert_options(Config) diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index 6cc6c4bdb2..c31f6c2d7d 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -56,9 +56,7 @@ init_per_suite(Config0) -> catch crypto:stop(), try crypto:start() of ok -> - application:start(public_key), ssl:start(), - %% make rsa certs using oppenssl Result = (catch make_certs:all(?config(data_dir, Config0), diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 0564b37f1c..019ed58b1b 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -99,7 +99,6 @@ init_per_suite(Config0) -> catch crypto:stop(), try crypto:start() of ok -> - application:start(public_key), ssl:start(), Result = (catch make_certs:all(?config(data_dir, Config0), diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml index 7737c34469..678b1964a6 100644 --- a/system/doc/reference_manual/introduction.xml +++ b/system/doc/reference_manual/introduction.xml @@ -75,7 +75,7 @@ <title>Reserved Words</title> <p>The following are reserved words in Erlang:</p> <p>after and andalso band begin bnot bor bsl bsr bxor case catch - cond div end fun if let not of or orelse query receive rem try + cond div end fun if let not of or orelse receive rem try when xor</p> </section> |