Commit 65492c5a authored by Paolo Abeni's avatar Paolo Abeni Committed by David S. Miller

mptcp: move from sha1 (v0) to sha256 (v1)

For simplicity's sake use directly sha256 primitives (and pull them
as a required build dep).
Add optional, boot-time self-tests for the hmac function.
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarChristoph Paasch <cpaasch@apple.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 048d19d4
...@@ -3,6 +3,7 @@ config MPTCP ...@@ -3,6 +3,7 @@ config MPTCP
bool "MPTCP: Multipath TCP" bool "MPTCP: Multipath TCP"
depends on INET depends on INET
select SKB_EXTENSIONS select SKB_EXTENSIONS
select CRYPTO_LIB_SHA256
help help
Multipath TCP (MPTCP) connections send and receive data over multiple Multipath TCP (MPTCP) connections send and receive data over multiple
subflows in order to utilize multiple network paths. Each subflow subflows in order to utilize multiple network paths. Each subflow
...@@ -14,3 +15,12 @@ config MPTCP_IPV6 ...@@ -14,3 +15,12 @@ config MPTCP_IPV6
depends on MPTCP depends on MPTCP
select IPV6 select IPV6
default y default y
config MPTCP_HMAC_TEST
bool "Tests for MPTCP HMAC implementation"
default n
help
This option enable boot time self-test for the HMAC implementation
used by the MPTCP code
Say N if you are unsure.
...@@ -21,67 +21,36 @@ ...@@ -21,67 +21,36 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/cryptohash.h> #include <crypto/sha.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "protocol.h" #include "protocol.h"
struct sha1_state { #define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / 4)
u32 workspace[SHA_WORKSPACE_WORDS];
u32 digest[SHA_DIGEST_WORDS];
unsigned int count;
};
static void sha1_init(struct sha1_state *state)
{
sha_init(state->digest);
state->count = 0;
}
static void sha1_update(struct sha1_state *state, u8 *input)
{
sha_transform(state->digest, input, state->workspace);
state->count += SHA_MESSAGE_BYTES;
}
static void sha1_pad_final(struct sha1_state *state, u8 *input,
unsigned int length, __be32 *mptcp_hashed_key)
{
int i;
input[length] = 0x80;
memset(&input[length + 1], 0, SHA_MESSAGE_BYTES - length - 9);
put_unaligned_be64((length + state->count) << 3,
&input[SHA_MESSAGE_BYTES - 8]);
sha_transform(state->digest, input, state->workspace);
for (i = 0; i < SHA_DIGEST_WORDS; ++i)
put_unaligned_be32(state->digest[i], &mptcp_hashed_key[i]);
memzero_explicit(state->workspace, SHA_WORKSPACE_WORDS << 2);
}
void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn) void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn)
{ {
__be32 mptcp_hashed_key[SHA_DIGEST_WORDS]; __be32 mptcp_hashed_key[SHA256_DIGEST_WORDS];
u8 input[SHA_MESSAGE_BYTES]; __be64 input = cpu_to_be64(key);
struct sha1_state state; struct sha256_state state;
sha1_init(&state); sha256_init(&state);
put_unaligned_be64(key, input); sha256_update(&state, (__force u8 *)&input, sizeof(input));
sha1_pad_final(&state, input, 8, mptcp_hashed_key); sha256_final(&state, (u8 *)mptcp_hashed_key);
if (token) if (token)
*token = be32_to_cpu(mptcp_hashed_key[0]); *token = be32_to_cpu(mptcp_hashed_key[0]);
if (idsn) if (idsn)
*idsn = be64_to_cpu(*((__be64 *)&mptcp_hashed_key[3])); *idsn = be64_to_cpu(*((__be64 *)&mptcp_hashed_key[6]));
} }
void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2, void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
u32 *hash_out) void *hmac)
{ {
u8 input[SHA_MESSAGE_BYTES * 2]; u8 input[SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE];
struct sha1_state state; __be32 mptcp_hashed_key[SHA256_DIGEST_WORDS];
__be32 *hash_out = (__force __be32 *)hmac;
struct sha256_state state;
u8 key1be[8]; u8 key1be[8];
u8 key2be[8]; u8 key2be[8];
int i; int i;
...@@ -96,17 +65,16 @@ void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2, ...@@ -96,17 +65,16 @@ void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
input[i + 8] ^= key2be[i]; input[i + 8] ^= key2be[i];
put_unaligned_be32(nonce1, &input[SHA_MESSAGE_BYTES]); put_unaligned_be32(nonce1, &input[SHA256_BLOCK_SIZE]);
put_unaligned_be32(nonce2, &input[SHA_MESSAGE_BYTES + 4]); put_unaligned_be32(nonce2, &input[SHA256_BLOCK_SIZE + 4]);
sha1_init(&state); sha256_init(&state);
sha1_update(&state, input); sha256_update(&state, input, SHA256_BLOCK_SIZE + 8);
/* emit sha256(K1 || msg) on the second input block, so we can /* emit sha256(K1 || msg) on the second input block, so we can
* reuse 'input' for the last hashing * reuse 'input' for the last hashing
*/ */
sha1_pad_final(&state, &input[SHA_MESSAGE_BYTES], 8, sha256_final(&state, &input[SHA256_BLOCK_SIZE]);
(__force __be32 *)&input[SHA_MESSAGE_BYTES]);
/* Prepare second part of hmac */ /* Prepare second part of hmac */
memset(input, 0x5C, SHA_MESSAGE_BYTES); memset(input, 0x5C, SHA_MESSAGE_BYTES);
...@@ -115,8 +83,70 @@ void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2, ...@@ -115,8 +83,70 @@ void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
input[i + 8] ^= key2be[i]; input[i + 8] ^= key2be[i];
sha1_init(&state); sha256_init(&state);
sha1_update(&state, input); sha256_update(&state, input, SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE);
sha1_pad_final(&state, &input[SHA_MESSAGE_BYTES], SHA_DIGEST_WORDS << 2, sha256_final(&state, (u8 *)mptcp_hashed_key);
(__be32 *)hash_out);
/* takes only first 160 bits */
for (i = 0; i < 5; i++)
hash_out[i] = mptcp_hashed_key[i];
}
#ifdef CONFIG_MPTCP_HMAC_TEST
struct test_cast {
char *key;
char *msg;
char *result;
};
/* we can't reuse RFC 4231 test vectors, as we have constraint on the
* input and key size, and we truncate the output.
*/
static struct test_cast tests[] = {
{
.key = "0b0b0b0b0b0b0b0b",
.msg = "48692054",
.result = "8385e24fb4235ac37556b6b886db106284a1da67",
},
{
.key = "aaaaaaaaaaaaaaaa",
.msg = "dddddddd",
.result = "2c5e219164ff1dca1c4a92318d847bb6b9d44492",
},
{
.key = "0102030405060708",
.msg = "cdcdcdcd",
.result = "e73b9ba9969969cefb04aa0d6df18ec2fcc075b6",
},
};
static int __init test_mptcp_crypto(void)
{
char hmac[20], hmac_hex[41];
u32 nonce1, nonce2;
u64 key1, key2;
int i, j;
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
/* mptcp hmap will convert to be before computing the hmac */
key1 = be64_to_cpu(*((__be64 *)&tests[i].key[0]));
key2 = be64_to_cpu(*((__be64 *)&tests[i].key[8]));
nonce1 = be32_to_cpu(*((__be32 *)&tests[i].msg[0]));
nonce2 = be32_to_cpu(*((__be32 *)&tests[i].msg[4]));
mptcp_crypto_hmac_sha(key1, key2, nonce1, nonce2, hmac);
for (j = 0; j < 20; ++j)
sprintf(&hmac_hex[j << 1], "%02x", hmac[j] & 0xff);
hmac_hex[40] = 0;
if (memcmp(hmac_hex, tests[i].result, 40))
pr_err("test %d failed, got %s expected %s", i,
hmac_hex, tests[i].result);
else
pr_info("test %d [ ok ]", i);
}
return 0;
} }
late_initcall(test_mptcp_crypto);
#endif
...@@ -9,6 +9,11 @@ ...@@ -9,6 +9,11 @@
#include <net/mptcp.h> #include <net/mptcp.h>
#include "protocol.h" #include "protocol.h"
static bool mptcp_cap_flag_sha256(u8 flags)
{
return (flags & MPTCP_CAP_FLAG_MASK) == MPTCP_CAP_HMAC_SHA256;
}
void mptcp_parse_option(const unsigned char *ptr, int opsize, void mptcp_parse_option(const unsigned char *ptr, int opsize,
struct tcp_options_received *opt_rx) struct tcp_options_received *opt_rx)
{ {
...@@ -29,7 +34,7 @@ void mptcp_parse_option(const unsigned char *ptr, int opsize, ...@@ -29,7 +34,7 @@ void mptcp_parse_option(const unsigned char *ptr, int opsize,
break; break;
flags = *ptr++; flags = *ptr++;
if (!((flags & MPTCP_CAP_FLAG_MASK) == MPTCP_CAP_HMAC_SHA1) || if (!mptcp_cap_flag_sha256(flags) ||
(flags & MPTCP_CAP_EXTENSIBILITY)) (flags & MPTCP_CAP_EXTENSIBILITY))
break; break;
...@@ -399,7 +404,7 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts) ...@@ -399,7 +404,7 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
*ptr++ = htonl((TCPOPT_MPTCP << 24) | (len << 16) | *ptr++ = htonl((TCPOPT_MPTCP << 24) | (len << 16) |
(MPTCPOPT_MP_CAPABLE << 12) | (MPTCPOPT_MP_CAPABLE << 12) |
(MPTCP_SUPPORTED_VERSION << 8) | (MPTCP_SUPPORTED_VERSION << 8) |
MPTCP_CAP_HMAC_SHA1); MPTCP_CAP_HMAC_SHA256);
put_unaligned_be64(opts->sndr_key, ptr); put_unaligned_be64(opts->sndr_key, ptr);
ptr += 2; ptr += 2;
if (OPTION_MPTCP_MPC_ACK & opts->suboptions) { if (OPTION_MPTCP_MPC_ACK & opts->suboptions) {
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
#define MPTCP_VERSION_MASK (0x0F) #define MPTCP_VERSION_MASK (0x0F)
#define MPTCP_CAP_CHECKSUM_REQD BIT(7) #define MPTCP_CAP_CHECKSUM_REQD BIT(7)
#define MPTCP_CAP_EXTENSIBILITY BIT(6) #define MPTCP_CAP_EXTENSIBILITY BIT(6)
#define MPTCP_CAP_HMAC_SHA1 BIT(0) #define MPTCP_CAP_HMAC_SHA256 BIT(0)
#define MPTCP_CAP_FLAG_MASK (0x3F) #define MPTCP_CAP_FLAG_MASK (0x3F)
/* MPTCP DSS flags */ /* MPTCP DSS flags */
...@@ -216,7 +216,7 @@ static inline void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn) ...@@ -216,7 +216,7 @@ static inline void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
} }
void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2, void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
u32 *hash_out); void *hash_out);
static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb) static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment