mptcp: use untruncated hash in ADD_ADDR HMAC

There is some ambiguity in the RFC as to whether the ADD_ADDR HMAC is
the rightmost 64 bits of the entire hash or of the leftmost 160 bits
of the hash.  The intention, as clarified with the author of the RFC,
is the entire hash.

This change returns the entire hash from
mptcp_crypto_hmac_sha (instead of only the first 160 bits), and moves
any truncation/selection operation on the hash to the caller.

Fixes: 12555a2d97 ("mptcp: use rightmost 64 bits in ADD_ADDR HMAC")
Reviewed-by: Christoph Paasch <cpaasch@apple.com>
Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: Todd Malsbary <todd.malsbary@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Todd Malsbary 2020-05-21 19:10:49 -07:00 committed by David S. Miller
parent a7654211d0
commit bd6972226f
4 changed files with 24 additions and 25 deletions

View File

@ -47,8 +47,6 @@ void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn)
void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u8 *msg, int len, void *hmac) void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u8 *msg, int len, void *hmac)
{ {
u8 input[SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE]; u8 input[SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE];
__be32 mptcp_hashed_key[SHA256_DIGEST_WORDS];
__be32 *hash_out = (__force __be32 *)hmac;
struct sha256_state state; struct sha256_state state;
u8 key1be[8]; u8 key1be[8];
u8 key2be[8]; u8 key2be[8];
@ -86,11 +84,7 @@ void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u8 *msg, int len, void *hmac)
sha256_init(&state); sha256_init(&state);
sha256_update(&state, input, SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE); sha256_update(&state, input, SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE);
sha256_final(&state, (u8 *)mptcp_hashed_key); sha256_final(&state, (u8 *)hmac);
/* takes only first 160 bits */
for (i = 0; i < 5; i++)
hash_out[i] = mptcp_hashed_key[i];
} }
#ifdef CONFIG_MPTCP_HMAC_TEST #ifdef CONFIG_MPTCP_HMAC_TEST
@ -101,29 +95,29 @@ struct test_cast {
}; };
/* we can't reuse RFC 4231 test vectors, as we have constraint on the /* we can't reuse RFC 4231 test vectors, as we have constraint on the
* input and key size, and we truncate the output. * input and key size.
*/ */
static struct test_cast tests[] = { static struct test_cast tests[] = {
{ {
.key = "0b0b0b0b0b0b0b0b", .key = "0b0b0b0b0b0b0b0b",
.msg = "48692054", .msg = "48692054",
.result = "8385e24fb4235ac37556b6b886db106284a1da67", .result = "8385e24fb4235ac37556b6b886db106284a1da671699f46db1f235ec622dcafa",
}, },
{ {
.key = "aaaaaaaaaaaaaaaa", .key = "aaaaaaaaaaaaaaaa",
.msg = "dddddddd", .msg = "dddddddd",
.result = "2c5e219164ff1dca1c4a92318d847bb6b9d44492", .result = "2c5e219164ff1dca1c4a92318d847bb6b9d44492984e1eb71aff9022f71046e9",
}, },
{ {
.key = "0102030405060708", .key = "0102030405060708",
.msg = "cdcdcdcd", .msg = "cdcdcdcd",
.result = "e73b9ba9969969cefb04aa0d6df18ec2fcc075b6", .result = "e73b9ba9969969cefb04aa0d6df18ec2fcc075b6f23b4d8c4da736a5dbbc6e7d",
}, },
}; };
static int __init test_mptcp_crypto(void) static int __init test_mptcp_crypto(void)
{ {
char hmac[20], hmac_hex[41]; char hmac[32], hmac_hex[65];
u32 nonce1, nonce2; u32 nonce1, nonce2;
u64 key1, key2; u64 key1, key2;
u8 msg[8]; u8 msg[8];
@ -140,11 +134,11 @@ static int __init test_mptcp_crypto(void)
put_unaligned_be32(nonce2, &msg[4]); put_unaligned_be32(nonce2, &msg[4]);
mptcp_crypto_hmac_sha(key1, key2, msg, 8, hmac); mptcp_crypto_hmac_sha(key1, key2, msg, 8, hmac);
for (j = 0; j < 20; ++j) for (j = 0; j < 32; ++j)
sprintf(&hmac_hex[j << 1], "%02x", hmac[j] & 0xff); sprintf(&hmac_hex[j << 1], "%02x", hmac[j] & 0xff);
hmac_hex[40] = 0; hmac_hex[64] = 0;
if (memcmp(hmac_hex, tests[i].result, 40)) if (memcmp(hmac_hex, tests[i].result, 64))
pr_err("test %d failed, got %s expected %s", i, pr_err("test %d failed, got %s expected %s", i,
hmac_hex, tests[i].result); hmac_hex, tests[i].result);
else else

View File

@ -7,6 +7,7 @@
#define pr_fmt(fmt) "MPTCP: " fmt #define pr_fmt(fmt) "MPTCP: " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <crypto/sha.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/mptcp.h> #include <net/mptcp.h>
#include "protocol.h" #include "protocol.h"
@ -535,7 +536,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
static u64 add_addr_generate_hmac(u64 key1, u64 key2, u8 addr_id, static u64 add_addr_generate_hmac(u64 key1, u64 key2, u8 addr_id,
struct in_addr *addr) struct in_addr *addr)
{ {
u8 hmac[MPTCP_ADDR_HMAC_LEN]; u8 hmac[SHA256_DIGEST_SIZE];
u8 msg[7]; u8 msg[7];
msg[0] = addr_id; msg[0] = addr_id;
@ -545,14 +546,14 @@ static u64 add_addr_generate_hmac(u64 key1, u64 key2, u8 addr_id,
mptcp_crypto_hmac_sha(key1, key2, msg, 7, hmac); mptcp_crypto_hmac_sha(key1, key2, msg, 7, hmac);
return get_unaligned_be64(&hmac[MPTCP_ADDR_HMAC_LEN - sizeof(u64)]); return get_unaligned_be64(&hmac[SHA256_DIGEST_SIZE - sizeof(u64)]);
} }
#if IS_ENABLED(CONFIG_MPTCP_IPV6) #if IS_ENABLED(CONFIG_MPTCP_IPV6)
static u64 add_addr6_generate_hmac(u64 key1, u64 key2, u8 addr_id, static u64 add_addr6_generate_hmac(u64 key1, u64 key2, u8 addr_id,
struct in6_addr *addr) struct in6_addr *addr)
{ {
u8 hmac[MPTCP_ADDR_HMAC_LEN]; u8 hmac[SHA256_DIGEST_SIZE];
u8 msg[19]; u8 msg[19];
msg[0] = addr_id; msg[0] = addr_id;
@ -562,7 +563,7 @@ static u64 add_addr6_generate_hmac(u64 key1, u64 key2, u8 addr_id,
mptcp_crypto_hmac_sha(key1, key2, msg, 19, hmac); mptcp_crypto_hmac_sha(key1, key2, msg, 19, hmac);
return get_unaligned_be64(&hmac[MPTCP_ADDR_HMAC_LEN - sizeof(u64)]); return get_unaligned_be64(&hmac[SHA256_DIGEST_SIZE - sizeof(u64)]);
} }
#endif #endif

View File

@ -81,7 +81,6 @@
/* MPTCP ADD_ADDR flags */ /* MPTCP ADD_ADDR flags */
#define MPTCP_ADDR_ECHO BIT(0) #define MPTCP_ADDR_ECHO BIT(0)
#define MPTCP_ADDR_HMAC_LEN 20
#define MPTCP_ADDR_IPVERSION_4 4 #define MPTCP_ADDR_IPVERSION_4 4
#define MPTCP_ADDR_IPVERSION_6 6 #define MPTCP_ADDR_IPVERSION_6 6

View File

@ -10,6 +10,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <crypto/algapi.h> #include <crypto/algapi.h>
#include <crypto/sha.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/inet_common.h> #include <net/inet_common.h>
#include <net/inet_hashtables.h> #include <net/inet_hashtables.h>
@ -89,7 +90,7 @@ static bool subflow_token_join_request(struct request_sock *req,
const struct sk_buff *skb) const struct sk_buff *skb)
{ {
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req); struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
u8 hmac[MPTCPOPT_HMAC_LEN]; u8 hmac[SHA256_DIGEST_SIZE];
struct mptcp_sock *msk; struct mptcp_sock *msk;
int local_id; int local_id;
@ -201,7 +202,7 @@ static void subflow_v6_init_req(struct request_sock *req,
/* validate received truncated hmac and create hmac for third ACK */ /* validate received truncated hmac and create hmac for third ACK */
static bool subflow_thmac_valid(struct mptcp_subflow_context *subflow) static bool subflow_thmac_valid(struct mptcp_subflow_context *subflow)
{ {
u8 hmac[MPTCPOPT_HMAC_LEN]; u8 hmac[SHA256_DIGEST_SIZE];
u64 thmac; u64 thmac;
subflow_generate_hmac(subflow->remote_key, subflow->local_key, subflow_generate_hmac(subflow->remote_key, subflow->local_key,
@ -267,6 +268,8 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
subflow->ssn_offset = TCP_SKB_CB(skb)->seq; subflow->ssn_offset = TCP_SKB_CB(skb)->seq;
} }
} else if (subflow->mp_join) { } else if (subflow->mp_join) {
u8 hmac[SHA256_DIGEST_SIZE];
pr_debug("subflow=%p, thmac=%llu, remote_nonce=%u", pr_debug("subflow=%p, thmac=%llu, remote_nonce=%u",
subflow, subflow->thmac, subflow, subflow->thmac,
subflow->remote_nonce); subflow->remote_nonce);
@ -279,7 +282,9 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
subflow_generate_hmac(subflow->local_key, subflow->remote_key, subflow_generate_hmac(subflow->local_key, subflow->remote_key,
subflow->local_nonce, subflow->local_nonce,
subflow->remote_nonce, subflow->remote_nonce,
subflow->hmac); hmac);
memcpy(subflow->hmac, hmac, MPTCPOPT_HMAC_LEN);
if (skb) if (skb)
subflow->ssn_offset = TCP_SKB_CB(skb)->seq; subflow->ssn_offset = TCP_SKB_CB(skb)->seq;
@ -347,7 +352,7 @@ static bool subflow_hmac_valid(const struct request_sock *req,
const struct mptcp_options_received *mp_opt) const struct mptcp_options_received *mp_opt)
{ {
const struct mptcp_subflow_request_sock *subflow_req; const struct mptcp_subflow_request_sock *subflow_req;
u8 hmac[MPTCPOPT_HMAC_LEN]; u8 hmac[SHA256_DIGEST_SIZE];
struct mptcp_sock *msk; struct mptcp_sock *msk;
bool ret; bool ret;
@ -361,7 +366,7 @@ static bool subflow_hmac_valid(const struct request_sock *req,
subflow_req->local_nonce, hmac); subflow_req->local_nonce, hmac);
ret = true; ret = true;
if (crypto_memneq(hmac, mp_opt->hmac, sizeof(hmac))) if (crypto_memneq(hmac, mp_opt->hmac, MPTCPOPT_HMAC_LEN))
ret = false; ret = false;
sock_put((struct sock *)msk); sock_put((struct sock *)msk);