Commit a33e3a4a authored by Vowstar's avatar Vowstar
Browse files

Merge pull request #687 from DiUS/dev140

Major upgrade to SDK 1.4.0 & open LWIP
parents 093a8959 8fba0f47
......@@ -57,6 +57,9 @@
#include "lwip/igmp.h"
#include "lwip/dns.h"
#ifdef MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
#endif
/** The one and only timeout list */
static struct sys_timeo *next_timeout = NULL;
......@@ -245,6 +248,7 @@ void sys_timeouts_init(void)
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
#endif /* LWIP_ARP */
#if LWIP_DHCP
DHCP_MAXRTX = 0;
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
#endif /* LWIP_DHCP */
......@@ -259,8 +263,8 @@ void sys_timeouts_init(void)
#endif /* LWIP_DNS */
#if LWIP_TCP
//sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL);
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
// sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL);
#endif
#if NO_SYS
......@@ -389,9 +393,9 @@ sys_check_timeouts(void)
if (next_timeout) {
/* this cares for wraparounds */
if (timer2_ms_flag == 0) {
diff = LWIP_U32_DIFF(now, timeouts_last_time)/((CPU_CLK_FREQ>>4)/1000);
diff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>4)/1000);
} else {
diff = LWIP_U32_DIFF(now, timeouts_last_time)/((CPU_CLK_FREQ>>8)/1000);
diff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>8)/1000);
}
do
{
......
......@@ -64,6 +64,10 @@
#include <string.h>
#ifdef MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
#endif
/* The list of UDP PCBs */
/* exported in udp.h (was static) */
struct udp_pcb *udp_pcbs;
......@@ -148,6 +152,15 @@ udp_input(struct pbuf *p, struct netif *inp)
pcb = inp->dhcp->pcb;
}
}
} else if (dest == DHCP_SERVER_PORT) {
if (src == DHCP_CLIENT_PORT) {
if ( inp->dhcps_pcb != NULL ) {
if ((ip_addr_isany(&inp->dhcps_pcb->local_ip) ||
ip_addr_cmp(&(inp->dhcps_pcb->local_ip), &current_iphdr_dest))) {
pcb = inp->dhcps_pcb;
}
}
}
}
} else
#endif /* LWIP_DHCP */
......@@ -935,7 +948,7 @@ udp_new(void)
* which means checksum is generated over the whole datagram per default
* (recommended as default by RFC 3828). */
/* initialize PCB to all zeroes */
memset(pcb, 0, sizeof(struct udp_pcb));
os_memset(pcb, 0, sizeof(struct udp_pcb));
pcb->ttl = UDP_TTL;
}
return pcb;
......
......@@ -62,6 +62,10 @@
#include <string.h>
#ifdef MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
#endif
const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
const struct eth_addr ethzero = {{0,0,0,0,0,0}};
......@@ -72,6 +76,9 @@ const struct eth_addr ethzero = {{0,0,0,0,0,0}};
* (240 * 5) seconds = 20 minutes.
*/
#define ARP_MAXAGE 240
/** Re-request a used ARP entry 1 minute before it would expire to prevent
* breaking a steadily used connection because the ARP entry timed out. */
#define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 12)
/** the time an ARP entry stays pending after first request,
* for ARP_TMR_INTERVAL = 5000, this is
* (2 * 5) seconds = 10 seconds.
......@@ -86,7 +93,8 @@ const struct eth_addr ethzero = {{0,0,0,0,0,0}};
enum etharp_state {
ETHARP_STATE_EMPTY = 0,
ETHARP_STATE_PENDING,
ETHARP_STATE_STABLE
ETHARP_STATE_STABLE,
ETHARP_STATE_STABLE_REREQUESTING
};
struct etharp_entry {
......@@ -219,10 +227,15 @@ etharp_tmr(void)
(arp_table[i].ctime >= ARP_MAXPENDING))) {
/* pending or stable entry has become old! */
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
/* clean up entries that have just been expired */
free_entry(i);
}
else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) {
/* Reset state to stable, so that the next transmitted packet will
re-send an ARP request. */
arp_table[i].state = ETHARP_STATE_STABLE;
}
#if ARP_QUEUEING
/* still pending entry? (not expired) */
if (arp_table[i].state == ETHARP_STATE_PENDING) {
......@@ -288,8 +301,8 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
/* remember first empty entry */
empty = i;
} else if (state != ETHARP_STATE_EMPTY) {
LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE",
state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE);
LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE",
state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE);
/* if given, does IP address match IP address in ARP entry? */
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i));
......@@ -313,7 +326,7 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
}
}
/* stable entry? */
} else if (state == ETHARP_STATE_STABLE) {
} else if (state >= ETHARP_STATE_STABLE) {
#if ETHARP_SUPPORT_STATIC_ENTRIES
/* don't record old_stable for static entries since they never expire */
if (arp_table[i].static_entry == 0)
......@@ -608,7 +621,7 @@ etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
LWIP_UNUSED_ARG(netif);
i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) {
*eth_ret = &arp_table[i].ethaddr;
*ip_ret = &arp_table[i].ipaddr;
return i;
......@@ -854,6 +867,28 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
pbuf_free(p);
}
/** Just a small helper function that sends a pbuf to an ethernet address
* in the arp_table specified by the index 'arp_idx'.
*/
static err_t ICACHE_FLASH_ATTR
etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)
{
LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE",
arp_table[arp_idx].state >= ETHARP_STATE_STABLE);
/* if arp table entry is about to expire: re-request it,
but only if its state is ETHARP_STATE_STABLE to prevent flooding the
network with ARP requests if this address is used frequently. */
if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) &&
(arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) {
if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) {
arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING;
}
}
return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
&arp_table[arp_idx].ethaddr);
}
/**
* Resolve and fill-in Ethernet address header for outgoing IP packet.
*
......@@ -908,7 +943,9 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
dest = &mcastaddr;
/* unicast destination IP address? */
} else {
/* outside local network? */
s8_t i;
/* outside local network? if so, this can neither be a global broadcast nor
a subnet broadcast. */
if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
!ip_addr_islinklocal(ipaddr)) {
#if LWIP_AUTOIP
......@@ -938,17 +975,26 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
u8_t etharp_cached_entry = *(netif->addr_hint);
if (etharp_cached_entry < ARP_TABLE_SIZE) {
#endif /* LWIP_NETIF_HWADDRHINT */
if ((arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) &&
if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
(ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) {
/* the per-pcb-cached entry is stable and the right one! */
ETHARP_STATS_INC(etharp.cachehit);
return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
&arp_table[etharp_cached_entry].ethaddr);
return etharp_output_to_arp_index(netif, q, etharp_cached_entry);
}
#if LWIP_NETIF_HWADDRHINT
}
}
#endif /* LWIP_NETIF_HWADDRHINT */
/* find stable entry: do this here since this is a critical path for
throughput and etharp_find_entry() is kind of slow */
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&
(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr))) {
/* found an existing, stable entry */
ETHARP_SET_HINT(netif, i);
return etharp_output_to_arp_index(netif, q, i);
}
}
/* queue on destination Ethernet address belonging to ipaddr */
return etharp_query(netif, ipaddr, q);
}
......@@ -1028,7 +1074,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
/* { i is either a STABLE or (new or existing) PENDING entry } */
LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
((arp_table[i].state == ETHARP_STATE_PENDING) ||
(arp_table[i].state == ETHARP_STATE_STABLE)));
(arp_table[i].state >= ETHARP_STATE_STABLE)));
/* do we have a pending entry? or an implicit query request? */
if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
......@@ -1048,7 +1094,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
/* packet given? */
LWIP_ASSERT("q != NULL", q != NULL);
/* stable entry? */
if (arp_table[i].state == ETHARP_STATE_STABLE) {
if (arp_table[i].state >= ETHARP_STATE_STABLE) {
/* we have a valid IP->Ethernet address mapping */
ETHARP_SET_HINT(netif, i);
/* send the packet */
......@@ -1092,20 +1138,30 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
/* allocate a new arp queue entry */
new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
if (new_entry != NULL) {
unsigned int qlen = 0;
new_entry->next = 0;
new_entry->p = p;
if(arp_table[i].q != NULL) {
/* queue was already existent, append the new entry to the end */
struct etharp_q_entry *r;
r = arp_table[i].q;
qlen++;
while (r->next != NULL) {
r = r->next;
qlen++;
}
r->next = new_entry;
} else {
/* queue did not exist, first item in queue */
arp_table[i].q = new_entry;
}
if(qlen >= 3) {
struct etharp_q_entry *old;
old = arp_table[i].q;
arp_table[i].q = arp_table[i].q->next;
pbuf_free(old->p);
memp_free(MEM_ARP_QUEUE, old);
}
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
result = ERR_OK;
} else {
......
......@@ -12,6 +12,7 @@
#include "c_types.h"
#include "mem.h"
#include "lwip/ip_addr.h"
#include "espconn.h"
#include "driver/uart.h"
......
......@@ -64,7 +64,7 @@ static int lgpio_trig( lua_State* L )
}else if(sl == 4 && c_strcmp(str, "down") == 0){
type = GPIO_PIN_INTR_NEGEDGE;
}else if(sl == 4 && c_strcmp(str, "both") == 0){
type = GPIO_PIN_INTR_ANYEGDE;
type = GPIO_PIN_INTR_ANYEDGE;
}else if(sl == 3 && c_strcmp(str, "low") == 0){
type = GPIO_PIN_INTR_LOLEVEL;
}else if(sl == 4 && c_strcmp(str, "high") == 0){
......@@ -147,8 +147,8 @@ static int lgpio_write( lua_State* L )
}
#define DELAY_TABLE_MAX_LEN 256
#define noInterrupts os_intr_lock
#define interrupts os_intr_unlock
#define noInterrupts ets_intr_lock
#define interrupts ets_intr_unlock
#define delayMicroseconds os_delay_us
#define DIRECT_WRITE(pin, level) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), level))
// Lua: serout( pin, firstLevel, delay_table, [repeatNum] )
......
......@@ -12,6 +12,7 @@
#include "c_types.h"
#include "mem.h"
#include "lwip/ip_addr.h"
#include "espconn.h"
#include "mqtt_msg.h"
......
......@@ -12,6 +12,7 @@
#include "c_types.h"
#include "mem.h"
#include "lwip/ip_addr.h"
#include "espconn.h"
#include "lwip/dns.h"
......@@ -1076,6 +1077,16 @@ static int net_send( lua_State* L, const char* mt )
luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_send_ref);
nud->cb_send_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
// SDK 1.4.0 changed behaviour, for UDP server need to look up remote ip/port
if (isserver && pesp_conn->type == ESPCONN_UDP)
{
remot_info *pr = 0;
if (espconn_get_connection_info (pesp_conn, &pr, 0) != ESPCONN_OK)
return luaL_error (L, "remote ip/port unavailable");
pesp_conn->proto.udp->remote_port = pr->remote_port;
os_memmove (pesp_conn->proto.udp->remote_ip, pr->remote_ip, 4);
// The remot_info apparently should *not* be os_free()d, fyi
}
#ifdef CLIENT_SSL_ENABLE
if(nud->secure)
espconn_secure_sent(pesp_conn, (unsigned char *)payload, l);
......
......@@ -145,8 +145,58 @@ static int node_heap( lua_State* L )
static lua_State *gL = NULL;
#ifdef DEVKIT_VERSION_0_9
extern int led_high_count; // this is defined in lua.c
extern int led_low_count;
static int led_high_count = LED_HIGH_COUNT_DEFAULT;
static int led_low_count = LED_LOW_COUNT_DEFAULT;
static int led_count = 0;
static int key_press_count = 0;
static bool key_short_pressed = false;
static bool key_long_pressed = false;
static os_timer_t keyled_timer;
static void update_key_led (void *p)
{
(void)p;
uint8_t temp = 1, level = 1;
led_count++;
if(led_count>led_low_count+led_high_count){
led_count = 0; // reset led_count, the level still high
} else if(led_count>led_low_count && led_count <=led_high_count+led_low_count){
level = 1; // output high level
} else if(led_count<=led_low_count){
level = 0; // output low level
}
temp = platform_key_led(level);
if(temp == 0){ // key is pressed
key_press_count++;
if(key_press_count>=KEY_LONG_COUNT){
// key_long_press(NULL);
key_long_pressed = true;
key_short_pressed = false;
// key_press_count = 0;
} else if(key_press_count>=KEY_SHORT_COUNT){ // < KEY_LONG_COUNT
// key_short_press(NULL);
key_short_pressed = true;
}
}else{ // key is released
key_press_count = 0;
if(key_long_pressed){
key_long_press(NULL);
key_long_pressed = false;
}
if(key_short_pressed){
key_short_press(NULL);
key_short_pressed = false;
}
}
}
static void prime_keyled_timer (void)
{
os_timer_disarm (&keyled_timer);
os_timer_setfn (&keyled_timer, update_key_led, 0);
os_timer_arm (&keyled_timer, KEYLED_INTERVAL, 1);
}
// Lua: led(low, high)
static int node_led( lua_State* L )
{
......@@ -171,6 +221,7 @@ static int node_led( lua_State* L )
}
led_high_count = (uint32_t)high / READLINE_INTERVAL;
led_low_count = (uint32_t)low / READLINE_INTERVAL;
prime_keyled_timer();
return 0;
}
......@@ -246,13 +297,12 @@ static int node_key( lua_State* L )
*ref = LUA_NOREF;
}
prime_keyled_timer();
return 0;
}
#endif
extern lua_Load gLoad;
extern os_timer_t lua_timer;
extern void dojob(lua_Load *load);
// Lua: input("string")
static int node_input( lua_State* L )
{
......@@ -269,9 +319,7 @@ static int node_input( lua_State* L )
NODE_DBG("Get command:\n");
NODE_DBG(load->line); // buggy here
NODE_DBG("\nResult(if any):\n");
os_timer_disarm(&lua_timer);
os_timer_setfn(&lua_timer, (os_timer_func_t *)dojob, load);
os_timer_arm(&lua_timer, READLINE_INTERVAL, 0); // no repeat
system_os_post (LUA_TASK_PRIO, LUA_PROCESS_LINE_SIG, 0);
}
}
return 0;
......@@ -410,10 +458,10 @@ static int node_setcpufreq(lua_State* L)
uint32_t new_freq = luaL_checkinteger(L, 1);
if (new_freq == CPU160MHZ){
REG_SET_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(CPU160MHZ);
ets_update_cpu_frequency(CPU160MHZ);
} else {
REG_CLR_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(CPU80MHZ);
ets_update_cpu_frequency(CPU80MHZ);
}
new_freq = ets_get_cpu_frequency();
lua_pushinteger(L, new_freq);
......
......@@ -28,12 +28,18 @@ static uint8 prev_wifi_status=0;
#else
static lua_State* smart_L = NULL;
#endif
static void wifi_smart_succeed_cb(void *arg){
static void wifi_smart_succeed_cb(sc_status status, void *pdata){
NODE_DBG("wifi_smart_succeed_cb is called.\n");
if (status == SC_STATUS_LINK_OVER)
{
smartconfig_stop();
return;
}
#if defined( NODE_SMART_OLDSTYLE )
if( !arg )
if (status != SC_STATUS_LINK || !pdata)
return;
if(wifi_smart_succeed == LUA_NOREF)
return;
......@@ -44,10 +50,10 @@ static void wifi_smart_succeed_cb(void *arg){
#else
if( !arg )
if (status != SC_STATUS_LINK || !pdata)
return;
struct station_config *sta_conf = arg;
struct station_config *sta_conf = pdata;
wifi_station_set_config(sta_conf);
wifi_station_disconnect();
wifi_station_connect();
......@@ -63,7 +69,6 @@ static void wifi_smart_succeed_cb(void *arg){
luaL_unref(smart_L, LUA_REGISTRYINDEX, wifi_smart_succeed);
wifi_smart_succeed = LUA_NOREF;
}
smartconfig_stop();
#endif // defined( NODE_SMART_OLDSTYLE )
}
......@@ -195,7 +200,8 @@ static int wifi_start_smart( lua_State* L )
if ( smart_type > 1 )
return luaL_error( L, "wrong arg range" );
smartconfig_start(smart_type, wifi_smart_succeed_cb);
smartconfig_set_type(smart_type);
smartconfig_start(wifi_smart_succeed_cb);
#endif // defined( NODE_SMART_OLDSTYLE )
......@@ -333,7 +339,7 @@ static int wifi_setmac( lua_State* L, uint8_t mode )
if(len!=17)
return luaL_error( L, "wrong arg type" );
os_str2macaddr(mac, macaddr);
ets_str2macaddr(mac, macaddr);
lua_pushboolean(L,wifi_set_macaddr(mode, (uint8 *)mac));
return 1;
}
......@@ -591,7 +597,7 @@ static int wifi_station_config( lua_State* L )
if (ml!=17)
return luaL_error( L, "MAC:FF:FF:FF:FF:FF:FF" );
c_memset(sta_conf.bssid, 0, 6);
os_str2macaddr(sta_conf.bssid, macaddr);
ets_str2macaddr(sta_conf.bssid, macaddr);
sta_conf.bssid_set = 1;
}
else
......@@ -743,7 +749,7 @@ static int wifi_station_listap( lua_State* L )
if(len!=17)
return luaL_error( L, "bssid: FF:FF:FF:FF:FF:FF" );
c_memset(bssid, 0, 6);
os_str2macaddr(bssid, macaddr);
ets_str2macaddr(bssid, macaddr);
scan_cfg.bssid=bssid;
NODE_DBG(MACSTR, MAC2STR(scan_cfg.bssid));
NODE_DBG("\n");
......@@ -1229,7 +1235,7 @@ static int wifi_ap_dhcp_config( lua_State* L )
if (ip == 0)
return luaL_error( L, "wrong arg type" );
lease.start_ip = ip;
lease.start_ip.addr = ip;
NODE_DBG(IPSTR, IP2STR(&lease.start_ip));
NODE_DBG("\n");
......@@ -1335,9 +1341,9 @@ const LUA_REG_TYPE wifi_map[] =
{ LSTRKEY( "SOFTAP" ), LNUMVAL( SOFTAP_MODE ) },
{ LSTRKEY( "STATIONAP" ), LNUMVAL( STATIONAP_MODE ) },
{ LSTRKEY( "PHYMODE_B" ), LNUMVAL( PHY_MODE_B ) },
{ LSTRKEY( "PHYMODE_G" ), LNUMVAL( PHY_MODE_G ) },
{ LSTRKEY( "PHYMODE_N" ), LNUMVAL( PHY_MODE_N ) },
{ LSTRKEY( "PHYMODE_B" ), LNUMVAL( PHY_MODE_11B ) },
{ LSTRKEY( "PHYMODE_G" ), LNUMVAL( PHY_MODE_11G ) },
{ LSTRKEY( "PHYMODE_N" ), LNUMVAL( PHY_MODE_11N ) },
{ LSTRKEY( "NONE_SLEEP" ), LNUMVAL( NONE_SLEEP_T ) },
{ LSTRKEY( "LIGHT_SLEEP" ), LNUMVAL( LIGHT_SLEEP_T ) },
......
......@@ -115,11 +115,11 @@ static int ICACHE_FLASH_ATTR ws2801_writergb(lua_State* L) {
os_delay_us(10);
os_intr_lock();
ets_intr_lock();
ws2801_strip(buffer, length);
os_intr_unlock();
ets_intr_unlock();
return 0;
}
......
......@@ -94,9 +94,9 @@ static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
platform_gpio_write(pin, 0);
// Send the buffer
os_intr_lock();
ets_intr_lock();
ws2812_write(pin_num[pin], (uint8_t*) buffer, length);
os_intr_unlock();
ets_intr_unlock();
c_free(buffer);
......@@ -120,9 +120,9 @@ static int ICACHE_FLASH_ATTR ws2812_writegrb(lua_State* L) {
platform_gpio_write(pin, 0);
// Send the buffer
os_intr_lock();
ets_intr_lock();
ws2812_write(pin_num[pin], (uint8_t*) buffer, length);
os_intr_unlock();
ets_intr_unlock();
return 0;
}
......
......@@ -55,20 +55,13 @@ int platform_gpio_mode( unsigned pin, unsigned mode, unsigned pull )
switch(pull){
case PLATFORM_GPIO_PULLUP:
PIN_PULLDWN_DIS(pin_mux[pin]);
PIN_PULLUP_EN(pin_mux[pin]);
break;
case PLATFORM_GPIO_PULLDOWN:
PIN_PULLUP_DIS(pin_mux[pin]);
PIN_PULLDWN_EN(pin_mux[pin]);
break;
case PLATFORM_GPIO_FLOAT:
PIN_PULLUP_DIS(pin_mux[pin]);
PIN_PULLDWN_DIS(pin_mux[pin]);
break;
default:
PIN_PULLUP_DIS(pin_mux[pin]);
PIN_PULLDWN_DIS(pin_mux[pin]);
break;
}
......@@ -197,7 +190,6 @@ uint32_t platform_uart_setup( unsigned id, uint32_t baud, int databits, int pari
case BIT_RATE_74880:
case BIT_RATE_115200:
case BIT_RATE_230400:
case BIT_RATE_256000:
case BIT_RATE_460800:
case BIT_RATE_921600:
case BIT_RATE_1843200:
......
......@@ -27,7 +27,6 @@ uint8_t platform_key_led( uint8_t level);
// GPIO subsection
#define PLATFORM_GPIO_FLOAT 0
#define PLATFORM_GPIO_PULLUP 1
#define PLATFORM_GPIO_PULLDOWN 2
#define PLATFORM_GPIO_INT 2
#define PLATFORM_GPIO_OUTPUT 1
......
......@@ -46,7 +46,11 @@ The small 4KB sectors allow for greater flexibility in applications th
void myspiffs_mount() {
spiffs_config cfg;
#ifdef SPIFFS_FIXED_LOCATION
cfg.phys_addr = SPIFFS_FIXED_LOCATION;
#else
cfg.phys_addr = ( u32_t )platform_flash_get_first_free_block_address( NULL );
#endif
cfg.phys_addr += 0x3000;
cfg.phys_addr &= 0xFFFFC000; // align to 4 sector.
cfg.phys_size = INTERNAL_FLASH_SIZE - ( ( u32_t )cfg.phys_addr - INTERNAL_FLASH_START_ADDRESS );
......@@ -85,7 +89,11 @@ int myspiffs_format( void )
{
SPIFFS_unmount(&fs);
u32_t sect_first, sect_last;
#ifdef SPIFFS_FIXED_LOCATION
sect_first = SPIFFS_FIXED_LOCATION;
#else
sect_first = ( u32_t )platform_flash_get_first_free_block_address( NULL );
#endif
sect_first += 0x3000;
sect_first &= 0xFFFFC000; // align to 4 sector.
sect_first = platform_flash_get_sector_of_address(sect_first);
......
/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: espconn_encry.c
*
* Description: data encrypt interface
*
* Modification history:
* 2014/3/31, v1.0 create this file.
*******************************************************************************/
#include "lwip/netif.h"
#include "lwip/inet.h"
#include "netif/etharp.h"
#include "lwip/tcp.h"
#include "lwip/ip.h"
#include "lwip/init.h"
#include "ets_sys.h"
#include "os_type.h"
//#include "os.h"
#include "ssl/app/espconn_ssl.h"
/******************************************************************************
* FunctionName : espconn_encry_connect
* Description : The function given as the connect
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR
espconn_secure_connect(struct espconn *espconn)
{
if (espconn == NULL)
return ESPCONN_ARG;
return espconn_ssl_client(espconn);
}
/******************************************************************************
* FunctionName : espconn_encry_disconnect
* Description : The function given as the disconnect
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR
espconn_secure_disconnect(struct espconn *espconn)
{
espconn_msg *pnode = NULL;
bool value = false;
if (espconn == NULL)
return ESPCONN_ARG;
value = espconn_find_connection(espconn, &pnode);
if (value){
espconn_ssl_disconnect(pnode);
return ESPCONN_OK;
}
else
return ESPCONN_ARG;
}
/******************************************************************************
* FunctionName : espconn_encry_sent
* Description : sent data for client or server
* Parameters : espconn -- espconn to set for client or server
* psent -- data to send
* length -- length of data to send
* Returns : none
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR
espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length)
{
espconn_msg *pnode = NULL;
bool value = false;
if (espconn == NULL)
return ESPCONN_ARG;
espconn ->state = ESPCONN_WRITE;
value = espconn_find_connection(espconn, &pnode);
if (value){
espconn_ssl_sent(pnode, psent, length);
return ESPCONN_OK;
}
else
return ESPCONN_ARG;
}
sint8 ICACHE_FLASH_ATTR
espconn_secure_accept(struct espconn *espconn)
{
if (espconn == NULL)
return ESPCONN_ARG;
return espconn_ssl_server(espconn);
}
/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: espconn_ssl.c
*
* Description: ssl encrypt interface
*
* Modification history:
* 2014/3/31, v1.0 create this file.
*******************************************************************************/
#include "lwip/netif.h"
#include "netif/etharp.h"
#include "lwip/tcp.h"
#include "lwip/ip.h"
#include "lwip/init.h"
#include "lwip/tcp_impl.h"
#include "ssl/ssl_os_port.h"
#include "ssl/app/espconn_ssl.h"
#include "ets_sys.h"
#include "os_type.h"
//#include "os.h"
#include "lwip/app/espconn.h"
struct pbuf *psslpbuf = NULL;
extern espconn_msg *plink_active;
static err_t espconn_ssl_crecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
static err_t espconn_ssl_srecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
static void espconn_ssl_sclose(void *arg, struct tcp_pcb *pcb);
static void espconn_ssl_cclose(void *arg, struct tcp_pcb *pcb);
/////////////////////////////common function///////////////////////////////////
/******************************************************************************
* FunctionName : display_session_id
* Description : Display what session id we have.
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR display_session_id(SSL *ssl)
{
int i;
const uint8_t *session_id = ssl_get_session_id(ssl);
int sess_id_size = ssl_get_session_id_size(ssl);
if (sess_id_size > 0) {
ssl_printf("-----BEGIN SSL SESSION PARAMETERS-----\n");
for (i = 0; i < sess_id_size; i++) {
ssl_printf("%02x", session_id[i]);
}
ssl_printf("\n-----END SSL SESSION PARAMETERS-----\n");
//TTY_FLUSH();
}
}
/******************************************************************************
* FunctionName : display_cipher
* Description : Display what cipher we are using
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR display_cipher(SSL *ssl)
{
ssl_printf("CIPHER is ");
switch (ssl_get_cipher_id(ssl)) {
case SSL_AES128_SHA:
ssl_printf("AES128-SHA");
break;
case SSL_AES256_SHA:
ssl_printf("AES256-SHA");
break;
case SSL_RC4_128_SHA:
ssl_printf("RC4-SHA");
break;
case SSL_RC4_128_MD5:
ssl_printf("RC4-MD5");
break;
default:
ssl_printf("Unknown - %d", ssl_get_cipher_id(ssl));
break;
}
ssl_printf("\n");
//TTY_FLUSH();
}
/******************************************************************************
* FunctionName : espconn_ssl_reconnect
* Description : reconnect with host
* Parameters : arg -- Additional argument to pass to the callback function
* Returns : none
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_reconnect(void *arg)
{
espconn_msg *pssl_recon = arg;
struct espconn *espconn = NULL;
ssl_msg *pssl = NULL;
sint8 ssl_reerr = 0;
if (pssl_recon != NULL) {
espconn = pssl_recon->preverse;
if (pssl_recon->pespconn != NULL){
if (espconn != NULL){
/*espconn_copy_partial(espconn, pssl_recon->pespconn);
if (pssl_recon->pespconn->proto.tcp != NULL){
os_free(pssl_recon->pespconn->proto.tcp);
pssl_recon->pespconn->proto.tcp = NULL;
}
os_free(pssl_recon->pespconn);
pssl_recon->pespconn = NULL;*/
espconn = pssl_recon->preverse;
} else {
espconn = pssl_recon->pespconn;
}
}
pssl = pssl_recon->pssl;
ssl_reerr = pssl_recon->pcommon.err;
if (pssl != NULL) {
if (pssl->ssl) {
ssl_free(pssl->ssl);
}
if (pssl->ssl_ctx) {
ssl_ctx_free(pssl->ssl_ctx);
}
os_free(pssl);
pssl = NULL;
pssl_recon->pssl = pssl;
}
os_free(pssl_recon);
pssl_recon = NULL;
if (espconn ->proto.tcp->reconnect_callback != NULL) {
espconn ->proto.tcp->reconnect_callback(espconn, ssl_reerr);
}
} else {
ssl_printf("espconn_ssl_reconnect err\n");
}
}
/******************************************************************************
* FunctionName : espconn_ssl_dissuccessful
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_dissuccessful(void *arg)
{
espconn_msg *pdiscon = arg;
struct espconn *espconn = NULL;
struct tcp_pcb *pcb = NULL;
ssl_msg *pssl = NULL;
if (pdiscon != NULL) {
espconn = pdiscon->preverse;
if (pdiscon->pespconn != NULL){
if (espconn != NULL){
/*espconn_copy_partial(espconn, pdiscon->pespconn);
if (pdiscon->pespconn->proto.tcp != NULL){
os_free(pdiscon->pespconn->proto.tcp);
pdiscon->pespconn->proto.tcp = NULL;
}
os_free(pdiscon->pespconn);
pdiscon->pespconn = NULL;*/
espconn = pdiscon->preverse;
} else{
espconn = pdiscon->pespconn;
}
pcb = pdiscon->pcommon.pcb;
tcp_arg(pcb, NULL);
tcp_err(pcb, NULL);
}
pssl = pdiscon->pssl;
if (pssl != NULL) {
if (pssl->ssl) {
ssl_free(pssl->ssl);
}
if (pssl->ssl_ctx) {
ssl_ctx_free(pssl->ssl_ctx);
}
os_free(pssl);
pssl = NULL;
pdiscon->pssl = pssl;
}
os_free(pdiscon);
pdiscon = NULL;
if (espconn ->proto.tcp->disconnect_callback != NULL) {
espconn ->proto.tcp->disconnect_callback(espconn);
}
} else {
espconn_printf("espconn_ssl_dissuccessful err\n");
}
}
/******************************************************************************
* FunctionName : espconn_ssl_write
* Description : sent data for client or server
* Parameters : void *arg -- client or server to send
* uint8* psent -- Data to send
* uint16 length -- Length of data to send
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
espconn_ssl_sent(void *arg, uint8 *psent, uint16 length)
{
espconn_msg *pssl_sent = arg;
struct tcp_pcb *pcb = NULL;
ssl_msg *pssl = NULL;
u16_t len = 0;
int res = 0;
ssl_printf("espconn_ssl_sent pcb %p psent %p length %d\n", arg, psent, length);
if (pssl_sent == NULL || psent == NULL || length == 0) {
return;
}
pcb = pssl_sent->pcommon.pcb;
pssl = pssl_sent->pssl;
if (RT_MAX_PLAIN_LENGTH < length) {
len = RT_MAX_PLAIN_LENGTH;
} else {
len = length;
}
if (pssl != NULL) {
if (pssl->ssl != NULL) {
pssl->ssl->SslClient_pcb = pcb;
res = ssl_write(pssl->ssl, psent, len);
pssl_sent->pcommon.ptrbuf = psent + len;
pssl_sent->pcommon.cntr = length - len;
}
}
}
/******************************************************************************
* FunctionName : espconn_sent_packet
* Description : sent data for client or server
* Parameters : void *arg -- client or server to send
* uint8* psent -- Data to send
* uint16 length -- Length of data to send
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
espconn_sent_packet(struct tcp_pcb *pcb, uint8 *psent, uint16 length)
{
err_t err = 0;
u16_t len = 0;
if (pcb == NULL || psent == NULL || length == 0) {
return;
}
if (tcp_sndbuf(pcb) < length) {
len = tcp_sndbuf(pcb);
} else {
len = length;
}
if (len > (2 * pcb->mss)) {
len = 2 * pcb->mss;
}
do {
err = tcp_write(pcb, psent, len, 0);
if (err == ERR_MEM) {
len /= 2;
}
} while (err == ERR_MEM && len > 1);
if (err == ERR_OK) {
err = tcp_output(pcb);
}
}
////////////////////////////////client function////////////////////////////////
/******************************************************************************
* FunctionName : espconn_ssl_cclose_cb
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_cclose_cb(void *arg)
{
static uint16 timecount = 0;
espconn_msg *pcclose_cb = arg;
if (pcclose_cb == NULL) {
return;
}
struct tcp_pcb *pcb = pcclose_cb->pcommon.pcb;
ssl_printf("espconn_ssl_cclose_cb %d %d\n", pcb->state, pcb->nrtx);
if (pcb->state == TIME_WAIT || pcb->state == CLOSED) {
pcclose_cb->pespconn ->state = ESPCONN_CLOSE;
/*remove the node from the client's active connection list*/
espconn_list_delete(&plink_active, pcclose_cb);
espconn_ssl_dissuccessful((void *)pcclose_cb);
} else {
os_timer_arm(&pcclose_cb->pcommon.ptimer, TCP_FAST_INTERVAL, 0);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_close
* Description : The connection shall be actively closed.
* Parameters : pcb -- Additional argument to pass to the callback function
* pcb -- the pcb to close
* Returns : none
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_cclose(void *arg, struct tcp_pcb *pcb)
{
espconn_msg *pcclose = arg;
os_timer_disarm(&pcclose->pcommon.ptimer);
os_timer_setfn(&pcclose->pcommon.ptimer, espconn_ssl_cclose_cb, pcclose);
os_timer_arm(&pcclose->pcommon.ptimer, TCP_FAST_INTERVAL, 0);
tcp_recv(pcb, NULL);
pcclose->pcommon.err = tcp_close(pcb);
ssl_printf("espconn_ssl_cclose %d\n", pcclose->pcommon.err);
if (pcclose->pcommon.err != ERR_OK) {
/* closing failed, try again later */
tcp_recv(pcb, espconn_ssl_crecv);
} else {
tcp_sent(pcb, NULL);
tcp_poll(pcb, NULL, 0);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_sent
* Description : Data has been sent and acknowledged by the remote host.
* This means that more data can be sent.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb for which data has been acknowledged
* len -- The amount of bytes acknowledged
* Returns : ERR_OK: try to send some data by calling tcp_output
* ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_ssl_csent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
espconn_msg *psent = arg;
ssl_msg *pssl = psent->pssl;
psent->pcommon.pcb = pcb;
if (pssl->quiet == true) {
int pkt_size = pssl->ssl->bm_index + SSL_RECORD_SIZE;
u16_t max_len = 2 * pcb->mss;
pssl->pkt_length += len;
ssl_printf("espconn_ssl_csent %d %d %d\n", len, pssl->pkt_length, pkt_size);
if (pssl->pkt_length == pkt_size){
pssl->ssl->bm_index = 0;
pssl->pkt_length = 0;
if (psent->pcommon.cntr == 0) {
psent->pespconn->state = ESPCONN_CONNECT;
if (psent->pespconn->sent_callback != NULL) {
psent->pespconn->sent_callback(psent->pespconn);
}
} else {
espconn_ssl_sent(psent, psent->pcommon.ptrbuf, psent->pcommon.cntr);
}
} else {
if (len == max_len){
espconn_sent_packet(pcb, &pssl->ssl->bm_all_data[pssl->pkt_length], pkt_size - pssl->pkt_length);
}
}
} else {
ssl_printf("espconn_ssl_csent %p %p %d\n", pcb, pssl->ssl->bm_all_data, len);
}
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_sslclient_recv
* Description : Data has been received on this pcb.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb which received data
* p -- The received data (or NULL when the connection has been closed!)
* err -- An error code if there has been an error receiving
* Returns : ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_ssl_crecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
u16_t ret = 0;
espconn_msg *precv = arg;
ssl_msg *pssl = precv->pssl;
ssl_printf("espconn_ssl_crecv %d %p %p\n", __LINE__, pssl->ssl, p);
if (p != NULL) {
tcp_recved(pcb, p ->tot_len);
if (pssl->ssl == NULL) {
pbuf_free(p);
} else {
pssl->ssl->ssl_pbuf = p;
if (ssl_handshake_status(pssl->ssl) != SSL_OK) {
ret = ssl_read(pssl->ssl, NULL);
pbuf_free(p);
if (ret != SSL_OK){
os_printf("client handshake failed\n");
espconn_ssl_cclose(arg, pcb);
}
}
if (ssl_handshake_status(pssl->ssl) == SSL_OK) {
if (!pssl->quiet) {
ssl_printf("client handshake need size %d\n", system_get_free_heap_size());
const char *common_name = ssl_get_cert_dn(pssl->ssl,
SSL_X509_CERT_COMMON_NAME);
if (common_name) {
ssl_printf("Common Name:\t\t\t%s\n", common_name);
}
display_session_id(pssl->ssl);
display_cipher(pssl->ssl);
pssl->quiet = true;
os_printf("client handshake ok!\n");
REG_CLR_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(80);
precv->pespconn->state = ESPCONN_CONNECT;
precv->pcommon.pcb = pcb;
pbuf_free(p);
if (precv->pespconn->proto.tcp->connect_callback != NULL) {
precv->pespconn->proto.tcp->connect_callback(precv->pespconn);
}
} else {
uint8_t *read_buf = NULL;
ret = ssl_read(pssl->ssl, &read_buf);
precv->pespconn->state = ESPCONN_READ;
precv->pcommon.pcb = pcb;
pbuf_free(p);
if (precv->pespconn->recv_callback != NULL && read_buf != NULL) {
precv->pespconn->recv_callback(precv->pespconn, read_buf, ret);
}
precv->pespconn->state = ESPCONN_CONNECT;
}
}
}
}
if (err == ERR_OK && p == NULL) {
espconn_ssl_cclose(precv, pcb);
}
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_client_err
* Description : The pcb had an error and is already deallocated.
* The argument might still be valid (if != NULL).
* Parameters : arg -- Additional argument to pass to the callback function
* err -- Error code to indicate why the pcb has been closed
* Returns : none
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_cerr(void *arg, err_t err)
{
espconn_msg *pssl_cerr = arg;
struct tcp_pcb *pcb = NULL;
LWIP_UNUSED_ARG(err);
if (pssl_cerr != NULL) {
os_timer_disarm(&pssl_cerr->pcommon.ptimer);
pcb = pssl_cerr->pcommon.pcb;
pssl_cerr->pespconn->state = ESPCONN_CLOSE;
espconn_printf("espconn_ssl_cerr %d %d %d\n", pcb->state, pcb->nrtx, err);
/*remove the node from the client's active connection list*/
espconn_list_delete(&plink_active, pssl_cerr);
if (err == ERR_ABRT) {
switch (pcb->state) {
case SYN_SENT:
if (pcb->nrtx == TCP_SYNMAXRTX) {
pssl_cerr->pcommon.err = ESPCONN_CONN;
} else {
pssl_cerr->pcommon.err = err;
}
break;
case ESTABLISHED:
if (pcb->nrtx == TCP_MAXRTX) {
pssl_cerr->pcommon.err = ESPCONN_TIMEOUT;
} else {
pssl_cerr->pcommon.err = err;
}
break;
case FIN_WAIT_1:
if (pcb->nrtx == TCP_MAXRTX) {
pssl_cerr->pcommon.err = ESPCONN_CLSD;
} else {
pssl_cerr->pcommon.err = err;
}
break;
case FIN_WAIT_2:
pssl_cerr->pcommon.err = ESPCONN_CLSD;
break;
case CLOSED:
pssl_cerr->pcommon.err = ESPCONN_CONN;
break;
default :
break;
}
} else {
pssl_cerr->pcommon.err = err;
}
os_timer_setfn(&pssl_cerr->pcommon.ptimer, espconn_ssl_reconnect, pssl_cerr);
os_timer_arm(&pssl_cerr->pcommon.ptimer, 10, 0);
}
}
#if 0
/******************************************************************************
* FunctionName : espconn_ssl_cpoll
* Description : The poll function is called every 3nd second.
* If there has been no data sent (which resets the retries) in 3 seconds, close.
* If the last portion of a file has not been sent in 3 seconds, close.
*
* This could be increased, but we don't want to waste resources for bad connections.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb for which data has been acknowledged
* Returns : ERR_OK: try to send some data by calling tcp_output
* ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_ssl_cpoll(void *arg, struct tcp_pcb *pcb)
{
ssl_printf("espconn_ssl_cpoll %p %d\n", pcb, pcb->state);
struct espconn *espconn = arg;
if (arg == NULL) {
tcp_abandon(pcb, 0);
tcp_poll(pcb, NULL, 0);
return ERR_ABRT;
}
if (pcb ->state == ESTABLISHED) {
espconn->recv_check ++;
if (espconn ->recv_check == 0x05){
//tcp_poll(pcb, espconn_ssl_cpoll, 0);
espconn->recv_check = 0;
espconn_ssl_cclose(arg, pcb);
}
} else {
//tcp_poll(pcb, espconn_ssl_cpoll, 0);
espconn_ssl_cclose(arg, pcb);
}
return ERR_OK;
}
#endif
/******************************************************************************
* FunctionName : espconn_sslclient_connect
* Description : A new incoming connection has been connected.
* Parameters : arg -- Additional argument to pass to the callback function
* tpcb -- The connection pcb which is connected
* err -- An unused error code, always ERR_OK currently
* Returns : connection result
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_ssl_connect(void *arg, struct tcp_pcb *tpcb, err_t err)
{
espconn_msg *pconnect = arg;
ssl_msg *pssl = NULL;
uint32_t options;
options = SSL_SERVER_VERIFY_LATER | SSL_DISPLAY_CERTS | SSL_NO_DEFAULT_KEY;
ssl_printf("espconn_ssl_connect %p %p %p %d\n", tpcb, arg, pespconn->psecure, system_get_free_heap_size());
//if (pespconn->psecure != NULL){
// return ERR_ISCONN;
//}
pconnect->pcommon.pcb = tpcb;
pssl = (ssl_msg *)os_zalloc(sizeof(ssl_msg));
pconnect->pssl = pssl;
if (pssl == NULL) {
return ERR_MEM;
}
REG_SET_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(160);
os_printf("client handshake start.\n");
pssl->quiet = false;
pssl->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS);
if (pssl->ssl_ctx == NULL) {
return ERR_MEM;
}
ssl_printf("espconn_ssl_client ssl_ctx %p\n", pssl->ssl_ctx);
pssl->ssl = SSLClient_new(pssl->ssl_ctx, tpcb, NULL, 0);
if (pssl->ssl == NULL) {
return ERR_MEM;
}
tcp_arg(tpcb, arg);
tcp_sent(tpcb, espconn_ssl_csent);
tcp_recv(tpcb, espconn_ssl_crecv);
//tcp_poll(tpcb, espconn_ssl_cpoll, 6);
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_ssl_disconnect
* Description : A new incoming connection has been disconnected.
* Parameters : espconn -- the espconn used to disconnect with host
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR espconn_ssl_disconnect(espconn_msg *pdis)
{
if (pdis != NULL) {
if (pdis->preverse == NULL)
espconn_ssl_cclose(pdis, pdis->pcommon.pcb);
else
espconn_ssl_sclose(pdis, pdis->pcommon.pcb);
} else {
ssl_printf("espconn_ssl_disconnect err.\n");
}
}
/******************************************************************************
* FunctionName : espconn_ssl_client
* Description : Initialize the client: set up a connect PCB and bind it to
* the defined port
* Parameters : espconn -- the espconn used to build client
* Returns : none
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR
espconn_ssl_client(struct espconn *espconn)
{
struct tcp_pcb *pcb;
struct ip_addr ipaddr;
espconn_msg *pclient = NULL;
pclient = plink_active;
while(pclient != NULL){
if (pclient->pssl != NULL)
return ESPCONN_ISCONN;
pclient = pclient->pnext;
}
pclient = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
if (pclient == NULL){
return ESPCONN_MEM;
}
IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0],
espconn->proto.tcp->remote_ip[1],
espconn->proto.tcp->remote_ip[2],
espconn->proto.tcp->remote_ip[3]);
pcb = tcp_new();
if (pcb == NULL) {
espconn ->state = ESPCONN_NONE;
os_free(pclient);
pclient = NULL;
return ESPCONN_MEM;
} else {
/*insert the node to the active connection list*/
espconn_list_creat(&plink_active, pclient);
tcp_arg(pcb, (void *)pclient);
tcp_err(pcb, espconn_ssl_cerr);
pclient->preverse = NULL;
pclient->pespconn = espconn;
pclient->pespconn->state = ESPCONN_WAIT;
pclient->pcommon.pcb = pcb;
tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port);
pclient->pcommon.err = tcp_connect(pcb, &ipaddr, pclient->pespconn->proto.tcp->remote_port, espconn_ssl_connect);
return ESPCONN_OK;
}
}
/////////////////////////////server's function/////////////////////////////////
/******************************************************************************
* FunctionName : espconn_ssl_sclose_cb
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_sclose_cb(void *arg)
{
static uint16 timecount = 0;
espconn_msg *psclose_cb = arg;
if (psclose_cb == NULL) {
return;
}
struct tcp_pcb *pcb = psclose_cb->pcommon.pcb;
ssl_printf("espconn_ssl_sclose_cb %d %d\n", pcb->state, pcb->nrtx);
if (pcb->state == CLOSED || pcb->state == TIME_WAIT) {
psclose_cb ->pespconn ->state = ESPCONN_CLOSE;
psclose_cb->pespconn->link_cnt --;
/*remove the node from the server's active connection list*/
espconn_list_delete(&plink_active, psclose_cb);
espconn_ssl_dissuccessful((void *)psclose_cb);
} else {
os_timer_arm(&psclose_cb->pcommon.ptimer, TCP_FAST_INTERVAL, 0);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_close
* Description : The connection shall be actively closed.
* Parameters : pcb -- Additional argument to pass to the callback function
* pcb -- the pcb to close
* Returns : none
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_sclose(void *arg, struct tcp_pcb *pcb)
{
espconn_msg *psclose = arg;
os_timer_disarm(&psclose->pcommon.ptimer);
os_timer_setfn(&psclose->pcommon.ptimer, espconn_ssl_sclose_cb, psclose);
os_timer_arm(&psclose->pcommon.ptimer, TCP_FAST_INTERVAL, 0);
tcp_recv(pcb, NULL);
psclose->pcommon.err = tcp_close(pcb);
if (psclose->pcommon.err != ERR_OK) {
/* closing failed, try again later */
tcp_recv(pcb, espconn_ssl_srecv);
} else {
tcp_sent(pcb, NULL);
tcp_poll(pcb, NULL, 0);
}
}
/******************************************************************************
* FunctionName : espconn_sslclient_sent
* Description : Data has been sent and acknowledged by the remote host.
* This means that more data can be sent.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb for which data has been acknowledged
* len -- The amount of bytes acknowledged
* Returns : ERR_OK: try to send some data by calling tcp_output
* ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_ssl_ssent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
espconn_msg *psent = arg;
ssl_msg *pssl = psent->pssl;
psent->pcommon.pcb = pcb;
psent->pcommon.recv_check = 0;
if (ssl_handshake_status(pssl->ssl) == SSL_OK) {
if (!pssl->quiet) {
ssl_printf("espconn_ssl_ssent %p %d\n",pcb, system_get_free_heap_size());
const char *common_name = ssl_get_cert_dn(pssl->ssl, SSL_X509_CERT_COMMON_NAME);
if (common_name) {
ssl_printf("Common Name:\t\t\t%s\n", common_name);
}
display_session_id(pssl->ssl);
display_cipher(pssl->ssl);
pssl->quiet = true;
os_printf("server handshake ok!\n");
REG_CLR_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(80);
psent->pespconn->state = ESPCONN_CONNECT;
if (psent->pespconn->proto.tcp->connect_callback != NULL) {
psent->pespconn->proto.tcp->connect_callback(psent->pespconn);
}
} else {
int pkt_size = pssl->ssl->bm_index + SSL_RECORD_SIZE;
u16_t max_len = 2 * pcb->mss;
pssl->pkt_length += len;
ssl_printf("espconn_ssl_ssent %d %d %d\n", len, pssl->pkt_length, pkt_size);
if (pssl->pkt_length == pkt_size){
pssl->ssl->bm_index = 0;
pssl->pkt_length = 0;
if (psent->pcommon.cntr == 0) {
psent->pespconn->state = ESPCONN_CONNECT;
if (psent->pespconn->sent_callback != NULL) {
psent->pespconn->sent_callback(psent->pespconn);
}
} else {
espconn_ssl_sent(psent, psent->pcommon.ptrbuf, psent->pcommon.cntr);
}
} else {
if (len == max_len){
espconn_sent_packet(pcb, &pssl->ssl->bm_all_data[pssl->pkt_length], pkt_size - pssl->pkt_length);
}
}
}
} else {
ssl_printf("espconn_ssl_ssent %p %p %d\n",pcb, pssl->ssl->bm_all_data, len);
}
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_sslclient_recv
* Description : Data has been received on this pcb.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb which received data
* p -- The received data (or NULL when the connection has been closed!)
* err -- An error code if there has been an error receiving
* Returns : ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_ssl_srecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
u16_t ret = 0;
espconn_msg *precv = arg;
ssl_msg *pssl = precv->pssl;
ssl_printf("espconn_ssl_srecv %d %p %p\n", __LINE__, pcb, p);
if (p != NULL) {
tcp_recved(pcb, p ->tot_len);
precv->pcommon.recv_check = 0;
if (pssl->ssl == NULL) {
pbuf_free(p);
} else {
pssl->ssl->ssl_pbuf = p;
if (ssl_handshake_status(pssl->ssl) != SSL_OK) {
ret = ssl_read(pssl->ssl, NULL);
pbuf_free(p);
if (ret != SSL_OK){
os_printf("server handshake failed.\n");
espconn_ssl_sclose(arg, pcb);
}
} else {
uint8_t *read_buf = NULL;
ret = ssl_read(pssl->ssl, &read_buf);
precv->pespconn->state = ESPCONN_READ;
precv->pcommon.pcb = pcb;
pbuf_free(p);
if (precv->pespconn->recv_callback != NULL && read_buf != NULL) {
precv->pespconn->recv_callback(precv->pespconn, read_buf, ret);
}
precv->pespconn->state = ESPCONN_CONNECT;
}
}
}
if (err == ERR_OK && p == NULL) {
espconn_ssl_sclose(precv, pcb);
}
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_server_poll
* Description : The poll function is called every 3nd second.
* If there has been no data sent (which resets the retries) in 3 seconds, close.
* If the last portion of a file has not been sent in 3 seconds, close.
*
* This could be increased, but we don't want to waste resources for bad connections.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb for which data has been acknowledged
* Returns : ERR_OK: try to send some data by calling tcp_output
* ERR_ABRT: if you have called tcp_abort from within the function!
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_ssl_spoll(void *arg, struct tcp_pcb *pcb)
{
ssl_printf("espconn_ssl_spoll %p %d\n", pcb, pcb->state);
espconn_msg *pspoll = arg;
if (arg == NULL) {
tcp_abandon(pcb, 0);
tcp_poll(pcb, NULL, 0);
return ERR_ABRT;
}
if (pcb ->state == ESTABLISHED) {
pspoll ->pcommon.recv_check ++;
if (pspoll ->pcommon.recv_check == pspoll ->pcommon.timeout){
tcp_poll(pcb, NULL, 0);
pspoll ->pcommon.recv_check = 0;
espconn_ssl_sclose(arg, pcb);
}
} else {
tcp_poll(pcb, NULL, 0);
espconn_ssl_sclose(arg, pcb);
}
return ERR_OK;
}
/******************************************************************************
* FunctionName : esponn_server_err
* Description : The pcb had an error and is already deallocated.
* The argument might still be valid (if != NULL).
* Parameters : arg -- Additional argument to pass to the callback function
* err -- Error code to indicate why the pcb has been closed
* Returns : none
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_ssl_serr(void *arg, err_t err)
{
espconn_msg *pserr = arg;
struct tcp_pcb *pcb = NULL;
LWIP_UNUSED_ARG(err);
if (pserr != NULL) {
os_timer_disarm(&pserr->pcommon.ptimer);
pcb = pserr->pcommon.pcb;
pserr->pespconn->state = ESPCONN_CLOSE;
/*remove the node from the server's active connection list*/
espconn_list_delete(&plink_active, pserr);
if (err == ERR_ABRT) {
switch (pcb->state) {
case SYN_RCVD:
if (pcb->nrtx == TCP_SYNMAXRTX) {
pserr->pcommon.err = ESPCONN_CONN;
} else {
pserr->pcommon.err = err;
}
break;
case ESTABLISHED:
if (pcb->nrtx == TCP_MAXRTX) {
pserr->pcommon.err = ESPCONN_TIMEOUT;
} else {
pserr->pcommon.err = err;
}
break;
case CLOSE_WAIT:
if (pcb->nrtx == TCP_MAXRTX) {
pserr->pcommon.err = ESPCONN_CLSD;
} else {
pserr->pcommon.err = err;
}
break;
case LAST_ACK:
pserr->pcommon.err = ESPCONN_CLSD;
break;
case CLOSED:
pserr->pcommon.err = ESPCONN_CONN;
break;
default :
break;
}
} else {
pserr->pcommon.err = err;
}
os_timer_setfn(&pserr->pcommon.ptimer, espconn_ssl_reconnect, pserr);
os_timer_arm(&pserr->pcommon.ptimer, 10, 0);
}
}
/******************************************************************************
* FunctionName : espconn_tcp_accept
* Description : A new incoming connection has been accepted.
* Parameters : arg -- Additional argument to pass to the callback function
* pcb -- The connection pcb which is accepted
* err -- An unused error code, always ERR_OK currently
* Returns : acception result
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_ssl_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct espconn *espconn = arg;
ssl_msg *pssl = NULL;
espconn_msg *paccept = NULL;
remot_info *pinfo = NULL;
ssl_printf("espconn_ssl_accept %p %p %p %d\n", pcb, arg, espconn->psecure, system_get_free_heap_size());
LWIP_UNUSED_ARG(err);
paccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
tcp_arg(pcb, paccept);
tcp_err(pcb, espconn_ssl_serr);
if (paccept == NULL)
return ERR_MEM;
/*insert the node to the active connection list*/
espconn_list_creat(&plink_active, paccept);
paccept->preverse = espconn;
paccept->pespconn = espconn;
paccept->pcommon.timeout = 0x0a;
paccept->pcommon.pcb = pcb;
paccept->pcommon.remote_port = pcb->remote_port;
paccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip);
paccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip);
paccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip);
paccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip);
os_memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4);
espconn->proto.tcp->remote_port = pcb->remote_port;
espconn_get_connection_info(espconn, &pinfo , ESPCONN_SSL);
if (espconn->link_cnt == 0x01)
return ERR_ISCONN;
pssl = (ssl_msg *)os_zalloc(sizeof(ssl_msg));
paccept->pssl = pssl;
if (pssl == NULL) {
return ERR_MEM;
}
REG_SET_BIT(0x3ff00014, BIT(0));
os_update_cpu_frequency(160);
os_printf("server handshake start.\n");
pssl->quiet = false;
pssl->ssl_ctx = ssl_ctx_new(SSL_DISPLAY_CERTS, SSL_DEFAULT_SVR_SESS);
if (pssl->ssl_ctx == NULL) {
ssl_printf("Error: Server context is invalid\n");
return ERR_MEM;
}
ssl_printf("Server context %p\n", pssl->ssl_ctx);
pssl->ssl = sslserver_new(pssl->ssl_ctx, pcb);
if (pssl->ssl == NULL) {
ssl_printf("Error: Server ssl connection is invalid\n");
return ERR_MEM;
}
tcp_sent(pcb, espconn_ssl_ssent);
tcp_recv(pcb, espconn_ssl_srecv);
tcp_poll(pcb, espconn_ssl_spoll, 2);
return ERR_OK;
}
/******************************************************************************
* FunctionName : espconn_ssl_server
* Description : as
* Parameters :
* Returns :
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR espconn_ssl_server(struct espconn *espconn)
{
struct tcp_pcb *pcb;
pcb = tcp_new();
if (pcb == NULL) {
espconn ->state = ESPCONN_NONE;
return ESPCONN_MEM;
} else {
tcp_bind(pcb, IP_ADDR_ANY, espconn->proto.tcp->local_port);
pcb = tcp_listen(pcb);
if (pcb != NULL) {
espconn ->state = ESPCONN_LISTEN;
tcp_arg(pcb, (void *)espconn);
tcp_accept(pcb, espconn_ssl_accept);
return ESPCONN_OK;
} else {
espconn ->state = ESPCONN_NONE;
return ESPCONN_MEM;
}
}
}
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 COPYRIGHT OWNER OR
* CONTRIBUTORS 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.
*/
/**
* AES implementation - this is a small code version. There are much faster
* versions around but they are much larger in size (i.e. they use large
* submix tables).
*/
//#include <string.h>
#include "lwip/opt.h"
#include "lwip/def.h"
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto.h"
/* all commented out in skeleton mode */
#ifndef CONFIG_SSL_SKELETON_MODE
#define rot1(x) (((x) << 24) | ((x) >> 8))
#define rot2(x) (((x) << 16) | ((x) >> 16))
#define rot3(x) (((x) << 8) | ((x) >> 24))
/*
* This cute trick does 4 'mul by two' at once. Stolen from
* Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is
* a standard graphics trick
* The key to this is that we need to xor with 0x1b if the top bit is set.
* a 1xxx xxxx 0xxx 0xxx First we mask the 7bit,
* b 1000 0000 0000 0000 then we shift right by 7 putting the 7bit in 0bit,
* c 0000 0001 0000 0000 we then subtract (c) from (b)
* d 0111 1111 0000 0000 and now we and with our mask
* e 0001 1011 0000 0000
*/
#define mt 0x80808080
#define ml 0x7f7f7f7f
#define mh 0xfefefefe
#define mm 0x1b1b1b1b
#define mul2(x,t) ((t)=((x)&mt), \
((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
#define inv_mix_col(x,f2,f4,f8,f9) (\
(f2)=mul2(x,f2), \
(f4)=mul2(f2,f4), \
(f8)=mul2(f4,f8), \
(f9)=(x)^(f8), \
(f8)=((f2)^(f4)^(f8)), \
(f2)^=(f9), \
(f4)^=(f9), \
(f8)^=rot3(f2), \
(f8)^=rot2(f4), \
(f8)^rot1(f9))
/*
* AES S-box
*/
static const uint8_t aes_sbox[256] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR =
{
0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,
0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,
0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,
0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,
0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,
0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,
0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,
0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,
0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,
0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,
0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,
0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,
0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,
0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,
0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,
0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,
0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,
};
/*
* AES is-box
*/
static const uint8_t aes_isbox[256] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR =
{
0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
};
static const unsigned char Rcon[30]=
{
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,
0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,
0xb3,0x7d,0xfa,0xef,0xc5,0x91,
};
/* ----- static functions ----- */
static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
x^8+x^4+x^3+x+1 */
static unsigned char ICACHE_FLASH_ATTR AES_xtime(uint32_t x)
{
return (x&0x80) ? (x<<1)^0x1b : x<<1;
}
/**
* Set up AES with the key/iv and cipher size.
*/
void ICACHE_FLASH_ATTR AES_set_key(AES_CTX *ctx, const uint8_t *key,
const uint8_t *iv, AES_MODE mode)
{
int i, ii;
uint32_t *W, tmp, tmp2;
const unsigned char *ip;
int words;
switch (mode)
{
case AES_MODE_128:
i = 10;
words = 4;
break;
case AES_MODE_256:
i = 14;
words = 8;
break;
default: /* fail silently */
return;
}
ctx->rounds = i;
ctx->key_size = words;
W = ctx->ks;
for (i = 0; i < words; i+=2)
{
W[i+0]= ((uint32_t)key[ 0]<<24)|
((uint32_t)key[ 1]<<16)|
((uint32_t)key[ 2]<< 8)|
((uint32_t)key[ 3] );
W[i+1]= ((uint32_t)key[ 4]<<24)|
((uint32_t)key[ 5]<<16)|
((uint32_t)key[ 6]<< 8)|
((uint32_t)key[ 7] );
key += 8;
}
ip = Rcon;
ii = 4 * (ctx->rounds+1);
for (i = words; i<ii; i++)
{
tmp = W[i-1];
if ((i % words) == 0)
{
// tmp2 =(uint32_t)aes_sbox[(tmp )&0xff]<< 8;
// tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
// tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
// tmp2|=(uint32_t)aes_sbox[(tmp>>24) ];
tmp2 =((uint32_t)byte_of_aligned_array(aes_sbox,(tmp )&0xff))<< 8;
tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>> 8)&0xff))<<16;
tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>>16)&0xff))<<24;
tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>>24) ));
tmp=tmp2^(((unsigned int)*ip)<<24);
ip++;
}
if ((words == 8) && ((i % words) == 4))
{
// tmp2 =(uint32_t)aes_sbox[(tmp )&0xff] ;
// tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
// tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
// tmp2|=(uint32_t)aes_sbox[(tmp>>24) ]<<24;
tmp2 =((uint32_t)byte_of_aligned_array(aes_sbox,(tmp )&0xff)) ;
tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>> 8)&0xff))<< 8;
tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>>16)&0xff))<<16;
tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>>24) ))<<24;
tmp=tmp2;
}
W[i]=W[i-words]^tmp;
}
/* copy the iv across */
os_memcpy(ctx->iv, iv, 16);
}
/**
* Change a key for decryption.
*/
void ICACHE_FLASH_ATTR AES_convert_key(AES_CTX *ctx)
{
int i;
uint32_t *k,w,t1,t2,t3,t4;
k = ctx->ks;
k += 4;
for (i= ctx->rounds*4; i > 4; i--)
{
w= *k;
w = inv_mix_col(w,t1,t2,t3,t4);
*k++ =w;
}
}
/**
* Encrypt a byte sequence (with a block size 16) using the AES cipher.
*/
void ICACHE_FLASH_ATTR AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
{
int i;
uint32_t tin[4], tout[4], iv[4];
os_memcpy(iv, ctx->iv, AES_IV_SIZE);
for (i = 0; i < 4; i++)
tout[i] = ntohl(iv[i]);
for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
{
uint32_t msg_32[4];
uint32_t out_32[4];
os_memcpy(msg_32, msg, AES_BLOCKSIZE);
msg += AES_BLOCKSIZE;
for (i = 0; i < 4; i++)
tin[i] = ntohl(msg_32[i])^tout[i];
AES_encrypt(ctx, tin);
for (i = 0; i < 4; i++)
{
tout[i] = tin[i];
out_32[i] = htonl(tout[i]);
}
os_memcpy(out, out_32, AES_BLOCKSIZE);
out += AES_BLOCKSIZE;
}
for (i = 0; i < 4; i++)
iv[i] = htonl(tout[i]);
os_memcpy(ctx->iv, iv, AES_IV_SIZE);
}
/**
* Decrypt a byte sequence (with a block size 16) using the AES cipher.
*/
void ICACHE_FLASH_ATTR AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
{
int i;
uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
os_memcpy(iv, ctx->iv, AES_IV_SIZE);
for (i = 0; i < 4; i++)
xor[i] = ntohl(iv[i]);
for (length -= 16; length >= 0; length -= 16)
{
uint32_t msg_32[4];
uint32_t out_32[4];
os_memcpy(msg_32, msg, AES_BLOCKSIZE);
msg += AES_BLOCKSIZE;
for (i = 0; i < 4; i++)
{
tin[i] = ntohl(msg_32[i]);
data[i] = tin[i];
}
AES_decrypt(ctx, data);
for (i = 0; i < 4; i++)
{
tout[i] = data[i]^xor[i];
xor[i] = tin[i];
out_32[i] = htonl(tout[i]);
}
os_memcpy(out, out_32, AES_BLOCKSIZE);
out += AES_BLOCKSIZE;
}
for (i = 0; i < 4; i++)
iv[i] = htonl(xor[i]);
os_memcpy(ctx->iv, iv, AES_IV_SIZE);
}
/**
* Encrypt a single block (16 bytes) of data
*/
static void ICACHE_FLASH_ATTR AES_encrypt(const AES_CTX *ctx, uint32_t *data)
{
/* To make this code smaller, generate the sbox entries on the fly.
* This will have a really heavy effect upon performance.
*/
uint32_t tmp[4];
uint32_t tmp1, old_a0, a0, a1, a2, a3, row;
int curr_rnd;
int rounds = ctx->rounds;
const uint32_t *k = ctx->ks;
/* Pre-round key addition */
for (row = 0; row < 4; row++)
data[row] ^= *(k++);
/* Encrypt one block. */
for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
{
/* Perform ByteSub and ShiftRow operations together */
for (row = 0; row < 4; row++)
{
// a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
// a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
// a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF];
// a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
a0 = (uint32_t)(byte_of_aligned_array(aes_sbox,(data[row%4]>>24)&0xFF));
a1 = (uint32_t)(byte_of_aligned_array(aes_sbox,(data[(row+1)%4]>>16)&0xFF));
a2 = (uint32_t)(byte_of_aligned_array(aes_sbox,(data[(row+2)%4]>>8)&0xFF));
a3 = (uint32_t)(byte_of_aligned_array(aes_sbox,(data[(row+3)%4])&0xFF));
/* Perform MixColumn iff not last round */
if (curr_rnd < (rounds - 1))
{
tmp1 = a0 ^ a1 ^ a2 ^ a3;
old_a0 = a0;
a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
}
tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
}
/* KeyAddition - note that it is vital that this loop is separate from
the MixColumn operation, which must be atomic...*/
for (row = 0; row < 4; row++)
data[row] = tmp[row] ^ *(k++);
}
}
/**
* Decrypt a single block (16 bytes) of data
*/
static void ICACHE_FLASH_ATTR AES_decrypt(const AES_CTX *ctx, uint32_t *data)
{
uint32_t tmp[4];
uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
uint32_t a0, a1, a2, a3, row;
int curr_rnd;
int rounds = ctx->rounds;
const uint32_t *k = ctx->ks + ((rounds+1)*4);
/* pre-round key addition */
for (row=4; row > 0;row--)
data[row-1] ^= *(--k);
/* Decrypt one block */
for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
{
/* Perform ByteSub and ShiftRow operations together */
for (row = 4; row > 0; row--)
{
// a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
// a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
// a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
// a3 = aes_isbox[(data[row%4])&0xFF];
a0 = byte_of_aligned_array(aes_isbox,(data[(row+3)%4]>>24)&0xFF);
a1 = byte_of_aligned_array(aes_isbox,(data[(row+2)%4]>>16)&0xFF);
a2 = byte_of_aligned_array(aes_isbox,(data[(row+1)%4]>>8)&0xFF);
a3 = byte_of_aligned_array(aes_isbox,(data[row%4])&0xFF);
/* Perform MixColumn iff not last round */
if (curr_rnd<(rounds-1))
{
/* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
are quite large compared to encryption; this
operation slows decryption down noticeably. */
xt0 = AES_xtime(a0^a1);
xt1 = AES_xtime(a1^a2);
xt2 = AES_xtime(a2^a3);
xt3 = AES_xtime(a3^a0);
xt4 = AES_xtime(xt0^xt1);
xt5 = AES_xtime(xt1^xt2);
xt6 = AES_xtime(xt4^xt5);
xt0 ^= a1^a2^a3^xt4^xt6;
xt1 ^= a0^a2^a3^xt5^xt6;
xt2 ^= a0^a1^a3^xt4^xt6;
xt3 ^= a0^a1^a2^xt5^xt6;
tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);
}
else
tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);
}
for (row = 4; row > 0; row--)
data[row-1] = tmp[row-1] ^ *(--k);
}
}
#endif
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 COPYRIGHT OWNER OR
* CONTRIBUTORS 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.
*/
/**
* @defgroup bigint_api Big Integer API
* @brief The bigint implementation as used by the axTLS project.
*
* The bigint library is for RSA encryption/decryption as well as signing.
* This code tries to minimise use of malloc/free by maintaining a small
* cache. A bigint context may maintain state by being made "permanent".
* It be be later released with a bi_depermanent() and bi_free() call.
*
* It supports the following reduction techniques:
* - Classical
* - Barrett
* - Montgomery
*
* It also implements the following:
* - Karatsuba multiplication
* - Squaring
* - Sliding window exponentiation
* - Chinese Remainder Theorem (implemented in rsa.c).
*
* All the algorithms used are pretty standard, and designed for different
* data bus sizes. Negative numbers are not dealt with at all, so a subtraction
* may need to be tested for negativity.
*
* This library steals some ideas from Jef Poskanzer
* <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
* and GMP <http://www.swox.com/gmp>. It gets most of its implementation
* detail from "The Handbook of Applied Cryptography"
* <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
* @{
*/
//#include <stdlib.h>
//#include <limits.h>
//#include <string.h>
//#include <stdio.h>
//#include <time.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_bigint.h"
//#include "os.h"
#include "lwip/mem.h"
#define V1 v->comps[v->size-1] /**< v1 for division */
#define V2 v->comps[v->size-2] /**< v2 for division */
#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */
#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */
static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);
static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);
static bigint *alloc(BI_CTX *ctx, int size);
static bigint *trim(bigint *bi);
static void more_comps(bigint *bi, int n);
#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
defined(CONFIG_BIGINT_MONTGOMERY)
static bigint *comp_right_shift(bigint *biR, int num_shifts);
static bigint *comp_left_shift(bigint *biR, int num_shifts);
#endif
#ifdef CONFIG_BIGINT_CHECK_ON
static void check(const bigint *bi);
#else
#define check(A) /**< disappears in normal production mode */
#endif
/**
* @brief Start a new bigint context.
* @return A bigint context.
*/
BI_CTX * ICACHE_FLASH_ATTR bi_initialize(void)
{
/* calloc() sets everything to zero */
BI_CTX *ctx = (BI_CTX *)os_zalloc(sizeof(BI_CTX));
/* the radix */
ctx->bi_radix = alloc(ctx, 2);
ctx->bi_radix->comps[0] = 0;
ctx->bi_radix->comps[1] = 1;
bi_permanent(ctx->bi_radix);
return ctx;
}
/**
* @brief Close the bigint context and free any resources.
*
* Free up any used memory - a check is done if all objects were not
* properly freed.
* @param ctx [in] The bigint session context.
*/
void ICACHE_FLASH_ATTR bi_terminate(BI_CTX *ctx)
{
bi_depermanent(ctx->bi_radix);
bi_free(ctx, ctx->bi_radix);
if (ctx->active_count != 0)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf("bi_terminate: there were %d un-freed bigints\n",
ctx->active_count);
#endif
return; /* wujg : org ---> abort(); */
}
bi_clear_cache(ctx);
os_free(ctx);
}
/**
*@brief Clear the memory cache.
*/
void ICACHE_FLASH_ATTR bi_clear_cache(BI_CTX *ctx)
{
bigint *p, *pn;
if (ctx->free_list == NULL)
return;
for (p = ctx->free_list; p != NULL; p = pn)
{
pn = p->next;
os_free(p->comps);
os_free(p);
}
ctx->free_count = 0;
ctx->free_list = NULL;
}
/**
* @brief Increment the number of references to this object.
* It does not do a full copy.
* @param bi [in] The bigint to copy.
* @return A reference to the same bigint.
*/
bigint * ICACHE_FLASH_ATTR bi_copy(bigint *bi)
{
check(bi);
if (bi->refs != PERMANENT)
bi->refs++;
return bi;
}
/**
* @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
*
* For this object to be freed, bi_depermanent() must be called.
* @param bi [in] The bigint to be made permanent.
*/
void ICACHE_FLASH_ATTR bi_permanent(bigint *bi)
{
check(bi);
if (bi->refs != 1)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf("bi_permanent: refs was not 1\n");
#endif
return; /* wujg : org ----> abort(); */
}
bi->refs = PERMANENT;
}
/**
* @brief Take a permanent object and make it eligible for freedom.
* @param bi [in] The bigint to be made back to temporary.
*/
void ICACHE_FLASH_ATTR bi_depermanent(bigint *bi)
{
check(bi);
if (bi->refs != PERMANENT)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf("bi_depermanent: bigint was not permanent\n");
#endif
return; /* wujg : org ----> abort(); */
}
bi->refs = 1;
}
/**
* @brief Free a bigint object so it can be used again.
*
* The memory itself it not actually freed, just tagged as being available
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint to be freed.
*/
void ICACHE_FLASH_ATTR bi_free(BI_CTX *ctx, bigint *bi)
{
check(bi);
if (bi->refs == PERMANENT)
{
return;
}
if (--bi->refs > 0)
{
return;
}
bi->next = ctx->free_list;
ctx->free_list = bi;
ctx->free_count++;
if (--ctx->active_count < 0)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf("bi_free: active_count went negative "
"- double-freed bigint?\n");
#endif
return; /* wujg : org ----> abort(); */
}
}
/**
* @brief Convert an (unsigned) integer into a bigint.
* @param ctx [in] The bigint session context.
* @param i [in] The (unsigned) integer to be converted.
*
*/
bigint * ICACHE_FLASH_ATTR int_to_bi(BI_CTX *ctx, comp i)
{
bigint *biR = alloc(ctx, 1);
biR->comps[0] = i;
return biR;
}
/**
* @brief Do a full copy of the bigint object.
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint object to be copied.
*/
bigint * ICACHE_FLASH_ATTR bi_clone(BI_CTX *ctx, const bigint *bi)
{
bigint *biR = alloc(ctx, bi->size);
check(bi);
os_memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);
return biR;
}
/**
* @brief Perform an addition operation between two bigints.
* @param ctx [in] The bigint session context.
* @param bia [in] A bigint.
* @param bib [in] Another bigint.
* @return The result of the addition.
*/
bigint * ICACHE_FLASH_ATTR bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
{
int n;
comp carry = 0;
comp *pa, *pb;
check(bia);
check(bib);
n = max(bia->size, bib->size);
more_comps(bia, n+1);
more_comps(bib, n);
pa = bia->comps;
pb = bib->comps;
do
{
comp sl, rl, cy1;
sl = *pa + *pb++;
rl = sl + carry;
cy1 = sl < *pa;
carry = cy1 | (rl < sl);
*pa++ = rl;
} while (--n != 0);
*pa = carry; /* do overflow */
bi_free(ctx, bib);
return trim(bia);
}
/**
* @brief Perform a subtraction operation between two bigints.
* @param ctx [in] The bigint session context.
* @param bia [in] A bigint.
* @param bib [in] Another bigint.
* @param is_negative [out] If defined, indicates that the result was negative.
* is_negative may be null.
* @return The result of the subtraction. The result is always positive.
*/
bigint * ICACHE_FLASH_ATTR bi_subtract(BI_CTX *ctx,
bigint *bia, bigint *bib, int *is_negative)
{
int n = bia->size;
comp *pa, *pb, carry = 0;
check(bia);
check(bib);
more_comps(bib, n);
pa = bia->comps;
pb = bib->comps;
do
{
comp sl, rl, cy1;
sl = *pa - *pb++;
rl = sl - carry;
cy1 = sl > *pa;
carry = cy1 | (rl > sl);
*pa++ = rl;
} while (--n != 0);
if (is_negative) /* indicate a negative result */
{
*is_negative = carry;
}
bi_free(ctx, trim(bib)); /* put bib back to the way it was */
return trim(bia);
}
/**
* Perform a multiply between a bigint an an (unsigned) integer
*/
static bigint * ICACHE_FLASH_ATTR bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)
{
int j = 0, n = bia->size;
bigint *biR = alloc(ctx, n + 1);
comp carry = 0;
comp *r = biR->comps;
comp *a = bia->comps;
check(bia);
/* clear things to start with */
os_memset(r, 0, ((n+1)*COMP_BYTE_SIZE));
do
{
long_comp tmp = *r + (long_comp)a[j]*b + carry;
*r++ = (comp)tmp; /* downsize */
carry = (comp)(tmp >> COMP_BIT_SIZE);
} while (++j < n);
*r = carry;
bi_free(ctx, bia);
return trim(biR);
}
/**
* @brief Does both division and modulo calculations.
*
* Used extensively when doing classical reduction.
* @param ctx [in] The bigint session context.
* @param u [in] A bigint which is the numerator.
* @param v [in] Either the denominator or the modulus depending on the mode.
* @param is_mod [n] Determines if this is a normal division (0) or a reduction
* (1).
* @return The result of the division/reduction.
*/
bigint * ICACHE_FLASH_ATTR bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
{
int n = v->size, m = u->size-n;
int j = 0, orig_u_size = u->size;
uint8_t mod_offset = ctx->mod_offset;
comp d;
bigint *quotient, *tmp_u;
comp q_dash;
check(u);
check(v);
/* if doing reduction and we are < mod, then return mod */
if (is_mod && bi_compare(v, u) > 0)
{
bi_free(ctx, v);
return u;
}
quotient = alloc(ctx, m+1);
tmp_u = alloc(ctx, n+1);
v = trim(v); /* make sure we have no leading 0's */
d = (comp)((long_comp)COMP_RADIX/(V1+1));
/* clear things to start with */
os_memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));
/* normalise */
if (d > 1)
{
u = bi_int_multiply(ctx, u, d);
if (is_mod)
{
v = ctx->bi_normalised_mod[mod_offset];
}
else
{
v = bi_int_multiply(ctx, v, d);
}
}
if (orig_u_size == u->size) /* new digit position u0 */
{
more_comps(u, orig_u_size + 1);
}
do
{
/* get a temporary short version of u */
os_memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);
/* calculate q' */
if (U(0) == V1)
{
q_dash = COMP_RADIX-1;
}
else
{
q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);
if (v->size > 1 && V2)
{
/* we are implementing the following:
if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) -
q_dash*V1)*COMP_RADIX) + U(2))) ... */
comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) -
(long_comp)q_dash*V1);
if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))
{
q_dash--;
}
}
}
/* multiply and subtract */
if (q_dash)
{
int is_negative;
tmp_u = bi_subtract(ctx, tmp_u,
bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);
more_comps(tmp_u, n+1);
Q(j) = q_dash;
/* add back */
if (is_negative)
{
Q(j)--;
tmp_u = bi_add(ctx, tmp_u, bi_copy(v));
/* lop off the carry */
tmp_u->size--;
v->size--;
}
}
else
{
Q(j) = 0;
}
/* copy back to u */
os_memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);
} while (++j <= m);
bi_free(ctx, tmp_u);
bi_free(ctx, v);
if (is_mod) /* get the remainder */
{
bi_free(ctx, quotient);
return bi_int_divide(ctx, trim(u), d);
}
else /* get the quotient */
{
bi_free(ctx, u);
return trim(quotient);
}
}
/*
* Perform an integer divide on a bigint.
*/
static bigint * ICACHE_FLASH_ATTR bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom)
{
int i = biR->size - 1;
long_comp r = 0;
check(biR);
do
{
r = (r<<COMP_BIT_SIZE) + biR->comps[i];
biR->comps[i] = (comp)(r / denom);
r %= denom;
} while (--i >= 0);
return trim(biR);
}
#ifdef CONFIG_BIGINT_MONTGOMERY
/**
* There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1,
* where B^-1(B-1) mod N=1. Actually, only the least significant part of
* N' is needed, hence the definition N0'=N' mod b. We reproduce below the
* simple algorithm from an article by Dusse and Kaliski to efficiently
* find N0' from N0 and b */
static comp ICACHE_FLASH_ATTR modular_inverse(bigint *bim)
{
int i;
comp t = 1;
comp two_2_i_minus_1 = 2; /* 2^(i-1) */
long_comp two_2_i = 4; /* 2^i */
comp N = bim->comps[0];
for (i = 2; i <= COMP_BIT_SIZE; i++)
{
if ((long_comp)N*t%two_2_i >= two_2_i_minus_1)
{
t += two_2_i_minus_1;
}
two_2_i_minus_1 <<= 1;
two_2_i <<= 1;
}
return (comp)(COMP_RADIX-t);
}
#endif
#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
defined(CONFIG_BIGINT_MONTGOMERY)
/**
* Take each component and shift down (in terms of components)
*/
static bigint * ICACHE_FLASH_ATTR comp_right_shift(bigint *biR, int num_shifts)
{
int i = biR->size-num_shifts;
comp *x = biR->comps;
comp *y = &biR->comps[num_shifts];
check(biR);
if (i <= 0) /* have we completely right shifted? */
{
biR->comps[0] = 0; /* return 0 */
biR->size = 1;
return biR;
}
do
{
*x++ = *y++;
} while (--i > 0);
biR->size -= num_shifts;
return biR;
}
/**
* Take each component and shift it up (in terms of components)
*/
static bigint * ICACHE_FLASH_ATTR comp_left_shift(bigint *biR, int num_shifts)
{
int i = biR->size-1;
comp *x, *y;
check(biR);
if (num_shifts <= 0)
{
return biR;
}
more_comps(biR, biR->size + num_shifts);
x = &biR->comps[i+num_shifts];
y = &biR->comps[i];
do
{
*x-- = *y--;
} while (i--);
os_memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */
return biR;
}
#endif
/**
* @brief Allow a binary sequence to be imported as a bigint.
* @param ctx [in] The bigint session context.
* @param data [in] The data to be converted.
* @param size [in] The number of bytes of data.
* @return A bigint representing this data.
*/
bigint * ICACHE_FLASH_ATTR bi_import(BI_CTX *ctx, const uint8_t *data, int size)
{
bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);
int i, j = 0, offset = 0;
os_memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
for (i = size-1; i >= 0; i--)
{
biR->comps[offset] += data[i] << (j*8);
if (++j == COMP_BYTE_SIZE)
{
j = 0;
offset ++;
}
}
return trim(biR);
}
#ifdef CONFIG_SSL_FULL_MODE
/**
* @brief The testharness uses this code to import text hex-streams and
* convert them into bigints.
* @param ctx [in] The bigint session context.
* @param data [in] A string consisting of hex characters. The characters must
* be in upper case.
* @return A bigint representing this data.
*/
bigint * ICACHE_FLASH_ATTR bi_str_import(BI_CTX *ctx, const char *data)
{
int size = os_strlen(data);
bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES);
int i, j = 0, offset = 0;
os_memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
for (i = size-1; i >= 0; i--)
{
int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10);
biR->comps[offset] += num << (j*4);
if (++j == COMP_NUM_NIBBLES)
{
j = 0;
offset ++;
}
}
return biR;
}
void ICACHE_FLASH_ATTR bi_print(const char *label, bigint *x)
{
int i, j;
if (x == NULL)
{
ssl_printf("%s: (null)\n", label);
return;
}
ssl_printf("%s: (size %d)\n", label, x->size);
for (i = x->size-1; i >= 0; i--)
{
for (j = COMP_NUM_NIBBLES-1; j >= 0; j--)
{
comp mask = 0x0f << (j*4);
comp num = (x->comps[i] & mask) >> (j*4);
os_putc((num <= 9) ? (num + '0') : (num + 'A' - 10));
}
}
ssl_printf("\n");
}
#endif
/**
* @brief Take a bigint and convert it into a byte sequence.
*
* This is useful after a decrypt operation.
* @param ctx [in] The bigint session context.
* @param x [in] The bigint to be converted.
* @param data [out] The converted data as a byte stream.
* @param size [in] The maximum size of the byte stream. Unused bytes will be
* zeroed.
*/
void ICACHE_FLASH_ATTR bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
{
int i, j, k = size-1;
check(x);
os_memset(data, 0, size); /* ensure all leading 0's are cleared */
for (i = 0; i < x->size; i++)
{
for (j = 0; j < COMP_BYTE_SIZE; j++)
{
comp mask = 0xff << (j*8);
int num = (x->comps[i] & mask) >> (j*8);
data[k--] = num;
if (k < 0)
{
goto buf_done;
}
}
}
buf_done:
bi_free(ctx, x);
}
/**
* @brief Pre-calculate some of the expensive steps in reduction.
*
* This function should only be called once (normally when a session starts).
* When the session is over, bi_free_mod() should be called. bi_mod_power()
* relies on this function being called.
* @param ctx [in] The bigint session context.
* @param bim [in] The bigint modulus that will be used.
* @param mod_offset [in] There are three moduluii that can be stored - the
* standard modulus, and its two primes p and q. This offset refers to which
* modulus we are referring to.
* @see bi_free_mod(), bi_mod_power().
*/
void ICACHE_FLASH_ATTR bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)
{
int k = bim->size;
comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));
#ifdef CONFIG_BIGINT_MONTGOMERY
bigint *R, *R2;
#endif
ctx->bi_mod[mod_offset] = bim;
bi_permanent(ctx->bi_mod[mod_offset]);
ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);
bi_permanent(ctx->bi_normalised_mod[mod_offset]);
#if defined(CONFIG_BIGINT_MONTGOMERY)
/* set montgomery variables */
R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1); /* R */
R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1); /* R^2 */
ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */
ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */
bi_permanent(ctx->bi_RR_mod_m[mod_offset]);
bi_permanent(ctx->bi_R_mod_m[mod_offset]);
ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]);
#elif defined (CONFIG_BIGINT_BARRETT)
ctx->bi_mu[mod_offset] =
bi_divide(ctx, comp_left_shift(
bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0);
bi_permanent(ctx->bi_mu[mod_offset]);
#endif
}
/**
* @brief Used when cleaning various bigints at the end of a session.
* @param ctx [in] The bigint session context.
* @param mod_offset [in] The offset to use.
* @see bi_set_mod().
*/
void ICACHE_FLASH_ATTR bi_free_mod(BI_CTX *ctx, int mod_offset)
{
bi_depermanent(ctx->bi_mod[mod_offset]);
bi_free(ctx, ctx->bi_mod[mod_offset]);
#if defined (CONFIG_BIGINT_MONTGOMERY)
bi_depermanent(ctx->bi_RR_mod_m[mod_offset]);
bi_depermanent(ctx->bi_R_mod_m[mod_offset]);
bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]);
bi_free(ctx, ctx->bi_R_mod_m[mod_offset]);
#elif defined(CONFIG_BIGINT_BARRETT)
bi_depermanent(ctx->bi_mu[mod_offset]);
bi_free(ctx, ctx->bi_mu[mod_offset]);
#endif
bi_depermanent(ctx->bi_normalised_mod[mod_offset]);
bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
}
/**
* Perform a standard multiplication between two bigints.
*
* Barrett reduction has no need for some parts of the product, so ignore bits
* of the multiply. This routine gives Barrett its big performance
* improvements over Classical/Montgomery reduction methods.
*/
static bigint * ICACHE_FLASH_ATTR regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib,
int inner_partial, int outer_partial)
{
int i = 0, j;
int n = bia->size;
int t = bib->size;
bigint *biR = alloc(ctx, n + t);
comp *sr = biR->comps;
comp *sa = bia->comps;
comp *sb = bib->comps;
check(bia);
check(bib);
/* clear things to start with */
os_memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));
do
{
long_comp tmp;
comp carry = 0;
int r_index = i;
j = 0;
if (outer_partial && outer_partial-i > 0 && outer_partial < n)
{
r_index = outer_partial-1;
j = outer_partial-i-1;
}
do
{
if (inner_partial && r_index >= inner_partial)
{
break;
}
tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry;
sr[r_index++] = (comp)tmp; /* downsize */
carry = tmp >> COMP_BIT_SIZE;
} while (++j < n);
sr[r_index] = carry;
} while (++i < t);
bi_free(ctx, bia);
bi_free(ctx, bib);
return trim(biR);
}
#ifdef CONFIG_BIGINT_KARATSUBA
/*
* Karatsuba improves on regular multiplication due to only 3 multiplications
* being done instead of 4. The additional additions/subtractions are O(N)
* rather than O(N^2) and so for big numbers it saves on a few operations
*/
static bigint * ICACHE_FLASH_ATTR karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square)
{
bigint *x0, *x1;
bigint *p0, *p1, *p2;
int m;
if (is_square)
{
m = (bia->size + 1)/2;
}
else
{
m = (max(bia->size, bib->size) + 1)/2;
}
x0 = bi_clone(ctx, bia);
x0->size = m;
x1 = bi_clone(ctx, bia);
comp_right_shift(x1, m);
bi_free(ctx, bia);
/* work out the 3 partial products */
if (is_square)
{
p0 = bi_square(ctx, bi_copy(x0));
p2 = bi_square(ctx, bi_copy(x1));
p1 = bi_square(ctx, bi_add(ctx, x0, x1));
}
else /* normal multiply */
{
bigint *y0, *y1;
y0 = bi_clone(ctx, bib);
y0->size = m;
y1 = bi_clone(ctx, bib);
comp_right_shift(y1, m);
bi_free(ctx, bib);
p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0));
p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1));
p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1));
}
p1 = bi_subtract(ctx,
bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL);
comp_left_shift(p1, m);
comp_left_shift(p2, 2*m);
return bi_add(ctx, p1, bi_add(ctx, p0, p2));
}
#endif
/**
* @brief Perform a multiplication operation between two bigints.
* @param ctx [in] The bigint session context.
* @param bia [in] A bigint.
* @param bib [in] Another bigint.
* @return The result of the multiplication.
*/
bigint * ICACHE_FLASH_ATTR bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
{
check(bia);
check(bib);
#ifdef CONFIG_BIGINT_KARATSUBA
if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH)
{
return regular_multiply(ctx, bia, bib, 0, 0);
}
return karatsuba(ctx, bia, bib, 0);
#else
return regular_multiply(ctx, bia, bib, 0, 0);
#endif
}
#ifdef CONFIG_BIGINT_SQUARE
/*
* Perform the actual square operion. It takes into account overflow.
*/
static bigint * ICACHE_FLASH_ATTR regular_square(BI_CTX *ctx, bigint *bi)
{
int t = bi->size;
int i = 0, j;
bigint *biR = alloc(ctx, t*2+1);
comp *w = biR->comps;
comp *x = bi->comps;
long_comp carry;
os_memset(w, 0, biR->size*COMP_BYTE_SIZE);
do
{
long_comp tmp = w[2*i] + (long_comp)x[i]*x[i];
w[2*i] = (comp)tmp;
carry = tmp >> COMP_BIT_SIZE;
for (j = i+1; j < t; j++)
{
uint8_t c = 0;
long_comp xx = (long_comp)x[i]*x[j];
if ((COMP_MAX-xx) < xx)
c = 1;
tmp = (xx<<1);
if ((COMP_MAX-tmp) < w[i+j])
c = 1;
tmp += w[i+j];
if ((COMP_MAX-tmp) < carry)
c = 1;
tmp += carry;
w[i+j] = (comp)tmp;
carry = tmp >> COMP_BIT_SIZE;
if (c)
carry += COMP_RADIX;
}
tmp = w[i+t] + carry;
w[i+t] = (comp)tmp;
w[i+t+1] = tmp >> COMP_BIT_SIZE;
} while (++i < t);
bi_free(ctx, bi);
return trim(biR);
}
/**
* @brief Perform a square operation on a bigint.
* @param ctx [in] The bigint session context.
* @param bia [in] A bigint.
* @return The result of the multiplication.
*/
bigint * ICACHE_FLASH_ATTR bi_square(BI_CTX *ctx, bigint *bia)
{
check(bia);
#ifdef CONFIG_BIGINT_KARATSUBA
if (bia->size < SQU_KARATSUBA_THRESH)
{
return regular_square(ctx, bia);
}
return karatsuba(ctx, bia, NULL, 1);
#else
return regular_square(ctx, bia);
#endif
}
#endif
/**
* @brief Compare two bigints.
* @param bia [in] A bigint.
* @param bib [in] Another bigint.
* @return -1 if smaller, 1 if larger and 0 if equal.
*/
int ICACHE_FLASH_ATTR bi_compare(bigint *bia, bigint *bib)
{
int r, i;
check(bia);
check(bib);
if (bia->size > bib->size)
r = 1;
else if (bia->size < bib->size)
r = -1;
else
{
comp *a = bia->comps;
comp *b = bib->comps;
/* Same number of components. Compare starting from the high end
* and working down. */
r = 0;
i = bia->size - 1;
do
{
if (a[i] > b[i])
{
r = 1;
break;
}
else if (a[i] < b[i])
{
r = -1;
break;
}
} while (--i >= 0);
}
return r;
}
/*
* Allocate and zero more components. Does not consume bi.
*/
static void ICACHE_FLASH_ATTR more_comps(bigint *bi, int n)
{
if (n > bi->max_comps)
{
bi->max_comps = max(bi->max_comps * 2, n);
bi->comps = (comp*)os_realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);
}
if (n > bi->size)
{
os_memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);
}
bi->size = n;
}
/*
* Make a new empty bigint. It may just use an old one if one is available.
* Otherwise get one off the heap.
*/
static bigint * ICACHE_FLASH_ATTR alloc(BI_CTX *ctx, int size)
{
bigint *biR;
/* Can we recycle an old bigint? */
if (ctx->free_list != NULL)
{
biR = ctx->free_list;
ctx->free_list = biR->next;
ctx->free_count--;
if (biR->refs != 0)
{
#ifdef CONFIG_SSL_FULL_MODE
ssl_printf("alloc: refs was not 0\n");
#endif
return; /* wujg : org ----> abort(); */
}
more_comps(biR, size);
}
else
{
/* No free bigints available - create a new one. */
biR = (bigint *)os_malloc(sizeof(bigint));
biR->comps = (comp*)os_malloc(size * COMP_BYTE_SIZE);
biR->max_comps = size; /* give some space to spare */
}
biR->size = size;
biR->refs = 1;
biR->next = NULL;
ctx->active_count++;
return biR;
}
/*
* Work out the highest '1' bit in an exponent. Used when doing sliding-window
* exponentiation.
*/
static int ICACHE_FLASH_ATTR find_max_exp_index(bigint *biexp)
{
int i = COMP_BIT_SIZE-1;
comp shift = COMP_RADIX/2;
comp test = biexp->comps[biexp->size-1]; /* assume no leading zeroes */
check(biexp);
do
{
if (test & shift)
{
return i+(biexp->size-1)*COMP_BIT_SIZE;
}
shift >>= 1;
} while (i-- != 0);
return -1; /* error - must have been a leading 0 */
}
/*
* Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
* exponentiation.
*/
static int ICACHE_FLASH_ATTR exp_bit_is_one(bigint *biexp, int offset)
{
comp test = biexp->comps[offset / COMP_BIT_SIZE];
int num_shifts = offset % COMP_BIT_SIZE;
comp shift = 1;
int i;
check(biexp);
for (i = 0; i < num_shifts; i++)
{
shift <<= 1;
}
return (test & shift) != 0;
}
#ifdef CONFIG_BIGINT_CHECK_ON
/*
* Perform a sanity check on bi.
*/
static void ICACHE_FLASH_ATTR check(const bigint *bi)
{
if (bi->refs <= 0)
{
ssl_printf("check: zero or negative refs in bigint\n");
return; /* wujg : org ----> abort(); */
}
if (bi->next != NULL)
{
ssl_printf("check: attempt to use a bigint from "
"the free list\n");
return; /* wujg : org ----> abort(); */
}
}
#endif
/*
* Delete any leading 0's (and allow for 0).
*/
static bigint * ICACHE_FLASH_ATTR trim(bigint *bi)
{
check(bi);
while (bi->comps[bi->size-1] == 0 && bi->size > 1)
{
bi->size--;
}
return bi;
}
#if defined(CONFIG_BIGINT_MONTGOMERY)
/**
* @brief Perform a single montgomery reduction.
* @param ctx [in] The bigint session context.
* @param bixy [in] A bigint.
* @return The result of the montgomery reduction.
*/
bigint * ICACHE_FLASH_ATTR bi_mont(BI_CTX *ctx, bigint *bixy)
{
int i = 0, n;
uint8_t mod_offset = ctx->mod_offset;
bigint *bim = ctx->bi_mod[mod_offset];
comp mod_inv = ctx->N0_dash[mod_offset];
check(bixy);
if (ctx->use_classical) /* just use classical instead */
{
return bi_mod(ctx, bixy);
}
n = bim->size;
do
{
bixy = bi_add(ctx, bixy, comp_left_shift(
bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i));
} while (++i < n);
comp_right_shift(bixy, n);
if (bi_compare(bixy, bim) >= 0)
{
bixy = bi_subtract(ctx, bixy, bim, NULL);
}
return bixy;
}
#elif defined(CONFIG_BIGINT_BARRETT)
/*
* Stomp on the most significant components to give the illusion of a "mod base
* radix" operation
*/
static bigint * ICACHE_FLASH_ATTR comp_mod(bigint *bi, int mod)
{
check(bi);
if (bi->size > mod)
{
bi->size = mod;
}
return bi;
}
/**
* @brief Perform a single Barrett reduction.
* @param ctx [in] The bigint session context.
* @param bi [in] A bigint.
* @return The result of the Barrett reduction.
*/
bigint * ICACHE_FLASH_ATTR bi_barrett(BI_CTX *ctx, bigint *bi)
{
bigint *q1, *q2, *q3, *r1, *r2, *r;
uint8_t mod_offset = ctx->mod_offset;
bigint *bim = ctx->bi_mod[mod_offset];
int k = bim->size;
check(bi);
check(bim);
/* use Classical method instead - Barrett cannot help here */
if (bi->size > k*2)
{
return bi_mod(ctx, bi);
}
q1 = comp_right_shift(bi_clone(ctx, bi), k-1);
/* do outer partial multiply */
q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1);
q3 = comp_right_shift(q2, k+1);
r1 = comp_mod(bi, k+1);
/* do inner partial multiply */
r2 = comp_mod(regular_multiply(ctx, q3, bim, k+1, 0), k+1);
r = bi_subtract(ctx, r1, r2, NULL);
/* if (r >= m) r = r - m; */
if (bi_compare(r, bim) >= 0)
{
r = bi_subtract(ctx, r, bim, NULL);
}
return r;
}
#endif /* CONFIG_BIGINT_BARRETT */
#ifdef CONFIG_BIGINT_SLIDING_WINDOW
/*
* Work out g1, g3, g5, g7... etc for the sliding-window algorithm
*/
static void ICACHE_FLASH_ATTR precompute_slide_window(BI_CTX *ctx, int window, bigint *g1)
{
int k = 1, i;
bigint *g2;
for (i = 0; i < window-1; i++) /* compute 2^(window-1) */
{
k <<= 1;
}
ctx->g = (bigint **)os_malloc(k*sizeof(bigint *));
ctx->g[0] = bi_clone(ctx, g1);
bi_permanent(ctx->g[0]);
g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */
for (i = 1; i < k; i++)
{
ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2)));
bi_permanent(ctx->g[i]);
}
bi_free(ctx, g2);
ctx->window = k;
}
#endif
/**
* @brief Perform a modular exponentiation.
*
* This function requires bi_set_mod() to have been called previously. This is
* one of the optimisations used for performance.
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint on which to perform the mod power operation.
* @param biexp [in] The bigint exponent.
* @return The result of the mod exponentiation operation
* @see bi_set_mod().
*/
bigint * ICACHE_FLASH_ATTR bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
{
int i = find_max_exp_index(biexp), j, window_size = 1;
bigint *biR = int_to_bi(ctx, 1);
#if defined(CONFIG_BIGINT_MONTGOMERY)
uint8_t mod_offset = ctx->mod_offset;
if (!ctx->use_classical)
{
/* preconvert */
bi = bi_mont(ctx,
bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */
bi_free(ctx, biR);
biR = ctx->bi_R_mod_m[mod_offset]; /* A */
}
#endif
check(bi);
check(biexp);
#ifdef CONFIG_BIGINT_SLIDING_WINDOW
for (j = i; j > 32; j /= 5) /* work out an optimum size */
window_size++;
/* work out the slide constants */
precompute_slide_window(ctx, window_size, bi);
#else /* just one constant */
ctx->g = (bigint **)os_malloc(sizeof(bigint *));
ctx->g[0] = bi_clone(ctx, bi);
ctx->window = 1;
bi_permanent(ctx->g[0]);
#endif
/* if sliding-window is off, then only one bit will be done at a time and
* will reduce to standard left-to-right exponentiation */
do
{
if (exp_bit_is_one(biexp, i))
{
int l = i-window_size+1;
int part_exp = 0;
if (l < 0) /* LSB of exponent will always be 1 */
l = 0;
else
{
while (exp_bit_is_one(biexp, l) == 0)
l++; /* go back up */
}
/* build up the section of the exponent */
for (j = i; j >= l; j--)
{
biR = bi_residue(ctx, bi_square(ctx, biR));
if (exp_bit_is_one(biexp, j))
part_exp++;
if (j != l)
part_exp <<= 1;
}
part_exp = (part_exp-1)/2; /* adjust for array */
biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp]));
i = l-1;
}
else /* square it */
{
biR = bi_residue(ctx, bi_square(ctx, biR));
i--;
}
} while (i >= 0);
/* cleanup */
for (i = 0; i < ctx->window; i++)
{
bi_depermanent(ctx->g[i]);
bi_free(ctx, ctx->g[i]);
}
os_free(ctx->g);
bi_free(ctx, bi);
bi_free(ctx, biexp);
#if defined CONFIG_BIGINT_MONTGOMERY
return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */
#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */
return biR;
#endif
}
#ifdef CONFIG_SSL_CERT_VERIFICATION
/**
* @brief Perform a modular exponentiation using a temporary modulus.
*
* We need this function to check the signatures of certificates. The modulus
* of this function is temporary as it's just used for authentication.
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint to perform the exp/mod.
* @param bim [in] The temporary modulus.
* @param biexp [in] The bigint exponent.
* @return The result of the mod exponentiation operation
* @see bi_set_mod().
*/
bigint * ICACHE_FLASH_ATTR bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp)
{
bigint *biR, *tmp_biR;
/* Set up a temporary bigint context and transfer what we need between
* them. We need to do this since we want to keep the original modulus
* which is already in this context. This operation is only called when
* doing peer verification, and so is not expensive :-) */
BI_CTX *tmp_ctx = bi_initialize();
bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET);
tmp_biR = bi_mod_power(tmp_ctx,
bi_clone(tmp_ctx, bi),
bi_clone(tmp_ctx, biexp));
biR = bi_clone(ctx, tmp_biR);
bi_free(tmp_ctx, tmp_biR);
bi_free_mod(tmp_ctx, BIGINT_M_OFFSET);
bi_terminate(tmp_ctx);
bi_free(ctx, bi);
bi_free(ctx, bim);
bi_free(ctx, biexp);
return biR;
}
#endif
#ifdef CONFIG_BIGINT_CRT
/**
* @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
*
* @param ctx [in] The bigint session context.
* @param bi [in] The bigint to perform the exp/mod.
* @param dP [in] CRT's dP bigint
* @param dQ [in] CRT's dQ bigint
* @param p [in] CRT's p bigint
* @param q [in] CRT's q bigint
* @param qInv [in] CRT's qInv bigint
* @return The result of the CRT operation
*/
bigint * ICACHE_FLASH_ATTR bi_crt(BI_CTX *ctx, bigint *bi,
bigint *dP, bigint *dQ,
bigint *p, bigint *q, bigint *qInv)
{
bigint *m1, *m2, *h;
/* Montgomery has a condition the 0 < x, y < m and these products violate
* that condition. So disable Montgomery when using CRT */
#if defined(CONFIG_BIGINT_MONTGOMERY)
ctx->use_classical = 1;
#endif
ctx->mod_offset = BIGINT_P_OFFSET;
m1 = bi_mod_power(ctx, bi_copy(bi), dP);
ctx->mod_offset = BIGINT_Q_OFFSET;
m2 = bi_mod_power(ctx, bi, dQ);
h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL);
h = bi_multiply(ctx, h, qInv);
ctx->mod_offset = BIGINT_P_OFFSET;
h = bi_residue(ctx, h);
#if defined(CONFIG_BIGINT_MONTGOMERY)
ctx->use_classical = 0; /* reset for any further operation */
#endif
return bi_add(ctx, m2, bi_multiply(ctx, q, h));
}
#endif
/** @} */
/*
* Copyright (c) 2007, Cameron Rich
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 COPYRIGHT OWNER OR
* CONTRIBUTORS 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.
*/
/**
* Some misc. routines to help things out
*/
#include <stdlib.h>
//#include <string.h>
//#include <stdarg.h>
//#include <stdio.h>
#include "ssl/ssl_os_port.h"
#include "ssl/ssl_crypto_misc.h"
#ifdef CONFIG_WIN32_USE_CRYPTO_LIB
#include "wincrypt.h"
#endif
#ifndef WIN32
static int rng_fd = -1;
#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
static HCRYPTPROV gCryptProv;
#endif
#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
/* change to processor registers as appropriate */
#define ENTROPY_POOL_SIZE 32
#define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec)
#define ENTROPY_COUNTER2 rand()
static uint8_t entropy_pool[ENTROPY_POOL_SIZE];
#endif
const char * const unsupported_str = "Error: Feature not supported\n";
#ifndef CONFIG_SSL_SKELETON_MODE
/**
* Retrieve a file and put it into memory
* @return The size of the file, or -1 on failure.
*/
int get_file(const char *filename, uint8_t **buf)
{
#if 0
int total_bytes = 0;
int bytes_read = 0;
int filesize;
FILE *stream = fopen(filename, "rb");
if (stream == NULL)
{
#ifdef CONFIG_SSL_FULL_MODE
printf("file '%s' does not exist\n", filename); //TTY_FLUSH();
#endif
return -1;
}
/* Win CE doesn't support stat() */
fseek(stream, 0, SEEK_END);
filesize = ftell(stream);
*buf = (uint8_t *)os_malloc(filesize);
fseek(stream, 0, SEEK_SET);
do
{
bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
total_bytes += bytes_read;
} while (total_bytes < filesize && bytes_read > 0);
fclose(stream);
return filesize;
#endif
return 0;
}
#endif
/**
* Initialise the Random Number Generator engine.
* - On Win32 use the platform SDK's crypto engine.
* - On Linux use /dev/urandom
* - If none of these work then use a custom RNG.
*/
EXP_FUNC void STDCALL ICACHE_FLASH_ATTR RNG_initialize()
{
#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
rng_fd = ax_open("/dev/urandom", O_RDONLY);
#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
if (!CryptAcquireContext(&gCryptProv,
NULL, NULL, PROV_RSA_FULL, 0))
{
if (GetLastError() == NTE_BAD_KEYSET &&
!CryptAcquireContext(&gCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
printf("CryptoLib: %x\n", unsupported_str, GetLastError());
exit(1);
}
}
#else
/* start of with a stack to copy across */
int i;
os_memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE);
srand((unsigned int)&i);
#endif
}
/**
* If no /dev/urandom, then initialise the RNG with something interesting.
*/
EXP_FUNC void STDCALL ICACHE_FLASH_ATTR RNG_custom_init(const uint8_t *seed_buf, int size)
{
#if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB)
int i;
for (i = 0; i < ENTROPY_POOL_SIZE && i < size; i++)
entropy_pool[i] ^= seed_buf[i];
#endif
}
/**
* Terminate the RNG engine.
*/
EXP_FUNC void STDCALL ICACHE_FLASH_ATTR RNG_terminate(void)
{
#ifndef WIN32
// close(rng_fd);
#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
CryptReleaseContext(gCryptProv, 0);
#endif
}
/**
* Set a series of bytes with a random number. Individual bytes can be 0
*/
EXP_FUNC void STDCALL ICACHE_FLASH_ATTR get_random(int num_rand_bytes, uint8_t *rand_data)
{
#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
/* use the Linux default */
read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */
#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
/* use Microsoft Crypto Libraries */
CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
#else /* nothing else to use, so use a custom RNG */
/* The method we use when we've got nothing better. Use RC4, time
and a couple of random seeds to generate a random sequence */
RC4_CTX rng_ctx;
struct timeval tv;
MD5_CTX rng_digest_ctx;
uint8_t digest[MD5_SIZE];
uint64_t *ep;
int i;
/* A proper implementation would use counters etc for entropy */
// gettimeofday(&tv, NULL);
ep = (uint64_t *)entropy_pool;
ep[0] ^= ENTROPY_COUNTER1;
ep[1] ^= ENTROPY_COUNTER2;
/* use a digested version of the entropy pool as a key */
MD5_Init(&rng_digest_ctx);
MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE);
MD5_Final(digest, &rng_digest_ctx);
/* come up with the random sequence */
RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */
os_memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ?
num_rand_bytes : ENTROPY_POOL_SIZE);
RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);
/* move things along */
for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--)
entropy_pool[i] = entropy_pool[i-MD5_SIZE];
/* insert the digest at the start of the entropy pool */
os_memcpy(entropy_pool, digest, MD5_SIZE);
#endif
}
/**
* Set a series of bytes with a random number. Individual bytes are not zero.
*/
void ICACHE_FLASH_ATTR get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
{
int i;
get_random(num_rand_bytes, rand_data);
for (i = 0; i < num_rand_bytes; i++)
{
while (rand_data[i] == 0) /* can't be 0 */
rand_data[i] = (uint8_t)(rand());
}
}
/**
* Some useful diagnostic routines
*/
#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
int hex_finish;
int hex_index;
static void ICACHE_FLASH_ATTR print_hex_init(int finish)
{
hex_finish = finish;
hex_index = 0;
}
static void ICACHE_FLASH_ATTR print_hex(uint8_t hex)
{
static int column;
if (hex_index == 0)
{
column = 0;
}
ssl_printf("%02x ", hex);
if (++column == 8)
{
ssl_printf(": ");
}
else if (column >= 16)
{
ssl_printf("\n");
column = 0;
}
if (++hex_index >= hex_finish && column > 0)
{
ssl_printf("\n");
}
}
/**
* Spit out a blob of data for diagnostics. The data is is a nice column format
* for easy reading.
*
* @param format [in] The string (with possible embedded format characters)
* @param size [in] The number of numbers to print
* @param data [in] The start of data to use
* @param ... [in] Any additional arguments
*/
EXP_FUNC void STDCALL ICACHE_FLASH_ATTR print_blob(const char *format,
const uint8_t *data, int size, ...)
{
// int i;
// char tmp[80];
// va_list(ap);
// va_start(ap, size);
// sprintf(tmp, "%s\n", format);
// vprintf(tmp, ap);
// print_hex_init(size);
// for (i = 0; i < size; i++)
// {
// print_hex(data[i]);
// }
// va_end(ap);
// TTY_FLUSH();
}
#elif defined(WIN32)
/* VC6.0 doesn't handle variadic macros */
EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,
int size, ...) {}
#endif
#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
/* base64 to binary lookup table */
static const uint8_t map[128] =
{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 255, 255, 255, 255, 255
};
EXP_FUNC int STDCALL ICACHE_FLASH_ATTR base64_decode(const char *in, int len,
uint8_t *out, int *outlen)
{
int g, t, x, y, z;
uint8_t c;
int ret = -1;
g = 3;
for (x = y = z = t = 0; x < len; x++)
{
if ((c = map[in[x]&0x7F]) == 0xff)
continue;
if (c == 254) /* this is the end... */
{
c = 0;
if (--g < 0)
goto error;
}
else if (g != 3) /* only allow = at end */
goto error;
t = (t<<6) | c;
if (++y == 4)
{
out[z++] = (uint8_t)((t>>16)&255);
if (g > 1)
out[z++] = (uint8_t)((t>>8)&255);
if (g > 2)
out[z++] = (uint8_t)(t&255);
y = t = 0;
}
/* check that we don't go past the output buffer */
if (z > *outlen)
goto error;
}
if (y != 0)
goto error;
*outlen = z;
ret = 0;
error:
#ifdef CONFIG_SSL_FULL_MODE
if (ret < 0)
ssl_printf("Error: Invalid base64\n"); //TTY_FLUSH();
#endif
//TTY_FLUSH();
return ret;
}
#endif
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