From 338f85ca7721fac16394ccabd561ddb5ccaacb36 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 3 Nov 2015 11:08:57 +0100 Subject: [PATCH 01/14] IO: Handle fd values too big for select() If the number of sockets is too much for select(), we should at least handle it with proper error messages and reject new sockets instead of breaking the event loop. Thanks to Alexander V. Chernikov for the patch. --- sysdep/unix/io.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 0724667d..726f1e49 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1309,6 +1309,16 @@ sk_passive_connected(sock *s, int type) return 0; } + if (fd >= FD_SETSIZE) + { + /* FIXME: Call err_hook instead ? */ + log(L_ERR "SOCK: Incoming connection from %I%J (port %d) %s", + t->daddr, ipa_is_link_local(t->daddr) ? t->iface : NULL, + t->dport, "rejected due to FD_SETSIZE limit"); + close(fd); + return 1; + } + sock *t = sk_new(s->pool); t->type = type; t->fd = fd; @@ -1404,6 +1414,9 @@ sk_open(sock *s) if (fd < 0) ERR("socket"); + if (fd >= FD_SETSIZE) + ERR2("FD_SETSIZE limit reached"); + s->af = af; s->fd = fd; From 3aed0a6ff7b2b811a535202fd787281d2ac33409 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 3 Nov 2015 11:27:27 +0100 Subject: [PATCH 02/14] IO: Fix the previous bugfix I should check it after making some trivial changes. The original patch from Alexander has it right. --- sysdep/unix/io.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 726f1e49..b636e799 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1309,16 +1309,6 @@ sk_passive_connected(sock *s, int type) return 0; } - if (fd >= FD_SETSIZE) - { - /* FIXME: Call err_hook instead ? */ - log(L_ERR "SOCK: Incoming connection from %I%J (port %d) %s", - t->daddr, ipa_is_link_local(t->daddr) ? t->iface : NULL, - t->dport, "rejected due to FD_SETSIZE limit"); - close(fd); - return 1; - } - sock *t = sk_new(s->pool); t->type = type; t->fd = fd; @@ -1338,6 +1328,18 @@ sk_passive_connected(sock *s, int type) log(L_WARN "SOCK: Cannot get remote IP address for TCP<"); } + if (fd >= FD_SETSIZE) + { + /* FIXME: Call err_hook instead ? */ + log(L_ERR "SOCK: Incoming connection from %I%J (port %d) %s", + t->daddr, ipa_is_link_local(t->daddr) ? t->iface : NULL, + t->dport, "rejected due to FD_SETSIZE limit"); + close(fd); + t->fd = -1; + rfree(t); + return 1; + } + if (sk_setup(t) < 0) { /* FIXME: Call err_hook instead ? */ From 9b9a7143c43d01f0459d40363d56e9c7690c596f Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 9 Nov 2015 00:42:02 +0100 Subject: [PATCH 03/14] Conf: Fixes bug in symbol lookup during reconfiguration Symbol lookup by cf_find_symbol() not only did the lookup but also added new void symbols allocated from cfg_mem linpool, which gets broken when lookups are done outside of config parsing, which may lead to crashes during reconfiguration. The patch separates lookup-only cf_find_symbol() and config-modifying cf_get_symbol(), while the later is called only during parsing. Also new_config and cfg_mem global variables are NULLed outside of parsing. --- conf/cf-lex.l | 64 ++++++++++++++++++++++++++++++--------------- conf/conf.c | 65 +++++++++++++++++++++++++++------------------- conf/conf.h | 4 ++- nest/proto.c | 2 +- nest/rt-roa.c | 2 +- nest/rt-table.c | 4 +-- sysdep/unix/main.c | 2 +- 7 files changed, 90 insertions(+), 53 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 61e04075..5a2a4d6b 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -70,7 +70,7 @@ struct sym_scope { static struct sym_scope *conf_this_scope; static int cf_hash(byte *c); -static struct symbol *cf_find_sym(byte *c, unsigned int h0); +static inline struct symbol * cf_get_sym(byte *c, uint h0); linpool *cfg_mem; @@ -194,7 +194,7 @@ else: { } k=k->next; } - cf_lval.s = cf_find_sym(yytext, h); + cf_lval.s = cf_get_sym(yytext, h); return SYM; } @@ -426,8 +426,9 @@ check_eof(void) } static struct symbol * -cf_new_sym(byte *c, unsigned int h) +cf_new_sym(byte *c, uint h0) { + uint h = h0 & (SYM_HASH_SIZE-1); struct symbol *s, **ht; int l; @@ -449,56 +450,77 @@ cf_new_sym(byte *c, unsigned int h) } static struct symbol * -cf_find_sym(byte *c, unsigned int h0) +cf_find_sym(struct config *cfg, byte *c, uint h0) { - unsigned int h = h0 & (SYM_HASH_SIZE-1); + uint h = h0 & (SYM_HASH_SIZE-1); struct symbol *s, **ht; - if (ht = new_config->sym_hash) + if (ht = cfg->sym_hash) { for(s = ht[h]; s; s=s->next) if (!strcmp(s->name, c) && s->scope->active) return s; } - if (new_config->sym_fallback) + if (ht = cfg->sym_fallback) { /* We know only top-level scope is active */ - for(s = new_config->sym_fallback[h]; s; s=s->next) + for(s = ht[h]; s; s=s->next) if (!strcmp(s->name, c) && s->scope->active) return s; } - return cf_new_sym(c, h); + + return NULL; +} + +static inline struct symbol * +cf_get_sym(byte *c, uint h0) +{ + return cf_find_sym(new_config, c, h0) ?: cf_new_sym(c, h0); } /** * cf_find_symbol - find a symbol by name + * @cfg: specificed config * @c: symbol name * - * This functions searches the symbol table for a symbol of given - * name. First it examines the current scope, then the second recent - * one and so on until it either finds the symbol and returns a pointer - * to its &symbol structure or reaches the end of the scope chain - * and returns %NULL to signify no match. + * This functions searches the symbol table in the config @cfg for a symbol of + * given name. First it examines the current scope, then the second recent one + * and so on until it either finds the symbol and returns a pointer to its + * &symbol structure or reaches the end of the scope chain and returns %NULL to + * signify no match. */ struct symbol * -cf_find_symbol(byte *c) +cf_find_symbol(struct config *cfg, byte *c) { - return cf_find_sym(c, cf_hash(c)); + return cf_find_sym(cfg, c, cf_hash(c)); +} + +/** + * cf_get_symbol - get a symbol by name + * @c: symbol name + * + * This functions searches the symbol table of the currently parsed config + * (@new_config) for a symbol of given name. It returns either the already + * existing symbol or a newly allocated undefined (%SYM_VOID) symbol if no + * existing symbol is found. + */ +struct symbol * +cf_get_symbol(byte *c) +{ + return cf_get_sym(c, cf_hash(c)); } struct symbol * cf_default_name(char *template, int *counter) { - char buf[32]; + char buf[SYM_MAX_LEN]; struct symbol *s; char *perc = strchr(template, '%'); for(;;) { bsprintf(buf, template, ++(*counter)); - s = cf_find_sym(buf, cf_hash(buf)); - if (!s) - break; + s = cf_get_sym(buf, cf_hash(buf)); if (s->class == SYM_VOID) return s; if (!perc) @@ -529,7 +551,7 @@ cf_define_symbol(struct symbol *sym, int type, void *def) { if (sym->scope == conf_this_scope) cf_error("Symbol already defined"); - sym = cf_new_sym(sym->name, cf_hash(sym->name) & (SYM_HASH_SIZE-1)); + sym = cf_new_sym(sym->name, cf_hash(sym->name)); } sym->class = type; sym->def = def; diff --git a/conf/conf.c b/conf/conf.c index a907402d..825a8e9f 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -20,19 +20,19 @@ * * There can exist up to four different configurations at one time: an active * one (pointed to by @config), configuration we are just switching from - * (@old_config), one queued for the next reconfiguration (@future_config; - * if there is one and the user wants to reconfigure once again, we just - * free the previous queued config and replace it with the new one) and - * finally a config being parsed (@new_config). The stored @old_config - * is also used for undo reconfiguration, which works in a similar way. - * Reconfiguration could also have timeout (using @config_timer) and undo - * is automatically called if the new configuration is not confirmed later. + * (@old_config), one queued for the next reconfiguration (@future_config; if + * there is one and the user wants to reconfigure once again, we just free the + * previous queued config and replace it with the new one) and finally a config + * being parsed (@new_config). The stored @old_config is also used for undo + * reconfiguration, which works in a similar way. Reconfiguration could also + * have timeout (using @config_timer) and undo is automatically called if the + * new configuration is not confirmed later. The new config (@new_config) and + * associated linear pool (@cfg_mem) is non-NULL only during parsing. * - * Loading of new configuration is very simple: just call config_alloc() - * to get a new &config structure, then use config_parse() to parse a - * configuration file and fill all fields of the structure - * and finally ask the config manager to switch to the new - * config by calling config_commit(). + * Loading of new configuration is very simple: just call config_alloc() to get + * a new &config structure, then use config_parse() to parse a configuration + * file and fill all fields of the structure and finally ask the config manager + * to switch to the new config by calling config_commit(). * * CLI commands are parsed in a very similar way -- there is also a stripped-down * &config structure associated with them and they are lex-ed and parsed by the @@ -91,10 +91,15 @@ config_alloc(byte *name) linpool *l = lp_new(p, 4080); struct config *c = lp_allocz(l, sizeof(struct config)); + /* Duplication of name string in local linear pool */ + uint nlen = strlen(name) + 1; + char *ndup = lp_allocu(l, nlen); + memcpy(ndup, name, nlen); + c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */ c->pool = p; - cfg_mem = c->mem = l; - c->file_name = cfg_strdup(name); + c->mem = l; + c->file_name = ndup; c->load_time = now; c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600}; c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0}; @@ -119,11 +124,13 @@ config_alloc(byte *name) int config_parse(struct config *c) { + int done = 0; DBG("Parsing configuration file `%s'\n", c->file_name); new_config = c; cfg_mem = c->mem; if (setjmp(conf_jmpbuf)) - return 0; + goto cleanup; + cf_lex_init(0, c); sysdep_preconfig(c); protos_preconfig(c); @@ -137,7 +144,12 @@ config_parse(struct config *c) if (!c->router_id) cf_error("Router ID must be configured manually on IPv6 routers"); #endif - return 1; + done = 1; + +cleanup: + new_config = NULL; + cfg_mem = NULL; + return done; } /** @@ -150,14 +162,22 @@ config_parse(struct config *c) int cli_parse(struct config *c) { - new_config = c; + int done = 0; c->sym_fallback = config->sym_hash; + new_config = c; cfg_mem = c->mem; if (setjmp(conf_jmpbuf)) - return 0; + goto cleanup; + cf_lex_init(1, c); cf_parse(); - return 1; + done = 1; + +cleanup: + c->sym_fallback = NULL; + new_config = NULL; + cfg_mem = NULL; + return done; } /** @@ -237,10 +257,6 @@ config_do_commit(struct config *c, int type) if (old_config && !config->shutdown) log(L_INFO "Reconfiguring"); - /* This should not be necessary, but it seems there are some - functions that access new_config instead of config */ - new_config = config; - if (old_config) old_config->obstacle_count++; @@ -254,9 +270,6 @@ config_do_commit(struct config *c, int type) DBG("protos_commit\n"); protos_commit(c, old_config, force_restart, type); - /* Just to be sure nobody uses that now */ - new_config = NULL; - int obs = 0; if (old_config) obs = --old_config->obstacle_count; diff --git a/conf/conf.h b/conf/conf.h index 515efbb3..89a2c5b7 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -147,7 +147,9 @@ int cf_lex(void); void cf_lex_init(int is_cli, struct config *c); void cf_lex_unwind(void); -struct symbol *cf_find_symbol(byte *c); +struct symbol *cf_find_symbol(struct config *cfg, byte *c); + +struct symbol *cf_get_symbol(byte *c); struct symbol *cf_default_name(char *template, int *counter); struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def); void cf_push_scope(struct symbol *); diff --git a/nest/proto.c b/nest/proto.c index 6531083c..d04da333 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -521,7 +521,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty WALK_LIST(oc, old->protos) { p = oc->proto; - sym = cf_find_symbol(oc->name); + sym = cf_find_symbol(new, oc->name); if (sym && sym->class == SYM_PROTO && !new->shutdown) { /* Found match, let's check if we can smoothly switch to new configuration */ diff --git a/nest/rt-roa.c b/nest/rt-roa.c index aa453f16..0fd89667 100644 --- a/nest/rt-roa.c +++ b/nest/rt-roa.c @@ -311,7 +311,7 @@ roa_commit(struct config *new, struct config *old) if (old) WALK_LIST(t, roa_table_list) { - struct symbol *sym = cf_find_symbol(t->name); + struct symbol *sym = cf_find_symbol(new, t->name); if (sym && sym->class == SYM_ROA) { /* Found old table in new config */ diff --git a/nest/rt-table.c b/nest/rt-table.c index 9e2c4e0d..2ddff12e 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1663,7 +1663,7 @@ rt_prune_loop(void) void rt_preconfig(struct config *c) { - struct symbol *s = cf_find_symbol("master"); + struct symbol *s = cf_get_symbol("master"); init_list(&c->tables); c->master_rtc = rt_new_table(s); @@ -1903,7 +1903,7 @@ rt_commit(struct config *new, struct config *old) rtable *ot = o->table; if (!ot->deleted) { - struct symbol *sym = cf_find_symbol(o->name); + struct symbol *sym = cf_find_symbol(new, o->name); if (sym && sym->class == SYM_TABLE && !new->shutdown) { DBG("\t%s: same\n", o->name); diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index e31471da..24d34f60 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -96,7 +96,7 @@ drop_gid(gid_t gid) static inline void add_num_const(char *name, int val) { - struct symbol *s = cf_find_symbol(name); + struct symbol *s = cf_get_symbol(name); s->class = SYM_CONSTANT | T_INT; s->def = cfg_allocz(sizeof(struct f_val)); SYM_TYPE(s) = T_INT; From 86b4e17001fe4cca6dde7ff523346121c0ae68fe Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 9 Nov 2015 01:01:12 +0100 Subject: [PATCH 04/14] Nest: Fixes bug in missing cleanup during table removal When a table is removed during reconfiguration, a reference was not cleared in the old configuration, which breaks undo. --- nest/rt-table.c | 1 + 1 file changed, 1 insertion(+) diff --git a/nest/rt-table.c b/nest/rt-table.c index 2ddff12e..10ce400a 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1868,6 +1868,7 @@ rt_unlock_table(rtable *r) { struct config *conf = r->deleted; DBG("Deleting routing table %s\n", r->name); + r->config->table = NULL; if (r->hostcache) rt_free_hostcache(r); rem_node(&r->n); From 9ddbfbddf87462bbf50437bdc1d44499a5c223e7 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Tue, 3 Nov 2015 14:42:41 +0100 Subject: [PATCH 05/14] Netlink: Allow more than 256 routing tables. Since 2.6.19, the netlink API defines RTA_TABLE routing attribute to allow 32-bit routing table IDs. Using this attribute to index routing tables at Linux, instead of 8-bit rtm_table field. --- sysdep/bsd/krt-sock.c | 7 +++- sysdep/bsd/krt-sys.h | 1 + sysdep/linux/krt-sys.h | 8 ++-- sysdep/linux/netlink.Y | 2 - sysdep/linux/netlink.c | 90 ++++++++++++++++++++++++++++-------------- sysdep/unix/krt.c | 11 +++++- sysdep/unix/krt.h | 3 +- 7 files changed, 82 insertions(+), 40 deletions(-) diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 064bae18..29203d1b 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -970,13 +970,15 @@ krt_sock_close_shared(void) } } -void +int krt_sys_start(struct krt_proto *p) { krt_table_map[KRT_CF->sys.table_id] = p; krt_sock_open_shared(); p->sys.sk = krt_sock; + + return 1; } void @@ -992,10 +994,11 @@ krt_sys_shutdown(struct krt_proto *p) #else -void +int krt_sys_start(struct krt_proto *p) { p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id); + return 1; } void diff --git a/sysdep/bsd/krt-sys.h b/sysdep/bsd/krt-sys.h index 2c6e35c5..a63f8caf 100644 --- a/sysdep/bsd/krt-sys.h +++ b/sysdep/bsd/krt-sys.h @@ -42,6 +42,7 @@ struct krt_state { }; +static inline void krt_sys_io_init(void) { } static inline void krt_sys_init(struct krt_proto *p UNUSED) { } static inline int krt_sys_get_attr(eattr *a UNUSED, byte *buf UNUSED, int buflen UNUSED) { } diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h index e32e4fe1..7fd5f139 100644 --- a/sysdep/linux/krt-sys.h +++ b/sysdep/linux/krt-sys.h @@ -84,18 +84,18 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; } #define EA_KRT_FEATURE_ALLFRAG EA_KRT_FEATURES | EA_BIT(0x3) - -#define NL_NUM_TABLES 256 - struct krt_params { - int table_id; /* Kernel table ID we sync with */ + u32 table_id; /* Kernel table ID we sync with */ }; struct krt_state { + struct krt_proto *hash_next; }; static inline void krt_sys_init(struct krt_proto *p UNUSED) { } +static inline void krt_sys_preconfig(struct config *c UNUSED) { } +static inline void krt_sys_postconfig(struct krt_config *x UNUSED) { } #endif diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index f8137e23..e9c225a2 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -23,8 +23,6 @@ CF_ADDTO(kern_proto, kern_proto kern_sys_item ';') kern_sys_item: KERNEL TABLE expr { - if ($3 <= 0 || $3 >= NL_NUM_TABLES) - cf_error("Kernel routing table number out of range"); THIS_KRT->sys.table_id = $3; } ; diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 674d338b..db998926 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -25,6 +25,7 @@ #include "lib/krt.h" #include "lib/socket.h" #include "lib/string.h" +#include "lib/hash.h" #include "conf/conf.h" #include @@ -32,6 +33,7 @@ #include #include + #ifndef MSG_TRUNC /* Hack: Several versions of glibc miss this one :( */ #define MSG_TRUNC 0x20 #endif @@ -40,6 +42,11 @@ #define IFF_LOWER_UP 0x10000 #endif +#ifndef RTA_TABLE +#define RTA_TABLE 15 +#endif + + /* * Synchronous Netlink interface */ @@ -650,7 +657,23 @@ kif_do_scan(struct kif_proto *p UNUSED) * Routes */ -static struct krt_proto *nl_table_map[NL_NUM_TABLES]; +static inline u32 +krt_table_id(struct krt_proto *p) +{ + return KRT_CF->sys.table_id; +} + +static HASH(struct krt_proto) nl_table_map; + +#define RTH_FN(k) u32_hash(k) +#define RTH_EQ(k1,k2) k1 == k2 +#define RTH_KEY(p) krt_table_id(p) +#define RTH_NEXT(p) p->sys.hash_next + +#define RTH_REHASH rth_rehash +#define RTH_PARAMS /8, *2, 2, 2, 6, 20 + +HASH_DEFINE_REHASH_FN(RTH, struct krt_proto) int krt_capable(rte *e) @@ -708,12 +731,15 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new) r.r.rtm_family = BIRD_AF; r.r.rtm_dst_len = net->n.pxlen; - r.r.rtm_tos = 0; - r.r.rtm_table = KRT_CF->sys.table_id; r.r.rtm_protocol = RTPROT_BIRD; r.r.rtm_scope = RT_SCOPE_UNIVERSE; nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix); + if (krt_table_id(p) < 256) + r.r.rtm_table = krt_table_id(p); + else + nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p)); + /* For route delete, we do not specify route attributes */ if (!new) return nl_exchange(&r.h); @@ -809,11 +835,12 @@ nl_parse_route(struct nlmsghdr *h, int scan) { struct krt_proto *p; struct rtmsg *i; - struct rtattr *a[RTA_CACHEINFO+1]; + struct rtattr *a[RTA_TABLE+1]; int new = h->nlmsg_type == RTM_NEWROUTE; ip_addr dst = IPA_NONE; u32 oif = ~0; + u32 table; int src; if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a))) @@ -825,6 +852,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) || #endif (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) || + (a[RTA_TABLE] && RTA_PAYLOAD(a[RTA_TABLE]) != 4) || (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)) || (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) || (a[RTA_PREFSRC] && RTA_PAYLOAD(a[RTA_PREFSRC]) != sizeof(ip_addr)) || @@ -843,10 +871,15 @@ nl_parse_route(struct nlmsghdr *h, int scan) if (a[RTA_OIF]) oif = rta_get_u32(a[RTA_OIF]); - p = nl_table_map[i->rtm_table]; /* Do we know this table? */ - DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p ? p->p.name : "(none)"); + if (a[RTA_TABLE]) + table = rta_get_u32(a[RTA_TABLE]); + else + table = i->rtm_table; + + p = HASH_FIND(nl_table_map, RTH, table); /* Do we know this table? */ + DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, table, i->rtm_protocol, p ? p->p.name : "(none)"); if (!p) - SKIP("unknown table %d\n", i->rtm_table); + SKIP("unknown table %d\n", table); #ifdef IPV6 @@ -1186,25 +1219,41 @@ nl_open_async(void) bug("Netlink: sk_open failed"); } + /* * Interface to the UNIX krt module */ -static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8]; - void +krt_sys_io_init(void) +{ + HASH_INIT(nl_table_map, krt_pool, 6); +} + +int krt_sys_start(struct krt_proto *p) { - nl_table_map[KRT_CF->sys.table_id] = p; + struct krt_proto *old = HASH_FIND(nl_table_map, RTH, krt_table_id(p)); + + if (old) + { + log(L_ERR "%s: Kernel table %u already registered by %s", + p->p.name, krt_table_id(p), old->p.name); + return 0; + } + + HASH_INSERT2(nl_table_map, RTH, krt_pool, p); nl_open(); nl_open_async(); + + return 1; } void -krt_sys_shutdown(struct krt_proto *p UNUSED) +krt_sys_shutdown(struct krt_proto *p) { - nl_table_map[KRT_CF->sys.table_id] = NULL; + HASH_REMOVE2(nl_table_map, RTH, krt_pool, p); } int @@ -1213,23 +1262,6 @@ krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt return n->sys.table_id == o->sys.table_id; } - -void -krt_sys_preconfig(struct config *c UNUSED) -{ - bzero(&nl_cf_table, sizeof(nl_cf_table)); -} - -void -krt_sys_postconfig(struct krt_config *x) -{ - int id = x->sys.table_id; - - if (nl_cf_table[id/8] & (1 << (id%8))) - cf_error("Multiple kernel syncers defined for table #%d", id); - nl_cf_table[id/8] |= (1 << (id%8)); -} - void krt_sys_init_config(struct krt_config *cf) { diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 2eab5cb2..49bf9519 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -77,6 +77,7 @@ krt_io_init(void) krt_pool = rp_new(&root_pool, "Kernel Syncer"); krt_filter_lp = lp_new(krt_pool, 4080); init_list(&krt_proto_list); + krt_sys_io_init(); } /* @@ -1126,7 +1127,11 @@ krt_start(struct proto *P) krt_learn_init(p); #endif - krt_sys_start(p); + if (!krt_sys_start(p)) + { + rem_node(&p->krt_node); + return PS_START; + } krt_scan_timer_start(p); @@ -1150,8 +1155,10 @@ krt_shutdown(struct proto *P) p->ready = 0; p->initialized = 0; - krt_sys_shutdown(p); + if (p->p.proto_state == PS_START) + return PS_DOWN; + krt_sys_shutdown(p); rem_node(&p->krt_node); return PS_DOWN; diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 9d5d4e8c..aea20102 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -119,8 +119,9 @@ struct proto_config * krt_init_config(int class); /* krt sysdep */ +void krt_sys_io_init(void); void krt_sys_init(struct krt_proto *); -void krt_sys_start(struct krt_proto *); +int krt_sys_start(struct krt_proto *); void krt_sys_shutdown(struct krt_proto *); int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o); From fce764f90e8331d1adb6a85ec00136dfeae1a398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Mon, 9 Nov 2015 09:14:26 +0100 Subject: [PATCH 06/14] Fix compiling with --enable-debug option --- sysdep/linux/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index db998926..f2f60100 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -246,7 +246,7 @@ nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize) return 1; } -static inline ip4_addr rta_get_u32(struct rtattr *a) +static inline u32 rta_get_u32(struct rtattr *a) { return *(u32 *) RTA_DATA(a); } static inline ip4_addr rta_get_ip4(struct rtattr *a) From 75ff08022ea58fe3efa96639f080ce375e997675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Fri, 13 Nov 2015 16:10:33 +0100 Subject: [PATCH 07/14] Add get_u64() and put_u64() into lib/unaligned.h --- lib/unaligned.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/unaligned.h b/lib/unaligned.h index af655204..a2dbae4f 100644 --- a/lib/unaligned.h +++ b/lib/unaligned.h @@ -35,6 +35,15 @@ get_u32(void *p) return ntohl(x); } +static inline u64 +get_u64(const void *p) +{ + u32 xh, xl; + memcpy(&xh, p, 4); + memcpy(&xl, p+4, 4); + return (((u64) ntohl(xh)) << 32) | ntohl(xl); +} + static inline void put_u16(void *p, u16 x) { @@ -49,4 +58,14 @@ put_u32(void *p, u32 x) memcpy(p, &x, 4); } +static inline void +put_u64(void *p, u64 x) +{ + u32 xh, xl; + xh = htonl(x >> 32); + xl = htonl((u32) x); + memcpy(p, &xh, 4); + memcpy(p+4, &xl, 4); +} + #endif From 5d0c36f1da83b2a2a07e043247410948d90c600e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Fri, 13 Nov 2015 16:11:51 +0100 Subject: [PATCH 08/14] Add SHA1 and SHA1-HMAC crypto hash --- lib/Modules | 2 + lib/sha1.c | 342 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/sha1.h | 86 +++++++++++++ 3 files changed, 430 insertions(+) create mode 100644 lib/sha1.c create mode 100644 lib/sha1.h diff --git a/lib/Modules b/lib/Modules index 7254df2d..a227f9a1 100644 --- a/lib/Modules +++ b/lib/Modules @@ -1,3 +1,5 @@ +sha1.c +sha1.h birdlib.h bitops.c bitops.h diff --git a/lib/sha1.c b/lib/sha1.c new file mode 100644 index 00000000..dd29b5fd --- /dev/null +++ b/lib/sha1.c @@ -0,0 +1,342 @@ +/* + * BIRD Library -- SHA-1 Hash Function (FIPS 180-1, RFC 3174) and HMAC-SHA-1 + * + * (c) 2015 CZ.NIC z.s.p.o. + * + * Based on the code from libucw-6.4 + * (c) 2008--2009 Martin Mares + * + * Based on the code from libgcrypt-1.2.3, which is + * (c) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "lib/sha1.h" +#include "lib/unaligned.h" + +void +sha1_init(struct sha1_context *hd) +{ + hd->h0 = 0x67452301; + hd->h1 = 0xefcdab89; + hd->h2 = 0x98badcfe; + hd->h3 = 0x10325476; + hd->h4 = 0xc3d2e1f0; + hd->nblocks = 0; + hd->count = 0; +} + +/* + * Transform the message X which consists of 16 32-bit-words + */ +static void +sha1_transform(struct sha1_context *hd, const byte *data) +{ + u32 a,b,c,d,e,tm; + u32 x[16]; + + /* Get values from the chaining vars. */ + a = hd->h0; + b = hd->h1; + c = hd->h2; + d = hd->h3; + e = hd->h4; + +#ifdef CPU_BIG_ENDIAN + memcpy(x, data, 64); +#else + int i; + for (i = 0; i < 16; i++) + x[i] = get_u32(data+4*i); +#endif + +#define K1 0x5A827999L +#define K2 0x6ED9EBA1L +#define K3 0x8F1BBCDCL +#define K4 0xCA62C1D6L +#define F1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) +#define F2(x,y,z) ( x ^ y ^ z ) +#define F3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) +#define F4(x,y,z) ( x ^ y ^ z ) + +#define M(i) (tm = x[i&0x0f] ^ x[(i-14)&0x0f] ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f], (x[i&0x0f] = ROL(tm, 1))) + +/* Bitwise rotation of an unsigned int to the left **/ +#define ROL(x, bits) (((x) << (bits)) | ((uint)(x) >> (sizeof(uint)*8 - (bits)))) + + #define R(a, b, c, d, e, f, k, m) \ + do \ + { \ + e += ROL(a, 5) + f(b, c, d) + k + m; \ + b = ROL( b, 30 ); \ + } while(0) + + R( a, b, c, d, e, F1, K1, x[ 0] ); + R( e, a, b, c, d, F1, K1, x[ 1] ); + R( d, e, a, b, c, F1, K1, x[ 2] ); + R( c, d, e, a, b, F1, K1, x[ 3] ); + R( b, c, d, e, a, F1, K1, x[ 4] ); + R( a, b, c, d, e, F1, K1, x[ 5] ); + R( e, a, b, c, d, F1, K1, x[ 6] ); + R( d, e, a, b, c, F1, K1, x[ 7] ); + R( c, d, e, a, b, F1, K1, x[ 8] ); + R( b, c, d, e, a, F1, K1, x[ 9] ); + R( a, b, c, d, e, F1, K1, x[10] ); + R( e, a, b, c, d, F1, K1, x[11] ); + R( d, e, a, b, c, F1, K1, x[12] ); + R( c, d, e, a, b, F1, K1, x[13] ); + R( b, c, d, e, a, F1, K1, x[14] ); + R( a, b, c, d, e, F1, K1, x[15] ); + R( e, a, b, c, d, F1, K1, M(16) ); + R( d, e, a, b, c, F1, K1, M(17) ); + R( c, d, e, a, b, F1, K1, M(18) ); + R( b, c, d, e, a, F1, K1, M(19) ); + R( a, b, c, d, e, F2, K2, M(20) ); + R( e, a, b, c, d, F2, K2, M(21) ); + R( d, e, a, b, c, F2, K2, M(22) ); + R( c, d, e, a, b, F2, K2, M(23) ); + R( b, c, d, e, a, F2, K2, M(24) ); + R( a, b, c, d, e, F2, K2, M(25) ); + R( e, a, b, c, d, F2, K2, M(26) ); + R( d, e, a, b, c, F2, K2, M(27) ); + R( c, d, e, a, b, F2, K2, M(28) ); + R( b, c, d, e, a, F2, K2, M(29) ); + R( a, b, c, d, e, F2, K2, M(30) ); + R( e, a, b, c, d, F2, K2, M(31) ); + R( d, e, a, b, c, F2, K2, M(32) ); + R( c, d, e, a, b, F2, K2, M(33) ); + R( b, c, d, e, a, F2, K2, M(34) ); + R( a, b, c, d, e, F2, K2, M(35) ); + R( e, a, b, c, d, F2, K2, M(36) ); + R( d, e, a, b, c, F2, K2, M(37) ); + R( c, d, e, a, b, F2, K2, M(38) ); + R( b, c, d, e, a, F2, K2, M(39) ); + R( a, b, c, d, e, F3, K3, M(40) ); + R( e, a, b, c, d, F3, K3, M(41) ); + R( d, e, a, b, c, F3, K3, M(42) ); + R( c, d, e, a, b, F3, K3, M(43) ); + R( b, c, d, e, a, F3, K3, M(44) ); + R( a, b, c, d, e, F3, K3, M(45) ); + R( e, a, b, c, d, F3, K3, M(46) ); + R( d, e, a, b, c, F3, K3, M(47) ); + R( c, d, e, a, b, F3, K3, M(48) ); + R( b, c, d, e, a, F3, K3, M(49) ); + R( a, b, c, d, e, F3, K3, M(50) ); + R( e, a, b, c, d, F3, K3, M(51) ); + R( d, e, a, b, c, F3, K3, M(52) ); + R( c, d, e, a, b, F3, K3, M(53) ); + R( b, c, d, e, a, F3, K3, M(54) ); + R( a, b, c, d, e, F3, K3, M(55) ); + R( e, a, b, c, d, F3, K3, M(56) ); + R( d, e, a, b, c, F3, K3, M(57) ); + R( c, d, e, a, b, F3, K3, M(58) ); + R( b, c, d, e, a, F3, K3, M(59) ); + R( a, b, c, d, e, F4, K4, M(60) ); + R( e, a, b, c, d, F4, K4, M(61) ); + R( d, e, a, b, c, F4, K4, M(62) ); + R( c, d, e, a, b, F4, K4, M(63) ); + R( b, c, d, e, a, F4, K4, M(64) ); + R( a, b, c, d, e, F4, K4, M(65) ); + R( e, a, b, c, d, F4, K4, M(66) ); + R( d, e, a, b, c, F4, K4, M(67) ); + R( c, d, e, a, b, F4, K4, M(68) ); + R( b, c, d, e, a, F4, K4, M(69) ); + R( a, b, c, d, e, F4, K4, M(70) ); + R( e, a, b, c, d, F4, K4, M(71) ); + R( d, e, a, b, c, F4, K4, M(72) ); + R( c, d, e, a, b, F4, K4, M(73) ); + R( b, c, d, e, a, F4, K4, M(74) ); + R( a, b, c, d, e, F4, K4, M(75) ); + R( e, a, b, c, d, F4, K4, M(76) ); + R( d, e, a, b, c, F4, K4, M(77) ); + R( c, d, e, a, b, F4, K4, M(78) ); + R( b, c, d, e, a, F4, K4, M(79) ); + + /* Update chaining vars. */ + hd->h0 += a; + hd->h1 += b; + hd->h2 += c; + hd->h3 += d; + hd->h4 += e; +} + +/* + * Update the message digest with the contents + * of INBUF with length INLEN. + */ +void +sha1_update(struct sha1_context *hd, const byte *inbuf, uint inlen) +{ + if (hd->count == 64) /* flush the buffer */ + { + sha1_transform(hd, hd->buf); + hd->count = 0; + hd->nblocks++; + } + if (!inbuf) + return; + + if (hd->count) + { + for (; inlen && hd->count < 64; inlen--) + hd->buf[hd->count++] = *inbuf++; + sha1_update( hd, NULL, 0 ); + if(!inlen) + return; + } + + while (inlen >= 64) + { + sha1_transform(hd, inbuf); + hd->count = 0; + hd->nblocks++; + inlen -= 64; + inbuf += 64; + } + for (; inlen && hd->count < 64; inlen--) + hd->buf[hd->count++] = *inbuf++; +} + +/* + * The routine final terminates the computation and + * returns the digest. + * The handle is prepared for a new cycle, but adding bytes to the + * handle will the destroy the returned buffer. + * Returns: 20 bytes representing the digest. + */ +byte * +sha1_final(struct sha1_context *hd) +{ + u32 t, msb, lsb; + u32 *p; + + sha1_update(hd, NULL, 0); /* flush */; + + t = hd->nblocks; + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = t >> 26; + /* add the count */ + t = lsb; + if ((lsb += hd->count) < t) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 29; + + if (hd->count < 56) /* enough room */ + { + hd->buf[hd->count++] = 0x80; /* pad */ + while (hd->count < 56) + hd->buf[hd->count++] = 0; /* pad */ + } + else /* need one extra block */ + { + hd->buf[hd->count++] = 0x80; /* pad character */ + while (hd->count < 64) + hd->buf[hd->count++] = 0; + sha1_update(hd, NULL, 0); /* flush */; + memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ + } + /* append the 64 bit count */ + hd->buf[56] = msb >> 24; + hd->buf[57] = msb >> 16; + hd->buf[58] = msb >> 8; + hd->buf[59] = msb ; + hd->buf[60] = lsb >> 24; + hd->buf[61] = lsb >> 16; + hd->buf[62] = lsb >> 8; + hd->buf[63] = lsb ; + sha1_transform(hd, hd->buf); + + p = (u32*) hd->buf; +#define X(a) do { put_u32(p, hd->h##a); p++; } while(0) + X(0); + X(1); + X(2); + X(3); + X(4); +#undef X + + return hd->buf; +} + + +/* + * SHA1-HMAC + */ + +/* + * Shortcut function which puts the hash value of the supplied buffer + * into outbuf which must have a size of 20 bytes. + */ +void +sha1_hash_buffer(byte *outbuf, const byte *buffer, uint length) +{ + struct sha1_context ctx; + + sha1_init(&ctx); + sha1_update(&ctx, buffer, length); + memcpy(outbuf, sha1_final(&ctx), SHA1_SIZE); +} + +void +sha1_hmac_init(struct sha1_hmac_context *ctx, const byte *key, uint keylen) +{ + byte keybuf[SHA1_BLOCK_SIZE], buf[SHA1_BLOCK_SIZE]; + + /* Hash the key if necessary */ + if (keylen <= SHA1_BLOCK_SIZE) + { + memcpy(keybuf, key, keylen); + bzero(keybuf + keylen, SHA1_BLOCK_SIZE - keylen); + } + else + { + sha1_hash_buffer(keybuf, key, keylen); + bzero(keybuf + SHA1_SIZE, SHA1_BLOCK_SIZE - SHA1_SIZE); + } + + /* Initialize the inner digest */ + sha1_init(&ctx->ictx); + int i; + for (i = 0; i < SHA1_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x36; + sha1_update(&ctx->ictx, buf, SHA1_BLOCK_SIZE); + + /* Initialize the outer digest */ + sha1_init(&ctx->octx); + for (i = 0; i < SHA1_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x5c; + sha1_update(&ctx->octx, buf, SHA1_BLOCK_SIZE); +} + +void +sha1_hmac_update(struct sha1_hmac_context *ctx, const byte *data, uint datalen) +{ + /* Just update the inner digest */ + sha1_update(&ctx->ictx, data, datalen); +} + +byte *sha1_hmac_final(struct sha1_hmac_context *ctx) +{ + /* Finish the inner digest */ + byte *isha = sha1_final(&ctx->ictx); + + /* Finish the outer digest */ + sha1_update(&ctx->octx, isha, SHA1_SIZE); + return sha1_final(&ctx->octx); +} + +void +sha1_hmac(byte *outbuf, const byte *key, uint keylen, const byte *data, uint datalen) +{ + struct sha1_hmac_context hd; + sha1_hmac_init(&hd, key, keylen); + sha1_hmac_update(&hd, data, datalen); + byte *osha = sha1_hmac_final(&hd); + memcpy(outbuf, osha, SHA1_SIZE); +} diff --git a/lib/sha1.h b/lib/sha1.h new file mode 100644 index 00000000..425160a0 --- /dev/null +++ b/lib/sha1.h @@ -0,0 +1,86 @@ +/* + * BIRD Library -- SHA-1 Hash Function (FIPS 180-1, RFC 3174) and HMAC-SHA-1 + * + * (c) 2015 CZ.NIC z.s.p.o. + * + * Based on the code from libucw-6.4 + * (c) 2008--2009 Martin Mares + * + * Based on the code from libgcrypt-1.2.3, which is + * (c) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_SHA1_H_ +#define _BIRD_SHA1_H_ + +#include "nest/bird.h" + +/* + * Internal SHA1 state. + * You should use it just as an opaque handle only. + */ +struct sha1_context { + u32 h0,h1,h2,h3,h4; + u32 nblocks; + byte buf[64]; + int count; +} ; + +void sha1_init(struct sha1_context *hd); /* Initialize new algorithm run in the @hd context. **/ +/* + * Push another @inlen bytes of data pointed to by @inbuf onto the + * SHA1 hash currently in @hd. You can call this any times you want on + * the same hash (and you do not need to reinitialize it by + * @sha1_init()). It has the same effect as concatenating all the data + * together and passing them at once. + */ +void sha1_update(struct sha1_context *hd, const byte *inbuf, uint inlen); +/* + * No more @sha1_update() calls will be done. This terminates the hash + * and returns a pointer to it. + * + * Note that the pointer points into data in the @hd context. If it ceases + * to exist, the pointer becomes invalid. + * + * To convert the hash to its usual hexadecimal representation, see + * <>. + */ +byte *sha1_final(struct sha1_context *hd); + +/* + * A convenience one-shot function for SHA1 hash. + * It is equivalent to this snippet of code: + * + * sha1_context hd; + * sha1_init(&hd); + * sha1_update(&hd, buffer, length); + * memcpy(outbuf, sha1_final(&hd), SHA1_SIZE); + */ +void sha1_hash_buffer(byte *outbuf, const byte *buffer, uint length); + +/* + * SHA1 HMAC message authentication. If you provide @key and @data, + * the result will be stored in @outbuf. + */ +void sha1_hmac(byte *outbuf, const byte *key, uint keylen, const byte *data, uint datalen); + +/* + * The HMAC also exists in a stream version in a way analogous to the + * plain SHA1. Pass this as a context. + */ +struct sha1_hmac_context { + struct sha1_context ictx; + struct sha1_context octx; +}; + +void sha1_hmac_init(struct sha1_hmac_context *hd, const byte *key, uint keylen); /* Initialize HMAC with context @hd and the given key. See sha1_init(). */ +void sha1_hmac_update(struct sha1_hmac_context *hd, const byte *data, uint datalen); /* Hash another @datalen bytes of data. See sha1_update(). */ +byte *sha1_hmac_final(struct sha1_hmac_context *hd); /* Terminate the HMAC and return a pointer to the allocated hash. See sha1_final(). */ + +#define SHA1_SIZE 20 /* Size of the SHA1 hash in its binary representation **/ +#define SHA1_HEX_SIZE 41 /* Buffer length for a string containing SHA1 in hexadecimal format. **/ +#define SHA1_BLOCK_SIZE 64 /* SHA1 splits input to blocks of this size. **/ + +#endif /* _BIRD_SHA1_H_ */ From 4035e0e79c609bde30a2f755eec864771ea08e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Fri, 13 Nov 2015 16:13:15 +0100 Subject: [PATCH 09/14] Add SHA-224/256 and HMAC-SHA-224/256 crypto hash --- lib/Modules | 2 + lib/sha256.c | 467 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/sha256.h | 71 ++++++++ 3 files changed, 540 insertions(+) create mode 100644 lib/sha256.c create mode 100644 lib/sha256.h diff --git a/lib/Modules b/lib/Modules index a227f9a1..b3daf25d 100644 --- a/lib/Modules +++ b/lib/Modules @@ -1,3 +1,5 @@ +sha256.c +sha256.h sha1.c sha1.h birdlib.h diff --git a/lib/sha256.c b/lib/sha256.c new file mode 100644 index 00000000..2d979f90 --- /dev/null +++ b/lib/sha256.c @@ -0,0 +1,467 @@ +/* + * BIRD Library -- SHA-256 and SHA-224 Hash Functions, + * HMAC-SHA-256 and HMAC-SHA-224 Functions + * + * (c) 2015 CZ.NIC z.s.p.o. + * + * Based on the code from libgcrypt-1.6.0, which is + * (c) 2003, 2006, 2008, 2009 Free Software Foundation, Inc. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "lib/sha256.h" +#include "lib/unaligned.h" + +static uint sha256_transform(void *ctx, const byte *data, size_t nblks); + +void +sha256_init(struct sha256_context *ctx) +{ + ctx->h0 = 0x6a09e667; + ctx->h1 = 0xbb67ae85; + ctx->h2 = 0x3c6ef372; + ctx->h3 = 0xa54ff53a; + ctx->h4 = 0x510e527f; + ctx->h5 = 0x9b05688c; + ctx->h6 = 0x1f83d9ab; + ctx->h7 = 0x5be0cd19; + + ctx->nblocks = 0; + ctx->nblocks_high = 0; + ctx->count = 0; + ctx->blocksize = 64; + ctx->transform = sha256_transform; +} + +void +sha224_init(struct sha224_context *ctx) +{ + ctx->h0 = 0xc1059ed8; + ctx->h1 = 0x367cd507; + ctx->h2 = 0x3070dd17; + ctx->h3 = 0xf70e5939; + ctx->h4 = 0xffc00b31; + ctx->h5 = 0x68581511; + ctx->h6 = 0x64f98fa7; + ctx->h7 = 0xbefa4fa4; + + ctx->nblocks = 0; + ctx->nblocks_high = 0; + ctx->count = 0; + ctx->blocksize = 64; + ctx->transform = sha256_transform; +} + +/* (4.2) same as SHA-1's F1. */ +static inline u32 +f1(u32 x, u32 y, u32 z) +{ + return (z ^ (x & (y ^ z))); +} + +/* (4.3) same as SHA-1's F3 */ +static inline u32 +f3(u32 x, u32 y, u32 z) +{ + return ((x & y) | (z & (x|y))); +} + +/* Bitwise rotation of an uint to the right */ +static inline u32 ror(u32 x, int n) +{ + return ( (x >> (n&(32-1))) | (x << ((32-n)&(32-1))) ); +} + +/* (4.4) */ +static inline u32 +sum0(u32 x) +{ + return (ror(x, 2) ^ ror(x, 13) ^ ror(x, 22)); +} + +/* (4.5) */ +static inline u32 +sum1(u32 x) +{ + return (ror(x, 6) ^ ror(x, 11) ^ ror(x, 25)); +} + +/* + Transform the message X which consists of 16 32-bit-words. See FIPS + 180-2 for details. */ +#define S0(x) (ror((x), 7) ^ ror((x), 18) ^ ((x) >> 3)) /* (4.6) */ +#define S1(x) (ror((x), 17) ^ ror((x), 19) ^ ((x) >> 10)) /* (4.7) */ +#define R(a,b,c,d,e,f,g,h,k,w) \ + do \ + { \ + t1 = (h) + sum1((e)) + f1((e),(f),(g)) + (k) + (w); \ + t2 = sum0((a)) + f3((a),(b),(c)); \ + h = g; \ + g = f; \ + f = e; \ + e = d + t1; \ + d = c; \ + c = b; \ + b = a; \ + a = t1 + t2; \ + } while (0) + +/* + The SHA-256 core: Transform the message X which consists of 16 + 32-bit-words. See FIPS 180-2 for details. + */ +static uint +sha256_transform_block(struct sha256_context *ctx, const byte *data) +{ + static const u32 K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + u32 a,b,c,d,e,f,g,h,t1,t2; + u32 w[64]; + int i; + + a = ctx->h0; + b = ctx->h1; + c = ctx->h2; + d = ctx->h3; + e = ctx->h4; + f = ctx->h5; + g = ctx->h6; + h = ctx->h7; + + for (i = 0; i < 16; i++) + w[i] = get_u32(data + i * 4); + for (; i < 64; i++) + w[i] = S1(w[i-2]) + w[i-7] + S0(w[i-15]) + w[i-16]; + + for (i = 0; i < 64;) + { + t1 = h + sum1(e) + f1(e, f, g) + K[i] + w[i]; + t2 = sum0 (a) + f3(a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + sum1(d) + f1(d, e, f) + K[i+1] + w[i+1]; + t2 = sum0 (h) + f3(h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + sum1(c) + f1(c, d, e) + K[i+2] + w[i+2]; + t2 = sum0 (g) + f3(g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + sum1(b) + f1(b, c, d) + K[i+3] + w[i+3]; + t2 = sum0 (f) + f3(f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + sum1(a) + f1(a, b, c) + K[i+4] + w[i+4]; + t2 = sum0 (e) + f3(e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + sum1(h) + f1(h, a, b) + K[i+5] + w[i+5]; + t2 = sum0 (d) + f3(d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + sum1(g) + f1(g, h, a) + K[i+6] + w[i+6]; + t2 = sum0 (c) + f3(c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + sum1(f) + f1(f, g, h) + K[i+7] + w[i+7]; + t2 = sum0 (b) + f3(b, c, d); + e += t1; + a = t1 + t2; + + i += 8; + } + + ctx->h0 += a; + ctx->h1 += b; + ctx->h2 += c; + ctx->h3 += d; + ctx->h4 += e; + ctx->h5 += f; + ctx->h6 += g; + ctx->h7 += h; + + return /*burn_stack*/ 74*4+32; +} +#undef S0 +#undef S1 +#undef R + +static uint +sha256_transform(void *ctx, const byte *data, size_t nblks) +{ + struct sha256_context *hd = ctx; + uint burn; + + do + { + burn = sha256_transform_block(hd, data); + data += 64; + } + while (--nblks); + + return burn; +} + +/* Common function to write a chunk of data to the transform function + of a hash algorithm. Note that the use of the term "block" does + not imply a fixed size block. Note that we explicitly allow to use + this function after the context has been finalized; the result does + not have any meaning but writing after finalize is sometimes + helpful to mitigate timing attacks. */ +void +sha256_update(struct sha256_context *ctx, const byte *in_buf, size_t in_len) +{ + const uint blocksize = ctx->blocksize; + size_t inblocks; + + if (sizeof(ctx->buf) < blocksize) + debug("BUG: in file %s at line %d", __FILE__ , __LINE__); + + if (ctx->count == blocksize) /* Flush the buffer. */ + { + ctx->transform(ctx, ctx->buf, 1); + ctx->count = 0; + if (!++ctx->nblocks) + ctx->nblocks_high++; + } + if (!in_buf) + return; + + if (ctx->count) + { + for (; in_len && ctx->count < blocksize; in_len--) + ctx->buf[ctx->count++] = *in_buf++; + sha256_update(ctx, NULL, 0); + if (!in_len) + return; + } + + if (in_len >= blocksize) + { + inblocks = in_len / blocksize; + ctx->transform(ctx, in_buf, inblocks); + ctx->count = 0; + ctx->nblocks_high += (ctx->nblocks + inblocks < inblocks); + ctx->nblocks += inblocks; + in_len -= inblocks * blocksize; + in_buf += inblocks * blocksize; + } + for (; in_len && ctx->count < blocksize; in_len--) + ctx->buf[ctx->count++] = *in_buf++; +} + +/* + The routine finally terminates the computation and returns the + digest. The handle is prepared for a new cycle, but adding bytes + to the handle will the destroy the returned buffer. Returns: 32 + bytes with the message the digest. */ +byte* +sha256_final(struct sha256_context *ctx) +{ + u32 t, th, msb, lsb; + byte *p; + + sha256_update(ctx, NULL, 0); /* flush */; + + t = ctx->nblocks; + if (sizeof t == sizeof ctx->nblocks) + th = ctx->nblocks_high; + else + th = 0; + + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = (th << 6) | (t >> 26); + /* add the count */ + t = lsb; + if ((lsb += ctx->count) < t) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 29; + + if (ctx->count < 56) + { /* enough room */ + ctx->buf[ctx->count++] = 0x80; /* pad */ + while (ctx->count < 56) + ctx->buf[ctx->count++] = 0; /* pad */ + } + else + { /* need one extra block */ + ctx->buf[ctx->count++] = 0x80; /* pad character */ + while (ctx->count < 64) + ctx->buf[ctx->count++] = 0; + sha256_update(ctx, NULL, 0); /* flush */; + memset (ctx->buf, 0, 56 ); /* fill next block with zeroes */ + } + /* append the 64 bit count */ + put_u32(ctx->buf + 56, msb); + put_u32(ctx->buf + 60, lsb); + sha256_transform(ctx, ctx->buf, 1); + + p = ctx->buf; + +#define X(a) do { put_u32(p, ctx->h##a); p += 4; } while(0) + X(0); + X(1); + X(2); + X(3); + X(4); + X(5); + X(6); + X(7); +#undef X + + return ctx->buf; +} + + +/* + * SHA256-HMAC + */ + +static void +sha256_hash_buffer(byte *outbuf, const byte *buffer, size_t length) +{ + struct sha256_context hd_tmp; + + sha256_init(&hd_tmp); + sha256_update(&hd_tmp, buffer, length); + memcpy(outbuf, sha256_final(&hd_tmp), SHA256_SIZE); +} + +void +sha256_hmac_init(struct sha256_hmac_context *ctx, const byte *key, size_t keylen) +{ + byte keybuf[SHA256_BLOCK_SIZE], buf[SHA256_BLOCK_SIZE]; + + /* Hash the key if necessary */ + if (keylen <= SHA256_BLOCK_SIZE) + { + memcpy(keybuf, key, keylen); + bzero(keybuf + keylen, SHA256_BLOCK_SIZE - keylen); + } + else + { + sha256_hash_buffer(keybuf, key, keylen); + bzero(keybuf + SHA256_SIZE, SHA256_BLOCK_SIZE - SHA256_SIZE); + } + + /* Initialize the inner digest */ + sha256_init(&ctx->ictx); + int i; + for (i = 0; i < SHA256_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x36; + sha256_update(&ctx->ictx, buf, SHA256_BLOCK_SIZE); + + /* Initialize the outer digest */ + sha256_init(&ctx->octx); + for (i = 0; i < SHA256_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x5c; + sha256_update(&ctx->octx, buf, SHA256_BLOCK_SIZE); +} + +void sha256_hmac_update(struct sha256_hmac_context *ctx, const byte *buf, size_t buflen) +{ + /* Just update the inner digest */ + sha256_update(&ctx->ictx, buf, buflen); +} + +byte *sha256_hmac_final(struct sha256_hmac_context *ctx) +{ + /* Finish the inner digest */ + byte *isha = sha256_final(&ctx->ictx); + + /* Finish the outer digest */ + sha256_update(&ctx->octx, isha, SHA256_SIZE); + return sha256_final(&ctx->octx); +} + + +/* + * SHA224-HMAC + */ + +static void +sha224_hash_buffer(byte *outbuf, const byte *buffer, size_t length) +{ + struct sha224_context hd_tmp; + + sha224_init(&hd_tmp); + sha224_update(&hd_tmp, buffer, length); + memcpy(outbuf, sha224_final(&hd_tmp), SHA224_SIZE); +} + +void +sha224_hmac_init(struct sha224_hmac_context *ctx, const byte *key, size_t keylen) +{ + byte keybuf[SHA224_BLOCK_SIZE], buf[SHA224_BLOCK_SIZE]; + + /* Hash the key if necessary */ + if (keylen <= SHA224_BLOCK_SIZE) + { + memcpy(keybuf, key, keylen); + bzero(keybuf + keylen, SHA224_BLOCK_SIZE - keylen); + } + else + { + sha224_hash_buffer(keybuf, key, keylen); + bzero(keybuf + SHA224_SIZE, SHA224_BLOCK_SIZE - SHA224_SIZE); + } + + /* Initialize the inner digest */ + sha224_init(&ctx->ictx); + int i; + for (i = 0; i < SHA224_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x36; + sha224_update(&ctx->ictx, buf, SHA224_BLOCK_SIZE); + + /* Initialize the outer digest */ + sha224_init(&ctx->octx); + for (i = 0; i < SHA224_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x5c; + sha224_update(&ctx->octx, buf, SHA224_BLOCK_SIZE); +} + +void sha224_hmac_update(struct sha224_hmac_context *ctx, const byte *buf, size_t buflen) +{ + /* Just update the inner digest */ + sha256_update(&ctx->ictx, buf, buflen); +} + +byte *sha224_hmac_final(struct sha224_hmac_context *ctx) +{ + /* Finish the inner digest */ + byte *isha = sha224_final(&ctx->ictx); + + /* Finish the outer digest */ + sha224_update(&ctx->octx, isha, SHA224_SIZE); + return sha224_final(&ctx->octx); +} diff --git a/lib/sha256.h b/lib/sha256.h new file mode 100644 index 00000000..848d2176 --- /dev/null +++ b/lib/sha256.h @@ -0,0 +1,71 @@ +/* + * BIRD Library -- SHA-256 and SHA-224 Hash Functions, + * HMAC-SHA-256 and HMAC-SHA-224 Functions + * + * (c) 2015 CZ.NIC z.s.p.o. + * + * Based on the code from libgcrypt-1.6.0, which is + * (c) 2003, 2006, 2008, 2009 Free Software Foundation, Inc. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_SHA256_H_ +#define _BIRD_SHA256_H_ + +#include "nest/bird.h" + +#define SHA224_SIZE 28 +#define SHA224_HEX_SIZE 57 +#define SHA224_BLOCK_SIZE 64 + +#define SHA256_SIZE 32 +#define SHA256_HEX_SIZE 65 +#define SHA256_BLOCK_SIZE 64 + +struct sha256_context { + u32 h0,h1,h2,h3,h4,h5,h6,h7; + byte buf[128]; /* 128 is for SHA384 and SHA512 support, otherwise for SHA224 and SHA256 is 64 enough */ + u32 nblocks; + u32 nblocks_high; + int count; + u32 blocksize; + uint (*transform)(void *c, const byte *blks, size_t nblks); +}; +#define sha224_context sha256_context /* aliasing 'struct sha224_context' to 'struct sha256_context' */ + +void sha256_init(struct sha256_context *ctx); +void sha224_init(struct sha224_context *ctx); + +void sha256_update(struct sha256_context *ctx, const byte *in_buf, size_t in_len); +static inline void sha224_update(struct sha224_context *ctx, const byte *in_buf, size_t in_len) +{ + sha256_update(ctx, in_buf, in_len); +} + +byte* sha256_final(struct sha256_context *ctx); +static inline byte* sha224_final(struct sha224_context *ctx) +{ + return sha256_final(ctx); +} + +/* + * HMAC-SHA256, HMAC-SHA224 + */ +struct sha256_hmac_context +{ + struct sha256_context ictx; + struct sha256_context octx; +}; +#define sha224_hmac_context sha256_hmac_context /* aliasing 'struct sha224_hmac_context' to 'struct sha256_hmac_context' */ + +void sha256_hmac_init(struct sha256_hmac_context *ctx, const byte *key, size_t keylen); +void sha224_hmac_init(struct sha224_hmac_context *ctx, const byte *key, size_t keylen); + +void sha256_hmac_update(struct sha256_hmac_context *ctx, const byte *buf, size_t buflen); +void sha224_hmac_update(struct sha224_hmac_context *ctx, const byte *buf, size_t buflen); + +byte *sha256_hmac_final(struct sha256_hmac_context *ctx); +byte *sha224_hmac_final(struct sha224_hmac_context *ctx); + +#endif /* _BIRD_SHA256_H_ */ From f312a837e919c660884ceb9c50c106df1e4c0658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Fri, 13 Nov 2015 16:14:36 +0100 Subject: [PATCH 10/14] Add SHA-384/512 and HMAC-SHA-384/512 crypto hash --- lib/Modules | 2 + lib/sha512.c | 614 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/sha512.h | 73 ++++++ 3 files changed, 689 insertions(+) create mode 100644 lib/sha512.c create mode 100644 lib/sha512.h diff --git a/lib/Modules b/lib/Modules index b3daf25d..745306d9 100644 --- a/lib/Modules +++ b/lib/Modules @@ -1,5 +1,7 @@ sha256.c sha256.h +sha512.c +sha512.h sha1.c sha1.h birdlib.h diff --git a/lib/sha512.c b/lib/sha512.c new file mode 100644 index 00000000..e46e4c98 --- /dev/null +++ b/lib/sha512.c @@ -0,0 +1,614 @@ +/* + * BIRD Library -- SHA-512 and SHA-384 Hash Functions, + * HMAC-SHA-512 and HMAC-SHA-384 Functions + * + * (c) 2015 CZ.NIC z.s.p.o. + * + * Based on the code from libgcrypt-1.6.0, which is + * (c) 2003, 2006, 2008, 2009 Free Software Foundation, Inc. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "lib/sha256.h" +#include "lib/sha512.h" +#include "lib/unaligned.h" + +static uint sha512_transform(void *context, const byte *data, size_t nblks); + +void +sha512_init(struct sha512_context *ctx) +{ + struct sha512_state *hd = &ctx->state; + + hd->h0 = UINT64_C(0x6a09e667f3bcc908); + hd->h1 = UINT64_C(0xbb67ae8584caa73b); + hd->h2 = UINT64_C(0x3c6ef372fe94f82b); + hd->h3 = UINT64_C(0xa54ff53a5f1d36f1); + hd->h4 = UINT64_C(0x510e527fade682d1); + hd->h5 = UINT64_C(0x9b05688c2b3e6c1f); + hd->h6 = UINT64_C(0x1f83d9abfb41bd6b); + hd->h7 = UINT64_C(0x5be0cd19137e2179); + + ctx->bctx.nblocks = 0; + ctx->bctx.nblocks_high = 0; + ctx->bctx.count = 0; + ctx->bctx.blocksize = 128; + ctx->bctx.transform = sha512_transform; +} + +void +sha384_init(struct sha384_context *ctx) +{ + struct sha512_state *hd = &ctx->state; + + hd->h0 = UINT64_C(0xcbbb9d5dc1059ed8); + hd->h1 = UINT64_C(0x629a292a367cd507); + hd->h2 = UINT64_C(0x9159015a3070dd17); + hd->h3 = UINT64_C(0x152fecd8f70e5939); + hd->h4 = UINT64_C(0x67332667ffc00b31); + hd->h5 = UINT64_C(0x8eb44a8768581511); + hd->h6 = UINT64_C(0xdb0c2e0d64f98fa7); + hd->h7 = UINT64_C(0x47b5481dbefa4fa4); + + ctx->bctx.nblocks = 0; + ctx->bctx.nblocks_high = 0; + ctx->bctx.count = 0; + ctx->bctx.blocksize = 128; + ctx->bctx.transform = sha512_transform; +} + +void sha512_update(struct sha512_context *ctx, const byte *in_buf, size_t in_len) +{ + sha256_update(&ctx->bctx, in_buf, in_len); +} + +static inline u64 +ROTR(u64 x, u64 n) +{ + return ((x >> n) | (x << (64 - n))); +} + +static inline u64 +Ch(u64 x, u64 y, u64 z) +{ + return ((x & y) ^ ( ~x & z)); +} + +static inline u64 +Maj(u64 x, u64 y, u64 z) +{ + return ((x & y) ^ (x & z) ^ (y & z)); +} + +static inline u64 +Sum0(u64 x) +{ + return (ROTR (x, 28) ^ ROTR (x, 34) ^ ROTR (x, 39)); +} + +static inline u64 +Sum1 (u64 x) +{ + return (ROTR (x, 14) ^ ROTR (x, 18) ^ ROTR (x, 41)); +} + +static const u64 k[] = +{ + UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), + UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc), + UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), + UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118), + UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), + UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2), + UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), + UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694), + UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), + UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65), + UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), + UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5), + UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), + UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4), + UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), + UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70), + UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), + UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df), + UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), + UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b), + UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), + UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30), + UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), + UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8), + UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), + UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8), + UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), + UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3), + UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), + UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec), + UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), + UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b), + UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), + UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178), + UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), + UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b), + UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), + UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c), + UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), + UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817) +}; + +/* + * Transform the message W which consists of 16 64-bit-words + */ +static uint +sha512_transform_block(struct sha512_state *hd, const byte *data) +{ + u64 a, b, c, d, e, f, g, h; + u64 w[16]; + int t; + + /* get values from the chaining vars */ + a = hd->h0; + b = hd->h1; + c = hd->h2; + d = hd->h3; + e = hd->h4; + f = hd->h5; + g = hd->h6; + h = hd->h7; + + for ( t = 0; t < 16; t++ ) + w[t] = get_u64(data + t * 8); + +#define S0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) +#define S1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) + + for (t = 0; t < 80 - 16; ) + { + u64 t1, t2; + + /* Performance on a AMD Athlon(tm) Dual Core Processor 4050e + with gcc 4.3.3 using gcry_md_hash_buffer of each 10000 bytes + initialized to 0,1,2,3...255,0,... and 1000 iterations: + + Not unrolled with macros: 440ms + Unrolled with macros: 350ms + Unrolled with inline: 330ms + */ +#if 0 /* Not unrolled. */ + t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[t%16]; + w[t%16] += S1 (w[(t - 2)%16]) + w[(t - 7)%16] + S0 (w[(t - 15)%16]); + t2 = Sum0 (a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; +#else /* Unrolled to interweave the chain variables. */ + t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[0]; + w[0] += S1 (w[14]) + w[9] + S0 (w[1]); + t2 = Sum0 (a) + Maj(a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+1] + w[1]; + w[1] += S1 (w[15]) + w[10] + S0 (w[2]); + t2 = Sum0 (h) + Maj(h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+2] + w[2]; + w[2] += S1 (w[0]) + w[11] + S0 (w[3]); + t2 = Sum0 (g) + Maj(g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+3] + w[3]; + w[3] += S1 (w[1]) + w[12] + S0 (w[4]); + t2 = Sum0 (f) + Maj(f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+4] + w[4]; + w[4] += S1 (w[2]) + w[13] + S0 (w[5]); + t2 = Sum0 (e) + Maj(e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+5] + w[5]; + w[5] += S1 (w[3]) + w[14] + S0 (w[6]); + t2 = Sum0 (d) + Maj(d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+6] + w[6]; + w[6] += S1 (w[4]) + w[15] + S0 (w[7]); + t2 = Sum0 (c) + Maj(c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+7] + w[7]; + w[7] += S1 (w[5]) + w[0] + S0 (w[8]); + t2 = Sum0 (b) + Maj(b, c, d); + e += t1; + a = t1 + t2; + + t1 = h + Sum1 (e) + Ch(e, f, g) + k[t+8] + w[8]; + w[8] += S1 (w[6]) + w[1] + S0 (w[9]); + t2 = Sum0 (a) + Maj(a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+9] + w[9]; + w[9] += S1 (w[7]) + w[2] + S0 (w[10]); + t2 = Sum0 (h) + Maj(h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+10] + w[10]; + w[10] += S1 (w[8]) + w[3] + S0 (w[11]); + t2 = Sum0 (g) + Maj(g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+11] + w[11]; + w[11] += S1 (w[9]) + w[4] + S0 (w[12]); + t2 = Sum0 (f) + Maj(f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+12] + w[12]; + w[12] += S1 (w[10]) + w[5] + S0 (w[13]); + t2 = Sum0 (e) + Maj(e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+13] + w[13]; + w[13] += S1 (w[11]) + w[6] + S0 (w[14]); + t2 = Sum0 (d) + Maj(d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+14] + w[14]; + w[14] += S1 (w[12]) + w[7] + S0 (w[15]); + t2 = Sum0 (c) + Maj(c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+15] + w[15]; + w[15] += S1 (w[13]) + w[8] + S0 (w[0]); + t2 = Sum0 (b) + Maj(b, c, d); + e += t1; + a = t1 + t2; + + t += 16; +#endif + } + + for (; t < 80; ) + { + u64 t1, t2; + +#if 0 /* Not unrolled. */ + t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[t%16]; + t2 = Sum0 (a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; +#else /* Unrolled to interweave the chain variables. */ + t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[0]; + t2 = Sum0 (a) + Maj(a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+1] + w[1]; + t2 = Sum0 (h) + Maj(h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+2] + w[2]; + t2 = Sum0 (g) + Maj(g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+3] + w[3]; + t2 = Sum0 (f) + Maj(f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+4] + w[4]; + t2 = Sum0 (e) + Maj(e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+5] + w[5]; + t2 = Sum0 (d) + Maj(d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+6] + w[6]; + t2 = Sum0 (c) + Maj(c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+7] + w[7]; + t2 = Sum0 (b) + Maj(b, c, d); + e += t1; + a = t1 + t2; + + t1 = h + Sum1 (e) + Ch(e, f, g) + k[t+8] + w[8]; + t2 = Sum0 (a) + Maj(a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+9] + w[9]; + t2 = Sum0 (h) + Maj(h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+10] + w[10]; + t2 = Sum0 (g) + Maj(g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+11] + w[11]; + t2 = Sum0 (f) + Maj(f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+12] + w[12]; + t2 = Sum0 (e) + Maj(e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+13] + w[13]; + t2 = Sum0 (d) + Maj(d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+14] + w[14]; + t2 = Sum0 (c) + Maj(c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+15] + w[15]; + t2 = Sum0 (b) + Maj(b, c, d); + e += t1; + a = t1 + t2; + + t += 16; +#endif + } + + /* Update chaining vars. */ + hd->h0 += a; + hd->h1 += b; + hd->h2 += c; + hd->h3 += d; + hd->h4 += e; + hd->h5 += f; + hd->h6 += g; + hd->h7 += h; + + return /* burn_stack */ (8 + 16) * sizeof(u64) + sizeof(u32) + 3 * sizeof(void*); +} + +static uint +sha512_transform(void *context, const byte *data, size_t nblks) +{ + struct sha512_context *ctx = context; + uint burn; + + do + { + burn = sha512_transform_block(&ctx->state, data) + 3 * sizeof(void*); + data += 128; + } + while(--nblks); + + return burn; +} + +/* The routine final terminates the computation and + * returns the digest. + * The handle is prepared for a new cycle, but adding bytes to the + * handle will the destroy the returned buffer. + * Returns: 64 bytes representing the digest. When used for sha384, + * we take the leftmost 48 of those bytes. + */ +byte * +sha512_final(struct sha512_context *ctx) +{ + u64 t, th, msb, lsb; + byte *p; + + sha256_update(&ctx->bctx, NULL, 0); /* flush */ ; + + t = ctx->bctx.nblocks; + /* if (sizeof t == sizeof ctx->bctx.nblocks) */ + th = ctx->bctx.nblocks_high; + /* else */ + /* th = ctx->bctx.nblocks >> 64; In case we ever use u128 */ + + /* multiply by 128 to make a byte count */ + lsb = t << 7; + msb = (th << 7) | (t >> 57); + /* add the count */ + t = lsb; + if ((lsb += ctx->bctx.count) < t) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 61; + + if (ctx->bctx.count < 112) + { /* enough room */ + ctx->bctx.buf[ctx->bctx.count++] = 0x80; /* pad */ + while(ctx->bctx.count < 112) + ctx->bctx.buf[ctx->bctx.count++] = 0; /* pad */ + } + else + { /* need one extra block */ + ctx->bctx.buf[ctx->bctx.count++] = 0x80; /* pad character */ + while(ctx->bctx.count < 128) + ctx->bctx.buf[ctx->bctx.count++] = 0; + sha256_update(&ctx->bctx, NULL, 0); /* flush */ ; + memset(ctx->bctx.buf, 0, 112); /* fill next block with zeroes */ + } + /* append the 128 bit count */ + put_u64(ctx->bctx.buf + 112, msb); + put_u64(ctx->bctx.buf + 120, lsb); + sha512_transform(ctx, ctx->bctx.buf, 1); + + p = ctx->bctx.buf; +#define X(a) do { put_u64(p, ctx->state.h##a); p += 8; } while(0) + X (0); + X (1); + X (2); + X (3); + X (4); + X (5); + /* Note that these last two chunks are included even for SHA384. + We just ignore them. */ + X (6); + X (7); +#undef X + + return ctx->bctx.buf; +} + + +/* + * SHA512-HMAC + */ + +static void +sha512_hash_buffer(byte *outbuf, const byte *buffer, size_t length) +{ + struct sha512_context hd_tmp; + + sha512_init(&hd_tmp); + sha512_update(&hd_tmp, buffer, length); + memcpy(outbuf, sha512_final(&hd_tmp), SHA512_SIZE); +} + +void +sha512_hmac_init(struct sha512_hmac_context *ctx, const byte *key, size_t keylen) +{ + byte keybuf[SHA512_BLOCK_SIZE], buf[SHA512_BLOCK_SIZE]; + + /* Hash the key if necessary */ + if (keylen <= SHA512_BLOCK_SIZE) + { + memcpy(keybuf, key, keylen); + bzero(keybuf + keylen, SHA512_BLOCK_SIZE - keylen); + } + else + { + sha512_hash_buffer(keybuf, key, keylen); + bzero(keybuf + SHA512_SIZE, SHA512_BLOCK_SIZE - SHA512_SIZE); + } + + /* Initialize the inner digest */ + sha512_init(&ctx->ictx); + int i; + for (i = 0; i < SHA512_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x36; + sha512_update(&ctx->ictx, buf, SHA512_BLOCK_SIZE); + + /* Initialize the outer digest */ + sha512_init(&ctx->octx); + for (i = 0; i < SHA512_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x5c; + sha512_update(&ctx->octx, buf, SHA512_BLOCK_SIZE); +} + +void sha512_hmac_update(struct sha512_hmac_context *ctx, const byte *buf, size_t buflen) +{ + /* Just update the inner digest */ + sha512_update(&ctx->ictx, buf, buflen); +} + +byte *sha512_hmac_final(struct sha512_hmac_context *ctx) +{ + /* Finish the inner digest */ + byte *isha = sha512_final(&ctx->ictx); + + /* Finish the outer digest */ + sha512_update(&ctx->octx, isha, SHA512_SIZE); + return sha512_final(&ctx->octx); +} + + +/* + * SHA384-HMAC + */ + +static void +sha384_hash_buffer(byte *outbuf, const byte *buffer, size_t length) +{ + struct sha384_context hd_tmp; + + sha384_init(&hd_tmp); + sha384_update(&hd_tmp, buffer, length); + memcpy(outbuf, sha384_final(&hd_tmp), SHA384_SIZE); +} + +void +sha384_hmac_init(struct sha384_hmac_context *ctx, const byte *key, size_t keylen) +{ + byte keybuf[SHA384_BLOCK_SIZE], buf[SHA384_BLOCK_SIZE]; + + /* Hash the key if necessary */ + if (keylen <= SHA384_BLOCK_SIZE) + { + memcpy(keybuf, key, keylen); + bzero(keybuf + keylen, SHA384_BLOCK_SIZE - keylen); + } + else + { + sha384_hash_buffer(keybuf, key, keylen); + bzero(keybuf + SHA384_SIZE, SHA384_BLOCK_SIZE - SHA384_SIZE); + } + + /* Initialize the inner digest */ + sha384_init(&ctx->ictx); + int i; + for (i = 0; i < SHA384_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x36; + sha384_update(&ctx->ictx, buf, SHA384_BLOCK_SIZE); + + /* Initialize the outer digest */ + sha384_init(&ctx->octx); + for (i = 0; i < SHA384_BLOCK_SIZE; i++) + buf[i] = keybuf[i] ^ 0x5c; + sha384_update(&ctx->octx, buf, SHA384_BLOCK_SIZE); +} + +void sha384_hmac_update(struct sha384_hmac_context *ctx, const byte *buf, size_t buflen) +{ + /* Just update the inner digest */ + sha384_update(&ctx->ictx, buf, buflen); +} + +byte *sha384_hmac_final(struct sha384_hmac_context *ctx) +{ + /* Finish the inner digest */ + byte *isha = sha384_final(&ctx->ictx); + + /* Finish the outer digest */ + sha384_update(&ctx->octx, isha, SHA384_SIZE); + return sha384_final(&ctx->octx); +} diff --git a/lib/sha512.h b/lib/sha512.h new file mode 100644 index 00000000..bd998152 --- /dev/null +++ b/lib/sha512.h @@ -0,0 +1,73 @@ +/* + * BIRD Library -- SHA-512 and SHA-384 Hash Functions, + * HMAC-SHA-512 and HMAC-SHA-384 Functions + * + * (c) 2015 CZ.NIC z.s.p.o. + * + * Based on the code from libgcrypt-1.6.0, which is + * (c) 2003, 2006, 2008, 2009 Free Software Foundation, Inc. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_SHA512_H_ +#define _BIRD_SHA512_H_ + +#include "lib/sha256.h" + +#define SHA384_SIZE 48 +#define SHA384_HEX_SIZE 97 +#define SHA384_BLOCK_SIZE 128 + +#define SHA512_SIZE 64 +#define SHA512_HEX_SIZE 129 +#define SHA512_BLOCK_SIZE 128 + +struct sha512_state +{ + u64 h0, h1, h2, h3, h4, h5, h6, h7; +}; + +struct sha512_context +{ + struct sha256_context bctx; + struct sha512_state state; +}; +#define sha384_context sha512_context /* aliasing 'struct sha384_context' to 'struct sha512_context' */ + + +void sha512_init(struct sha512_context *ctx); +void sha384_init(struct sha384_context *ctx); + +void sha512_update(struct sha512_context *ctx, const byte *in_buf, size_t in_len); +static inline void sha384_update(struct sha384_context *ctx, const byte *in_buf, size_t in_len) +{ + sha512_update(ctx, in_buf, in_len); +} + +byte* sha512_final(struct sha512_context *ctx); +static inline byte* sha384_final(struct sha384_context *ctx) +{ + return sha512_final(ctx); +} + +/* + * HMAC-SHA512, HMAC-SHA384 + */ +struct sha512_hmac_context +{ + struct sha512_context ictx; + struct sha512_context octx; +} ; +#define sha384_hmac_context sha512_hmac_context /* aliasing 'struct sha384_hmac_context' to 'struct sha384_hmac_context' */ + +void sha512_hmac_init(struct sha512_hmac_context *ctx, const byte *key, size_t keylen); +void sha384_hmac_init(struct sha384_hmac_context *ctx, const byte *key, size_t keylen); + +void sha512_hmac_update(struct sha512_hmac_context *ctx, const byte *buf, size_t buflen); +void sha384_hmac_update(struct sha384_hmac_context *ctx, const byte *buf, size_t buflen); + +byte *sha512_hmac_final(struct sha512_hmac_context *ctx); +byte *sha384_hmac_final(struct sha384_hmac_context *ctx); + +#endif /* _BIRD_SHA512_H_ */ From 1e4891e48e7b6f022564e7409d15c3fdb65ec2ad Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 23 Nov 2015 11:13:40 +0100 Subject: [PATCH 11/14] Nest: Fix bug in device proto If an interface address notification is received during device protocol shutdown/restart, BIRD crashed. Thanks to Wei Huang for the bugreport. --- sysdep/linux/netlink.c | 6 ++++-- sysdep/unix/krt.c | 2 +- sysdep/unix/krt.h | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index f2f60100..efbf41a6 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -1116,12 +1116,14 @@ nl_async_msg(struct nlmsghdr *h) case RTM_NEWLINK: case RTM_DELLINK: DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type); - nl_parse_link(h, 0); + if (kif_proto) + nl_parse_link(h, 0); break; case RTM_NEWADDR: case RTM_DELADDR: DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type); - nl_parse_addr(h, 0); + if (kif_proto) + nl_parse_addr(h, 0); break; default: DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type); diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 49bf9519..5e78586b 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -84,8 +84,8 @@ krt_io_init(void) * Interfaces */ +struct kif_proto *kif_proto; static struct kif_config *kif_cf; -static struct kif_proto *kif_proto; static timer *kif_scan_timer; static bird_clock_t kif_last_shot; diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index aea20102..d4a8717e 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -112,6 +112,8 @@ struct kif_proto { struct kif_state sys; /* Sysdep state */ }; +struct kif_proto *kif_proto; + #define KIF_CF ((struct kif_config *)p->p.cf) struct proto_config * krt_init_config(int class); From 5126380beace4e39578f005fe115917b8e8b8ff3 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 24 Nov 2015 13:47:28 +0100 Subject: [PATCH 12/14] Minor changes to SHA hash functions --- lib/birdlib.h | 1 + lib/sha1.c | 176 +++++++++-------- lib/sha1.h | 72 +++---- lib/sha256.c | 180 ++++++++--------- lib/sha256.h | 42 ++-- lib/sha512.c | 526 +++++++++++++++++++++++++------------------------- lib/sha512.h | 42 ++-- 7 files changed, 518 insertions(+), 521 deletions(-) diff --git a/lib/birdlib.h b/lib/birdlib.h index ad41dca3..16f437ef 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -30,6 +30,7 @@ #define MAX(a,b) MAX_(a,b) #endif +#define U64(c) UINT64_C(c) #define ABS(a) ((a)>=0 ? (a) : -(a)) #define DELTA(a,b) (((a)>=(b))?(a)-(b):(b)-(a)) #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) diff --git a/lib/sha1.c b/lib/sha1.c index dd29b5fd..73b4b280 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -15,33 +15,35 @@ #include "lib/sha1.h" #include "lib/unaligned.h" + void -sha1_init(struct sha1_context *hd) +sha1_init(struct sha1_context *ctx) { - hd->h0 = 0x67452301; - hd->h1 = 0xefcdab89; - hd->h2 = 0x98badcfe; - hd->h3 = 0x10325476; - hd->h4 = 0xc3d2e1f0; - hd->nblocks = 0; - hd->count = 0; + ctx->h0 = 0x67452301; + ctx->h1 = 0xefcdab89; + ctx->h2 = 0x98badcfe; + ctx->h3 = 0x10325476; + ctx->h4 = 0xc3d2e1f0; + + ctx->nblocks = 0; + ctx->count = 0; } /* * Transform the message X which consists of 16 32-bit-words */ static void -sha1_transform(struct sha1_context *hd, const byte *data) +sha1_transform(struct sha1_context *ctx, const byte *data) { u32 a,b,c,d,e,tm; u32 x[16]; /* Get values from the chaining vars. */ - a = hd->h0; - b = hd->h1; - c = hd->h2; - d = hd->h3; - e = hd->h4; + a = ctx->h0; + b = ctx->h1; + c = ctx->h2; + d = ctx->h3; + e = ctx->h4; #ifdef CPU_BIG_ENDIAN memcpy(x, data, 64); @@ -69,7 +71,7 @@ sha1_transform(struct sha1_context *hd, const byte *data) do \ { \ e += ROL(a, 5) + f(b, c, d) + k + m; \ - b = ROL( b, 30 ); \ + b = ROL(b, 30); \ } while(0) R( a, b, c, d, e, F1, K1, x[ 0] ); @@ -154,72 +156,72 @@ sha1_transform(struct sha1_context *hd, const byte *data) R( b, c, d, e, a, F4, K4, M(79) ); /* Update chaining vars. */ - hd->h0 += a; - hd->h1 += b; - hd->h2 += c; - hd->h3 += d; - hd->h4 += e; + ctx->h0 += a; + ctx->h1 += b; + ctx->h2 += c; + ctx->h3 += d; + ctx->h4 += e; } /* - * Update the message digest with the contents - * of INBUF with length INLEN. + * Update the message digest with the contents of BUF with length LEN. */ void -sha1_update(struct sha1_context *hd, const byte *inbuf, uint inlen) +sha1_update(struct sha1_context *ctx, const byte *buf, uint len) { - if (hd->count == 64) /* flush the buffer */ + if (ctx->count) { - sha1_transform(hd, hd->buf); - hd->count = 0; - hd->nblocks++; + /* Fill rest of internal buffer */ + for (; len && ctx->count < SHA1_BLOCK_SIZE; len--) + ctx->buf[ctx->count++] = *buf++; + + if (ctx->count < SHA1_BLOCK_SIZE) + return; + + /* Process data from internal buffer */ + sha1_transform(ctx, ctx->buf); + ctx->nblocks++; + ctx->count = 0; } - if (!inbuf) + + if (!len) return; - if (hd->count) + /* Process data from input buffer */ + while (len >= SHA1_BLOCK_SIZE) { - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; - sha1_update( hd, NULL, 0 ); - if(!inlen) - return; + sha1_transform(ctx, buf); + ctx->nblocks++; + buf += SHA1_BLOCK_SIZE; + len -= SHA1_BLOCK_SIZE; } - while (inlen >= 64) - { - sha1_transform(hd, inbuf); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; + /* Copy remaining data to internal buffer */ + memcpy(ctx->buf, buf, len); + ctx->count = len; } /* - * The routine final terminates the computation and - * returns the digest. - * The handle is prepared for a new cycle, but adding bytes to the - * handle will the destroy the returned buffer. + * The routine final terminates the computation and returns the digest. The + * handle is prepared for a new cycle, but adding bytes to the handle will the + * destroy the returned buffer. + * * Returns: 20 bytes representing the digest. */ byte * -sha1_final(struct sha1_context *hd) +sha1_final(struct sha1_context *ctx) { u32 t, msb, lsb; - u32 *p; - sha1_update(hd, NULL, 0); /* flush */; + sha1_update(ctx, NULL, 0); /* flush */ - t = hd->nblocks; + t = ctx->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; msb = t >> 26; /* add the count */ t = lsb; - if ((lsb += hd->count) < t) + if ((lsb += ctx->count) < t) msb++; /* multiply by 8 to make a bit count */ t = lsb; @@ -227,33 +229,36 @@ sha1_final(struct sha1_context *hd) msb <<= 3; msb |= t >> 29; - if (hd->count < 56) /* enough room */ + if (ctx->count < 56) { - hd->buf[hd->count++] = 0x80; /* pad */ - while (hd->count < 56) - hd->buf[hd->count++] = 0; /* pad */ + /* enough room */ + ctx->buf[ctx->count++] = 0x80; /* pad */ + while (ctx->count < 56) + ctx->buf[ctx->count++] = 0; /* pad */ } - else /* need one extra block */ + else { - hd->buf[hd->count++] = 0x80; /* pad character */ - while (hd->count < 64) - hd->buf[hd->count++] = 0; - sha1_update(hd, NULL, 0); /* flush */; - memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ + /* need one extra block */ + ctx->buf[ctx->count++] = 0x80; /* pad character */ + while (ctx->count < 64) + ctx->buf[ctx->count++] = 0; + sha1_update(ctx, NULL, 0); /* flush */ + memset(ctx->buf, 0, 56); /* fill next block with zeroes */ } - /* append the 64 bit count */ - hd->buf[56] = msb >> 24; - hd->buf[57] = msb >> 16; - hd->buf[58] = msb >> 8; - hd->buf[59] = msb ; - hd->buf[60] = lsb >> 24; - hd->buf[61] = lsb >> 16; - hd->buf[62] = lsb >> 8; - hd->buf[63] = lsb ; - sha1_transform(hd, hd->buf); - p = (u32*) hd->buf; -#define X(a) do { put_u32(p, hd->h##a); p++; } while(0) + /* append the 64 bit count */ + ctx->buf[56] = msb >> 24; + ctx->buf[57] = msb >> 16; + ctx->buf[58] = msb >> 8; + ctx->buf[59] = msb; + ctx->buf[60] = lsb >> 24; + ctx->buf[61] = lsb >> 16; + ctx->buf[62] = lsb >> 8; + ctx->buf[63] = lsb; + sha1_transform(ctx, ctx->buf); + + byte *p = ctx->buf; +#define X(a) do { put_u32(p, ctx->h##a); p += 4; } while(0) X(0); X(1); X(2); @@ -261,12 +266,12 @@ sha1_final(struct sha1_context *hd) X(4); #undef X - return hd->buf; + return ctx->buf; } /* - * SHA1-HMAC + * SHA1-HMAC */ /* @@ -292,12 +297,12 @@ sha1_hmac_init(struct sha1_hmac_context *ctx, const byte *key, uint keylen) if (keylen <= SHA1_BLOCK_SIZE) { memcpy(keybuf, key, keylen); - bzero(keybuf + keylen, SHA1_BLOCK_SIZE - keylen); + memset(keybuf + keylen, 0, SHA1_BLOCK_SIZE - keylen); } else { sha1_hash_buffer(keybuf, key, keylen); - bzero(keybuf + SHA1_SIZE, SHA1_BLOCK_SIZE - SHA1_SIZE); + memset(keybuf + SHA1_SIZE, 0, SHA1_BLOCK_SIZE - SHA1_SIZE); } /* Initialize the inner digest */ @@ -321,7 +326,8 @@ sha1_hmac_update(struct sha1_hmac_context *ctx, const byte *data, uint datalen) sha1_update(&ctx->ictx, data, datalen); } -byte *sha1_hmac_final(struct sha1_hmac_context *ctx) +byte * +sha1_hmac_final(struct sha1_hmac_context *ctx) { /* Finish the inner digest */ byte *isha = sha1_final(&ctx->ictx); @@ -334,9 +340,9 @@ byte *sha1_hmac_final(struct sha1_hmac_context *ctx) void sha1_hmac(byte *outbuf, const byte *key, uint keylen, const byte *data, uint datalen) { - struct sha1_hmac_context hd; - sha1_hmac_init(&hd, key, keylen); - sha1_hmac_update(&hd, data, datalen); - byte *osha = sha1_hmac_final(&hd); - memcpy(outbuf, osha, SHA1_SIZE); + struct sha1_hmac_context ctx; + + sha1_hmac_init(&ctx, key, keylen); + sha1_hmac_update(&ctx, data, datalen); + memcpy(outbuf, sha1_hmac_final(&ctx), SHA1_SIZE); } diff --git a/lib/sha1.h b/lib/sha1.h index 425160a0..c019bb49 100644 --- a/lib/sha1.h +++ b/lib/sha1.h @@ -17,70 +17,70 @@ #include "nest/bird.h" + +#define SHA1_SIZE 20 /* Size of the SHA1 hash in its binary representation */ +#define SHA1_HEX_SIZE 41 /* Buffer length for a string containing SHA1 in hexadecimal format. */ +#define SHA1_BLOCK_SIZE 64 /* SHA1 splits input to blocks of this size. */ + + /* * Internal SHA1 state. * You should use it just as an opaque handle only. */ struct sha1_context { - u32 h0,h1,h2,h3,h4; - u32 nblocks; - byte buf[64]; - int count; -} ; + u32 h0, h1, h2, h3, h4; + byte buf[SHA1_BLOCK_SIZE]; + uint nblocks; + uint count; +}; -void sha1_init(struct sha1_context *hd); /* Initialize new algorithm run in the @hd context. **/ + +void sha1_init(struct sha1_context *ctx); /* Initialize new algorithm run in the @ctx context. **/ /* - * Push another @inlen bytes of data pointed to by @inbuf onto the - * SHA1 hash currently in @hd. You can call this any times you want on - * the same hash (and you do not need to reinitialize it by - * @sha1_init()). It has the same effect as concatenating all the data - * together and passing them at once. + * Push another @len bytes of data pointed to by @buf onto the SHA1 hash + * currently in @ctx. You can call this any times you want on the same hash (and + * you do not need to reinitialize it by @sha1_init()). It has the same effect + * as concatenating all the data together and passing them at once. */ -void sha1_update(struct sha1_context *hd, const byte *inbuf, uint inlen); +void sha1_update(struct sha1_context *ctx, const byte *buf, uint len); /* - * No more @sha1_update() calls will be done. This terminates the hash - * and returns a pointer to it. + * No more @sha1_update() calls will be done. This terminates the hash and + * returns a pointer to it. * - * Note that the pointer points into data in the @hd context. If it ceases - * to exist, the pointer becomes invalid. - * - * To convert the hash to its usual hexadecimal representation, see - * <>. + * Note that the pointer points into data in the @ctx context. If it ceases to + * exist, the pointer becomes invalid. */ -byte *sha1_final(struct sha1_context *hd); +byte *sha1_final(struct sha1_context *ctx); /* - * A convenience one-shot function for SHA1 hash. - * It is equivalent to this snippet of code: + * A convenience one-shot function for SHA1 hash. It is equivalent to this + * snippet of code: * - * sha1_context hd; - * sha1_init(&hd); - * sha1_update(&hd, buffer, length); - * memcpy(outbuf, sha1_final(&hd), SHA1_SIZE); + * sha1_context ctx; + * sha1_init(&ctx); + * sha1_update(&ctx, buffer, length); + * memcpy(outbuf, sha1_final(&ctx), SHA1_SIZE); */ void sha1_hash_buffer(byte *outbuf, const byte *buffer, uint length); /* - * SHA1 HMAC message authentication. If you provide @key and @data, - * the result will be stored in @outbuf. + * SHA1 HMAC message authentication. If you provide @key and @data, the result + * will be stored in @outbuf. */ void sha1_hmac(byte *outbuf, const byte *key, uint keylen, const byte *data, uint datalen); /* - * The HMAC also exists in a stream version in a way analogous to the - * plain SHA1. Pass this as a context. + * The HMAC also exists in a stream version in a way analogous to the plain + * SHA1. Pass this as a context. */ struct sha1_hmac_context { struct sha1_context ictx; struct sha1_context octx; }; -void sha1_hmac_init(struct sha1_hmac_context *hd, const byte *key, uint keylen); /* Initialize HMAC with context @hd and the given key. See sha1_init(). */ -void sha1_hmac_update(struct sha1_hmac_context *hd, const byte *data, uint datalen); /* Hash another @datalen bytes of data. See sha1_update(). */ -byte *sha1_hmac_final(struct sha1_hmac_context *hd); /* Terminate the HMAC and return a pointer to the allocated hash. See sha1_final(). */ +void sha1_hmac_init(struct sha1_hmac_context *ctx, const byte *key, uint keylen); /* Initialize HMAC with context @ctx and the given key. See sha1_init(). */ +void sha1_hmac_update(struct sha1_hmac_context *ctx, const byte *data, uint datalen); /* Hash another @datalen bytes of data. See sha1_update(). */ +byte *sha1_hmac_final(struct sha1_hmac_context *ctx); /* Terminate the HMAC and return a pointer to the allocated hash. See sha1_final(). */ -#define SHA1_SIZE 20 /* Size of the SHA1 hash in its binary representation **/ -#define SHA1_HEX_SIZE 41 /* Buffer length for a string containing SHA1 in hexadecimal format. **/ -#define SHA1_BLOCK_SIZE 64 /* SHA1 splits input to blocks of this size. **/ #endif /* _BIRD_SHA1_H_ */ diff --git a/lib/sha256.c b/lib/sha256.c index 2d979f90..440245d5 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -13,7 +13,8 @@ #include "lib/sha256.h" #include "lib/unaligned.h" -static uint sha256_transform(void *ctx, const byte *data, size_t nblks); + +// #define SHA256_UNROLLED void sha256_init(struct sha256_context *ctx) @@ -28,10 +29,7 @@ sha256_init(struct sha256_context *ctx) ctx->h7 = 0x5be0cd19; ctx->nblocks = 0; - ctx->nblocks_high = 0; ctx->count = 0; - ctx->blocksize = 64; - ctx->transform = sha256_transform; } void @@ -47,10 +45,7 @@ sha224_init(struct sha224_context *ctx) ctx->h7 = 0xbefa4fa4; ctx->nblocks = 0; - ctx->nblocks_high = 0; ctx->count = 0; - ctx->blocksize = 64; - ctx->transform = sha256_transform; } /* (4.2) same as SHA-1's F1. */ @@ -70,7 +65,7 @@ f3(u32 x, u32 y, u32 z) /* Bitwise rotation of an uint to the right */ static inline u32 ror(u32 x, int n) { - return ( (x >> (n&(32-1))) | (x << ((32-n)&(32-1))) ); + return ((x >> (n&(32-1))) | (x << ((32-n)&(32-1)))); } /* (4.4) */ @@ -112,7 +107,7 @@ sum1(u32 x) 32-bit-words. See FIPS 180-2 for details. */ static uint -sha256_transform_block(struct sha256_context *ctx, const byte *data) +sha256_transform(struct sha256_context *ctx, const byte *data) { static const u32 K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, @@ -148,52 +143,58 @@ sha256_transform_block(struct sha256_context *ctx, const byte *data) for (i = 0; i < 16; i++) w[i] = get_u32(data + i * 4); + for (; i < 64; i++) w[i] = S1(w[i-2]) + w[i-7] + S0(w[i-15]) + w[i-16]; for (i = 0; i < 64;) { +#ifndef SHA256_UNROLLED + R(a,b,c,d,e,f,g,h,K[i],w[i]); + i++; +#else /* Unrolled */ t1 = h + sum1(e) + f1(e, f, g) + K[i] + w[i]; - t2 = sum0 (a) + f3(a, b, c); + t2 = sum0(a) + f3(a, b, c); d += t1; h = t1 + t2; t1 = g + sum1(d) + f1(d, e, f) + K[i+1] + w[i+1]; - t2 = sum0 (h) + f3(h, a, b); + t2 = sum0(h) + f3(h, a, b); c += t1; g = t1 + t2; t1 = f + sum1(c) + f1(c, d, e) + K[i+2] + w[i+2]; - t2 = sum0 (g) + f3(g, h, a); + t2 = sum0(g) + f3(g, h, a); b += t1; f = t1 + t2; t1 = e + sum1(b) + f1(b, c, d) + K[i+3] + w[i+3]; - t2 = sum0 (f) + f3(f, g, h); + t2 = sum0(f) + f3(f, g, h); a += t1; e = t1 + t2; t1 = d + sum1(a) + f1(a, b, c) + K[i+4] + w[i+4]; - t2 = sum0 (e) + f3(e, f, g); + t2 = sum0(e) + f3(e, f, g); h += t1; d = t1 + t2; t1 = c + sum1(h) + f1(h, a, b) + K[i+5] + w[i+5]; - t2 = sum0 (d) + f3(d, e, f); + t2 = sum0(d) + f3(d, e, f); g += t1; c = t1 + t2; t1 = b + sum1(g) + f1(g, h, a) + K[i+6] + w[i+6]; - t2 = sum0 (c) + f3(c, d, e); + t2 = sum0(c) + f3(c, d, e); f += t1; b = t1 + t2; t1 = a + sum1(f) + f1(f, g, h) + K[i+7] + w[i+7]; - t2 = sum0 (b) + f3(b, c, d); + t2 = sum0(b) + f3(b, c, d); e += t1; a = t1 + t2; i += 8; +#endif } ctx->h0 += a; @@ -211,22 +212,6 @@ sha256_transform_block(struct sha256_context *ctx, const byte *data) #undef S1 #undef R -static uint -sha256_transform(void *ctx, const byte *data, size_t nblks) -{ - struct sha256_context *hd = ctx; - uint burn; - - do - { - burn = sha256_transform_block(hd, data); - data += 64; - } - while (--nblks); - - return burn; -} - /* Common function to write a chunk of data to the transform function of a hash algorithm. Note that the use of the term "block" does not imply a fixed size block. Note that we explicitly allow to use @@ -234,65 +219,56 @@ sha256_transform(void *ctx, const byte *data, size_t nblks) not have any meaning but writing after finalize is sometimes helpful to mitigate timing attacks. */ void -sha256_update(struct sha256_context *ctx, const byte *in_buf, size_t in_len) +sha256_update(struct sha256_context *ctx, const byte *buf, size_t len) { - const uint blocksize = ctx->blocksize; - size_t inblocks; - - if (sizeof(ctx->buf) < blocksize) - debug("BUG: in file %s at line %d", __FILE__ , __LINE__); - - if (ctx->count == blocksize) /* Flush the buffer. */ - { - ctx->transform(ctx, ctx->buf, 1); - ctx->count = 0; - if (!++ctx->nblocks) - ctx->nblocks_high++; - } - if (!in_buf) - return; - if (ctx->count) { - for (; in_len && ctx->count < blocksize; in_len--) - ctx->buf[ctx->count++] = *in_buf++; - sha256_update(ctx, NULL, 0); - if (!in_len) + /* Fill rest of internal buffer */ + for (; len && ctx->count < SHA256_BLOCK_SIZE; len--) + ctx->buf[ctx->count++] = *buf++; + + if (ctx->count < SHA256_BLOCK_SIZE) return; + + /* Process data from internal buffer */ + sha256_transform(ctx, ctx->buf); + ctx->nblocks++; + ctx->count = 0; } - if (in_len >= blocksize) + if (!len) + return; + + /* Process data from input buffer */ + while (len >= SHA256_BLOCK_SIZE) { - inblocks = in_len / blocksize; - ctx->transform(ctx, in_buf, inblocks); - ctx->count = 0; - ctx->nblocks_high += (ctx->nblocks + inblocks < inblocks); - ctx->nblocks += inblocks; - in_len -= inblocks * blocksize; - in_buf += inblocks * blocksize; + sha256_transform(ctx, buf); + ctx->nblocks++; + buf += SHA256_BLOCK_SIZE; + len -= SHA256_BLOCK_SIZE; } - for (; in_len && ctx->count < blocksize; in_len--) - ctx->buf[ctx->count++] = *in_buf++; + + /* Copy remaining data to internal buffer */ + memcpy(ctx->buf, buf, len); + ctx->count = len; } /* - The routine finally terminates the computation and returns the - digest. The handle is prepared for a new cycle, but adding bytes - to the handle will the destroy the returned buffer. Returns: 32 - bytes with the message the digest. */ -byte* + * The routine finally terminates the computation and returns the digest. The + * handle is prepared for a new cycle, but adding bytes to the handle will the + * destroy the returned buffer. + * + * Returns: 32 bytes with the message the digest. 28 bytes for SHA-224. + */ +byte * sha256_final(struct sha256_context *ctx) { u32 t, th, msb, lsb; - byte *p; - sha256_update(ctx, NULL, 0); /* flush */; + sha256_update(ctx, NULL, 0); /* flush */ t = ctx->nblocks; - if (sizeof t == sizeof ctx->nblocks) - th = ctx->nblocks_high; - else - th = 0; + th = 0; /* multiply by 64 to make a byte count */ lsb = t << 6; @@ -308,26 +284,28 @@ sha256_final(struct sha256_context *ctx) msb |= t >> 29; if (ctx->count < 56) - { /* enough room */ + { + /* enough room */ ctx->buf[ctx->count++] = 0x80; /* pad */ while (ctx->count < 56) ctx->buf[ctx->count++] = 0; /* pad */ } else - { /* need one extra block */ + { + /* need one extra block */ ctx->buf[ctx->count++] = 0x80; /* pad character */ while (ctx->count < 64) ctx->buf[ctx->count++] = 0; sha256_update(ctx, NULL, 0); /* flush */; - memset (ctx->buf, 0, 56 ); /* fill next block with zeroes */ + memset(ctx->buf, 0, 56 ); /* fill next block with zeroes */ } + /* append the 64 bit count */ put_u32(ctx->buf + 56, msb); put_u32(ctx->buf + 60, lsb); - sha256_transform(ctx, ctx->buf, 1); - - p = ctx->buf; + sha256_transform(ctx, ctx->buf); + byte *p = ctx->buf; #define X(a) do { put_u32(p, ctx->h##a); p += 4; } while(0) X(0); X(1); @@ -344,17 +322,17 @@ sha256_final(struct sha256_context *ctx) /* - * SHA256-HMAC + * SHA256-HMAC */ static void sha256_hash_buffer(byte *outbuf, const byte *buffer, size_t length) { - struct sha256_context hd_tmp; + struct sha256_context ctx; - sha256_init(&hd_tmp); - sha256_update(&hd_tmp, buffer, length); - memcpy(outbuf, sha256_final(&hd_tmp), SHA256_SIZE); + sha256_init(&ctx); + sha256_update(&ctx, buffer, length); + memcpy(outbuf, sha256_final(&ctx), SHA256_SIZE); } void @@ -366,12 +344,12 @@ sha256_hmac_init(struct sha256_hmac_context *ctx, const byte *key, size_t keylen if (keylen <= SHA256_BLOCK_SIZE) { memcpy(keybuf, key, keylen); - bzero(keybuf + keylen, SHA256_BLOCK_SIZE - keylen); + memset(keybuf + keylen, 0, SHA256_BLOCK_SIZE - keylen); } else { sha256_hash_buffer(keybuf, key, keylen); - bzero(keybuf + SHA256_SIZE, SHA256_BLOCK_SIZE - SHA256_SIZE); + memset(keybuf + SHA256_SIZE, 0, SHA256_BLOCK_SIZE - SHA256_SIZE); } /* Initialize the inner digest */ @@ -388,13 +366,15 @@ sha256_hmac_init(struct sha256_hmac_context *ctx, const byte *key, size_t keylen sha256_update(&ctx->octx, buf, SHA256_BLOCK_SIZE); } -void sha256_hmac_update(struct sha256_hmac_context *ctx, const byte *buf, size_t buflen) +void +sha256_hmac_update(struct sha256_hmac_context *ctx, const byte *buf, size_t buflen) { /* Just update the inner digest */ sha256_update(&ctx->ictx, buf, buflen); } -byte *sha256_hmac_final(struct sha256_hmac_context *ctx) +byte * +sha256_hmac_final(struct sha256_hmac_context *ctx) { /* Finish the inner digest */ byte *isha = sha256_final(&ctx->ictx); @@ -406,17 +386,17 @@ byte *sha256_hmac_final(struct sha256_hmac_context *ctx) /* - * SHA224-HMAC + * SHA224-HMAC */ static void sha224_hash_buffer(byte *outbuf, const byte *buffer, size_t length) { - struct sha224_context hd_tmp; + struct sha224_context ctx; - sha224_init(&hd_tmp); - sha224_update(&hd_tmp, buffer, length); - memcpy(outbuf, sha224_final(&hd_tmp), SHA224_SIZE); + sha224_init(&ctx); + sha224_update(&ctx, buffer, length); + memcpy(outbuf, sha224_final(&ctx), SHA224_SIZE); } void @@ -428,12 +408,12 @@ sha224_hmac_init(struct sha224_hmac_context *ctx, const byte *key, size_t keylen if (keylen <= SHA224_BLOCK_SIZE) { memcpy(keybuf, key, keylen); - bzero(keybuf + keylen, SHA224_BLOCK_SIZE - keylen); + memset(keybuf + keylen, 0, SHA224_BLOCK_SIZE - keylen); } else { sha224_hash_buffer(keybuf, key, keylen); - bzero(keybuf + SHA224_SIZE, SHA224_BLOCK_SIZE - SHA224_SIZE); + memset(keybuf + SHA224_SIZE, 0, SHA224_BLOCK_SIZE - SHA224_SIZE); } /* Initialize the inner digest */ @@ -450,13 +430,15 @@ sha224_hmac_init(struct sha224_hmac_context *ctx, const byte *key, size_t keylen sha224_update(&ctx->octx, buf, SHA224_BLOCK_SIZE); } -void sha224_hmac_update(struct sha224_hmac_context *ctx, const byte *buf, size_t buflen) +void +sha224_hmac_update(struct sha224_hmac_context *ctx, const byte *buf, size_t buflen) { /* Just update the inner digest */ sha256_update(&ctx->ictx, buf, buflen); } -byte *sha224_hmac_final(struct sha224_hmac_context *ctx) +byte * +sha224_hmac_final(struct sha224_hmac_context *ctx) { /* Finish the inner digest */ byte *isha = sha224_final(&ctx->ictx); diff --git a/lib/sha256.h b/lib/sha256.h index 848d2176..381200a9 100644 --- a/lib/sha256.h +++ b/lib/sha256.h @@ -15,6 +15,7 @@ #include "nest/bird.h" + #define SHA224_SIZE 28 #define SHA224_HEX_SIZE 57 #define SHA224_BLOCK_SIZE 64 @@ -23,44 +24,44 @@ #define SHA256_HEX_SIZE 65 #define SHA256_BLOCK_SIZE 64 + struct sha256_context { - u32 h0,h1,h2,h3,h4,h5,h6,h7; - byte buf[128]; /* 128 is for SHA384 and SHA512 support, otherwise for SHA224 and SHA256 is 64 enough */ - u32 nblocks; - u32 nblocks_high; - int count; - u32 blocksize; - uint (*transform)(void *c, const byte *blks, size_t nblks); + u32 h0, h1, h2, h3, h4, h5, h6, h7; + byte buf[SHA256_BLOCK_SIZE]; + uint nblocks; + uint count; }; -#define sha224_context sha256_context /* aliasing 'struct sha224_context' to 'struct sha256_context' */ + +#define sha224_context sha256_context + void sha256_init(struct sha256_context *ctx); void sha224_init(struct sha224_context *ctx); -void sha256_update(struct sha256_context *ctx, const byte *in_buf, size_t in_len); -static inline void sha224_update(struct sha224_context *ctx, const byte *in_buf, size_t in_len) -{ - sha256_update(ctx, in_buf, in_len); -} +void sha256_update(struct sha256_context *ctx, const byte *buf, size_t len); +static inline void sha224_update(struct sha224_context *ctx, const byte *buf, size_t len) +{ sha256_update(ctx, buf, len); } + +byte *sha256_final(struct sha256_context *ctx); +static inline byte *sha224_final(struct sha224_context *ctx) +{ return sha256_final(ctx); } -byte* sha256_final(struct sha256_context *ctx); -static inline byte* sha224_final(struct sha224_context *ctx) -{ - return sha256_final(ctx); -} /* * HMAC-SHA256, HMAC-SHA224 */ + struct sha256_hmac_context { struct sha256_context ictx; struct sha256_context octx; }; -#define sha224_hmac_context sha256_hmac_context /* aliasing 'struct sha224_hmac_context' to 'struct sha256_hmac_context' */ + +#define sha224_hmac_context sha256_hmac_context + void sha256_hmac_init(struct sha256_hmac_context *ctx, const byte *key, size_t keylen); -void sha224_hmac_init(struct sha224_hmac_context *ctx, const byte *key, size_t keylen); +void sha224_hmac_init(struct sha224_hmac_context *ctx, const byte *key, size_t keylen); void sha256_hmac_update(struct sha256_hmac_context *ctx, const byte *buf, size_t buflen); void sha224_hmac_update(struct sha224_hmac_context *ctx, const byte *buf, size_t buflen); @@ -68,4 +69,5 @@ void sha224_hmac_update(struct sha224_hmac_context *ctx, const byte *buf, size_t byte *sha256_hmac_final(struct sha256_hmac_context *ctx); byte *sha224_hmac_final(struct sha224_hmac_context *ctx); + #endif /* _BIRD_SHA256_H_ */ diff --git a/lib/sha512.c b/lib/sha512.c index e46e4c98..37e660f7 100644 --- a/lib/sha512.c +++ b/lib/sha512.c @@ -10,57 +10,42 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ -#include "lib/sha256.h" #include "lib/sha512.h" #include "lib/unaligned.h" -static uint sha512_transform(void *context, const byte *data, size_t nblks); + +// #define SHA512_UNROLLED void sha512_init(struct sha512_context *ctx) { - struct sha512_state *hd = &ctx->state; + ctx->h0 = U64(0x6a09e667f3bcc908); + ctx->h1 = U64(0xbb67ae8584caa73b); + ctx->h2 = U64(0x3c6ef372fe94f82b); + ctx->h3 = U64(0xa54ff53a5f1d36f1); + ctx->h4 = U64(0x510e527fade682d1); + ctx->h5 = U64(0x9b05688c2b3e6c1f); + ctx->h6 = U64(0x1f83d9abfb41bd6b); + ctx->h7 = U64(0x5be0cd19137e2179); - hd->h0 = UINT64_C(0x6a09e667f3bcc908); - hd->h1 = UINT64_C(0xbb67ae8584caa73b); - hd->h2 = UINT64_C(0x3c6ef372fe94f82b); - hd->h3 = UINT64_C(0xa54ff53a5f1d36f1); - hd->h4 = UINT64_C(0x510e527fade682d1); - hd->h5 = UINT64_C(0x9b05688c2b3e6c1f); - hd->h6 = UINT64_C(0x1f83d9abfb41bd6b); - hd->h7 = UINT64_C(0x5be0cd19137e2179); - - ctx->bctx.nblocks = 0; - ctx->bctx.nblocks_high = 0; - ctx->bctx.count = 0; - ctx->bctx.blocksize = 128; - ctx->bctx.transform = sha512_transform; + ctx->nblocks = 0; + ctx->count = 0; } void sha384_init(struct sha384_context *ctx) { - struct sha512_state *hd = &ctx->state; + ctx->h0 = U64(0xcbbb9d5dc1059ed8); + ctx->h1 = U64(0x629a292a367cd507); + ctx->h2 = U64(0x9159015a3070dd17); + ctx->h3 = U64(0x152fecd8f70e5939); + ctx->h4 = U64(0x67332667ffc00b31); + ctx->h5 = U64(0x8eb44a8768581511); + ctx->h6 = U64(0xdb0c2e0d64f98fa7); + ctx->h7 = U64(0x47b5481dbefa4fa4); - hd->h0 = UINT64_C(0xcbbb9d5dc1059ed8); - hd->h1 = UINT64_C(0x629a292a367cd507); - hd->h2 = UINT64_C(0x9159015a3070dd17); - hd->h3 = UINT64_C(0x152fecd8f70e5939); - hd->h4 = UINT64_C(0x67332667ffc00b31); - hd->h5 = UINT64_C(0x8eb44a8768581511); - hd->h6 = UINT64_C(0xdb0c2e0d64f98fa7); - hd->h7 = UINT64_C(0x47b5481dbefa4fa4); - - ctx->bctx.nblocks = 0; - ctx->bctx.nblocks_high = 0; - ctx->bctx.count = 0; - ctx->bctx.blocksize = 128; - ctx->bctx.transform = sha512_transform; -} - -void sha512_update(struct sha512_context *ctx, const byte *in_buf, size_t in_len) -{ - sha256_update(&ctx->bctx, in_buf, in_len); + ctx->nblocks = 0; + ctx->count = 0; } static inline u64 @@ -82,82 +67,82 @@ Maj(u64 x, u64 y, u64 z) } static inline u64 -Sum0(u64 x) +sum0(u64 x) { - return (ROTR (x, 28) ^ ROTR (x, 34) ^ ROTR (x, 39)); + return (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)); } static inline u64 -Sum1 (u64 x) +sum1(u64 x) { - return (ROTR (x, 14) ^ ROTR (x, 18) ^ ROTR (x, 41)); + return (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)); } static const u64 k[] = { - UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), - UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc), - UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), - UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118), - UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), - UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2), - UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), - UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694), - UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), - UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65), - UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), - UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5), - UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), - UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4), - UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), - UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70), - UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), - UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df), - UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), - UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b), - UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), - UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30), - UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), - UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8), - UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), - UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8), - UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), - UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3), - UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), - UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec), - UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), - UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b), - UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), - UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178), - UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), - UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b), - UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), - UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c), - UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), - UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817) + U64(0x428a2f98d728ae22), U64(0x7137449123ef65cd), + U64(0xb5c0fbcfec4d3b2f), U64(0xe9b5dba58189dbbc), + U64(0x3956c25bf348b538), U64(0x59f111f1b605d019), + U64(0x923f82a4af194f9b), U64(0xab1c5ed5da6d8118), + U64(0xd807aa98a3030242), U64(0x12835b0145706fbe), + U64(0x243185be4ee4b28c), U64(0x550c7dc3d5ffb4e2), + U64(0x72be5d74f27b896f), U64(0x80deb1fe3b1696b1), + U64(0x9bdc06a725c71235), U64(0xc19bf174cf692694), + U64(0xe49b69c19ef14ad2), U64(0xefbe4786384f25e3), + U64(0x0fc19dc68b8cd5b5), U64(0x240ca1cc77ac9c65), + U64(0x2de92c6f592b0275), U64(0x4a7484aa6ea6e483), + U64(0x5cb0a9dcbd41fbd4), U64(0x76f988da831153b5), + U64(0x983e5152ee66dfab), U64(0xa831c66d2db43210), + U64(0xb00327c898fb213f), U64(0xbf597fc7beef0ee4), + U64(0xc6e00bf33da88fc2), U64(0xd5a79147930aa725), + U64(0x06ca6351e003826f), U64(0x142929670a0e6e70), + U64(0x27b70a8546d22ffc), U64(0x2e1b21385c26c926), + U64(0x4d2c6dfc5ac42aed), U64(0x53380d139d95b3df), + U64(0x650a73548baf63de), U64(0x766a0abb3c77b2a8), + U64(0x81c2c92e47edaee6), U64(0x92722c851482353b), + U64(0xa2bfe8a14cf10364), U64(0xa81a664bbc423001), + U64(0xc24b8b70d0f89791), U64(0xc76c51a30654be30), + U64(0xd192e819d6ef5218), U64(0xd69906245565a910), + U64(0xf40e35855771202a), U64(0x106aa07032bbd1b8), + U64(0x19a4c116b8d2d0c8), U64(0x1e376c085141ab53), + U64(0x2748774cdf8eeb99), U64(0x34b0bcb5e19b48a8), + U64(0x391c0cb3c5c95a63), U64(0x4ed8aa4ae3418acb), + U64(0x5b9cca4f7763e373), U64(0x682e6ff3d6b2b8a3), + U64(0x748f82ee5defb2fc), U64(0x78a5636f43172f60), + U64(0x84c87814a1f0ab72), U64(0x8cc702081a6439ec), + U64(0x90befffa23631e28), U64(0xa4506cebde82bde9), + U64(0xbef9a3f7b2c67915), U64(0xc67178f2e372532b), + U64(0xca273eceea26619c), U64(0xd186b8c721c0c207), + U64(0xeada7dd6cde0eb1e), U64(0xf57d4f7fee6ed178), + U64(0x06f067aa72176fba), U64(0x0a637dc5a2c898a6), + U64(0x113f9804bef90dae), U64(0x1b710b35131c471b), + U64(0x28db77f523047d84), U64(0x32caab7b40c72493), + U64(0x3c9ebe0a15c9bebc), U64(0x431d67c49c100d4c), + U64(0x4cc5d4becb3e42b6), U64(0x597f299cfc657e2a), + U64(0x5fcb6fab3ad6faec), U64(0x6c44198c4a475817) }; /* * Transform the message W which consists of 16 64-bit-words */ static uint -sha512_transform_block(struct sha512_state *hd, const byte *data) +sha512_transform(struct sha512_context *ctx, const byte *data) { u64 a, b, c, d, e, f, g, h; u64 w[16]; - int t; + uint t; /* get values from the chaining vars */ - a = hd->h0; - b = hd->h1; - c = hd->h2; - d = hd->h3; - e = hd->h4; - f = hd->h5; - g = hd->h6; - h = hd->h7; + a = ctx->h0; + b = ctx->h1; + c = ctx->h2; + d = ctx->h3; + e = ctx->h4; + f = ctx->h5; + g = ctx->h6; + h = ctx->h7; - for ( t = 0; t < 16; t++ ) + for (t = 0; t < 16; t++) w[t] = get_u64(data + t * 8); #define S0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) @@ -175,10 +160,10 @@ sha512_transform_block(struct sha512_state *hd, const byte *data) Unrolled with macros: 350ms Unrolled with inline: 330ms */ -#if 0 /* Not unrolled. */ - t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[t%16]; - w[t%16] += S1 (w[(t - 2)%16]) + w[(t - 7)%16] + S0 (w[(t - 15)%16]); - t2 = Sum0 (a) + Maj(a, b, c); +#ifndef SHA512_UNROLLED + t1 = h + sum1(e) + Ch(e, f, g) + k[t] + w[t%16]; + w[t%16] += S1(w[(t - 2)%16]) + w[(t - 7)%16] + S0(w[(t - 15)%16]); + t2 = sum0(a) + Maj(a, b, c); h = g; g = f; f = e; @@ -188,100 +173,100 @@ sha512_transform_block(struct sha512_state *hd, const byte *data) b = a; a = t1 + t2; t++; -#else /* Unrolled to interweave the chain variables. */ - t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[0]; - w[0] += S1 (w[14]) + w[9] + S0 (w[1]); - t2 = Sum0 (a) + Maj(a, b, c); +#else /* Unrolled */ + t1 = h + sum1(e) + Ch(e, f, g) + k[t] + w[0]; + w[0] += S1(w[14]) + w[9] + S0(w[1]); + t2 = sum0(a) + Maj(a, b, c); d += t1; h = t1 + t2; - t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+1] + w[1]; - w[1] += S1 (w[15]) + w[10] + S0 (w[2]); - t2 = Sum0 (h) + Maj(h, a, b); + t1 = g + sum1(d) + Ch(d, e, f) + k[t+1] + w[1]; + w[1] += S1(w[15]) + w[10] + S0(w[2]); + t2 = sum0(h) + Maj(h, a, b); c += t1; g = t1 + t2; - t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+2] + w[2]; - w[2] += S1 (w[0]) + w[11] + S0 (w[3]); - t2 = Sum0 (g) + Maj(g, h, a); + t1 = f + sum1(c) + Ch(c, d, e) + k[t+2] + w[2]; + w[2] += S1(w[0]) + w[11] + S0(w[3]); + t2 = sum0(g) + Maj(g, h, a); b += t1; f = t1 + t2; - t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+3] + w[3]; - w[3] += S1 (w[1]) + w[12] + S0 (w[4]); - t2 = Sum0 (f) + Maj(f, g, h); + t1 = e + sum1(b) + Ch(b, c, d) + k[t+3] + w[3]; + w[3] += S1(w[1]) + w[12] + S0(w[4]); + t2 = sum0(f) + Maj(f, g, h); a += t1; e = t1 + t2; - t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+4] + w[4]; - w[4] += S1 (w[2]) + w[13] + S0 (w[5]); - t2 = Sum0 (e) + Maj(e, f, g); + t1 = d + sum1(a) + Ch(a, b, c) + k[t+4] + w[4]; + w[4] += S1(w[2]) + w[13] + S0(w[5]); + t2 = sum0(e) + Maj(e, f, g); h += t1; d = t1 + t2; - t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+5] + w[5]; - w[5] += S1 (w[3]) + w[14] + S0 (w[6]); - t2 = Sum0 (d) + Maj(d, e, f); + t1 = c + sum1(h) + Ch(h, a, b) + k[t+5] + w[5]; + w[5] += S1(w[3]) + w[14] + S0(w[6]); + t2 = sum0(d) + Maj(d, e, f); g += t1; c = t1 + t2; - t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+6] + w[6]; - w[6] += S1 (w[4]) + w[15] + S0 (w[7]); - t2 = Sum0 (c) + Maj(c, d, e); + t1 = b + sum1(g) + Ch(g, h, a) + k[t+6] + w[6]; + w[6] += S1(w[4]) + w[15] + S0(w[7]); + t2 = sum0(c) + Maj(c, d, e); f += t1; b = t1 + t2; - t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+7] + w[7]; - w[7] += S1 (w[5]) + w[0] + S0 (w[8]); - t2 = Sum0 (b) + Maj(b, c, d); + t1 = a + sum1(f) + Ch(f, g, h) + k[t+7] + w[7]; + w[7] += S1(w[5]) + w[0] + S0(w[8]); + t2 = sum0(b) + Maj(b, c, d); e += t1; a = t1 + t2; - t1 = h + Sum1 (e) + Ch(e, f, g) + k[t+8] + w[8]; - w[8] += S1 (w[6]) + w[1] + S0 (w[9]); - t2 = Sum0 (a) + Maj(a, b, c); + t1 = h + sum1(e) + Ch(e, f, g) + k[t+8] + w[8]; + w[8] += S1(w[6]) + w[1] + S0(w[9]); + t2 = sum0(a) + Maj(a, b, c); d += t1; h = t1 + t2; - t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+9] + w[9]; - w[9] += S1 (w[7]) + w[2] + S0 (w[10]); - t2 = Sum0 (h) + Maj(h, a, b); + t1 = g + sum1(d) + Ch(d, e, f) + k[t+9] + w[9]; + w[9] += S1(w[7]) + w[2] + S0(w[10]); + t2 = sum0(h) + Maj(h, a, b); c += t1; g = t1 + t2; - t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+10] + w[10]; - w[10] += S1 (w[8]) + w[3] + S0 (w[11]); - t2 = Sum0 (g) + Maj(g, h, a); + t1 = f + sum1(c) + Ch(c, d, e) + k[t+10] + w[10]; + w[10] += S1(w[8]) + w[3] + S0(w[11]); + t2 = sum0(g) + Maj(g, h, a); b += t1; f = t1 + t2; - t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+11] + w[11]; - w[11] += S1 (w[9]) + w[4] + S0 (w[12]); - t2 = Sum0 (f) + Maj(f, g, h); + t1 = e + sum1(b) + Ch(b, c, d) + k[t+11] + w[11]; + w[11] += S1(w[9]) + w[4] + S0(w[12]); + t2 = sum0(f) + Maj(f, g, h); a += t1; e = t1 + t2; - t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+12] + w[12]; - w[12] += S1 (w[10]) + w[5] + S0 (w[13]); - t2 = Sum0 (e) + Maj(e, f, g); + t1 = d + sum1(a) + Ch(a, b, c) + k[t+12] + w[12]; + w[12] += S1(w[10]) + w[5] + S0(w[13]); + t2 = sum0(e) + Maj(e, f, g); h += t1; d = t1 + t2; - t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+13] + w[13]; - w[13] += S1 (w[11]) + w[6] + S0 (w[14]); - t2 = Sum0 (d) + Maj(d, e, f); + t1 = c + sum1(h) + Ch(h, a, b) + k[t+13] + w[13]; + w[13] += S1(w[11]) + w[6] + S0(w[14]); + t2 = sum0(d) + Maj(d, e, f); g += t1; c = t1 + t2; - t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+14] + w[14]; - w[14] += S1 (w[12]) + w[7] + S0 (w[15]); - t2 = Sum0 (c) + Maj(c, d, e); + t1 = b + sum1(g) + Ch(g, h, a) + k[t+14] + w[14]; + w[14] += S1(w[12]) + w[7] + S0(w[15]); + t2 = sum0(c) + Maj(c, d, e); f += t1; b = t1 + t2; - t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+15] + w[15]; - w[15] += S1 (w[13]) + w[8] + S0 (w[0]); - t2 = Sum0 (b) + Maj(b, c, d); + t1 = a + sum1(f) + Ch(f, g, h) + k[t+15] + w[15]; + w[15] += S1(w[13]) + w[8] + S0(w[0]); + t2 = sum0(b) + Maj(b, c, d); e += t1; a = t1 + t2; @@ -293,9 +278,9 @@ sha512_transform_block(struct sha512_state *hd, const byte *data) { u64 t1, t2; -#if 0 /* Not unrolled. */ - t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[t%16]; - t2 = Sum0 (a) + Maj(a, b, c); +#ifndef SHA512_UNROLLED + t1 = h + sum1(e) + Ch(e, f, g) + k[t] + w[t%16]; + t2 = sum0(a) + Maj(a, b, c); h = g; g = f; f = e; @@ -305,84 +290,84 @@ sha512_transform_block(struct sha512_state *hd, const byte *data) b = a; a = t1 + t2; t++; -#else /* Unrolled to interweave the chain variables. */ - t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[0]; - t2 = Sum0 (a) + Maj(a, b, c); +#else /* Unrolled */ + t1 = h + sum1(e) + Ch(e, f, g) + k[t] + w[0]; + t2 = sum0(a) + Maj(a, b, c); d += t1; h = t1 + t2; - t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+1] + w[1]; - t2 = Sum0 (h) + Maj(h, a, b); + t1 = g + sum1(d) + Ch(d, e, f) + k[t+1] + w[1]; + t2 = sum0(h) + Maj(h, a, b); c += t1; g = t1 + t2; - t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+2] + w[2]; - t2 = Sum0 (g) + Maj(g, h, a); + t1 = f + sum1(c) + Ch(c, d, e) + k[t+2] + w[2]; + t2 = sum0(g) + Maj(g, h, a); b += t1; f = t1 + t2; - t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+3] + w[3]; - t2 = Sum0 (f) + Maj(f, g, h); + t1 = e + sum1(b) + Ch(b, c, d) + k[t+3] + w[3]; + t2 = sum0(f) + Maj(f, g, h); a += t1; e = t1 + t2; - t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+4] + w[4]; - t2 = Sum0 (e) + Maj(e, f, g); + t1 = d + sum1(a) + Ch(a, b, c) + k[t+4] + w[4]; + t2 = sum0(e) + Maj(e, f, g); h += t1; d = t1 + t2; - t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+5] + w[5]; - t2 = Sum0 (d) + Maj(d, e, f); + t1 = c + sum1(h) + Ch(h, a, b) + k[t+5] + w[5]; + t2 = sum0(d) + Maj(d, e, f); g += t1; c = t1 + t2; - t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+6] + w[6]; - t2 = Sum0 (c) + Maj(c, d, e); + t1 = b + sum1(g) + Ch(g, h, a) + k[t+6] + w[6]; + t2 = sum0(c) + Maj(c, d, e); f += t1; b = t1 + t2; - t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+7] + w[7]; - t2 = Sum0 (b) + Maj(b, c, d); + t1 = a + sum1(f) + Ch(f, g, h) + k[t+7] + w[7]; + t2 = sum0(b) + Maj(b, c, d); e += t1; a = t1 + t2; - t1 = h + Sum1 (e) + Ch(e, f, g) + k[t+8] + w[8]; - t2 = Sum0 (a) + Maj(a, b, c); + t1 = h + sum1(e) + Ch(e, f, g) + k[t+8] + w[8]; + t2 = sum0(a) + Maj(a, b, c); d += t1; h = t1 + t2; - t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+9] + w[9]; - t2 = Sum0 (h) + Maj(h, a, b); + t1 = g + sum1(d) + Ch(d, e, f) + k[t+9] + w[9]; + t2 = sum0(h) + Maj(h, a, b); c += t1; g = t1 + t2; - t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+10] + w[10]; - t2 = Sum0 (g) + Maj(g, h, a); + t1 = f + sum1(c) + Ch(c, d, e) + k[t+10] + w[10]; + t2 = sum0(g) + Maj(g, h, a); b += t1; f = t1 + t2; - t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+11] + w[11]; - t2 = Sum0 (f) + Maj(f, g, h); + t1 = e + sum1(b) + Ch(b, c, d) + k[t+11] + w[11]; + t2 = sum0(f) + Maj(f, g, h); a += t1; e = t1 + t2; - t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+12] + w[12]; - t2 = Sum0 (e) + Maj(e, f, g); + t1 = d + sum1(a) + Ch(a, b, c) + k[t+12] + w[12]; + t2 = sum0(e) + Maj(e, f, g); h += t1; d = t1 + t2; - t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+13] + w[13]; - t2 = Sum0 (d) + Maj(d, e, f); + t1 = c + sum1(h) + Ch(h, a, b) + k[t+13] + w[13]; + t2 = sum0(d) + Maj(d, e, f); g += t1; c = t1 + t2; - t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+14] + w[14]; - t2 = Sum0 (c) + Maj(c, d, e); + t1 = b + sum1(g) + Ch(g, h, a) + k[t+14] + w[14]; + t2 = sum0(c) + Maj(c, d, e); f += t1; b = t1 + t2; - t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+15] + w[15]; - t2 = Sum0 (b) + Maj(b, c, d); + t1 = a + sum1(f) + Ch(f, g, h) + k[t+15] + w[15]; + t2 = sum0(b) + Maj(b, c, d); e += t1; a = t1 + t2; @@ -391,61 +376,77 @@ sha512_transform_block(struct sha512_state *hd, const byte *data) } /* Update chaining vars. */ - hd->h0 += a; - hd->h1 += b; - hd->h2 += c; - hd->h3 += d; - hd->h4 += e; - hd->h5 += f; - hd->h6 += g; - hd->h7 += h; + ctx->h0 += a; + ctx->h1 += b; + ctx->h2 += c; + ctx->h3 += d; + ctx->h4 += e; + ctx->h5 += f; + ctx->h6 += g; + ctx->h7 += h; return /* burn_stack */ (8 + 16) * sizeof(u64) + sizeof(u32) + 3 * sizeof(void*); } -static uint -sha512_transform(void *context, const byte *data, size_t nblks) +void +sha512_update(struct sha512_context *ctx, const byte *buf, size_t len) { - struct sha512_context *ctx = context; - uint burn; - - do + if (ctx->count) { - burn = sha512_transform_block(&ctx->state, data) + 3 * sizeof(void*); - data += 128; - } - while(--nblks); + /* Fill rest of internal buffer */ + for (; len && ctx->count < SHA512_BLOCK_SIZE; len--) + ctx->buf[ctx->count++] = *buf++; - return burn; + if (ctx->count < SHA512_BLOCK_SIZE) + return; + + /* Process data from internal buffer */ + sha512_transform(ctx, ctx->buf); + ctx->nblocks++; + ctx->count = 0; + } + + if (!len) + return; + + /* Process data from input buffer */ + while (len >= SHA512_BLOCK_SIZE) + { + sha512_transform(ctx, buf); + ctx->nblocks++; + buf += SHA512_BLOCK_SIZE; + len -= SHA512_BLOCK_SIZE; + } + + /* Copy remaining data to internal buffer */ + memcpy(ctx->buf, buf, len); + ctx->count = len; } -/* The routine final terminates the computation and - * returns the digest. - * The handle is prepared for a new cycle, but adding bytes to the - * handle will the destroy the returned buffer. - * Returns: 64 bytes representing the digest. When used for sha384, - * we take the leftmost 48 of those bytes. +/* + * The routine final terminates the computation and returns the digest. The + * handle is prepared for a new cycle, but adding bytes to the handle will the + * destroy the returned buffer. + * + * Returns: 64 bytes representing the digest. When used for sha384, we take the + * first 48 of those bytes. */ byte * sha512_final(struct sha512_context *ctx) { u64 t, th, msb, lsb; - byte *p; - sha256_update(&ctx->bctx, NULL, 0); /* flush */ ; + sha512_update(ctx, NULL, 0); /* flush */ - t = ctx->bctx.nblocks; - /* if (sizeof t == sizeof ctx->bctx.nblocks) */ - th = ctx->bctx.nblocks_high; - /* else */ - /* th = ctx->bctx.nblocks >> 64; In case we ever use u128 */ + t = ctx->nblocks; + th = 0; /* multiply by 128 to make a byte count */ lsb = t << 7; msb = (th << 7) | (t >> 57); /* add the count */ t = lsb; - if ((lsb += ctx->bctx.count) < t) + if ((lsb += ctx->count) < t) msb++; /* multiply by 8 to make a bit count */ t = lsb; @@ -453,55 +454,56 @@ sha512_final(struct sha512_context *ctx) msb <<= 3; msb |= t >> 61; - if (ctx->bctx.count < 112) - { /* enough room */ - ctx->bctx.buf[ctx->bctx.count++] = 0x80; /* pad */ - while(ctx->bctx.count < 112) - ctx->bctx.buf[ctx->bctx.count++] = 0; /* pad */ + if (ctx->count < 112) + { + /* enough room */ + ctx->buf[ctx->count++] = 0x80; /* pad */ + while(ctx->count < 112) + ctx->buf[ctx->count++] = 0; /* pad */ } else - { /* need one extra block */ - ctx->bctx.buf[ctx->bctx.count++] = 0x80; /* pad character */ - while(ctx->bctx.count < 128) - ctx->bctx.buf[ctx->bctx.count++] = 0; - sha256_update(&ctx->bctx, NULL, 0); /* flush */ ; - memset(ctx->bctx.buf, 0, 112); /* fill next block with zeroes */ + { + /* need one extra block */ + ctx->buf[ctx->count++] = 0x80; /* pad character */ + while(ctx->count < 128) + ctx->buf[ctx->count++] = 0; + sha512_update(ctx, NULL, 0); /* flush */ + memset(ctx->buf, 0, 112); /* fill next block with zeroes */ } - /* append the 128 bit count */ - put_u64(ctx->bctx.buf + 112, msb); - put_u64(ctx->bctx.buf + 120, lsb); - sha512_transform(ctx, ctx->bctx.buf, 1); - p = ctx->bctx.buf; -#define X(a) do { put_u64(p, ctx->state.h##a); p += 8; } while(0) - X (0); - X (1); - X (2); - X (3); - X (4); - X (5); - /* Note that these last two chunks are included even for SHA384. - We just ignore them. */ - X (6); - X (7); + /* append the 128 bit count */ + put_u64(ctx->buf + 112, msb); + put_u64(ctx->buf + 120, lsb); + sha512_transform(ctx, ctx->buf); + + byte *p = ctx->buf; +#define X(a) do { put_u64(p, ctx->h##a); p += 8; } while(0) + X(0); + X(1); + X(2); + X(3); + X(4); + X(5); + X(6); + X(7); #undef X - return ctx->bctx.buf; + return ctx->buf; } /* - * SHA512-HMAC + * SHA512-HMAC */ static void sha512_hash_buffer(byte *outbuf, const byte *buffer, size_t length) { - struct sha512_context hd_tmp; + struct sha512_context ctx; - sha512_init(&hd_tmp); - sha512_update(&hd_tmp, buffer, length); - memcpy(outbuf, sha512_final(&hd_tmp), SHA512_SIZE); + sha512_init(&ctx); + sha512_update(&ctx, buffer, length); + memcpy(outbuf, sha512_final(&ctx), SHA512_SIZE); } void @@ -513,12 +515,12 @@ sha512_hmac_init(struct sha512_hmac_context *ctx, const byte *key, size_t keylen if (keylen <= SHA512_BLOCK_SIZE) { memcpy(keybuf, key, keylen); - bzero(keybuf + keylen, SHA512_BLOCK_SIZE - keylen); + memset(keybuf + keylen, 0, SHA512_BLOCK_SIZE - keylen); } else { sha512_hash_buffer(keybuf, key, keylen); - bzero(keybuf + SHA512_SIZE, SHA512_BLOCK_SIZE - SHA512_SIZE); + memset(keybuf + SHA512_SIZE, 0, SHA512_BLOCK_SIZE - SHA512_SIZE); } /* Initialize the inner digest */ @@ -535,13 +537,15 @@ sha512_hmac_init(struct sha512_hmac_context *ctx, const byte *key, size_t keylen sha512_update(&ctx->octx, buf, SHA512_BLOCK_SIZE); } -void sha512_hmac_update(struct sha512_hmac_context *ctx, const byte *buf, size_t buflen) +void +sha512_hmac_update(struct sha512_hmac_context *ctx, const byte *buf, size_t buflen) { /* Just update the inner digest */ sha512_update(&ctx->ictx, buf, buflen); } -byte *sha512_hmac_final(struct sha512_hmac_context *ctx) +byte * +sha512_hmac_final(struct sha512_hmac_context *ctx) { /* Finish the inner digest */ byte *isha = sha512_final(&ctx->ictx); @@ -553,17 +557,17 @@ byte *sha512_hmac_final(struct sha512_hmac_context *ctx) /* - * SHA384-HMAC + * SHA384-HMAC */ static void sha384_hash_buffer(byte *outbuf, const byte *buffer, size_t length) { - struct sha384_context hd_tmp; + struct sha384_context ctx; - sha384_init(&hd_tmp); - sha384_update(&hd_tmp, buffer, length); - memcpy(outbuf, sha384_final(&hd_tmp), SHA384_SIZE); + sha384_init(&ctx); + sha384_update(&ctx, buffer, length); + memcpy(outbuf, sha384_final(&ctx), SHA384_SIZE); } void @@ -575,12 +579,12 @@ sha384_hmac_init(struct sha384_hmac_context *ctx, const byte *key, size_t keylen if (keylen <= SHA384_BLOCK_SIZE) { memcpy(keybuf, key, keylen); - bzero(keybuf + keylen, SHA384_BLOCK_SIZE - keylen); + memset(keybuf + keylen, 0, SHA384_BLOCK_SIZE - keylen); } else { sha384_hash_buffer(keybuf, key, keylen); - bzero(keybuf + SHA384_SIZE, SHA384_BLOCK_SIZE - SHA384_SIZE); + memset(keybuf + SHA384_SIZE, 0, SHA384_BLOCK_SIZE - SHA384_SIZE); } /* Initialize the inner digest */ @@ -597,13 +601,15 @@ sha384_hmac_init(struct sha384_hmac_context *ctx, const byte *key, size_t keylen sha384_update(&ctx->octx, buf, SHA384_BLOCK_SIZE); } -void sha384_hmac_update(struct sha384_hmac_context *ctx, const byte *buf, size_t buflen) +void +sha384_hmac_update(struct sha384_hmac_context *ctx, const byte *buf, size_t buflen) { /* Just update the inner digest */ sha384_update(&ctx->ictx, buf, buflen); } -byte *sha384_hmac_final(struct sha384_hmac_context *ctx) +byte * +sha384_hmac_final(struct sha384_hmac_context *ctx) { /* Finish the inner digest */ byte *isha = sha384_final(&ctx->ictx); diff --git a/lib/sha512.h b/lib/sha512.h index bd998152..1614a3ac 100644 --- a/lib/sha512.h +++ b/lib/sha512.h @@ -13,7 +13,8 @@ #ifndef _BIRD_SHA512_H_ #define _BIRD_SHA512_H_ -#include "lib/sha256.h" +#include "nest/bird.h" + #define SHA384_SIZE 48 #define SHA384_HEX_SIZE 97 @@ -23,43 +24,41 @@ #define SHA512_HEX_SIZE 129 #define SHA512_BLOCK_SIZE 128 -struct sha512_state -{ + +struct sha512_context { u64 h0, h1, h2, h3, h4, h5, h6, h7; + byte buf[SHA512_BLOCK_SIZE]; + uint nblocks; + uint count; }; -struct sha512_context -{ - struct sha256_context bctx; - struct sha512_state state; -}; -#define sha384_context sha512_context /* aliasing 'struct sha384_context' to 'struct sha512_context' */ +#define sha384_context sha512_context void sha512_init(struct sha512_context *ctx); void sha384_init(struct sha384_context *ctx); -void sha512_update(struct sha512_context *ctx, const byte *in_buf, size_t in_len); -static inline void sha384_update(struct sha384_context *ctx, const byte *in_buf, size_t in_len) -{ - sha512_update(ctx, in_buf, in_len); -} +void sha512_update(struct sha512_context *ctx, const byte *buf, size_t len); +static inline void sha384_update(struct sha384_context *ctx, const byte *buf, size_t len) +{ sha512_update(ctx, buf, len); } + +byte *sha512_final(struct sha512_context *ctx); +static inline byte *sha384_final(struct sha384_context *ctx) +{ return sha512_final(ctx); } -byte* sha512_final(struct sha512_context *ctx); -static inline byte* sha384_final(struct sha384_context *ctx) -{ - return sha512_final(ctx); -} /* * HMAC-SHA512, HMAC-SHA384 */ + struct sha512_hmac_context { struct sha512_context ictx; struct sha512_context octx; -} ; -#define sha384_hmac_context sha512_hmac_context /* aliasing 'struct sha384_hmac_context' to 'struct sha384_hmac_context' */ +}; + +#define sha384_hmac_context sha512_hmac_context + void sha512_hmac_init(struct sha512_hmac_context *ctx, const byte *key, size_t keylen); void sha384_hmac_init(struct sha384_hmac_context *ctx, const byte *key, size_t keylen); @@ -70,4 +69,5 @@ void sha384_hmac_update(struct sha384_hmac_context *ctx, const byte *buf, size_t byte *sha512_hmac_final(struct sha512_hmac_context *ctx); byte *sha384_hmac_final(struct sha384_hmac_context *ctx); + #endif /* _BIRD_SHA512_H_ */ From e422ca0f292d08a873deacdbffbb6c6cbd79f88a Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 24 Nov 2015 13:52:26 +0100 Subject: [PATCH 13/14] Some consts for function arguments Patch from Pavel Tvrdik --- lib/ip.c | 6 +++--- lib/ip.h | 4 ++-- lib/patmatch.c | 2 +- lib/string.h | 2 +- lib/unaligned.h | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/ip.c b/lib/ip.c index e1bfba49..2061a1f7 100644 --- a/lib/ip.c +++ b/lib/ip.c @@ -233,7 +233,7 @@ ip6_ntop(ip6_addr a, char *b) } int -ip4_pton(char *a, ip4_addr *o) +ip4_pton(const char *a, ip4_addr *o) { int i; unsigned long int l; @@ -258,11 +258,11 @@ ip4_pton(char *a, ip4_addr *o) } int -ip6_pton(char *a, ip6_addr *o) +ip6_pton(const char *a, ip6_addr *o) { u16 words[8]; int i, j, k, l, hfil; - char *start; + const char *start; if (a[0] == ':') /* Leading :: */ { diff --git a/lib/ip.h b/lib/ip.h index 90bb7f8a..e33adc6e 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -446,8 +446,8 @@ static inline char * ip4_ntox(ip4_addr a, char *b) static inline char * ip6_ntox(ip6_addr a, char *b) { return b + bsprintf(b, "%08x.%08x.%08x.%08x", _I0(a), _I1(a), _I2(a), _I3(a)); } -int ip4_pton(char *a, ip4_addr *o); -int ip6_pton(char *a, ip6_addr *o); +int ip4_pton(const char *a, ip4_addr *o); +int ip6_pton(const char *a, ip6_addr *o); // XXXX these functions must be redesigned or removed #ifdef IPV6 diff --git a/lib/patmatch.c b/lib/patmatch.c index 923e8f86..d2e1e313 100644 --- a/lib/patmatch.c +++ b/lib/patmatch.c @@ -16,7 +16,7 @@ #endif int -MATCH_FUNC_NAME(byte *p, byte *s) +MATCH_FUNC_NAME(const byte *p, const byte *s) { while (*p) { diff --git a/lib/string.h b/lib/string.h index 528a1a19..218f7b1c 100644 --- a/lib/string.h +++ b/lib/string.h @@ -22,6 +22,6 @@ int buffer_vprint(buffer *buf, const char *fmt, va_list args); int buffer_print(buffer *buf, const char *fmt, ...); void buffer_puts(buffer *buf, const char *str); -int patmatch(byte *pat, byte *str); +int patmatch(const byte *pat, const byte *str); #endif diff --git a/lib/unaligned.h b/lib/unaligned.h index a2dbae4f..dc777fbf 100644 --- a/lib/unaligned.h +++ b/lib/unaligned.h @@ -20,7 +20,7 @@ #include "lib/string.h" static inline u16 -get_u16(void *p) +get_u16(const void *p) { u16 x; memcpy(&x, p, 2); @@ -28,7 +28,7 @@ get_u16(void *p) } static inline u32 -get_u32(void *p) +get_u32(const void *p) { u32 x; memcpy(&x, p, 4); From ad27615760e2795da3efe5e97c0e888281d5ca59 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Tue, 10 Nov 2015 14:59:41 +0100 Subject: [PATCH 14/14] Netlink: attribute validation before parsing Wanted netlink attributes are defined in a table, specifying their size and neediness. Removing the long conditions that did the validation before. Also parsing IPv4 and IPv6 versions regardless on the IPV6 macro. --- sysdep/linux/netlink.c | 191 ++++++++++++++++++++++++++++++----------- 1 file changed, 143 insertions(+), 48 deletions(-) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index efbf41a6..640d1877 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -226,24 +226,98 @@ nl_checkin(struct nlmsghdr *h, int lsize) return NLMSG_DATA(h); } +struct nl_want_attrs { + u8 defined:1; + u8 checksize:1; + u8 size; +}; + + +#define BIRD_IFLA_MAX (IFLA_WIRELESS+1) + +static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = { + [IFLA_IFNAME] = { 1, 0, 0 }, + [IFLA_MTU] = { 1, 1, sizeof(u32) }, + [IFLA_WIRELESS] = { 1, 0, 0 }, +}; + + +#define BIRD_IFA_MAX (IFA_ANYCAST+1) + +#ifndef IPV6 +static struct nl_want_attrs ifa_attr_want4[BIRD_IFA_MAX] = { + [IFA_ADDRESS] = { 1, 1, sizeof(ip4_addr) }, + [IFA_LOCAL] = { 1, 1, sizeof(ip4_addr) }, + [IFA_BROADCAST] = { 1, 1, sizeof(ip4_addr) }, +}; +#else +static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = { + [IFA_ADDRESS] = { 1, 1, sizeof(ip6_addr) }, + [IFA_LOCAL] = { 1, 1, sizeof(ip6_addr) }, +}; +#endif + + +#define BIRD_RTA_MAX (RTA_TABLE+1) + +static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = { + [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) }, +}; + +#ifndef IPV6 +static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = { + [RTA_DST] = { 1, 1, sizeof(ip4_addr) }, + [RTA_OIF] = { 1, 1, sizeof(u32) }, + [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) }, + [RTA_PRIORITY] = { 1, 1, sizeof(u32) }, + [RTA_PREFSRC] = { 1, 1, sizeof(ip4_addr) }, + [RTA_METRICS] = { 1, 0, 0 }, + [RTA_MULTIPATH] = { 1, 0, 0 }, + [RTA_FLOW] = { 1, 1, sizeof(u32) }, + [RTA_TABLE] = { 1, 1, sizeof(u32) }, +}; +#else +static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = { + [RTA_DST] = { 1, 1, sizeof(ip6_addr) }, + [RTA_IIF] = { 1, 1, sizeof(u32) }, + [RTA_OIF] = { 1, 1, sizeof(u32) }, + [RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) }, + [RTA_PRIORITY] = { 1, 1, sizeof(u32) }, + [RTA_PREFSRC] = { 1, 1, sizeof(ip6_addr) }, + [RTA_METRICS] = { 1, 0, 0 }, + [RTA_FLOW] = { 1, 1, sizeof(u32) }, + [RTA_TABLE] = { 1, 1, sizeof(u32) }, +}; +#endif + + static int -nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize) +nl_parse_attrs(struct rtattr *a, struct nl_want_attrs *want, struct rtattr **k, int ksize) { int max = ksize / sizeof(struct rtattr *); bzero(k, ksize); - while (RTA_OK(a, nl_attr_len)) + + for ( ; RTA_OK(a, nl_attr_len); a = RTA_NEXT(a, nl_attr_len)) { - if (a->rta_type < max) - k[a->rta_type] = a; - a = RTA_NEXT(a, nl_attr_len); + if ((a->rta_type >= max) || !want[a->rta_type].defined) + continue; + + if (want[a->rta_type].checksize && (RTA_PAYLOAD(a) != want[a->rta_type].size)) + { + log(L_ERR "nl_parse_attrs: Malformed message received"); + return 0; + } + + k[a->rta_type] = a; } + if (nl_attr_len) { log(L_ERR "nl_parse_attrs: remnant of size %d", nl_attr_len); return 0; } - else - return 1; + + return 1; } static inline u32 rta_get_u32(struct rtattr *a) @@ -350,7 +424,7 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra) static int nh_buf_size; /* in number of structures */ static int nh_buf_used; - struct rtattr *a[RTA_CACHEINFO+1]; + struct rtattr *a[BIRD_RTA_MAX]; struct rtnexthop *nh = RTA_DATA(ra); struct mpnh *rv, *first, **last; int len = RTA_PAYLOAD(ra); @@ -381,12 +455,9 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra) /* Nonexistent RTNH_PAYLOAD ?? */ nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0); - nl_parse_attrs(RTNH_DATA(nh), a, sizeof(a)); + nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a)); if (a[RTA_GATEWAY]) { - if (RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)) - return NULL; - memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ip_addr)); ipa_ntoh(rv->gw); @@ -455,7 +526,7 @@ static void nl_parse_link(struct nlmsghdr *h, int scan) { struct ifinfomsg *i; - struct rtattr *a[IFLA_WIRELESS+1]; + struct rtattr *a[BIRD_IFLA_MAX]; int new = h->nlmsg_type == RTM_NEWLINK; struct iface f = {}; struct iface *ifi; @@ -463,15 +534,23 @@ nl_parse_link(struct nlmsghdr *h, int scan) u32 mtu; uint fl; - if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), a, sizeof(a))) + if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a))) return; - if (!a[IFLA_IFNAME] || RTA_PAYLOAD(a[IFLA_IFNAME]) < 2 || - !a[IFLA_MTU] || RTA_PAYLOAD(a[IFLA_MTU]) != 4) + if (!a[IFLA_IFNAME] || (RTA_PAYLOAD(a[IFLA_IFNAME]) < 2) || !a[IFLA_MTU]) { - if (scan || !a[IFLA_WIRELESS]) - log(L_ERR "nl_parse_link: Malformed message received"); + /* + * IFLA_IFNAME and IFLA_MTU are required, in fact, but there may also come + * a message with IFLA_WIRELESS set, where (e.g.) no IFLA_IFNAME exists. + * We simply ignore all such messages with IFLA_WIRELESS without notice. + */ + + if (a[IFLA_WIRELESS]) + return; + + log(L_ERR "KIF: Malformed message received"); return; } + name = RTA_DATA(a[IFLA_IFNAME]); mtu = rta_get_u32(a[IFLA_MTU]); @@ -522,26 +601,40 @@ static void nl_parse_addr(struct nlmsghdr *h, int scan) { struct ifaddrmsg *i; - struct rtattr *a[IFA_ANYCAST+1]; + struct rtattr *a[BIRD_IFA_MAX]; int new = h->nlmsg_type == RTM_NEWADDR; struct ifa ifa; struct iface *ifi; int scope; - if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFA_RTA(i), a, sizeof(a))) + if (!(i = nl_checkin(h, sizeof(*i)))) return; - if (i->ifa_family != BIRD_AF) - return; - if (!a[IFA_ADDRESS] || RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip_addr) -#ifdef IPV6 - || a[IFA_LOCAL] && RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr) -#else - || !a[IFA_LOCAL] || RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr) - || (a[IFA_BROADCAST] && RTA_PAYLOAD(a[IFA_BROADCAST]) != sizeof(ip_addr)) -#endif - ) + + switch (i->ifa_family) { - log(L_ERR "nl_parse_addr: Malformed message received"); +#ifndef IPV6 + case AF_INET: + if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a))) + return; + if (!a[IFA_LOCAL]) + { + log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)"); + return; + } + break; +#else + case AF_INET6: + if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a))) + return; + break; +#endif + default: + return; + } + + if (!a[IFA_ADDRESS]) + { + log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)"); return; } @@ -835,7 +928,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) { struct krt_proto *p; struct rtmsg *i; - struct rtattr *a[RTA_TABLE+1]; + struct rtattr *a[BIRD_RTA_MAX]; int new = h->nlmsg_type == RTM_NEWROUTE; ip_addr dst = IPA_NONE; @@ -843,25 +936,27 @@ nl_parse_route(struct nlmsghdr *h, int scan) u32 table; int src; - if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a))) + if (!(i = nl_checkin(h, sizeof(*i)))) return; - if (i->rtm_family != BIRD_AF) - return; - if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) || -#ifdef IPV6 - (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) || -#endif - (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) || - (a[RTA_TABLE] && RTA_PAYLOAD(a[RTA_TABLE]) != 4) || - (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)) || - (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) || - (a[RTA_PREFSRC] && RTA_PAYLOAD(a[RTA_PREFSRC]) != sizeof(ip_addr)) || - (a[RTA_FLOW] && RTA_PAYLOAD(a[RTA_FLOW]) != 4)) + + switch (i->rtm_family) { - log(L_ERR "KRT: Malformed message received"); - return; +#ifndef IPV6 + case AF_INET: + if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want4, a, sizeof(a))) + return; + break; +#else + case AF_INET6: + if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a))) + return; + break; +#endif + default: + return; } + if (a[RTA_DST]) { memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst)); @@ -938,7 +1033,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) { case RTN_UNICAST: - if (a[RTA_MULTIPATH]) + if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET)) { ra.dest = RTD_MULTIPATH; ra.nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH]);