diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2016-10-27 20:58:21 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2016-11-02 17:53:22 +0100 |
commit | 29239ba2bbee3e9ec7d17793b25936a1bfc795ca (patch) | |
tree | 3e0b5a6d76d9bc508a86b45fb222bcd57999a277 /proto/ospf/packet.c | |
parent | 390601f038b69d5de3841c691f92af0fcd088454 (diff) |
OSPF: Use message authentication interface
Based on former commit from Pavel Tvrdik
Diffstat (limited to 'proto/ospf/packet.c')
-rw-r--r-- | proto/ospf/packet.c | 108 |
1 files changed, 49 insertions, 59 deletions
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index a2fbd089..6b6a97a4 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -32,25 +32,12 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type) pkt->autype = ifa->autype; } -uint -ospf_pkt_maxsize(struct ospf_iface *ifa) -{ - uint headers = SIZE_OF_IP_HEADER; - - /* Relevant just for OSPFv2 */ - if (ifa->autype == OSPF_AUTH_CRYPT) - headers += OSPF_AUTH_CRYPT_SIZE; - - return ifa->tx_length - headers; -} - /* We assume OSPFv2 in ospf_pkt_finalize() */ static void -ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) +ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen) { - struct password_item *passwd = NULL; + struct password_item *pass = NULL; union ospf_auth *auth = (void *) (pkt + 1); - uint plen = ntohs(pkt->length); pkt->checksum = 0; pkt->autype = ifa->autype; @@ -62,25 +49,25 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) switch (ifa->autype) { case OSPF_AUTH_SIMPLE: - passwd = password_find(ifa->passwords, 1); - if (!passwd) + pass = password_find(ifa->passwords, 1); + if (!pass) { log(L_ERR "No suitable password found for authentication"); return; } - strncpy(auth->password, passwd->password, sizeof(auth->password)); + strncpy(auth->password, pass->password, sizeof(auth->password)); case OSPF_AUTH_NONE: { void *body = (void *) (auth + 1); - uint blen = plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth); + uint blen = *plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth); pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL); } break; case OSPF_AUTH_CRYPT: - passwd = password_find(ifa->passwords, 0); - if (!passwd) + pass = password_find(ifa->passwords, 0); + if (!pass) { log(L_ERR "No suitable password found for authentication"); return; @@ -101,20 +88,25 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) ifa->csn_use = now; - auth->md5.zero = 0; - auth->md5.keyid = passwd->id; - auth->md5.len = OSPF_AUTH_CRYPT_SIZE; - auth->md5.csn = htonl(ifa->csn); + uint auth_len = mac_type_length(pass->alg); + byte *auth_tail = ((byte *) pkt + *plen); + *plen += auth_len; + + ASSERT(*plen < ifa->sk->tbsize); - void *tail = ((void *) pkt) + plen; - char password[OSPF_AUTH_CRYPT_SIZE]; - strncpy(password, passwd->password, sizeof(password)); + auth->c32.zero = 0; + auth->c32.keyid = pass->id; + auth->c32.len = auth_len; + auth->c32.csn = htonl(ifa->csn); - struct hash_context ctx; - md5_init(&ctx); - md5_update(&ctx, (char *) pkt, plen); - md5_update(&ctx, password, OSPF_AUTH_CRYPT_SIZE); - memcpy((byte *) tail, md5_final(&ctx), MD5_SIZE); + /* Append key for keyed hash, append padding for HMAC (RFC 5709 3.3) */ + if (pass->alg < ALG_HMAC) + strncpy(auth_tail, pass->password, auth_len); + else + memset32(auth_tail, HMAC_MAGIC, auth_len / 4); + + mac_fill(pass->alg, pass->password, pass->length, + (byte *) pkt, *plen, auth_tail); break; default: @@ -155,13 +147,19 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ return 1; case OSPF_AUTH_CRYPT: - if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE) - DROP("invalid MD5 digest length", auth->md5.len); + pass = password_find_by_id(ifa->passwords, auth->c32.keyid); + if (!pass) + DROP("no suitable password found", auth->c32.keyid); + + uint auth_len = mac_type_length(pass->alg); - if (plen + OSPF_AUTH_CRYPT_SIZE > len) - DROP("length mismatch", len); + if (plen + auth->c32.len > len) + DROP("packet length mismatch", len); - u32 rcv_csn = ntohl(auth->md5.csn); + if (auth->c32.len != auth_len) + DROP("wrong authentication length", auth->c32.len); + + u32 rcv_csn = ntohl(auth->c32.csn); if (n && (rcv_csn < n->csn)) // DROP("lower sequence number", rcv_csn); { @@ -172,22 +170,19 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ return 0; } - pass = password_find_by_id(ifa->passwords, auth->md5.keyid); - if (!pass) - DROP("no suitable password found", auth->md5.keyid); - - byte *tail = ((byte *) pkt) + plen; - char received[OSPF_AUTH_CRYPT_SIZE]; - memcpy(received, tail, OSPF_AUTH_CRYPT_SIZE); - strncpy(tail, pass->password, OSPF_AUTH_CRYPT_SIZE); + byte *auth_tail = ((byte *) pkt) + plen; + byte *auth_data = alloca(auth_len); + memcpy(auth_data, auth_tail, auth_len); - struct hash_context ctx; - md5_init(&ctx); - md5_update(&ctx, (byte *) pkt, plen + OSPF_AUTH_CRYPT_SIZE); - char *computed = md5_final(&ctx); + /* Append key for keyed hash, append padding for HMAC (RFC 5709 3.3) */ + if (pass->alg < ALG_HMAC) + strncpy(auth_tail, pass->password, auth_len); + else + memset32(auth_tail, HMAC_MAGIC, auth_len / 4); - if (memcmp(received, computed, OSPF_AUTH_CRYPT_SIZE)) - DROP("wrong MD5 digest", pass->id); + if (!mac_verify(pass->alg, pass->password, pass->length, + (byte *) pkt, plen + auth_len, auth_data)) + DROP("wrong authentication code", pass->id); if (n) n->csn = rcv_csn; @@ -473,15 +468,10 @@ ospf_send_to(struct ospf_iface *ifa, ip_addr dst) { sock *sk = ifa->sk; struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf; - int plen = ntohs(pkt->length); + uint plen = ntohs(pkt->length); if (ospf_is_v2(ifa->oa->po)) - { - if (ifa->autype == OSPF_AUTH_CRYPT) - plen += OSPF_AUTH_CRYPT_SIZE; - - ospf_pkt_finalize(ifa, pkt); - } + ospf_pkt_finalize(ifa, pkt, &plen); int done = sk_send_to(sk, plen, dst, 0); if (!done) |