Merge pull request #4284 from mikaleppanen/lwip_randlib

LWIP random library and TCP sequence number improvements
pull/4322/head
Martin Kojtal 2017-05-15 16:15:39 +01:00 committed by GitHub
commit 27a6965842
7 changed files with 383 additions and 4 deletions

View File

@ -27,9 +27,14 @@ EthernetInterface::EthernetInterface()
nsapi_error_t EthernetInterface::set_network(const char *ip_address, const char *netmask, const char *gateway)
{
_dhcp = false;
strncpy(_ip_address, ip_address ? ip_address : "", sizeof(_ip_address));
_ip_address[sizeof(_ip_address) - 1] = '\0';
strncpy(_netmask, netmask ? netmask : "", sizeof(_netmask));
_netmask[sizeof(_netmask) - 1] = '\0';
strncpy(_gateway, gateway ? gateway : "", sizeof(_gateway));
_gateway[sizeof(_gateway) - 1] = '\0';
return NSAPI_ERROR_OK;
}

View File

@ -0,0 +1,53 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "lwip_random.h"
#if FEATURE_COMMON_PAL
#include "randLIB.h"
void lwip_seed_random(void)
{
randLIB_seed_random();
}
void lwip_add_random_seed(uint64_t seed)
{
randLIB_add_seed(seed);
}
inline uint32_t lwip_get_random(void)
{
return randLIB_get_32bit();
}
#else
void lwip_seed_random(void)
{
}
void lwip_add_random_seed(uint64_t seed)
{
}
uint32_t lwip_get_random(void)
{
return rand();
}
#endif

View File

@ -0,0 +1,54 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LWIP_HDR_RANDOM_H
#define LWIP_HDR_RANDOM_H
#include "lwip/opt.h"
#include "lwip/debug.h"
#include "lwip/def.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Init seed for Pseudo Random
*
* Function shall seed the pseudo-random generator. Function
* is called during lwip initialisation.
*/
void lwip_seed_random(void);
/** Update seed for pseudo-random generator
*
* Adds seed information to existing generator, to perturb the
* sequence.
*
* @param seed 64 bits of data to add to the seed.
*/
void lwip_add_random_seed(uint64_t seed);
/** Generates random number.
*
* @return 32-bit random number
*/
uint32_t lwip_get_random(void);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_RANDOM_H */

View File

@ -0,0 +1,185 @@
/**
* @file
*
* Reference implementation of the TCP ISN algorithm standardized in RFC 6528.
* Produce TCP Initial Sequence Numbers by combining an MD5-generated hash
* based on the new TCP connection's identity and a stable secret, with the
* current time at 4-microsecond granularity.
*
* Specifically, the implementation uses MD5 to compute a hash of the input
* buffer, which contains both the four-tuple of the new TCP connection (local
* and remote IP address and port), as well as a 16-byte secret to make the
* results unpredictable to external parties. The secret must be given at
* initialization time and should ideally remain the same across system
* reboots. To be sure: the spoofing-resistance of the resulting ISN depends
* mainly on the strength of the supplied secret!
*
* The implementation takes 32 bits from the computed hash, and adds to it the
* current time, in 4-microsecond units. The current time is computed from a
* boot time given at initialization, and the current uptime as provided by
* sys_now(). Thus, it assumes that sys_now() returns a time value that is
* relative to the boot time, i.e., that it starts at 0 at system boot, and
* only ever increases monotonically.
*
* For efficiency reasons, a single MD5 input buffer is used, and partially
* filled in at initialization time. Specifically, of this 64-byte buffer, the
* first 36 bytes are used for the four-way TCP tuple data, followed by the
* 16-byte secret, followed by 12-byte zero padding. The 64-byte size of the
* buffer should achieve the best performance for the actual MD5 computation.
*
* Basic usage:
*
* 1. in your lwipopts.h, add the following lines:
*
* #include <lwip/arch.h>
* struct ip_addr;
* u32_t lwip_hook_tcp_isn(const struct ip_addr *local_ip, u16_t local_port,
* const struct ip_addr *remote_ip, u16_t remote_port);
* "#define LWIP_HOOK_TCP_ISN lwip_hook_tcp_isn";
*
* 2. from your own code, call lwip_init_tcp_isn() at initialization time, with
* appropriate parameters.
*/
/*
* Copyright (c) 2016 The MINIX 3 Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: David van Moolenbroek <david@minix3.org>
*/
#include "lwip_tcp_isn.h"
#include "lwip/ip_addr.h"
#include "lwip/sys.h"
#include <string.h>
/* pull in md5 of ppp? */
#define PPP_SUPPORT 1
#include "netif/ppp/ppp_opts.h"
#include "netif/ppp/ppp.h"
#include "netif/ppp/pppcrypt.h"
#if !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS
#undef LWIP_INCLUDED_POLARSSL_MD5
#define LWIP_INCLUDED_POLARSSL_MD5 1
#include "netif/ppp/polarssl/lwip_md5.c"
#endif
#if LWIP_USE_EXTERNAL_MBEDTLS
#include "mbedtls/inc/mbedtls/md5.h"
#define md5_context mbedtls_md5_context
#endif
static u8_t input[64];
static u32_t base_time;
/**
* Initialize the TCP ISN module, with the boot time and a secret.
*
* @param boot_time Wall clock boot time of the system, in seconds.
* @param secret_16_bytes A 16-byte secret used to randomize the TCP ISNs.
*/
void
lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes)
{
/* Initialize the input buffer with the secret and trailing zeroes. */
memset(input, 0, sizeof(input));
MEMCPY(&input[36], secret_16_bytes, 16);
/* Save the boot time in 4-us units. Overflow is no problem here. */
base_time = boot_time * 250000;
}
/**
* Hook to generate an Initial Sequence Number (ISN) for a new TCP connection.
*
* @param local_ip The local IP address.
* @param local_port The local port number, in host-byte order.
* @param remote_ip The remote IP address.
* @param remote_port The remote port number, in host-byte order.
* @return The ISN to use for the new TCP connection.
*/
u32_t
lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port,
const ip_addr_t *remote_ip, u16_t remote_port)
{
md5_context ctx;
u8_t output[16];
u32_t isn;
#if LWIP_IPV4 && LWIP_IPV6
if (IP_IS_V6(local_ip))
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_IPV6
{
const ip6_addr_t *local_ip6, *remote_ip6;
local_ip6 = ip_2_ip6(local_ip);
remote_ip6 = ip_2_ip6(remote_ip);
SMEMCPY(&input[0], &local_ip6->addr, 16);
SMEMCPY(&input[16], &remote_ip6->addr, 16);
}
#endif /* LWIP_IPV6 */
#if LWIP_IPV4 && LWIP_IPV6
else
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_IPV4
{
const ip4_addr_t *local_ip4, *remote_ip4;
local_ip4 = ip_2_ip4(local_ip);
remote_ip4 = ip_2_ip4(remote_ip);
/* Represent IPv4 addresses as IPv4-mapped IPv6 addresses, to ensure that
* the IPv4 and IPv6 address spaces are completely disjoint. */
memset(&input[0], 0, 10);
input[10] = 0xff;
input[11] = 0xff;
SMEMCPY(&input[12], &local_ip4->addr, 4);
memset(&input[16], 0, 10);
input[26] = 0xff;
input[27] = 0xff;
SMEMCPY(&input[28], &remote_ip4->addr, 4);
}
#endif /* LWIP_IPV4 */
input[32] = local_port >> 8;
input[33] = local_port & 0xff;
input[34] = remote_port >> 8;
input[35] = remote_port & 0xff;
/* The secret and padding are already filled in. */
/* Generate the hash, using MD5. */
lwip_md5_starts(&ctx);
lwip_md5_update(&ctx, input, sizeof(input));
lwip_md5_finish(&ctx, output);
/* Arbitrarily take the first 32 bits from the generated hash. */
MEMCPY(&isn, output, sizeof(isn));
/* Add the current time in 4-microsecond units. */
return isn + base_time + sys_now() * 250;
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2016 The MINIX 3 Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: David van Moolenbroek <david@minix3.org>
*/
#ifndef LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H
#define LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
void lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes);
u32_t lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port,
const ip_addr_t *remote_ip, u16_t remote_port);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H */

View File

@ -34,6 +34,7 @@
#include "lwip/udp.h"
#include "emac_api.h"
#include "lwip_tcp_isn.h"
#if DEVICE_EMAC
#define MBED_NETIF_INIT_FN emac_lwip_if_init
@ -108,7 +109,9 @@ static void mbed_lwip_socket_callback(struct netconn *nc, enum netconn_evt eh, u
/* TCP/IP and Network Interface Initialisation */
static struct netif lwip_netif;
#if LWIP_IPV4
static bool lwip_dhcp = false;
#endif
static char lwip_mac_address[NSAPI_MAC_SIZE];
#if !LWIP_IPV4 || !LWIP_IPV6
@ -189,7 +192,9 @@ static bool convert_lwip_addr_to_mbed(nsapi_addr_t *out, const ip_addr_t *in)
return true;
}
#endif
#if LWIP_IPV6 && LWIP_IPV4
return false;
#endif
}
static const ip_addr_t *mbed_lwip_get_ipv4_addr(const struct netif *netif)
@ -324,15 +329,23 @@ static void mbed_lwip_netif_status_irq(struct netif *lwip_netif)
static void mbed_lwip_set_mac_address(void)
{
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
(void) snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2,
MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5);
#else
char mac[6];
mbed_mac_address(mac);
snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
(void) snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
#endif
/* Use mac address as additional seed to random number generator */
uint64_t seed = mac[0];
for (uint8_t i = 1; i < 8; i++) {
seed <<= 8;
seed |= mac[i % 6];
}
lwip_add_random_seed(seed);
}
/* LWIP interface implementation */
@ -357,7 +370,9 @@ char *mbed_lwip_get_ip_address(char *buf, nsapi_size_t buflen)
return ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen);
}
#endif
#if LWIP_IPV6 && LWIP_IPV4
return NULL;
#endif
}
const char *mbed_lwip_get_netmask(char *buf, nsapi_size_t buflen)
@ -390,9 +405,20 @@ char *mbed_lwip_get_gateway(char *buf, nsapi_size_t buflen)
nsapi_error_t mbed_lwip_init(emac_interface_t *emac)
{
// Check if we've already brought up lwip
if (!mbed_lwip_get_mac_address()) {
// Seed lwip random
lwip_seed_random();
// Set up network
// Initialise TCP sequence number
uint32_t tcp_isn_secret[4];
for (int i = 0; i < 4; i++) {
tcp_isn_secret[i] = LWIP_RAND();
}
lwip_init_tcp_isn(0, (u8_t *) &tcp_isn_secret);
sys_sem_new(&lwip_tcpip_inited, 0);
sys_sem_new(&lwip_netif_linked, 0);
sys_sem_new(&lwip_netif_has_addr, 0);
@ -656,7 +682,7 @@ static nsapi_error_t mbed_lwip_socket_open(nsapi_stack_t *stack, nsapi_socket_t
return NSAPI_ERROR_NO_SOCKET;
}
u8_t lwip_proto = proto == NSAPI_TCP ? NETCONN_TCP : NETCONN_UDP;
enum netconn_type lwip_proto = proto == NSAPI_TCP ? NETCONN_TCP : NETCONN_UDP;
#if LWIP_IPV6 && LWIP_IPV4
const ip_addr_t *ip_addr;

View File

@ -176,7 +176,7 @@
// Support Multicast
#include "stdlib.h"
#define LWIP_IGMP LWIP_IPV4
#define LWIP_RAND() rand()
#define LWIP_RAND() lwip_get_random()
#define LWIP_COMPAT_SOCKETS 0
#define LWIP_POSIX_SOCKETS_IO_NAMES 0
@ -275,4 +275,12 @@
#error A transport mechanism (Ethernet or PPP) must be defined
#endif
#include <lwip/arch.h>
#include "lwip_random.h"
#include "lwip_tcp_isn.h"
#define LWIP_HOOK_TCP_ISN lwip_hook_tcp_isn
#if MBEDTLS_MD5_C
#define LWIP_USE_EXTERNAL_MBEDTLS 1
#endif
#endif /* LWIPOPTS_H_ */